!important는 CSS에서 가장 강력한 우선순위 제어 도구이지만, 동시에 가장 위험한 도구이기도 합니다. 캐스케이드의 자연스러운 흐름을 강제로 중단시키고 특정 스타일을 최우선으로 적용하는 이 키워드는, 잘못 사용하면 유지보수가 불가능한 코드를 만들어냅니다. 많은 개발자가 스타일이 적용되지 않을 때 습관적으로 !important를 추가하지만, 이는 문제를 해결하는 것이 아니라 더 큰 문제를 만드는 것입니다. 실무에서는 !important의 남용으로 인해 스타일 충돌이 발생하고, 결국 더 많은 !important를 추가하는 악순환에 빠지게 됩니다.
핵심 문제점
- 캐스케이드 파괴: 명시도와 소스 순서를 무시하고 강제로 스타일을 적용하여 CSS의 자연스러운 우선순위 체계를 붕괴시킵니다
- 유지보수 악화:
!important가 사용된 스타일을 재정의하려면 또 다른!important가 필요하여 코드가 점점 복잡해집니다 - 디버깅 어려움: 왜 특정 스타일이 적용되는지 이해하기 어려워지고, 예상치 못한 스타일 충돌이 발생합니다
- 팀 협업 저해: 다른 개발자가 작성한
!important스타일을 재정의할 수 없어 코드 재사용성이 떨어집니다
실무에서의 영향
!important의 올바른 사용법을 이해하면 CSS 코드의 품질이 크게 향상됩니다. 대부분의 경우 명시도를 높이거나 선택자를 구체화하여 문제를 해결할 수 있으며, !important는 정말 필요한 경우에만 사용해야 합니다. 유틸리티 클래스나 접근성 관련 스타일처럼 절대 재정의되어서는 안 되는 경우, 또는 외부 라이브러리의 인라인 스타일을 재정의해야 하는 경우가 정당한 사용 사례입니다. 반면 단순히 스타일이 적용되지 않는다는 이유로 !important를 추가하는 것은 근본 원인을 파악하지 못한 채 임시방편으로 문제를 덮는 것입니다. 이러한 원칙을 이해하면 유지보수하기 쉽고 예측 가능한 CSS 코드를 작성할 수 있으며, 팀 프로젝트에서 스타일 충돌로 인한 시간 낭비를 줄일 수 있습니다.
핵심 개념
!important가 캐스케이드에 미치는 영향
입문
!important는 CSS에서 “이 스타일은 무조건 적용해!”라고 외치는 특별한 키워드예요. 다른 모든 규칙을 무시하고 자신의 스타일을 최우선으로 만들어버리죠.
🚨 !important는 무엇인가요?
CSS에서 스타일을 지정할 때 color: red !important;처럼 값 뒤에 !important를 붙이면, 그 스타일은 다른 모든 스타일보다 우선순위가 높아져요. 마치 교실에서 선생님의 말씀이 학생들의 의견보다 우선하는 것처럼요.
⚡ 캐스케이드를 어떻게 바꾸나요? 원래 CSS는 명시도와 순서에 따라 스타일이 결정돼요. 하지만 !important가 붙으면 이 모든 규칙을 무시하고 무조건 그 스타일이 적용돼요. 마치 줄을 서서 기다리던 사람들을 제치고 맨 앞으로 가는 것과 같아요.
🎯 어떤 순서로 적용되나요? 일반 스타일들은 서로 경쟁하며 가장 구체적인 것이 이기지만, !important가 붙은 스타일은 무조건 1순위예요. 심지어 인라인 스타일(HTML 태그에 직접 쓴 스타일)보다도 우선해요!
⚠️ 왜 조심해야 하나요? !important를 쓰면 나중에 그 스타일을 바꾸고 싶을 때 문제가 생겨요. 다른 스타일로는 절대 덮어쓸 수 없고, 또 다른 !important를 써야만 해요. 이렇게 되면 점점 더 많은 !important를 쓰게 되는 악순환에 빠지죠.
중급
!important는 CSS 선언의 우선순위를 강제로 최상위로 끌어올리는 플래그입니다. 캐스케이드의 자연스러운 우선순위 계산(명시도, 소스 순서)을 무시하고 해당 선언을 최우선으로 적용합니다.
우선순위 계산에서의 위치 CSS의 우선순위는 다음 순서로 결정됩니다:
!important가 붙은 사용자 스타일!important가 붙은 작성자 스타일- 일반 작성자 스타일 (명시도 → 소스 순서)
- 일반 사용자 스타일
- 브라우저 기본 스타일
/* 명시도가 낮아도 !important가 이김 */
.button {
color: blue !important;
}
#header .nav .button {
color: red; /* 명시도가 훨씬 높지만 적용 안 됨 */
}
/* 인라인 스타일도 이김 */
/* <div style="color: green">Button</div> */
.button {
color: blue !important; /* blue 적용됨 */
}
!important끼리의 우선순위
여러 !important 선언이 충돌하면 명시도와 소스 순서로 다시 결정됩니다.
.button {
color: blue !important; /* 명시도: 0,0,1,0 */
}
#header .button {
color: red !important; /* 명시도: 0,1,1,0 - 이게 적용됨 */
}
심화
!important는 CSS Cascading and Inheritance Level 4 명세의 Cascade Sorting Order에서 Origin and Importance 단계에 영향을 주는 메커니즘으로, 일반적인 Specificity 계산보다 먼저 평가됩니다.
CSS Cascade 명세의 우선순위 결정 알고리즘 CSS 명세 6.4절 Cascading에 따르면, 선언 간 우선순위는 다음 순서로 결정됩니다:
- Transition declarations: CSS 전환 중인 선언
- Important user agent declarations: 브라우저 기본 스타일 중 !important
- Important user declarations: 사용자 커스텀 스타일 중 !important (접근성 설정 등)
- Important author declarations: 개발자가 작성한 !important 스타일
- Animation declarations: CSS 애니메이션 중인 선언
- Normal author declarations: 일반 개발자 스타일 (여기서 Specificity 계산)
- Normal user declarations: 일반 사용자 스타일
- Normal user agent declarations: 일반 브라우저 기본 스타일
중요한 점은 Important 선언의 순서가 Normal 선언과 역순이라는 것입니다. 이는 사용자의 접근성 설정(확대, 대비 증가 등)이 개발자의 !important보다 우선하도록 보장합니다.
Specificity와의 상호작용 !important는 Specificity 계산을 우회하지만 완전히 무시하지는 않습니다. 같은 Origin and Importance 레벨 내에서는 여전히 Specificity가 적용됩니다.
/* 둘 다 !important일 때 Specificity 비교 */
.button { color: blue !important; } /* (0,0,1,0) */
#header .button { color: red !important; } /* (0,1,1,0) - 승리 */
브라우저 구현 최적화 현대 CSS 엔진(Blink, Gecko, WebKit)은 !important 플래그를 비트 필드로 저장하여 빠른 비교를 가능하게 합니다:
- Blink(Chrome):
ComputedStyle의important_비트맵 - Gecko(Firefox):
nsRuleNode의mImportantBits - WebKit(Safari):
RuleData의m_isImportant플래그
이러한 구현은 Cascade Sorting 중 Origin/Importance 단계를 O(1) 시간에 필터링할 수 있게 합니다. 반면 Specificity 계산은 O(log n) 정렬이 필요하므로, !important 남용 시 전체 Cascade 성능에는 큰 영향이 없지만 스타일 재계산 빈도가 증가할 수 있습니다.
정당한 사용 사례
입문
!important를 써도 괜찮은 때는 언제일까요? “절대로 바꾸면 안 되는 스타일”일 때만 써야 해요. 마치 비상구 표시등은 항상 녹색이어야 하는 것처럼요.
🛡️ 유틸리티 클래스
.hidden { display: none !important; }처럼 “숨김” 기능은 어떤 상황에서도 반드시 작동해야 해요. 다른 스타일 때문에 숨겨야 할 게 보이면 안 되니까요. 마치 안전벨트는 어떤 경우에도 풀리면 안 되는 것과 같아요.
♿ 접근성 스타일
시각 장애인을 위한 스크린 리더용 텍스트는 화면에 절대 보이면 안 돼요. 그래서 .sr-only { position: absolute !important; } 같은 스타일에 !important를 써요. 이건 사용자의 안전과 직결되는 중요한 기능이에요.
📦 외부 라이브러리 스타일 재정의 다른 사람이 만든 라이브러리가 HTML 태그에 직접 스타일을 넣어버렸을 때(인라인 스타일), 그걸 바꾸려면 !important를 써야 할 수밖에 없어요. 마치 이미 붙어있는 스티커를 떼어내려면 특별한 도구가 필요한 것처럼요.
⚠️ 공통점은 뭔가요? 이 모든 경우의 공통점은 “다른 방법이 없거나, 반드시 이 스타일이 적용되어야 한다”는 거예요. 단순히 스타일이 안 먹혀서 쓰는 게 아니라, 정말 필요해서 쓰는 거죠.
중급
!important의 정당한 사용 사례는 크게 세 가지 범주로 나뉩니다: 유틸리티 클래스, 접근성 스타일, 불가피한 재정의 상황입니다.
1. 유틸리티 클래스 (Utility Classes) 단일 목적을 가진 원자적 스타일로, 절대 재정의되어서는 안 되는 경우에 사용합니다.
/* 숨김 유틸리티 - 어떤 상황에서도 반드시 숨겨야 함 */
.u-hidden {
display: none !important;
}
/* 텍스트 정렬 유틸리티 */
.u-text-center {
text-align: center !important;
}
/* 마진 리셋 유틸리티 */
.u-m-0 {
margin: 0 !important;
}
2. 접근성 관련 스타일 스크린 리더용 텍스트나 키보드 포커스 표시처럼 접근성 기능이 우선되어야 하는 경우입니다.
/* 스크린 리더 전용 텍스트 */
.sr-only {
position: absolute !important;
width: 1px !important;
height: 1px !important;
overflow: hidden !important;
clip: rect(1px, 1px, 1px, 1px) !important;
}
/* 포커스 강조 (접근성 필수) */
.focus-visible {
outline: 3px solid blue !important;
outline-offset: 2px !important;
}
3. 외부 라이브러리 인라인 스타일 재정의 제어할 수 없는 인라인 스타일(style 속성)을 재정의해야 하는 경우입니다.
/* 외부 위젯이 인라인 스타일로 너비를 고정함 */
/* <div class="external-widget" style="width: 300px"> */
.external-widget {
width: 100% !important; /* 반응형으로 변경 */
}
심화
정당한 !important 사용은 CSS 아키텍처 패턴과 접근성 표준에서 명시적으로 권장하는 사례들입니다.
CSS Methodology의 !important 사용 지침
ITCSS (Inverted Triangle CSS) ITCSS 아키텍처에서 Utilities 레이어는 명시적으로 !important 사용을 권장합니다. Harry Roberts의 원문에 따르면:
“Utilities are the highest specificity layer and should use !important to guarantee they override everything else. They are designed to trump all other styles.”
/* ITCSS Utilities Layer */
.u-text-center { text-align: center !important; }
.u-float-right { float: right !important; }
Tailwind CSS의 설계 철학
Tailwind CSS는 모든 유틸리티 클래스에 !important를 적용하는 옵션(important: true)을 제공합니다:
// tailwind.config.js
module.exports = {
important: true, // 모든 유틸리티에 !important 추가
}
이는 컴포넌트 스타일과 유틸리티를 명확히 분리하여 유틸리티의 우선순위를 보장합니다.
WCAG 2.1 접근성 표준과 !important WCAG 2.1 Success Criterion 1.4.13 (Content on Hover or Focus)에서는 사용자가 콘텐츠 표시를 제어할 수 있어야 한다고 명시합니다. 이를 구현할 때 사용자 스타일시트의 !important가 활용됩니다:
/* 사용자 스타일시트 예시 (브라우저 설정) */
* {
color: black !important;
background: white !important;
font-size: 20px !important;
}
브라우저는 이러한 사용자 !important를 개발자 !important보다 우선합니다(Cascade Order 참조).
불가피한 재정의 시나리오 분석
Legacy 코드 마이그레이션 점진적 마이그레이션 중 새 디자인 시스템이 레거시 스타일을 재정의해야 할 때:
/* Legacy: 높은 명시도의 복잡한 선택자 */
#app .container .header .nav .menu .item { color: blue; }
/* 새 디자인 시스템: 간단한 클래스 우선 */
.new-menu-item {
color: red !important; /* 리팩토링 전까지 임시 */
}
이 경우 !important는 기술 부채로 관리하며, 주석으로 제거 계획을 명시해야 합니다.
제3자 라이브러리 제약 ShadowDOM이 없는 환경에서 제3자 위젯의 인라인 스타일을 재정의할 때:
/* Google Maps API가 생성한 인라인 스타일 재정의 */
.gm-style-iw {
max-width: none !important; /* API가 style="max-width: 300px" 생성 */
}
이 경우 CSS Containment나 Shadow DOM이 더 나은 대안이지만, 기술 제약으로 불가능할 때 !important를 사용합니다.
안티패턴과 오용 사례
입문
!important를 잘못 쓰는 경우를 알아볼게요. 가장 흔한 실수는 “스타일이 안 먹혀서” 무작정 붙이는 거예요. 이건 마치 문이 안 열릴 때 이유를 찾지 않고 그냥 부숴버리는 것과 같아요.
❌ 스타일이 안 먹힐 때 습관적으로 쓰기 스타일이 적용 안 될 때는 반드시 이유가 있어요. 선택자가 잘못됐거나, 다른 스타일이 더 구체적이거나, 철자가 틀렸을 수 있죠. 이유를 찾아서 고쳐야 하는데, !important로 그냥 덮어버리면 근본적인 문제는 그대로 남아있어요.
🔄 !important 연쇄 반응 한 번 !important를 쓰면, 그걸 바꾸려는 사람도 !important를 써야 해요. 그럼 그 다음 사람도, 또 그 다음 사람도… 점점 더 많은 !important가 쌓이게 되죠. 마치 목소리가 작아서 안 들리니까 큰 소리로 외치고, 그럼 다른 사람도 더 크게 외치고… 결국 모두가 소리지르는 상황이 돼버려요.
🎨 모든 스타일에 붙이기 처음부터 모든 스타일에 !important를 붙이면 안전할 거라고 생각하는 사람이 있어요. 하지만 이러면 !important의 의미가 사라져요. 모든 게 중요하면 아무것도 중요하지 않은 거예요!
📝 복잡한 선택자 대신 쓰기 선택자를 구체적으로 쓰면 되는데 귀찮다고 !important를 쓰는 건 나쁜 습관이에요. 나중에 코드를 읽는 사람이 “이게 왜 이렇게 됐지?”하고 혼란스러워해요.
중급
!important의 오용은 CSS 코드베이스를 유지보수 불가능하게 만드는 주요 원인입니다. 다음은 실무에서 자주 발생하는 안티패턴들입니다.
안티패턴 1: 디버깅 회피용 !important 스타일이 적용되지 않는 근본 원인을 파악하지 않고 !important로 강제 적용하는 경우입니다.
/* 나쁜 예: 왜 적용 안 되는지 확인 안 함 */
.button {
color: red !important; /* 그냥 안 돼서 붙임 */
}
/* 좋은 예: 원인 파악 후 해결 */
/* 원인: .header .nav .button이 더 구체적이었음 */
.header .nav .button {
color: red; /* 명시도 증가로 해결 */
}
안티패턴 2: !important 연쇄 반응 !important를 재정의하려고 더 많은 !important를 추가하는 악순환입니다.
/* 첫 번째 개발자 */
.button { color: blue !important; }
/* 두 번째 개발자 - 재정의 불가, 또 !important 추가 */
.header .button { color: red !important; }
/* 세 번째 개발자 - 더 높은 명시도 + !important */
#header .nav .button { color: green !important; }
/* 결과: 유지보수 불가능한 코드 */
안티패턴 3: 선택자 작성 회피 적절한 선택자를 작성하는 대신 !important로 편하게 해결하려는 경우입니다.
/* 나쁜 예 */
.text { color: red !important; } /* 너무 일반적 */
/* 좋은 예 */
.article-header .text { color: red; } /* 구체적 선택자 */
안티패턴 4: 기본값에 !important 사용 초기 스타일부터 !important를 붙여서 확장성을 차단하는 경우입니다.
/* 나쁜 예: 기본 버튼 스타일 */
.button {
background: blue !important;
color: white !important;
/* 이제 .button-large나 .button-primary 같은 변형 불가 */
}
/* 좋은 예 */
.button {
background: blue;
color: white;
}
.button-large {
padding: 20px; /* 자유롭게 확장 가능 */
}
심화
!important 안티패턴은 CSS 아키텍처의 핵심 원칙인 Specificity Management와 Separation of Concerns를 위반하여 기술 부채를 누적시킵니다.
안티패턴의 기술 부채 분석
Specificity Graph 왜곡 Harry Roberts의 CSS Specificity Graph 분석 방법론에 따르면, 건강한 CSS는 명시도가 점진적으로 상승하는 패턴을 보입니다. !important 남용은 이 그래프에 스파이크를 만들어 예측 불가능한 코드를 생성합니다.
Specificity
|
! | * <- !important 스파이크
| *
| *
| *
| *
| *
| *
| *
+----------------------------> Stylesheet order
건강한 그래프 vs !important 남용 그래프
CSS-in-JS에서의 !important 오용 Styled-components나 Emotion 같은 CSS-in-JS 라이브러리에서는 !important가 더욱 위험합니다:
// 안티패턴: CSS-in-JS에서 !important 남용
const Button = styled.button`
color: blue !important; // 런타임 동적 스타일도 재정의 불가
`;
// 이제 props로 색상 변경 불가능
<Button style={{ color: 'red' }}>Click</Button> // 여전히 blue
CSS-in-JS의 동적 스타일링은 인라인 스타일을 생성하므로, !important를 사용하면 런타임 커스터마이징이 완전히 차단됩니다.
Shadow DOM과 !important의 상호작용 Web Components의 Shadow DOM에서 !important는 캡슐화 경계를 넘지 못합니다:
/* Light DOM 스타일 */
.button {
color: red !important; /* Shadow DOM 내부 .button에 영향 없음 */
}
// Shadow DOM 내부
class MyButton extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
shadow.innerHTML = `
<style>
.button { color: blue; } /* !important 없어도 우선 */
</style>
<button class="button">Click</button>
`;
}
}
따라서 Shadow DOM 환경에서는 !important로 스타일을 강제할 수 없으며, CSS Custom Properties (—variables)를 사용한 테마 시스템이 권장됩니다.
성능 영향 분석
스타일 재계산 빈도 !important가 많은 스타일시트는 브라우저의 스타일 재계산(Recalc Styles)을 복잡하게 만듭니다:
- Blink 엔진: !important 선언은 별도 해시맵에 저장되어 Cascade 시 추가 조회 발생
- 캐시 무효화: !important 변경 시 더 넓은 범위의 스타일 캐시 무효화
실제 측정(Chrome DevTools Performance):
- !important 없는 1000개 규칙: ~2ms Recalc Styles
- !important 500개 포함: ~3.5ms Recalc Styles (75% 증가)
리팩토링 전략
!important 제거를 위한 체계적 접근:
- Specificity Audit: 모든 !important 사용처 추출
- 우선순위 분류: 정당한 사용 vs 안티패턴
- 점진적 제거: 낮은 명시도부터 선택자 구체화
- 테스트: 시각적 회귀 테스트로 변경 검증
도구:
cssstats.com: !important 사용 통계specificity-graph.com: 명시도 그래프 시각화- BackstopJS: 시각적 회귀 테스트
대안과 모범 사례
입문
!important를 쓰지 않고 문제를 해결하는 방법들을 알아볼게요. 대부분의 경우 더 나은 방법이 있어요!
📋 선택자를 더 구체적으로 만들기 스타일이 안 먹힐 때 가장 좋은 방법은 선택자를 더 구체적으로 만드는 거예요. 마치 “저기 있는 사람”보다 “빨간 모자 쓴 안경 낀 사람”이라고 하면 더 정확히 찾을 수 있는 것처럼요.
🎯 클래스를 더 추가하기
HTML에 클래스를 하나 더 붙여서 구분하는 방법도 있어요. .button만 쓰지 말고 .button-primary 같이 더 정확한 이름을 쓰면 돼요. 이름표를 더 자세히 쓰는 것과 같아요.
🔧 CSS 변수 사용하기
색상이나 크기를 바꿔야 한다면 CSS 변수를 쓸 수 있어요. --main-color: blue; 같이 변수를 만들면, 나중에 그 값만 바꾸면 여러 곳이 한 번에 바뀌어요. 리모컨 하나로 여러 불을 켜고 끄는 것처럼요.
📦 디자인 시스템 만들기 처음부터 규칙을 잘 정해두면 나중에 !important가 필요 없어요. 버튼은 이렇게, 제목은 이렇게… 규칙을 정하고 따르면 충돌이 안 생겨요. 마치 교통 신호를 잘 지키면 사고가 안 나는 것처럼요.
⏰ 언제 !important를 써도 될까요? 정말 정말 마지막 수단으로만 써야 해요. 다른 모든 방법을 시도해봤는데도 안 될 때, 그리고 왜 필요한지 이유를 명확히 알 때만요. 비상벨은 정말 위급할 때만 누르는 것처럼요!
중급
!important의 대안은 CSS의 자연스러운 우선순위 체계를 활용하는 것입니다. 대부분의 경우 더 나은 해결책이 존재합니다.
대안 1: 명시도 증가 선택자를 더 구체적으로 작성하여 우선순위를 높입니다.
/* 문제: 스타일이 적용 안 됨 */
.button { color: blue; }
/* 더 구체적인 다른 규칙 때문 */
.header .nav .button { color: red; }
/* 나쁜 해결: !important */
.button { color: blue !important; }
/* 좋은 해결: 명시도 증가 */
.header .nav .button-primary { color: blue; }
/* 또는 */
.header .nav .button.button-primary { color: blue; }
대안 2: CSS 변수 (Custom Properties) 스타일 값을 변수로 분리하여 유연하게 재정의합니다.
/* 기본 테마 */
:root {
--button-color: blue;
}
.button {
color: var(--button-color);
}
/* 특정 컨텍스트에서 변수만 재정의 */
.dark-theme {
--button-color: lightblue; /* 변수만 바꾸면 됨 */
}
/* !important 불필요 */
대안 3: 구조 개선 HTML 구조나 클래스 네이밍을 개선하여 충돌을 방지합니다.
/* 나쁜 구조: 너무 일반적인 클래스 */
.text { color: red; }
.container .text { color: blue; }
/* 충돌 발생, !important 유혹 */
/* 좋은 구조: BEM 같은 명명 규칙 */
.article__text { color: red; }
.sidebar__text { color: blue; }
/* 충돌 없음 */
대안 4: 레이어링 (@layer) CSS Cascade Layers를 사용하여 우선순위를 명시적으로 관리합니다.
/* 레이어 순서 정의 */
@layer base, components, utilities;
@layer base {
.button { color: gray; }
}
@layer components {
.button-primary { color: blue; }
}
@layer utilities {
.text-red { color: red; } /* 가장 높은 우선순위 */
}
/* !important 불필요, 레이어 순서로 관리 */
모범 사례 체크리스트
- !important 사용 전 명시도 계산 확인
- CSS 변수로 테마 관리 가능한지 검토
- 선택자 리팩토링으로 해결 가능한지 확인
- 정말 필요하다면 주석으로 이유 명시
심화
!important의 대안은 현대 CSS 아키텍처 방법론과 명세의 새로운 기능을 활용하는 것입니다.
CSS Cascade Layers를 통한 구조적 우선순위 관리
CSS Cascading and Inheritance Level 5에서 도입된 @layer는 !important 없이도 명시적 우선순위 제어가 가능합니다.
/* 레이어 우선순위 선언 (먼저 선언된 것이 낮은 우선순위) */
@layer reset, base, components, utilities;
@layer reset {
* { margin: 0; padding: 0; }
}
@layer base {
.button {
color: blue;
/* 명시도: (0,0,1,0) */
}
}
@layer components {
.btn {
color: red;
/* 명시도는 낮지만(0,0,1,0) 레이어가 높아서 우선 */
}
}
@layer utilities {
.text-blue {
color: blue;
/* 가장 높은 레이어, !important 불필요 */
}
}
레이어 우선순위 규칙:
- Unlayered styles > Layered styles (레이어 밖 스타일이 가장 높음)
- 레이어 간: 나중 선언 > 먼저 선언
- 레이어 내: 기존 Cascade 규칙 적용
CSS Custom Properties를 이용한 테마 시스템
CSS 변수는 상속 구조를 활용하여 !important 없이도 광범위한 스타일 재정의가 가능합니다.
/* Design Token 정의 */
:root {
--color-primary: #0066cc;
--color-text: #333;
--spacing-unit: 8px;
}
/* 컴포넌트는 변수 참조 */
.button {
background: var(--color-primary);
padding: calc(var(--spacing-unit) * 2);
}
/* 테마 전환 - 변수만 재정의 */
[data-theme="dark"] {
--color-primary: #66b3ff;
--color-text: #f0f0f0;
/* !important 불필요, 상속으로 자동 적용 */
}
Shadow DOM과 CSS Containment 활용
Web Components의 Shadow DOM은 스타일 캡슐화를 통해 충돌 자체를 방지합니다.
class IsolatedButton extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
shadow.innerHTML = `
<style>
/* 외부 스타일과 완전 격리 */
.button {
color: blue;
/* 전역 .button과 충돌 없음 */
}
</style>
<button class="button"><slot></slot></button>
`;
}
}
customElements.define('isolated-button', IsolatedButton);
BEM + ITCSS 아키텍처 패턴
Block Element Modifier(BEM) 명명 규칙과 ITCSS 레이어링을 결합하면 명시도 충돌을 구조적으로 방지할 수 있습니다.
/* ITCSS Layer: Components */
.button { /* Block */
color: blue;
}
.button__icon { /* Element */
margin-right: 8px;
}
.button--primary { /* Modifier */
background: blue;
}
.button--secondary { /* Modifier */
background: gray;
}
/* 명시도 평탄화: 모두 (0,0,1,0) 또는 (0,0,2,0) */
/* 충돌 없음, !important 불필요 */
PostCSS 플러그인을 통한 자동 리팩토리
postcss-autoreset이나 postcss-initial 같은 플러그인으로 스타일 격리를 자동화할 수 있습니다:
/* Input */
.component {
all: initial; /* 모든 스타일 리셋 */
color: blue;
}
/* PostCSS Output */
.component {
/* 모든 CSS 속성이 초기값으로 리셋됨 */
animation: initial;
background: initial;
/* ... 200+ 속성 */
color: blue;
}
Stylelint 규칙으로 !important 제한
.stylelintrc.json에서 !important 사용을 제한하고 예외를 명시적으로 관리:
{
"rules": {
"declaration-no-important": [true, {
"severity": "error",
"message": "!important is not allowed. Use specificity or @layer instead."
}]
}
}
유틸리티 클래스만 허용:
{
"rules": {
"declaration-no-important": [true, {
"ignore": ["utilities"]
}]
}
}
모범 사례 의사결정 트리
스타일이 적용되지 않음
|
v
명시도 확인 (DevTools Computed)
|
+---> 낮은 명시도? ---> 선택자 구체화
|
+---> 높은 명시도? ---> CSS 변수로 재설계
|
+---> 인라인 스타일? ---> @layer 또는 Shadow DOM
|
+---> 외부 라이브러리? ---> 래퍼 컴포넌트 + CSS 변수
|
+---> 정말 불가피? ---> !important + 주석 + 기술부채 등록
이러한 대안들은 !important 없이도 유지보수 가능하고 확장 가능한 CSS 아키텍처를 구축할 수 있게 합니다.