HTML, CSS

CSS Combinators(결합자) :: 마이구미

mygumi 2019. 4. 4. 20:02
반응형
이 글은 CSS 의 결합자(Combinators) 에 대해 다룬다.
각 결합자를 단순한 예제가 아닌, 실제로 많이 사용하고, 활용할 수 있는 예제를 통해 진행한다.
본인은 부끄럽게도 최근 들어서야, 모든 결합자를 사용하고 있다.
혹시나 특정 몇개만 사용하거나, 각 용도를 구분해서 사용하지 않고 있다면, 도움이 될 것이다.
우선 결론적으로, 이 글을 작성하게 된 이유는 인접 형제 결합자와 일반 형제 결합자 때문이다.

 

CSS 구문에 있어, 크게 선택자와 결합자로 분류할 수 있다.

CSS 선택자는 스타일을 적용시키기 위한 HTML 요소를 선택할 수 있다.

 

h1 {...}
#app {...}
.container {...}
input[type="text"] {...}

 

위와 같은 정해진 규칙(선택자)을 통해 우리는 쉽게 요소에 접근할 수 있다.

하지만 조금 더 복잡해지면, 위와 같은 형태로는 상당한 고충이 있다.

부모-자식, 조상-자손 등의 관계가 깊어질수록 요소를 선택하는 데 있어서, 우리가 원하는 요소는 더욱 세밀하게 찾아야한다.

이러한 상황에서 하나의 선택자만으로는 세밀하게 원하는 요소를 찾는 것이 굉장히 비효율적이다.

 

이를 위해, 하나의 선택자가 아닌 선택자들을 결합하여 세밀하게 찾을 수 있는 것이 바로 결합자(Combinator)이다.

결합자는 크게 4가지 종류로 볼 수 있다.

 

  • 자손(Descendant) 결합자 (A B)
  • 자식(Child) 결합자 (A > B)
  • 인접 형제(Adjacent sibling) 결합자 (A + B)
  • 일반 형제(General sibling) 결합자 (A ~ B)

 

성격으로 분류하면 {자손 결합자, 자식 결합자}, {인접 형제 결합자, 일반 형제 결합자} 로 나눌 수 있다.

자손, 자식 결합자는 부모-자식 관계와 같은 계층 구조에 영향을 준다.

형제 결합자는 단어 그대로, 부모-자식이 아닌 형제와 관련이 있다.

 

우선, 자손 결합자부터 차례대로 알아보자.

 

A B
ex).parent .child

 

자손 결합자는 A 를 만족하는 요소의 자손(하위) 요소 중 B 를 만족하는 요소를 가르킨다. (A의 자식, A의 자식의 자식, A의 자식의 자식의 자식...)

실제로 처음에 많이 사용하고, 웬만한 경우를 모두 처리할 수 있기 때문에 익숙할 것이다.

하지만 이것을 위주로 사용하는 습관이 생기면 안 좋은 상황이 발생할 수 있다.

그 예로는 본인이 원하지 않았던 자손들에게까지 영향을 끼치는 것이다.

 

1
2
3
4
5
6
7
8
9
10
11
<div>
   <p>I want red</p>
    <p>I want red</p>
   <div>
       <p>I don't want red</p>
   </div>
</div>
 
div p {
   color: red;
}
cs

 

위처럼 사용할 경우에는 모든 <p> 태그의 글자색은 빨간색으로 적용되어 원치 않는 결과를 초래한다.

 

그렇다면, 자식 결합자는 무엇인가?

 

A > B
ex) .praent > .child

 

자식 결합자는 A 를 만족하는 요소의 자식 요소 중 B 를 만족하는 요소를 가르킨다. (A의 자식)

자손 결합자는 모든 자손들을 가르킨다면, 자식 결합자는 본인의 자식만을 가르킨다.

개인적으로 본인이 좋아하는 결합자이다.

본인은 이 결합자를 통해, 추후에 요소들의 관계와 작성된 CSS 목적을 파악하기도 한다.

 

1
2
3
4
5
6
7
8
9
10
11
<div>
   <p>I want red</p>
    <p>I want red</p>
   <div>
       <p>I don't want red</p>
   </div>
</div>
 
div > p {
   color: red;
}
cs

 

