:first-child, :first-of-type 차이 :: 마이구미
이 글은 CSS 의 :first-child 와 :first-of-type 차이를 다룬다.
first 이외에도 last-*, nth-* 와 같은 셀렉터가 존재하기 때문에, 크게 *-child, *-type 으로 볼 수 있다.
같은 결과를 내는 경우가 많지만, 분명 다른 차이를 가지고 있다.
둘 사이의 차이를 인지하고 있지 않다면, 예기치 못한 이슈를 발생할 것이다.
<div class="parent">
<h1>TITLE</h1>
<div class="child">Child1</div>
<div class="child">Child2</div>
<div class="child">Child3</div>
<div class="child">Child4</div>
</div>
.parent > .child:first-child {
color: red;
}
위와 같은 코드의 결과가 어떻게 나올 것 같은가? (엘리멘트를 요소라고 말하겠다.)
클래스명이 parent 요소의 다음 자식인 DIV 요소들 중의 첫번째 요소를 선택하는 CSS 셀렉터를 작성했다.
본인은 처음에 아무 문제 없이 동작할 것이라 예상했지만, 결과는 아무런 변화가 존재하지 않았다.
그래서 반대의 경우로, first-child 대신 last-child 를 써서 잘 동작하는지 확인해보았다.
.parent > .child.last-child {
color: red;
}
결과는 원하는 대로, Child4 텍스트가 빨간색을 노출했다.
결과적으로, first-child 는 원하는 결과가 아니였지만, last-child 은 원하는 결과를 냈다.
이로 인해, first-child 는 내가 추측 또는 알고 있던 정보가 아니라는 것을 인지했다.
본론으로 넘어가서, first-child 와 first-of-type 를 차이를 알아본다.
MDN 의 정의에 의하면, 다음과 같다.
:first-child => 형제 요소의 그룹 중 첫번째 요소를 나타낸다.
:first-of-type => 형제 요소의 그룹 중 해당 타입의 첫번째 요소를 나타낸다.
형제 요소란, 태그 or 클래스명 등과 같은 것으로 구분하는 것이 아닌, 단순히 같은 레벨의 요소라고 보면 된다.
아래는 같은 색상을 가진 요소들은 서로 형제라는 것을 의미한다.
<div>
<div class="a">
<h1/>
<div/>
</div>
<div class="b"></div>
</div>
<ul></ul>
정의대로 해석하면, 클래스명이 .child 인 요소의 형제 요소는 <div class="child"> 요소 4개뿐만 아니라, <h1> 요소도 같은 레벨에 있는 형제 요소에 포함된다.
아무리 클래스명을 child 로 지정했다해도, first-child 는 형제 요소를 찾는 것이고, 단순히 부모 요소의 자식 요소들을 찾는다고 보면 이해하기 쉽다.
즉, <div class="parent"> 의 자식 요소들은 <h1> 1개, <div class="child"> 4개로, 총 5개가 된다.
이러한 자식 요소 중 first-child 는 <h1> 요소가 되기에, 본인이 원하는 결과를 볼 수 없었던 것이다.
그로 인해, 원하는 결과를 내기 위해서는 타입을 고려하는 first-of-type 을 사용해서 해결할 수 있었다.
<div class="parent">
<h1>TITLE</h1>
<div class="child">Child1</div>
<div class="child">Child2</div>
<div class="child">Child3</div>
<div class="child">Child4</div>
</div>
.parent > .child:first-of-type {
color: red;
}
last-*, nth-* 과 같은 CSS 셀렉터도 같은 맥락으로 이해하면 된다.
<div class="parent">
<h1>TITLE</h1> /* :first-child, :first-of-type, h1:first-child, h1:first-of-type */
<div class="child">Child1</div> /* :first-of-type, .child:nth-child(2), .child:first-of-type */
<div class="child">Child2</div> /* .child:nth-child(3) */
<div class="child">Child3</div> /* .child:nth-child(4) */
<div class="child">Child4</div> /* .child:nth-child(5) */
<button>Click</button> /* :last-child */
</div>
주의할 점으로는, :first-of-type 은 위처럼(빨간색) <h1>, <div> 중복으로 결과를 낼 수 있다.
그렇기에 명확히 셀럭터를 명확히 표현해주면 더더욱 좋을 것이다.
.parent > :first-of-type {} // bad
.parent > .child:first-of-type {} // better
.parent > div:first-of-type {} // better
본인은 child 를 사용하는 것보다 type 을 사용하는 것이 훨씬 유용한 방식이라고 생각한다.
예를 들어 코드를 수정하는 경우, 자식 요소에 다른 요소 추가될지 모르기 때문에, 이는 훨씬 느슨한 관계를 유지할 수 방법 중 하나가 될 것이다.
본인의 경우 type 과 비교해서 child 를 쓰면 더 좋은 경우가 있는지 모르겠다.
어쩔 수 없이 익스플로러의 경우 ie9 이상 지원하는 것처럼, 하위 브라우저 지원하지 못하는 이슈가 크지 않을까한다.
(있으면 댓글을 통해 알려주면 좋겠다.)