inherit, initial, unset의 차이는?

CSS 값 키워드인 inherit, initial, unset의 차이점과 각각의 리셋 메커니즘을 이해하고 적절히 사용하는 방법을 익힙니다

중급 15분 inherit initial unset 값 리셋

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 키워드는 다음 단계로 처리됩니다:

  1. 값 계산 단계(Value Processing): specified value 단계에서 inherit를 만나면 즉시 부모의 computed value를 참조
  2. 상속 체인 탐색: 부모 요소의 해당 속성 computed value를 검색, 부모가 없으면 initial value로 대체
  3. 계산된 값 전파: 부모의 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 키워드는 다음과 같이 동작합니다:

  1. 명세 초기값 참조: 각 CSS 속성 정의에 명시된 initial value를 사용 (예: CSS Color Module Level 4에서 color의 initial value는 CanvasText)
  2. Cascade 무시: 사용자 에이전트 스타일시트, 사용자 스타일시트, 저자 스타일시트 모두 무시
  3. 상속 차단: 상속 속성(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은 다음과 같이 처리됩니다:

  1. 속성 메타데이터 검사: 해당 속성의 inherited 플래그 확인
  2. 조건부 분기:
    • inherited: yes → inherit와 동일하게 처리
    • inherited: no → initial과 동일하게 처리
  3. 값 계산 위임: 이후 값 계산은 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 단계에 따르면:

  1. Declared Value Stage: 세 키워드 모두 이 단계에서 specified value 결정
  2. 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는 이를 최적화하기 위해 다음 전략을 사용합니다:

  1. Property Set Partitioning: 상속/비상속 속성을 두 그룹으로 분리
  2. Batch Value Assignment: 각 그룹에 일괄 값 할당 (O(1) per group)
  3. Diff-based Invalidation: 이전 ComputedStyle과 비교하여 변경된 속성만 무효화

실무 선택 기준 매트릭스

상황키워드이유
비상속 속성을 부모와 동기화inherit강제 상속
프레임워크 스타일 완전 제거initialCascade 우회
컴포넌트 스타일 격리all: unset선택적 리셋
CSS Reset 구현initial + 명시적 재정의예측 가능

성능 고려사항

  • inherit: 부모 의존성으로 인한 재계산 전파 (depth에 비례)
  • initial: 독립적이므로 재계산 최소화
  • unset: 조건부 분기로 약간의 오버헤드 (약 5-10 CPU cycles)

성능 순서: initial이 가장 빠르고(정적 테이블 참조), unset이 중간(조건부 분기), inherit가 가장 느립니다(부모 체인 탐색 필요).