처리중입니다. 잠시만 기다려주세요.
TTJ 코딩클래스
정규반 단과 자료실 테크 뉴스 코딩 퀴즈
테크 뉴스
Hacker News 2026.04.24 33
#AI

CSS 상태를 예측 가능하게 만들기까지, 한 개발자가 수년간 헤맨 이야기

Hacker News 원문 보기
CSS 상태를 예측 가능하게 만들기까지, 한 개발자가 수년간 헤맨 이야기

CSS 상태는 왜 이렇게 꼬일까

프론트엔드를 해본 분이라면 한 번쯤 겪어보셨을 거예요. 버튼 하나에 :hover, :focus, :active, :disabled, aria-expanded="true" 같은 상태가 겹치면서, 어느 순간 "왜 호버하면 이 색이 나와야 하는데 저 색이 나오지?" 하고 머리를 쥐어뜯게 되는 상황이요. 한 개발자가 수년간 이 문제와 씨름하면서 "CSS 상태를 예측 가능하게 만드는 방법"을 탐구한 긴 회고 글을 공개했어요.

글쓴이는 처음엔 BEM이나 OOCSS 같은 고전적인 방법론으로 시작했대요. .button--primary.is-hover 이런 식으로 클래스를 붙여 관리하는 방식이죠. 그런데 상태가 늘어날수록 클래스가 기하급수적으로 늘어나고, 모디파이어(수식 클래스) 조합이 폭발하면서 유지보수가 불가능해지는 경험을 했다고 해요.

핵심 문제: 상태의 조합 폭발

이게 뭐가 그렇게 어려운 문제냐면, CSS에서 상태는 곱집합이에요. 버튼에 4가지 크기, 3가지 색상, 5가지 인터랙션 상태가 있다고 하면 4×3×5=60가지 조합이 생기거든요. 그리고 CSS의 캐스케이드(cascade, 선택자 우선순위 규칙) 특성상 어떤 규칙이 이겼는지 추적하기가 쉽지 않아요. 특히 :hover:focus-visible, [aria-pressed="true"] 같은 게 겹치면 어느 규칙이 실제로 적용되는지 개발자 도구를 한참 들여다봐야 해요.

글쓴이는 이 문제를 풀려고 여러 접근을 시도했어요. CSS 변수(Custom Properties)를 상태별로 토글하는 방식, 컴포넌트 루트에서 데이터 속성(data-state="hover")을 관리하는 방식, 심지어 JS로 상태를 직접 계산해서 스타일을 주입하는 방식까지요. 각 방식은 장단점이 있었는데, 결국 도달한 결론은 "상태를 한 곳에서 명시적으로 정의하고, 스타일은 그 상태에 반응만 하도록 분리하자"는 거였어요.

구체적으로는 상태 변수를 컴포넌트 최상단에 --is-hover: 0, --is-focus: 0, --is-pressed: 0 같은 형태로 선언해두고, 실제 CSS 선택자(:hover, :focus-visible, [aria-pressed="true"])는 이 변수를 1로 바꾸는 역할만 하게 해요. 그런 다음 색상이나 그림자 같은 값은 calc()와 변수 조합으로 계산하게 만드는 패턴이에요. 이러면 상태 선언과 스타일 값이 분리되니까 "이 상태일 땐 뭐가 나올까?"를 훨씬 예측하기 쉬워진다는 거죠.

최근 CSS 흐름과 비교

이 고민은 글쓴이 혼자만의 것이 아니에요. 업계 전체가 같은 방향을 더듬고 있거든요. Tailwind CSS는 유틸리티 클래스로 조합 폭발을 해결하려 하고, CSS-in-JS(styled-components, Emotion 등)는 컴포넌트 스코프 안에서 상태를 JS 값으로 다루려고 해요. Radix UIArk UI 같은 헤드리스 컴포넌트 라이브러리는 data-state 속성을 표준처럼 써서, 스타일은 소비자가 자유롭게 입힐 수 있게 만들죠.

최근엔 CSS 자체도 진화하고 있어요. :has() 선택자로 부모가 자식의 상태에 반응할 수 있게 됐고, @container 쿼리로 컴포넌트 단위 반응형이 가능해졌어요. 곧 표준화될 CSS NestingStyle Queries(@container style())까지 더해지면, 글쓴이가 JS와 커스텀 프로퍼티로 힘겹게 만들던 패턴을 CSS가 네이티브로 지원하게 될 거예요. 글쓴이의 회고는 말하자면 "플랫폼이 따라오기 전에 먼저 걸어본 사람의 기록"인 셈이죠.

한국 개발자에게 주는 시사점

실무 관점에서 당장 가져갈 만한 포인트가 몇 가지 있어요. 첫째, 디자인 시스템을 만들고 있다면 data-state 기반 패턴을 진지하게 검토해보세요. 호버, 포커스, 프레스드, 로딩, 디스에이블드 같은 상태를 HTML 속성으로 명시하면, CSS에서도 JS에서도 테스트에서도 같은 이름으로 참조할 수 있어서 디버깅이 훨씬 쉬워져요.

둘째, CSS 커스텀 프로퍼티를 값이 아니라 상태 플래그로 쓰는 기법을 익혀두세요. 글에서 소개한 --is-hover: 0/1 트릭은 처음 보면 낯설지만, 한 번 감 잡으면 복잡한 컴포넌트를 놀라울 만큼 깔끔하게 만들 수 있어요. 특히 접근성 요구사항(다크모드, 고대비, 모션 감소)까지 같이 걸고 갈 때 빛을 발해요.

셋째, 기존 스타일 자산을 다 갈아엎지 말고 부분적으로 도입하세요. 회고 글의 교훈 중 하나가 "완벽한 추상화를 찾아 헤맸지만, 결국 프로젝트마다 맞는 수준의 규칙이 다르다"는 거였어요. 우리 팀도 무리한 리팩토링보다는, 새로 만드는 컴포넌트부터 이 패턴을 시도해보는 게 현실적일 거예요.

마무리

한 줄로 정리하면 "CSS 상태는 선언과 스타일을 분리할 때 비로소 예측 가능해진다"는 거예요. 수년 동안의 시행착오 끝에 도달한 결론치고는 의외로 단순하지만, 그 단순함에 이르기까지의 여정이 값진 기록이에요.

여러분 팀은 컴포넌트 상태를 어떻게 관리하고 계신가요? BEM, 유틸리티, CSS-in-JS, 데이터 속성 중 어느 쪽이 가장 잘 맞으셨는지 경험담이 궁금해요.


🔗 출처: Hacker News

이 뉴스가 유용했나요?

이 기술을 직접 배워보세요

AI 도구, 직접 활용해보세요

AI 시대, 코딩으로 수익을 만드는 방법을 배울 수 있습니다.

AI 활용 강의 보기

"비전공 직장인인데 반년 만에 수익 파이프라인을 여러 개 만들었습니다"

실제 수강생 후기
  • 비전공자도 6개월이면 첫 수익
  • 20년 경력 개발자 직강
  • 자동화 프로그램 + 소스코드 제공

매일 AI·개발 뉴스를 받아보세요

주요 테크 뉴스를 매일 아침 이메일로 전해드립니다.

스팸 없이, 언제든 구독 취소 가능합니다.