라이브러리 스타일을 덮으려고 !important를 쓰다가 @layer로 정리한 과정
문제 발생
UI 라이브러리의 .btn 스타일을 덮으려는데 상대 특이도가 더 높아서 계속 밀렸습니다. 선택자를 길게 늘이다가 결국 !important를 붙였고, 그러자 이번엔 우리 쪽의 상태 스타일이 그걸 덮지 못했습니다.
/* 라이브러리 */
.theme .btn.btn-primary { background: blue; }
/* 우리 코드 — 계속 지는 중 */
.btn-primary { background: green; }
.page .content .btn-primary { background: green; } /* 특이도 경쟁 */
.btn-primary { background: green !important; } /* 결국 이렇게 */원인 분석
특이도는 누가 더 구체적으로 썼는가를 재는 규칙이지 누가 더 중요한가를 재는 규칙이 아닙니다. 그래서 "라이브러리보다 우리 코드가 우선"이라는 의도를 특이도로 표현하려면 선택자를 계속 길게 만들어야 하고, 그 경쟁의 끝이 !important입니다.
캐스케이드 레이어(@layer)는 이 의도를 직접 표현합니다. 레이어를 선언한 순서가 우선순위이고, 특이도는 같은 레이어 안에서만 비교됩니다. 늦게 선언한 레이어의 낮은 특이도 규칙이 먼저 선언한 레이어의 높은 특이도 규칙을 이깁니다.
두 가지를 더 알아야 합니다.
- 레이어에 속하지 않은 스타일이 가장 강합니다. 어떤 레이어에도 넣지 않은 규칙은 모든 레이어를 이깁니다.
!important는 레이어 순서를 뒤집습니다. 일반 선언은 나중 레이어가 이기지만,!important끼리는 먼저 선언한 레이어가 이깁니다.
해결 방안
- 순서를 파일 맨 위에서 한 번에 선언합니다. 규칙이 없어도 순서만 먼저 정할 수 있고, 이후 어디서 레이어에 내용을 추가하든 이 순서가 유지됩니다.
@layer reset, vendor, base, components, utilities;- 라이브러리는 import하면서 레이어에 넣습니다. 라이브러리 CSS를 한 줄도 고치지 않고 우선순위를 낮출 수 있습니다.
@import url("ui-library.css") layer(vendor);이제 components 레이어의 .btn-primary { background: green; }가 vendor 레이어의 .theme .btn.btn-primary를 이깁니다. 특이도를 올릴 필요도, !important도 필요 없습니다.
- 유틸리티는 마지막 레이어에 둡니다. "이건 무조건 이겨야 한다"는 성격의 클래스가 사는 자리입니다.
@layer utilities {
.hidden { display: none; }
}- 레이어 밖에는 아무것도 두지 않는 편이 낫습니다. 레이어 밖 스타일이 전부를 이기므로, 하나라도 새어 나가면 레이어 설계가 무의미해집니다. 정말 마지막 수단으로만 남겨 둡니다.
!important가 남아 있다면 순서가 뒤집힌다는 점을 기억합니다. 레이어를 도입하면서 기존!important를 그대로 두면 의도와 반대로 동작할 수 있습니다. 레이어로 옮기는 김에 걷어내는 것이 목적에 맞습니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.