자손 결합자를 사용해서 원치 않던 결과를 자식 결합자를 사용해서 우리는 원하는 자식만을 스타일을 적용할 수 있다.

자손, 자식 결합자는 대부분 작성되는 요소들은 계층 구조를 가지기 때문에, 일반적으로 많이 사용되는 결합자이다.

 

그렇다면, 형제 결합자란 무엇인가?

우선 형제란, 같은 레벨 또는 층에 있다고 보면 된다.

이러한 의미는 결국 형제 결합자 A와 B 는 같은 부모를 가르키고 있다는 것을 뜻한다.

 

그렇다면, 형제 결합자 중 일반 형제 결합자는 무엇인가?

 

A ~ B
ex) p ~ span

 

일반 형제 결합자는 A 의 다음 형제 요소를 만족하면서 B 를 만족하는 요소를 가르킨다.

형제 요소를 많이 사용하는 예는 <input> 태그를 사용할 경우이다.

<input> 태그에 대한 checkbox, radio 같은 것을 커스텀하거나, <label> 태그를 사용하고 싶을 때 유용하다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<input type="checkbox" id="checkbox-1" value="Apple">
<label for="checkbox-1">Apple</label> 
<div class="check check-checkbox"></div>
 
input:checked ~ .check {
    border: 5px solid red;
}
 
input:checked ~ .check::before {
    background: red;
}
 
input:checked ~ .check-checkbox {
    background: red;
    &:before {
        opacity: 1;
    }
}
 
input:checked + label {
    color: red;
}
cs

 

위처럼 대부분 <input> 태그의 형제 요소에 <label> 태그 또는 커스텀 div 를 작성하여 조작한다.

이처럼 형제 요소를 찾는 경우에서 굉장히 유용하게 사용할 수 있다. (아래 전체 예제 코드가 존재한다)

 

인접 형제 결합자는 무엇인가?

 

A + B
ex) h2 + p

 

인접 형제 결합자는 A 의 바로 즉시 오는 다음 형제 요소를 만족하면서 B 를 만족하는 요소를 가르킨다.

다시 말하면, A 요소 바로 즉시 다음에 오는 형제 요소를 가르키는데 그 요소는 B 를 만족해야한다.

 

1
2
3
4
5
6
7
<h2>H2</h2>
<p>P</p>
<span>SPAN</span>
 
h2 + span {
    color: red;
}
cs

 

위와 같은 CSS 스타일은 적용되지않는다.

h2 바로 즉시 다음에 오는 요소는 span 태그가 아닌 p 태그이기 때문에 조건에 맞지 않는다.

일반 형제 결합자보다 더 타이트하다고 볼 수 있다.

 

일반 형제 결합자에서 사용한 예제에 일반 형제 결합자로 업데이트하면 다음과 같다.

 

1
2
3
input:checked + label {
    color: red;
}
cs

 

<input> 태그 다음에 오는 <label> 태그에 스타일을 부여한다는 의미를 명확하게 작성해줄 수 있다.

 

결론적으로, 1)두 형제 결합자 모두 다음에 오는 요소에 영향을 준다.

이 의미는 형제 결합자는 형제라도 이전에 존재하는 것이 아닌, 다음에 위치해야한다는 것이다.

 

1
2
3
4
5
6
7
8
<p>no change<p>
<h1>H1</h1>
<p>P1</p>
<p>P2</p>
 
h1 ~ p {
    color: red;
}
cs

 

그리고 2)일반 형제 결합자는 형제 요소가 즉시 오지 않아도 되고, 인접 형제 결합자는 즉시 와야한다.

 

사실상 두 형제 결합자의 모든 차이점은 영향을 끼치는 요소의 갯수의 차이에서 온다.

일반 형제 결합자는 하나 또는 두개이상의 요소에 영향을 끼치고, 인접 형제 결합자는 하나의 요소에만 영향을 끼친다.

 

모든 결합자를 목적에 맞게 사용한다면, CSS 코드 작성에 도움이 될 것이다.

 

마지막으로 글에서 설명한 모든 결합자를 사용한 예제 코드이다.

 

See the Pen input[type='checkbox'] by leejunghyun (@mygumi) on CodePen.

 

반응형