CSS 상속(Inheritance)은 부모 요소에 적용된 스타일이 자식 요소로 자동으로 전달되는 메커니즘입니다. 이는 CSS의 가장 강력하면서도 기본적인 기능 중 하나로, 스타일을 반복해서 작성하지 않아도 되게 만들어줍니다. 예를 들어, body 요소에 글꼴을 지정하면 페이지 전체의 텍스트가 동일한 글꼴을 사용하게 됩니다. 그러나 모든 CSS 속성이 상속되는 것은 아니며, 어떤 속성이 상속되고 어떤 속성이 상속되지 않는지 이해하는 것이 효율적인 CSS 작성의 핵심입니다.
💎 핵심 특징
- 자동 전달: 부모 요소의 특정 스타일 속성이 자식 요소로 자동으로 전달됨
- 선택적 상속: 모든 속성이 상속되는 것은 아니며, 주로 텍스트 관련 속성이 상속됨
- 코드 효율성: 공통 스타일을 상위 요소에 한 번만 정의하면 하위 요소에 자동 적용
- 상속 제어: inherit, initial, unset 같은 키워드로 상속 동작을 명시적으로 제어 가능
🎯 실무에서의 영향
CSS 상속을 제대로 이해하고 활용하면 스타일시트의 크기를 크게 줄이고 유지보수성을 높일 수 있습니다. 예를 들어, 글꼴, 색상, 줄 간격 같은 타이포그래피 속성을 body나 컨테이너 요소에 한 번만 정의하면 모든 하위 텍스트 요소에 자동으로 적용되어 반복적인 코드 작성을 피할 수 있습니다. 반대로 상속을 잘못 이해하면 예상치 못한 스타일이 적용되거나, 필요 없는 스타일 재정의로 인해 CSS 파일이 비대해질 수 있습니다. 디자인 시스템을 구축할 때 상속을 전략적으로 활용하면 일관된 시각적 경험을 제공하면서도 유연한 커스터마이징이 가능한 구조를 만들 수 있습니다. 또한 어떤 속성이 상속되지 않는지 알면(예: margin, padding, border) 불필요한 재정의를 줄이고 스타일 충돌을 방지할 수 있습니다.
핵심 개념
상속 메커니즘
입문
CSS에서는 부모 요소에 적용한 스타일이 자식 요소에게 자동으로 전달돼요. 마치 가족에게 물려받는 유전처럼요!
🌳 나무처럼 자라는 스타일 HTML은 나무 구조로 되어 있어요. 큰 가지(부모 요소)에 색을 칠하면, 그 아래 작은 가지들(자식 요소)도 같은 색이 되는 것처럼, CSS 스타일도 위에서 아래로 흘러내려요.
📦 자동으로 물려받기 부모 상자 안에 작은 상자가 있다고 상상해보세요. 부모 상자에 “글씨는 파란색”이라고 적으면, 안에 있는 모든 작은 상자의 글씨도 자동으로 파란색이 돼요. 일일이 각 상자마다 파란색이라고 적을 필요가 없죠!
🎨 한 번 칠하면 전부 바뀜 학교 교실에서 칠판에 쓴 글씨 색깔을 바꾸면, 모든 학생이 같은 색으로 따라 쓰는 것처럼, 부모 요소의 글꼴이나 색상을 바꾸면 모든 자식 요소가 함께 바뀌어요.
💡 왜 이렇게 만들었을까요? 매번 똑같은 스타일을 반복해서 쓰는 건 너무 귀찮잖아요? 상속 덕분에 공통된 스타일은 한 번만 쓰면 되니까 훨씬 편리해요!
중급
CSS 상속은 DOM 트리 구조를 따라 부모 노드에서 자식 노드로 특정 속성 값이 전파되는 메커니즘입니다.
상속의 동작 원리 브라우저는 요소를 렌더링할 때 다음 순서로 속성 값을 결정합니다:
- 해당 요소에 직접 선언된 값이 있는지 확인
- 없으면 부모 요소의 계산된 값을 확인
- 속성이 상속 가능하면(inheritable) 부모의 값을 사용
- 상속 불가능하면 브라우저 기본값(initial value) 사용
body {
font-family: 'Noto Sans KR', sans-serif;
color: #333;
line-height: 1.6;
}
/* div, p, span 등 모든 하위 요소가 자동으로 위 스타일을 상속받음 */
<body>
<div>
<p>이 텍스트는 body의 font-family, color, line-height를 상속받습니다.</p>
<span>이 텍스트도 마찬가지입니다.</span>
</div>
</body>
상속의 장점
- DRY(Don’t Repeat Yourself) 원칙 준수: 중복 코드 제거
- 일관성: 전역 스타일 정의로 디자인 시스템 구축 용이
- 유지보수성: 한 곳만 수정하면 전체에 반영
심화
CSS 상속은 CSS 2.1 명세 6.2절에 정의된 값 처리 알고리즘(Value Processing)의 핵심 메커니즘으로, 계산된 값(Computed Value)의 트리 전파를 통해 구현됩니다.
명세 기반 상속 알고리즘 W3C CSS Cascading and Inheritance Level 4 명세에 따르면, 속성 값 결정은 다음 6단계를 거칩니다:
- 선언 값(Declared Values): 모든 CSS 선언 수집
- 캐스케이드 값(Cascaded Value): Origin, Specificity, Order로 하나 선택
- 지정 값(Specified Value): 캐스케이드 값이 없으면 상속 또는 초기값 사용
- 계산 값(Computed Value): 상대값을 절대값으로 변환 (em → px)
- 사용 값(Used Value): 레이아웃 계산 후 최종 값
- 실제 값(Actual Value): 디바이스 제약 적용
상속 값 전파 타이밍 상속은 3단계(Specified Value)에서 발생하며, 부모의 **계산 값(Computed Value)**을 자식에게 전달합니다. 이는 중요한 의미를 가집니다:
.parent {
font-size: 2em; /* 부모의 16px 기준 → 32px로 계산됨 */
}
.child {
/* font-size 미지정 시 부모의 계산 값 32px을 상속 (2em이 아님!) */
}
렌더링 엔진 최적화 Blink(Chrome)와 Gecko(Firefox)는 상속 처리를 다음과 같이 최적화합니다:
Style Sharing: 동일한 상속 값을 공유하는 요소들은 계산된 스타일(Computed Style)을 재사용합니다. 이를 위해 Matched Rules와 Inherited Properties를 해시하여 Style Sharing Candidate로 분류합니다.
Incremental Style Recalculation: 부모 스타일 변경 시 전체 하위 트리를 재계산하지 않고, 영향받는 속성만 선택적으로 업데이트합니다. Blink의 경우 Invalidation Set을 사용하여 O(1) 시간 복잡도로 영향 범위를 판별합니다.
Performance Impact: 깊은 DOM 트리에서 상속 가능 속성 변경 시 모든 하위 요소의 재계산이 필요하므로, 대규모 DOM(>10,000 nodes)에서는 성능 병목이 발생할 수 있습니다. 이 경우 CSS Containment(contain: layout)를 사용하여 레이아웃 재계산 범위를 제한할 수 있습니다.
상속 가능 속성과 불가능 속성
입문
모든 CSS 스타일이 부모에서 자식으로 전달되는 건 아니에요. 어떤 건 전달되고, 어떤 건 전달되지 않아요!
📝 글자 관련은 물려받아요 글자 크기, 글꼴, 글자 색깔처럼 “글자”와 관련된 스타일은 부모에서 자식으로 자동으로 전달돼요. 엄마가 쓴 글씨체를 아이가 닮는 것처럼요!
📦 상자 모양은 물려받지 않아요 테두리(border), 여백(padding), 배경색(background)처럼 “상자의 모양”과 관련된 건 전달되지 않아요. 각 상자마다 자기만의 테두리와 배경이 있어야 하니까요!
🎯 왜 이렇게 구분했을까요? 만약 부모 상자의 테두리가 자식에게도 똑같이 적용된다면, 상자 안의 모든 것에 테두리가 중복으로 그려져서 이상해질 거예요. 그래서 상자 모양은 각자 따로 정하는 게 맞아요!
💡 기억하는 팁 “글자처럼 내용물과 관련된 건 물려받고, 상자처럼 겉모습과 관련된 건 물려받지 않는다”라고 생각하면 쉬워요!
중급
CSS 속성은 기본적으로 상속 가능 속성(inherited property)과 상속 불가능 속성(non-inherited property)으로 구분됩니다.
상속 가능한 속성 (Inherited Properties) 주로 타이포그래피와 텍스트 관련 속성이 상속됩니다:
- 폰트: font-family, font-size, font-weight, font-style
- 텍스트: color, line-height, text-align, letter-spacing
- 가시성: visibility
- 커서: cursor
- 리스트: list-style
상속 불가능한 속성 (Non-inherited Properties) 주로 박스 모델과 레이아웃 관련 속성은 상속되지 않습니다:
- 박스 모델: margin, padding, border, width, height
- 배경: background, background-color, background-image
- 포지셔닝: position, top, left, right, bottom
- 디스플레이: display, float, overflow
- 변형: transform, transition, animation
.parent {
/* 상속됨 */
color: blue;
font-size: 16px;
/* 상속 안 됨 */
border: 2px solid red;
padding: 20px;
background: yellow;
}
<div class="parent">
부모 요소
<div class="child">
자식 요소: color와 font-size는 상속받지만,
border, padding, background는 상속받지 않음
</div>
</div>
판단 기준 “이 속성이 자식에게 자동으로 적용되면 도움이 될까?”를 생각하면 됩니다. 글꼴은 일관성이 중요하므로 상속되지만, 여백은 각 요소마다 달라야 하므로 상속되지 않습니다.
심화
CSS 속성의 상속 가능 여부는 각 속성 정의에 명시된 “Inherited” 필드로 결정되며, 이는 해당 속성의 설계 철학을 반영합니다.
속성 상속 분류 원칙 W3C CSS 명세는 다음 원칙에 따라 속성의 상속 여부를 결정합니다:
상속 가능 속성 설계 원칙: 문서의 의미론적 구조(semantic structure)를 따라 전파되어야 하는 속성. 주로 텍스트 노드의 시각적 표현과 관련된 속성이 해당됩니다.
상속 불가능 속성 설계 원칙: 요소의 박스 생성(box generation)과 레이아웃 배치(layout positioning)에 관여하는 속성. 각 요소가 독립적으로 결정해야 하는 값입니다.
예외 사례 분석
일부 속성은 직관과 다르게 분류됩니다:
visibility: inherit (상속됨): opacity(상속 안 됨)와 달리 visibility는 상속됩니다. 이는 visibility가 레이아웃 공간은 유지하면서 시각적 표현만 제어하기 때문입니다. 반면 opacity는 렌더링 레이어에 영향을 주므로 비상속 속성입니다.
direction, writing-mode (상속됨): 텍스트 방향성은 문서 전체의 일관성이 중요하므로 상속됩니다. RTL(Right-to-Left) 언어 지원을 위해 필수적입니다.
quotes (상속됨): 따옴표 스타일은 언어와 문화권에 따라 결정되므로 상속되어야 합니다.
브라우저 기본 스타일시트(User Agent Stylesheet)의 역할
브라우저는 기본 스타일시트에서 비상속 속성의 초기값을 정의합니다:
/* Chrome의 기본 스타일 (blink/renderer/core/html/resources/html.css) */
div {
display: block; /* 비상속: 각 div는 독립적으로 block */
}
body {
margin: 8px; /* 비상속: body만의 margin */
}
성능 고려사항
상속 가능 속성 변경 시 하위 트리 전체의 스타일 재계산이 필요하므로, 대규모 DOM에서는 성능 영향이 큽니다:
/* 나쁨: 10,000개 하위 요소 모두 재계산 */
.large-container { color: red; }
/* 좋음: 필요한 요소만 직접 지정 */
.large-container .text { color: red; }
Blink의 프로파일링 결과, 상속 가능 속성 변경은 평균 3-5배 더 많은 스타일 재계산 시간이 소요됩니다(n=1000 DOM nodes 기준).
상속 제어 키워드
입문
CSS에는 상속을 마음대로 조절할 수 있는 마법 단어들이 있어요!
🎯 inherit - 강제로 물려받기 원래는 물려받지 않는 스타일도 “inherit”이라고 쓰면 부모에게서 받을 수 있어요. 마치 “나도 엄마처럼 할래!”라고 말하는 거예요.
🔄 initial - 처음으로 돌아가기 브라우저가 처음에 정해놓은 기본값으로 되돌리는 거예요. “공장 초기화”라고 생각하면 돼요. 부모가 뭘 줬든 무시하고 원래대로 돌아가요.
🧹 unset - 자동으로 정하기 “알아서 해줘”라는 의미예요. 원래 물려받는 스타일이면 물려받고, 아니면 기본값으로 돌아가요. 스마트하게 자동으로 판단해줘요!
⏮️ revert - 한 단계 되돌리기 브라우저가 원래 정해놓은 스타일로 돌아가는 거예요. initial과 비슷하지만, 브라우저의 기본 스타일시트를 존중해요.
💡 언제 사용하나요? 특별한 경우에만 쓰이는 단어들이에요. 보통은 그냥 값을 직접 쓰지만, 상속을 정확하게 제어해야 할 때 유용해요!
중급
CSS는 상속 동작을 명시적으로 제어할 수 있는 전역 키워드(global keywords)를 제공합니다.
inherit 키워드 부모 요소의 계산된 값을 강제로 상속받습니다. 비상속 속성에도 사용 가능합니다.
initial 키워드 속성의 초기값(initial value)으로 재설정합니다. 상속 체인을 끊고 명세에 정의된 기본값을 사용합니다.
unset 키워드 상속 가능 속성이면 inherit처럼 동작하고, 비상속 속성이면 initial처럼 동작합니다. 조건부 초기화에 유용합니다.
revert 키워드 CSS Cascade 레벨을 한 단계 되돌립니다. 사용자 에이전트 스타일시트의 값으로 복원하며, initial보다 더 자연스러운 초기화를 제공합니다.
.parent {
border: 2px solid blue;
}
.child {
border: inherit; /* 부모의 border 강제 상속 */
}
.reset-all {
all: unset; /* 모든 속성을 unset */
}
/* 결과:
- 상속 가능 속성(color, font-size 등)은 부모에서 상속
- 비상속 속성(margin, border 등)은 초기값으로 재설정
*/
button {
all: initial; /* 명세의 초기값: display: inline; */
}
button {
all: revert; /* 브라우저 기본값: display: inline-block; */
}
실용적 활용
- inherit: 비상속 속성을 부모와 동일하게 만들 때
- initial: 모든 커스텀 스타일 제거 시
- unset: 리셋 CSS 작성 시
- revert: 사용자 에이전트 스타일 복원 시
심화
상속 제어 키워드는 CSS Cascading and Inheritance Level 4 명세의 핵심 기능으로, 값 처리 알고리즘의 각기 다른 단계에 개입합니다.
키워드별 값 처리 단계 분석
CSS 값 처리는 6단계를 거치며, 각 키워드는 다음 단계에서 동작합니다:
inherit (3단계: Specified Value)
Specified Value 계산 시:
if (property value === 'inherit') {
return parent.computedValue(property);
}
부모의 계산 값(Computed Value)을 직접 가져옵니다. 이는 중요한 의미를 가집니다:
.parent { font-size: 2em; } /* 32px로 계산됨 */
.child { font-size: inherit; } /* 2em이 아닌 32px을 상속 */
initial (3단계: Specified Value)
Specified Value 계산 시:
if (property value === 'initial') {
return spec.initialValue(property);
}
명세에 정의된 초기값을 사용합니다. 예: display의 initial value는 inline입니다.
unset (3단계: Specified Value)
Specified Value 계산 시:
if (property value === 'unset') {
return spec.isInherited(property) ? inherit : initial;
}
조건부로 inherit 또는 initial을 적용합니다.
revert (2단계: Cascaded Value)
Cascaded Value 계산 시:
if (property value === 'revert') {
return cascade.getPreviousOriginValue(property);
}
캐스케이드의 이전 Origin으로 롤백합니다:
- Author → User Agent
- User → User Agent
- User Agent → initial
all 속성과의 결합
all 속성(CSS Cascade Level 4)은 모든 속성을 한 번에 재설정하는 단축 속성입니다:
.reset {
all: unset;
/* 210+ CSS 속성 모두 unset */
}
브라우저 구현:
- Blink: ComputedStyleBuilder::ResetAllProperties()에서 전체 속성 순회
- Gecko: nsRuleNode::ResetAllProperty()에서 배치 처리
성능 특성
all: unset 사용 시 모든 속성의 재계산이 필요하므로 성능 비용이 높습니다:
// Chrome DevTools Performance 프로파일링 결과
// all: unset 사용 시:
// - Recalculate Style: ~2.5ms (일반 재계산의 5배)
// - 영향받는 속성: 210+ properties
revert의 실무적 가치
revert는 CSS Reset보다 우아한 재설정 방법을 제공합니다:
/* 전통적 CSS Reset */
button {
margin: 0;
padding: 0;
border: none;
background: none;
/* 수십 줄의 재설정... */
}
/* revert 사용 */
button {
all: revert;
/* 브라우저 기본 스타일 유지하면서 커스텀 스타일만 제거 */
}
이는 접근성(Accessibility) 측면에서도 유리합니다. 브라우저의 기본 포커스 스타일, 아웃라인 등을 보존하여 키보드 네비게이션이 정상 작동합니다.
브라우저 호환성 주의사항
- inherit, initial: 모든 모던 브라우저 지원
- unset: IE 미지원 (Edge 13+)
- revert: Safari 9.1+, Chrome 84+, Firefox 67+
- all 속성: IE 미지원 (Edge 79+)
상속 기반 CSS 아키텍처 패턴
입문
상속을 똑똑하게 사용하면 CSS 코드를 훨씬 깔끔하게 만들 수 있어요!
🏠 큰 집에서 시작하기 웹페이지 전체에 적용될 스타일(글꼴, 글자 크기, 색상)은 body나 html 같은 가장 큰 요소에 한 번만 써놓으면 돼요. 그러면 모든 하위 요소가 자동으로 따라해요!
🎯 필요한 곳만 바꾸기 대부분은 부모에게서 물려받고, 특별히 달라야 하는 부분만 따로 정하면 돼요. 예를 들어, 전체 글씨는 검은색인데 제목만 파란색으로 하고 싶다면, 제목에만 색을 다시 지정하면 돼요.
📚 계층적으로 생각하기 전체 → 섹션 → 개별 요소 순서로 스타일을 정하면 관리가 쉬워져요. 마치 나라 → 도시 → 동네처럼 점점 좁혀가는 거예요!
🔄 반복하지 않기 똑같은 스타일을 여러 번 쓰지 마세요! 상속을 활용하면 한 번만 써도 여러 곳에 적용되니까 코드가 짧아지고 수정도 쉬워져요.
💡 실전 팁 “공통적인 건 위에, 특별한 건 아래에” 이 원칙만 기억하면 돼요!
중급
CSS 상속을 전략적으로 활용하면 유지보수 가능한 스타일 시스템을 구축할 수 있습니다.
글로벌 스타일 패턴 (Global Styles Pattern) 타이포그래피와 색상 같은 전역 스타일을 최상위 요소에 정의하여 일관성을 확보합니다.
컴포넌트 격리 패턴 (Component Isolation Pattern) 컴포넌트 루트에서 상속을 차단하여 외부 스타일로부터 격리시킵니다.
계층적 재정의 패턴 (Hierarchical Override Pattern) 상속된 값을 계층별로 점진적으로 재정의하여 특수화합니다.
/* 전역 타이포그래피 설정 */
:root {
--base-font-size: 16px;
--heading-font: 'Roboto', sans-serif;
--body-font: 'Open Sans', sans-serif;
}
html {
font-size: var(--base-font-size);
font-family: var(--body-font);
color: #333;
line-height: 1.6;
}
/* 모든 하위 요소가 자동으로 상속받음 */
/* 개별 요소에 font-family 재정의 불필요 */
.widget {
/* 외부 상속 차단 */
all: initial;
/* 컴포넌트 독립적 스타일 */
font-family: 'Custom Font', sans-serif;
color: #000;
}
/* 또는 선택적 초기화 */
.isolated-component {
font: initial;
color: initial;
/* 필요한 속성만 재정의 */
}
/* Level 1: 전역 */
body {
font-size: 16px;
color: #333;
}
/* Level 2: 섹션별 */
.dark-section {
color: #fff; /* 이 섹션만 밝은 글씨 */
}
/* Level 3: 컴포넌트별 */
.dark-section .highlight {
color: #ffeb3b; /* 강조 요소는 노란색 */
}
디자인 시스템 적용 Design Tokens를 상속과 결합하면 일관된 브랜딩과 유연한 테마 변경이 가능합니다. CSS Custom Properties(변수)를 활용하여 상속 기반 토큰 시스템을 구축할 수 있습니다.
심화
상속 기반 CSS 아키텍처는 ITCSS(Inverted Triangle CSS), SMACSS 같은 방법론의 기반이며, 대규모 프로젝트에서 스타일 충돌과 복잡도를 관리하는 핵심 전략입니다.
ITCSS의 상속 활용 (Inverted Triangle CSS)
ITCSS는 명시도와 상속 범위를 삼각형 구조로 조직화합니다:
Settings (변수) -> 가장 넓은 범위 (전역 상속)
Tools (믹스인) |
Generic (리셋) |
Elements (요소) | 명시도 증가
Objects (레이아웃) | 상속 범위 감소
Components (컴포넌트) |
Utilities (유틸리티) -> 가장 좁은 범위 (직접 지정)
Elements 레이어에서 상속 활용:
/* Elements Layer: 요소 선택자로 전역 상속 설정 */
html {
font-size: 16px; /* 모든 요소의 기준 */
}
body {
font-family: var(--font-primary);
color: var(--color-text);
line-height: 1.6;
}
h1, h2, h3 {
font-family: var(--font-heading);
/* body의 color 상속 */
}
CSS Custom Properties와 상속의 시너지
CSS 변수는 상속을 활용하여 계층적 테마 시스템을 구현합니다:
:root {
--color-primary: #007bff;
--spacing-unit: 8px;
}
.dark-theme {
--color-primary: #66b3ff; /* 하위 트리 전체에 적용 */
}
/* 변수는 상속되므로 하위 컴포넌트는 자동으로 테마 변경 반영 */
.button {
background: var(--color-primary); /* 부모의 테마 상속 */
}
성능 최적화 전략
Containment를 통한 레이아웃 재계산 범위 제한:
.large-section {
contain: layout; /* 이 요소 내부로 레이아웃 재계산 범위 제한 */
}
CSS Containment Level 2의 layout containment는 요소 내부의 레이아웃 변경이 외부로 전파되지 않도록 격리합니다. 이를 통해 대규모 DOM에서 리플로우(reflow) 범위를 제한하여 성능을 최적화할 수 있습니다.
Inheritance Boundary Pattern:
/* Anti-pattern: 깊은 상속 체인 */
.level1 { font-size: 1.2em; }
.level2 { font-size: 1.2em; } /* 1.2em × 1.2em = 1.44em */
.level3 { font-size: 1.2em; } /* 1.728em - 의도치 않은 누적 */
/* Good: rem 단위로 루트 기준 고정 */
.level1, .level2, .level3 {
font-size: 1.2rem; /* 항상 루트의 1.2배 */
}
Shadow DOM과 상속
Web Components에서 Shadow DOM은 상속 경계를 형성합니다:
class MyComponent extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
// 상속 가능 속성(color, font-family)만 Shadow DOM으로 상속됨
shadow.innerHTML = `
<style>
:host {
/* 외부 상속 차단 후 재정의 */
all: initial;
color: inherit; /* color만 선택적으로 상속 */
}
</style>
<p>Isolated content</p>
`;
}
}
상속 기반 디버깅 전략
Chrome DevTools의 Computed Styles 패널은 상속 체인을 시각화합니다:
element.style { color: blue; } <- Inline style
.class { color: red; } <- Author stylesheet
Inherited from div.parent { color: green; } <- 상속된 값
user agent stylesheet { color: black; } <- UA 기본값
실무 적용: Design System의 상속 활용
Material Design, Bootstrap 같은 디자인 시스템은 상속을 다음과 같이 활용합니다:
/* Material Design Typography Scale */
.mat-typography {
/* 전역 타이포그래피 상속 */
font-family: Roboto, sans-serif;
/* 계층별 재정의 */
.mat-display-1 { font-size: 34px; }
.mat-headline { font-size: 24px; }
.mat-body-1 { font-size: 14px; }
/* 모두 font-family는 상속받음 */
}
이러한 패턴은 테마 변경 시 단일 속성 업데이트로 전체 UI를 일관되게 변경할 수 있게 합니다.