블로그 목록
frontend

CSS @layer로 스타일 우선순위 정리하기 — !important 남발 그만

프로젝트가 커지면 항상 겪는 일이 있다. 분명 스타일을 줬는데 안 먹는다. 개발자 도구를 열어보면 어디선가 명시도가 더 높은 규칙이 이기고 있고, 결국 !important를 붙이거나 선택자를 .card .title.title처럼 억지로 길게 늘려서 이긴다. 이게 반복되면 CSS는 점점 누가 더 세게 쓰나 싸움판이 된다.

@layer는 이 문제를 명시도가 아니라 계층 순서로 푼다. 어떤 레이어가 이길지를 파일 위쪽에서 한 번 정해두면, 레이어 안에서 선택자를 아무리 세게 써도 나중 레이어를 못 이긴다.

문제 상황

외부 UI 라이브러리를 깔았는데, 그쪽 .btn.button.button 같은 이중 선택자로 되어 있어서 내 .btn이 안 먹는 경우가 대표적이다. 예전엔 이럴 때 !important로 눌렀다.

/* 라이브러리 */
.button.button { background: gray; }

/* 내 코드 — 명시도로 지려고 억지 */
.btn { background: blue !important; }

@layer로 순서 정하기

레이어 우선순위는 선언한 순서로 결정된다. 나중에 선언한 레이어가 이긴다. 명시도는 같은 레이어 안에서만 따진다.

/* 이 한 줄이 우선순위 규칙 전체를 정한다 */
@layer reset, library, components;

@layer library {
  .button.button { background: gray; }
}

@layer components {
  /* 선택자는 더 약한데도 이긴다 — components가 뒤에 있으니까 */
  .btn { background: blue; }
}

.button.button은 명시도가 (0,2,0)이고 .btn은 (0,1,0)이라 원래는 라이브러리가 이겨야 한다. 하지만 components 레이어가 library보다 뒤에 선언됐으니, 명시도와 상관없이 .btn이 파란색으로 이긴다. !important 없이.

핵심은 첫 줄의 @layer reset, library, components;다. 여기서 순서를 미리 못 박아두면, 실제 스타일이 파일 어디에 흩어져 있든 우선순위는 이 선언을 따른다.

외부 CSS를 레이어에 밀어넣기

라이브러리 CSS는 대개 레이어가 없는 채로 온다. @import할 때 레이어로 감싸버리면 된다.

@import 'some-ui-lib/dist/styles.css' layer(library);

이러면 라이브러리 전체가 library 레이어로 들어가고, 레이어 없이 작성한 내 스타일은 항상 레이어보다 우선하므로 자동으로 이긴다. 레이어가 없는 규칙이 가장 세다는 점만 기억하면 된다.

실전 팁

  • 레이어 순서는 프로젝트 진입점에서 @layer reset, base, library, components, utilities;처럼 딱 한 번만 선언한다.
  • utilities를 맨 뒤에 두면 유틸리티 클래스가 항상 이겨서 !important 없이도 덮어쓰기가 된다. Tailwind v4가 실제로 이 구조를 쓴다.
  • !important는 레이어 안에서 순서가 거꾸로 뒤집힌다. 앞 레이어의 !important가 더 세지는데, 헷갈리니 애초에 안 쓰는 걸 추천한다.

명시도로 싸우던 걸 순서 문제로 바꾸는 것뿐인데, CSS를 읽고 고치기가 확 편해진다. 이제 모든 최신 브라우저에서 쓸 수 있으니 새 프로젝트라면 처음부터 레이어 순서를 잡고 시작하는 걸 권한다.