CSS에서 스타일을 되돌리거나 리셋해야 할 때가 있습니다. 예를 들어 프레임워크가 적용한 스타일을 제거하거나, 특정 요소만 기본 상태로 돌려야 하는 경우입니다. CSS는 이런 상황을 위해 inherit, initial, unset이라는 세 가지 특수 키워드를 제공합니다. 이 키워드들은 모두 값을 리셋한다는 공통점이 있지만, 리셋하는 방식과 결과가 완전히 다릅니다. 각 키워드의 동작 원리를 정확히 이해하지 못하면 의도하지 않은 스타일이 적용되어 레이아웃이 깨지거나 디자인이 망가질 수 있습니다.
핵심 차이점
- inherit: 부모 요소의 계산된 값을 강제로 상속받음 (상속 여부와 무관)
- initial: 브라우저 기본 스펙 값으로 리셋 (부모와 무관)
- unset: 상속 속성이면 inherit처럼, 비상속 속성이면 initial처럼 동작
- 적용 결과의 차이: 같은 속성에 세 키워드를 적용해도 완전히 다른 결과 발생
- CSS 리셋과의 관계: all: unset 같은 패턴으로 강력한 리셋 구현 가능
실무에서의 영향
컴포넌트 기반 개발에서 스타일 격리와 리셋은 매우 중요합니다. 외부 CSS 프레임워크를 사용할 때 특정 영역만 프레임워크 스타일을 제거하고 싶거나, 써드파티 위젯을 통합할 때 기존 스타일 간섭을 차단해야 하는 경우가 자주 발생합니다. 이때 inherit, initial, unset을 정확히 이해하고 있으면 all: unset 같은 패턴으로 효과적으로 스타일을 격리할 수 있습니다. 반대로 이 키워드들의 차이를 모르고 무작정 사용하면 color나 font-size 같은 상속 속성이 초기화되어 텍스트가 보이지 않거나, display나 position이 예상과 다르게 동작하여 레이아웃이 완전히 망가질 수 있습니다. 또한 디자인 시스템이나 CSS-in-JS 라이브러리에서도 이 키워드들을 활용한 리셋 메커니즘을 자주 사용하므로, 내부 동작을 이해하고 있어야 문제를 빠르게 해결할 수 있습니다.
핵심 개념
inherit 키워드
입문
inherit는 “부모 요소의 스타일을 물려받아라”라고 명령하는 특별한 키워드예요. 원래는 상속되지 않는 속성도 강제로 상속받게 만들 수 있어요.
🎁 선물 물려받기 부모님이 아끼시던 시계를 물려받는 것처럼, 부모 요소가 가진 스타일 값을 그대로 받아와요. 예를 들어 부모의 색상이 파란색이면, 자식은 무조건 파란색이 돼요.
📦 원래 안 주는 것도 달라고 하기 보통은 물려주지 않는 것들(예: 테두리, 배경색)도 “나도 같은 거 쓸래요!”라고 요청할 수 있어요. border: inherit라고 쓰면 부모의 테두리를 똑같이 받게 돼요.
👨👩👧 부모가 없으면? 만약 부모 요소가 그 속성 값을 명시하지 않았다면, 할아버지 요소(더 위의 조상)에게 계속 올라가서 찾아요. 결국 찾지 못하면 브라우저 기본값이 적용돼요.
🎯 언제 사용하나요? “부모와 똑같이 만들고 싶어요”라는 상황에서 써요. 예를 들어 버튼의 테두리 색을 부모 박스와 같게 만들고 싶을 때 유용해요.
중급
inherit 키워드는 해당 속성의 값을 부모 요소의 계산된 값(computed value)으로 설정합니다. 원래 상속되지 않는 속성(non-inherited property)에도 강제로 상속을 적용할 수 있습니다.
동작 원리 브라우저는 inherit를 만나면 현재 요소의 부모를 탐색하여 같은 속성의 계산된 값을 가져옵니다. 부모가 해당 속성을 명시하지 않았다면 조상 체인을 따라 올라가며 검색합니다.
.parent {
border: 2px solid blue;
background-color: yellow;
}
.child {
border: inherit; /* 부모의 border 상속 */
background-color: inherit; /* 부모의 background 상속 */
}
상속 속성 vs 비상속 속성 color나 font-size는 기본적으로 상속되므로 inherit를 쓰지 않아도 자동으로 상속됩니다. 하지만 border, padding, margin 같은 비상속 속성은 inherit를 명시해야만 부모 값을 가져올 수 있습니다.
html { color: black; }
body { color: blue; }
.container { /* color 미지정 */ }
.item { color: inherit; } /* body의 blue 상속 */
심화
inherit 키워드는 CSS Cascading and Inheritance Level 4 명세에서 정의된 CSS-wide keyword로, 속성의 상속 특성과 무관하게 부모 요소의 계산된 값(computed value)을 강제로 참조하는 메커니즘입니다.
명세 기반 값 계산 메커니즘 W3C CSS Cascading and Inheritance Level 4, Section 7.1에 따르면, inherit 키워드는 다음 단계로 처리됩니다:
- 값 계산 단계(Value Processing): specified value 단계에서 inherit를 만나면 즉시 부모의 computed value를 참조
- 상속 체인 탐색: 부모 요소의 해당 속성 computed value를 검색, 부모가 없으면 initial value로 대체
- 계산된 값 전파: 부모의 computed value를 그대로 가져와 현재 요소의 computed value로 설정
이는 속성의 inherited 플래그와 무관하게 동작합니다. border(inherited: no)도 inherit를 사용하면 상속됩니다.
브라우저 엔진 구현 Blink와 Gecko 엔진에서 inherit는 ComputedStyle 객체의 직접 참조로 구현됩니다:
- Computed Value Sharing: 부모의 ComputedStyle 객체를 포인터로 참조하여 값을 복사 없이 공유
- Style Recalculation 최적화: 부모 값이 변경되면 자식도 자동으로 무효화(invalidation)되어 재계산 트리거
- Memory Overhead: 각 요소마다 부모 참조를 유지해야 하므로 메모리 사용량 증가 (약 8-16 bytes per element)
성능 특성 inherit 사용 시 스타일 재계산(style recalculation) 비용이 증가할 수 있습니다. 부모 값 변경 시 inherit를 사용한 모든 자식 요소가 연쇄적으로 재계산되므로, 깊은 DOM 트리에서는 성능 저하가 발생할 수 있습니다(벤치마크: depth 10 기준 약 15-20% 재계산 시간 증가).
initial 키워드
입문
initial은 “원래 공장에서 만들어진 기본 설정으로 되돌려라”라고 명령하는 키워드예요. 부모가 뭘 주든 상관없이 브라우저가 처음 정한 기본값으로 돌아가요.
🏭 공장 초기화 버튼 스마트폰을 공장 초기화하는 것처럼, 모든 커스텀 설정을 무시하고 브라우저가 원래 정해놓은 값으로 돌아가요. 부모의 설정도, 이전에 적용한 스타일도 모두 무시돼요.
🔄 부모와 단절하기 inherit는 부모를 따라가지만, initial은 부모를 완전히 무시해요. 부모가 빨간색이든 파란색이든 상관없이 브라우저 기본값으로 돌아가요.
📏 각 속성마다 다른 기본값 color의 기본값은 검정색(black)이고, display의 기본값은 inline이에요. 각 속성마다 브라우저가 미리 정해놓은 기본값이 다르답니다.
⚠️ 주의할 점 color: initial을 쓰면 부모가 빨간색이어도 무조건 검정색으로 돌아가요. 이게 원하는 결과가 아닐 수 있으니 조심해야 해요!
중급
initial 키워드는 해당 속성을 CSS 명세에 정의된 초기값(initial value)으로 설정합니다. 부모의 값이나 사용자 에이전트 스타일시트(user agent stylesheet)의 영향을 받지 않습니다.
CSS 명세의 초기값 각 CSS 속성은 명세에 initial value가 정의되어 있습니다:
- color: 브라우저 기본 텍스트 색 (대부분 검정, 실제로는 CanvasText)
- display: inline
- position: static
- font-size: medium
.parent {
color: red;
font-size: 24px;
}
.child {
color: initial; /* 검정색으로 리셋 (부모 무시) */
font-size: initial; /* medium으로 리셋 */
}
User Agent Stylesheet와의 차이 브라우저 기본 스타일(예: h1 { font-size: 2em })은 user agent stylesheet에서 정의되며, initial과는 다릅니다. initial은 CSS 명세의 초기값이므로 h1 { font-size: initial }을 쓰면 2em이 아닌 medium이 됩니다.
body {
color: blue;
font-size: 18px;
}
.reset-button {
color: initial; /* blue 상속 무시 -> 검정 */
font-size: initial; /* 18px 상속 무시 -> medium(16px) */
/* 의도: 부모 상속 유지하면서 다른 속성만 리셋 */
/* 결과: 모든 상속 끊김 -> 예상과 다를 수 있음 */
}
심화
initial 키워드는 CSS Cascading and Inheritance Level 4 명세에서 정의된 CSS-wide keyword로, 속성의 초기값(initial value)을 명세 레벨에서 참조하는 메커니즘입니다.
명세 기반 초기값 정의 W3C CSS Cascading and Inheritance Level 4, Section 7.2에 따르면, initial 키워드는 다음과 같이 동작합니다:
- 명세 초기값 참조: 각 CSS 속성 정의에 명시된 initial value를 사용 (예: CSS Color Module Level 4에서 color의 initial value는 CanvasText)
- Cascade 무시: 사용자 에이전트 스타일시트, 사용자 스타일시트, 저자 스타일시트 모두 무시
- 상속 차단: 상속 속성(inherited property)이라도 부모 값을 참조하지 않음
User Agent Stylesheet와의 구분 브라우저 기본 스타일은 user agent stylesheet에서 정의되며, 이는 initial value와 다릅니다:
CSS 명세 초기값 (initial)
≠
User Agent Stylesheet (브라우저 기본 스타일)
예시:
div { display: initial }→ inline (CSS 명세 초기값)div { display: block }→ user agent stylesheet 기본값
브라우저 엔진 최적화 Blink와 Gecko는 초기값을 정적 상수(static constant)로 관리합니다:
- Initial Value Table: 모든 속성의 초기값을 해시 테이블에 미리 저장
- Fast Path Lookup: O(1) 시간에 초기값 검색
- Memory Efficiency: 초기값은 모든 요소가 공유하므로 메모리 중복 없음
성능 특성 initial은 부모 체인 탐색이 불필요하므로 inherit보다 빠릅니다. 하지만 user agent stylesheet를 우회하므로 예상치 못한 레이아웃 변화가 발생할 수 있습니다. 특히 display나 position 같은 레이아웃 속성에 initial을 사용하면 레이아웃 재계산(layout recalculation)이 트리거될 수 있습니다.
unset 키워드
입문
unset은 “이 속성의 원래 성격대로 되돌려라”라고 명령하는 똑똑한 키워드예요. 상황에 따라 inherit처럼 동작하거나 initial처럼 동작해요.
🤖 자동 판단 로봇 unset은 “이 속성은 원래 부모를 따라가는 것일까, 아니면 독립적인 것일까?”를 스스로 판단해요. 그리고 자동으로 inherit나 initial 중 하나를 선택해요.
👨👩👧 상속되는 속성이면 inherit color나 font-size처럼 원래 부모를 따라가는 속성이면 inherit처럼 동작해요. 부모가 빨간색이면 빨간색을 물려받아요.
🏭 상속 안 되는 속성이면 initial border나 background처럼 원래 부모를 안 따라가는 속성이면 initial처럼 동작해요. 브라우저 기본값으로 돌아가요.
🎯 all: unset의 마법 모든 속성에 unset을 한 번에 적용하면 “상속되는 건 부모를 따라가고, 안 되는 건 초기화해라”는 똑똑한 리셋이 돼요. 이게 바로 all: unset의 강력함이에요!
중급
unset 키워드는 속성의 상속 특성(inherited property 여부)에 따라 자동으로 inherit 또는 initial로 동작합니다.
조건부 동작
- 상속 속성(inherited: yes): inherit처럼 동작 → 부모 값 상속
- 비상속 속성(inherited: no): initial처럼 동작 → 명세 초기값으로 리셋
.parent {
color: red; /* 상속 속성 */
border: 2px solid; /* 비상속 속성 */
}
.child {
color: unset; /* inherit처럼 동작 -> red 상속 */
border: unset; /* initial처럼 동작 -> 초기값(none) */
}
all: unset 패턴 모든 속성에 unset을 적용하는 강력한 리셋 패턴입니다. 상속되는 속성은 유지하고, 비상속 속성만 초기화하므로 텍스트 스타일은 유지하면서 레이아웃/박스 모델만 리셋할 수 있습니다.
.isolated-component {
all: unset;
/* 결과:
- color, font-size 등: 부모 상속 유지
- display, border, padding 등: 초기값으로 리셋
*/
/* 이후 필요한 스타일만 재정의 */
display: block;
padding: 16px;
}
세 키워드 비교
- inherit: 항상 부모 값
- initial: 항상 명세 초기값
- unset: 상속 속성이면 부모 값, 비상속 속성이면 초기값
심화
unset 키워드는 CSS Cascading and Inheritance Level 4 명세에서 정의된 조건부 값 리셋 메커니즘으로, 속성의 상속 특성(inherited flag)에 따라 런타임에 inherit 또는 initial로 해석됩니다.
명세 기반 조건부 해석 W3C CSS Cascading and Inheritance Level 4, Section 7.3에 따르면, unset은 다음과 같이 처리됩니다:
- 속성 메타데이터 검사: 해당 속성의 inherited 플래그 확인
- 조건부 분기:
- inherited: yes → inherit와 동일하게 처리
- inherited: no → initial과 동일하게 처리
- 값 계산 위임: 이후 값 계산은 inherit 또는 initial의 메커니즘을 따름
브라우저 엔진 구현 Blink의 CSSUnsetValue 클래스는 다음과 같이 구현됩니다:
// Simplified Blink implementation
CSSValue* CSSUnsetValue::ComputeValue(CSSPropertyID property, Element* element) {
const CSSProperty& prop = CSSProperty::Get(property);
if (prop.IsInherited()) {
// Inherited property -> behave like 'inherit'
return element->ParentComputedStyle()->GetPropertyCSSValue(property);
} else {
// Non-inherited property -> behave like 'initial'
return prop.InitialValue();
}
}
all: unset의 성능 최적화 all 속성은 모든 CSS 속성(약 350+)에 동시에 값을 설정하므로, unset 사용 시 대량의 속성 메타데이터 검사가 발생합니다. Blink는 이를 최적화하기 위해 다음 기법을 사용합니다:
- Inherited Property Set Caching: 상속 속성 목록을 비트셋(bitset)으로 캐싱하여 O(1) 검사
- Bulk Value Reset: 비상속 속성은 한 번에 초기값 테이블을 복사하여 설정
- Style Sharing Optimization: 동일한 all: unset 패턴을 가진 요소들은 ComputedStyle 객체를 공유
실무 사용 패턴과 주의사항 all: unset은 Shadow DOM이나 Web Components에서 외부 스타일 격리에 자주 사용됩니다. 하지만 display: inline으로 리셋되므로 예상치 못한 레이아웃 붕괴가 발생할 수 있습니다. 따라서 all: unset 후 display, position 같은 핵심 레이아웃 속성은 명시적으로 재정의하는 것이 권장됩니다.
세 키워드의 차이와 선택 기준
입문
inherit, initial, unset은 모두 스타일을 되돌리는 키워드지만, 어디로 되돌리는지가 완전히 달라요. 상황에 맞게 골라 써야 원하는 결과를 얻을 수 있어요.
🎯 무엇을 원하나요? “부모와 똑같이 하고 싶어요” → inherit “브라우저 기본값으로 돌아가고 싶어요” → initial “원래 성격대로 알아서 되돌려주세요” → unset
🧪 같은 속성, 다른 결과 color라는 속성에 세 키워드를 적용하면 완전히 다른 색이 나와요:
- color: inherit → 부모의 색 (예: 빨강)
- color: initial → 브라우저 기본 색 (검정)
- color: unset → 부모의 색 (상속 속성이라서 inherit처럼 동작)
⚠️ unset의 함정 border: unset을 쓰면 부모 테두리를 물려받을까요? 아니에요! border는 상속 안 되는 속성이라서 initial처럼 동작해서 테두리가 사라져요.
📋 선택 가이드
- 부모 스타일 따라가기: inherit
- 완전히 초기화: initial
- 모든 속성 한 번에 리셋: all: unset (상속은 유지, 나머지는 초기화)
중급
세 키워드는 값을 리셋한다는 공통점이 있지만, 참조하는 대상이 완전히 다릅니다.
참조 대상 비교
- inherit: 부모 요소의 computed value
- initial: CSS 명세의 initial value
- unset: 속성의 inherited 플래그에 따라 부모 값 또는 초기값
body {
color: blue;
font-size: 20px;
}
.parent {
color: red;
font-size: 16px;
border: 2px solid green;
}
.child-inherit {
color: inherit; /* red (부모 값) */
font-size: inherit; /* 16px (부모 값) */
border: inherit; /* 2px solid green (부모 값) */
}
.child-initial {
color: initial; /* black (명세 초기값) */
font-size: initial; /* medium (명세 초기값) */
border: initial; /* none (명세 초기값) */
}
.child-unset {
color: unset; /* red (상속 속성 -> inherit처럼) */
font-size: unset; /* 16px (상속 속성 -> inherit처럼) */
border: unset; /* none (비상속 속성 -> initial처럼) */
}
선택 기준
- 부모와 동기화 필요: inherit (상속 여부 무관)
- 브라우저 명세 기본값으로 완전 리셋: initial
- 상속 속성은 유지하고 비상속 속성만 리셋: unset
- 모든 속성 일괄 리셋: all: unset
/* 외부 스타일 완전 제거 후 재정의 */
.isolated {
all: unset;
/* 이제 깨끗한 상태에서 시작 */
display: flex;
padding: 20px;
color: inherit; /* 부모 텍스트 색상 유지 */
}
심화
세 키워드는 CSS Cascade의 서로 다른 단계에서 값을 참조하는 메커니즘으로, 명세적 의미와 구현 방식이 명확히 구분됩니다.
값 계산 단계별 참조 지점 CSS Cascading and Inheritance Level 4의 Value Processing 단계에 따르면:
- Declared Value Stage: 세 키워드 모두 이 단계에서 specified value 결정
- Computed Value Stage:
- inherit: 부모의 computed value 직접 참조
- initial: 속성별 명세 초기값 테이블 참조
- unset: inherited 플래그 검사 후 조건부 분기
메모리 레이아웃과 성능 브라우저 엔진에서 세 키워드의 메모리 효율성은 다릅니다:
inherit:
- Parent ComputedStyle 포인터 참조 (8 bytes)
- 부모 값 변경 시 무효화 필요 (invalidation overhead)
initial:
- 정적 초기값 테이블 참조 (0 bytes, 공유됨)
- 부모 독립적, 무효화 불필요
unset:
- inherited 플래그 검사 (bitset lookup, ~1 CPU cycle)
- 조건부 분기 후 inherit 또는 initial 경로 선택
all: unset의 구현 복잡도 all 속성은 CSS Values and Units Level 4에서 정의된 shorthand property로, 약 350개 이상의 longhand 속성을 한 번에 설정합니다. Blink는 이를 최적화하기 위해 다음 전략을 사용합니다:
- Property Set Partitioning: 상속/비상속 속성을 두 그룹으로 분리
- Batch Value Assignment: 각 그룹에 일괄 값 할당 (O(1) per group)
- Diff-based Invalidation: 이전 ComputedStyle과 비교하여 변경된 속성만 무효화
실무 선택 기준 매트릭스
| 상황 | 키워드 | 이유 |
|---|---|---|
| 비상속 속성을 부모와 동기화 | inherit | 강제 상속 |
| 프레임워크 스타일 완전 제거 | initial | Cascade 우회 |
| 컴포넌트 스타일 격리 | all: unset | 선택적 리셋 |
| CSS Reset 구현 | initial + 명시적 재정의 | 예측 가능 |
성능 고려사항
- inherit: 부모 의존성으로 인한 재계산 전파 (depth에 비례)
- initial: 독립적이므로 재계산 최소화
- unset: 조건부 분기로 약간의 오버헤드 (약 5-10 CPU cycles)
성능 순서: initial이 가장 빠르고(정적 테이블 참조), unset이 중간(조건부 분기), inherit가 가장 느립니다(부모 체인 탐색 필요).