하위 결합자는 키보드의 스페이스바(공백 한 칸 )로 표시합니다. 두 개의 선택자를 연결하는데, 뒤에 오는 선택자의 요소가 앞에 오는 선택자 요소의 자손(하위 요소)일 때 선택됩니다. 여기서 자손이란 바로 밑에 있는 자식(Child)뿐만 아니라, 손자, 증손자 등 그 안에 중첩되어 있는 모든 요소를 포함합니다. 하위 결합자를 사용한 선택자를 하위 선택자(descendant selectors)라고 부릅니다.
body article p {
}
아래 예제를 보면, 우리는 오직 .box 클래스를 가진 요소 안에 있는(하위에 있는) <p> 요소만 선택해서 빨간색 글씨를 적용했습니다. 밖에 있는 <p>는 안전하죠!
<div class="box"><p>Text in .box</p></div>
<p>Text not in .box</p>
.box p {
color: red;
}
💡 강사의 실무 팁!
이 하위 결합자는 정말 무의식적으로 매일 쓰게 될 겁니다. 예를 들어.navbar li a처럼 "내비게이션 바 안에 있는 리스트 안의 링크"에만 스타일을 줄 때 아주 유용하죠. 하지만 너무 길게 이어서 쓰면(예:.header .nav .menu ul li a span) 나중에 스타일을 덮어쓰기(Overriding) 힘들어지는 '명시도(Specificity) 지옥'에 빠질 수 있으니 주의하세요!
📝 참고사항 (Note):
Scrimba의 복합 선택자 (Compound selectors) MDN 학습 파트너라는 인터랙티브 레슨에서 하위 결합자를 직접 다루며 실습해 볼 수 있습니다.
자식 결합자는 꺾쇠괄호(>)를 사용합니다. 하위 결합자와 비슷해 보이지만 훨씬 엄격해요. 오직 앞에 있는 선택자의 직계 자식(바로 한 단계 아래)인 요소만 선택합니다. 더 깊이 중첩된 손자나 증손자 요소는 선택하지 않아요.
예를 들어, <article> 요소의 바로 밑에 있는 직계 <p> 요소만 선택하려면 이렇게 씁니다.
article > p {
/* … */
}
다음 예제를 볼까요? <ul> 태그 안에 또 다른 <ol> 태그가 중첩되어 있는 구조입니다. 여기서 ul > li 선택자를 사용하면, <ul>의 바로 직계 자식인 겉쪽 <li> 요소들만 선택되어 위쪽 빨간색 테두리가 생깁니다. 안쪽 <ol>에 속한 <li>들은 손자 뻘이기 때문에 선택되지 않아요.
<ul>
<li>Unordered item</li>
<li>
Unordered item
<ol>
<li>Item 1</li>
<li>Item 2</li>
</ol>
</li>
</ul>
ul > li {
border-top: 5px solid red;
}
💡 강사 미니 미션:
위 CSS 코드에서>기호를 지우고 그냥 스페이스바(하위 결합자)로 바꿔보세요. 어떻게 될까요? 안쪽에 숨어있던 1번, 2번<li>아이템들까지 몽땅 빨간 줄이 생기는 걸 보실 수 있을 거예요!
인접 형제 결합자는 더하기 기호(+)를 사용합니다. 이 녀석은 같은 부모를 가진 형제 요소들 중에서, 앞의 선택자 바로 뒤에 바짝 붙어있는(인접한) 요소 딱 하나만 선택합니다.
예를 들어, <p> 태그가 끝난 직후에 바로 따라오는 <img> 태그를 선택하려면 이렇게 씁니다.
p + img {
/* … */
}
이건 실무에서 제목 바로 밑에 따라오는 문단을 꾸밀 때 정말 많이 쓰입니다. 아래 예제를 보면, <h1> 태그 바로 뒤에 나오는 <p> 태그만 선택해서 배경색과 폰트를 바꿔줬어요. 그 아래에 있는 다른 <p> 태그는 <h1>과 바로 인접해 있지 않기 때문에 스타일이 적용되지 않죠.
<article>
<h1>A heading</h1>
<p>
Veggies es bonus vobis, proinde vos postulo essum magis kohlrabi welsh onion
daikon amaranth tatsoi tomatillo melon azuki bean garlic.
</p>
<p>
Gumbo beet greens corn soko endive gumbo gourd. Parsley shallot courgette
tatsoi pea sprouts fava bean collard greens dandelion okra wakame tomato.
Dandelion cucumber earthnut pea peanut soko zucchini.
</p>
</article>
body {
font-family: sans-serif;
}
h1 + p {
font-weight: bold;
background-color: #333333;
color: white;
padding: 0.5em;
}
💡 강사의 실무 팁!
"여백(Margin) 상쇄" 문제를 해결하거나, 폼(Form) 요소에서 유효성 검사를 할 때 정말 빛을 발합니다. 예를 들어input:invalid + .error-message처럼 작성하면, input 창에 에러가 났을 때 바로 밑에 있는 에러 메시지 창을 띄우는 동작을 자바스크립트 없이 CSS만으로 구현할 수 있어요!
위 예제에서 이렇게 실험해 보세요:
1. HTML에서 <h1>과 첫 번째 <p> 사이에 <h2> 같은 다른 태그를 하나 몰래 끼워 넣어 보세요. 어떻게 되나요? 이제 <p>가 <h1>의 바로 다음 형제가 아니게 되면서, 까만색 배경 스타일이 쏙 빠져버릴 겁니다.
2. 그럼 방금 추가한 <h2> 바로 밑의 <p>에 다시 스타일이 먹히도록 하려면 CSS를 어떻게 고쳐야 할까요? h1 + p를 h2 + p로 슬쩍 바꿔주면 해결되겠죠!
바로 옆에 바짝 붙어있지 않더라도, 어쨌든 같은 부모 밑에 있는 동생(뒤에 나오는 형제)들을 몽땅 선택하고 싶다면? 그때는 틸드 기호(~)를 사용하는 일반 형제 결합자를 쓰면 됩니다.
예를 들어, <p> 태그보다 뒤에 나오는 모든 <img> 태그를 다 선택하고 싶다면 이렇게 씁니다.
p ~ img {
/* … */
}
아래 예제에서는 <h1> 뒤에 나오는 모든 <p>를 선택하도록 h1 ~ p라고 작성했어요. 중간에 뜬금없이 <div>가 하나 끼어있지만, 그 <div> 뒤에 나오는 <p> 역시 <h1>의 동생이 맞기 때문에 스타일이 잘 적용되는 걸 확인할 수 있습니다.
<article>
<h1>A heading</h1>
<p>I am a paragraph.</p>
<div>I am a div</div>
<p>I am another paragraph.</p>
</article>
body {
font-family: sans-serif;
}
h1 ~ p {
font-weight: bold;
background-color: #333333;
color: white;
padding: 0.5em;
}
우리가 이전에 배웠던 요소, 클래스, 아이디, 속성, 가상 클래스 등등... 이 모든 선택자들을 오늘 배운 결합자와 자유롭게 짬뽕해서 쓸 수 있습니다!
예를 들어, "어떤 <ul> 태그의 직계 자식(>)인 <li> 태그들 중에서, 속성값이 딱 a인 클래스([class="a"])를 가진 녀석!"을 타겟팅하고 싶다면 이렇게 쓰면 됩니다.
ul > li[class="a"] {
}
⚠️ 강사의 주의사항! (매우 중요)
이렇게 길고 복잡하게 엮어서 "이 문서의 요기 요 위치에 있는 요 태그!"라고 너무 구체적으로 지정하는 건, 초보자분들이 자주 하는 실수 중 하나입니다.코드가 이렇게 엮여버리면 나중에 HTML 구조가 조금만 바뀌어도 CSS가 와장창 깨져버려요. 게다가 이 스타일을 다른 페이지에서 재사용하기도 거의 불가능해지죠.
실무에서는 보통 이렇게 길게 엮기보다는, 차라리 그 HTML 태그에 직접 의미 있는 클래스(예:
.highlight-item)를 하나 달아주고 그 클래스로 심플하게 스타일링하는 것을 훨씬 권장합니다. BEM(Block Element Modifier) 같은 CSS 방법론이 나온 이유도 바로 이 때문이죠.다만, 여러분이 워드프레스 같은 CMS(콘텐츠 관리 시스템)를 다루거나, 외부 라이브러리를 써서 HTML을 마음대로 수정할 수 없는 억울한(?) 상황에 처했을 때는 오늘 배운 결합자 지식이 여러분을 살려주는 동아줄이 될 것입니다!