티스토리 뷰
개요
프론트엔드 전문이 아닌 개발자가 CSS로 고통받는 이유는 CSS의 요소들이 예상한 대로 동작하지 않기 때문이다. 이번 포스팅은 CSS에 대한 기본적인 개념이라기보다 CSS로 고통받는 순간에 확인해볼 만한 키워드들을 정리해보았다.
그리고 CSS를 공부한 지 오래된 백엔드 개발자라면, 특히 flexbox나 grid가 아직까지도 잘 사용되지 않는다고 믿는다면 다시 한번 공부하고 mdn 문서와 친해지는 것을 적극 권한다.
1. Margin Collapsing (margin 상쇄)
margin-top, margin-bottom이 의도한 대로 동작하지 않는다면 Margin Collapsing(이하 margin 상쇄)을 의심해봐야 한다. margin 상쇄란 여러 개의 margin 중 제일 큰 margin만 사용되는 현상을 말하며 위쪽(top), 아래쪽(bottom)에 대해서만 발생한다. margin 상쇄는 다음 세 가지 상황에서 발생한다.
1.1 인접 형제간의 margin 상쇄
<div>
<div id="first-sibling"> 형제1 </div>
<div id="second-sibling"> 형제2 </div>
</div>
#first-sibling {
margin-bottom: 50px;
}
#second-sibling {
margin-top: 100px;
}
형제1은 margin-bottom:50px을 형제2는 margin-top:100px을 갖고 있다. 두 형제가 만나는 접점에서 서로의 margin이 적용된다면 총 150px의 여백이 존재해야 하지만 100px만큼만 적용된다. margin 상쇄 현상이 발생되었기 때문이다. 형제1의 margin-bottom 값을 수정하더라도 100px이상 넘어가지 않는다면 여백은 변하지 않는다.
1.2 부모 자식 간의 margin 상쇄
<div id="parent">
<div id="child">Child</div>
</div>
#parent {
margin-top: 50px ;
}
#child {
margin-top: 100px;
}
부모는 margin-top:50px을 자식은 margin-top:100px을 갖고 있다. 이러한 경우 중첩된 margin-top값 중에 더 큰 100px만 적용된다. margin 상쇄 현상이 발생되었기 때문이다. 부모의 margin-top 값을 수정하더라도 100px이상 넘어가지 않는다면 여백은 변하지 않는다.
부모 자식간의 margin 상쇄는 부모와 자식이 온전히 포개졌을 때만 발생한다. 다시 말해 부모와 자식 사이의 border, padding, (글자와 같은) 인라인 부분이 있다면 발생되지 않는다. 이러한 경우 자식의 margin-top만큼 부모의 content가 채워지게 되고, 부모의 margin-top값도 별도로 적용된다.
1.3 Empty blocks
<div>Hello</div>
<div></div>
<div>World</div>
div {
margin: 10px 0;
}
위와 같이 인접한 요소들 중에서 boder, padding, (글자와 같은) 인라인 부분, height값이 없는 요소가 존재하다면 해당 요소의 margin은 무시된다. 첫 번째와 세 번째 div 요소는 글자가 있지만 두 번째 div는 글자와 어떠한 border, padding, height값이 없기 때문에 margin 값을 변경해도 여백은 변하지 않는다.
첫 번째와 세 번째 사이에는 margin이 10px만 적용된다. 20px이 아닌 이유는 형제간의 margin 상쇄가 발생했기 때문이다.
2. position과 top, bottom, left, right, z-index
top, bottom, left, right, z-index와 같은 속성을 사용하여서 요소들을 원하는 곳에 위치시키기 어렵다면 position에 대한 이해가 없기 때문이다. position에 대해서 공부를 하자.
top, bottom, left, right, z-index 를 사용하기 위한 가장 기본적인 전제는 position이 static이면 안된다는 점이다. position은 기본값이 static이기 때문에 반드시 명시적으로 position을 변경해주어야 한다. 참고로 position을 변경하더라도 페이지 레이아웃에서 요소가 차지하는 공간은 static일 때와 같기 때문에 다른 요소들의 레이아웃에 영향을 주지 않는다. 시각적으로 보이는 것만 변경시킨다는 말이다.
일반적인 상황에서 top, bottom, left, right를 사용한다면 position: relative면 충분하다. 레이아웃상 기본적으로 배치되는 위치를 기준으로 이동을 할 수 있다.
스크롤을 해도 같은 자리에 고정시키고 싶다면 position: fixed를 사용한다. 레이아웃상 배치되는 위치가 아닌 화면(브라우저)을 기준으로 움직이게 된다. position: absolute는 fixed와 유사해 보이지만 화면에 고정된 값이 아닌 position이 static이 아닌 가장 가까운 조상을 기준으로 움직인다. 즉 absolute를 제대로 사용하기 위해서는 기준점으로 삼을 조상의 position을 명시적으로 선언해줘야 한다.
z-index는 Z축 순서를 지정하게 되는데 relative인 요소들끼리는 z-index가 양수인 경우 아무런 영향을 주지 않는다. 하나를 음수로 지정하거나, 하나 이상의 요소가 fixed 혹은 absolute처럼 다른 layer를 나타내는 position이어야 한다.
3. display: inline
width, height, margin-top, margin-bottom이 의도한 대로 동작하지 않는다면 해당 요소가 display: inline이 아닌지 확인해야 한다. display: inline인 경우 width, height, margin-top, margin-bottom 속성을 사용할 수 없다. (display: inline-block인 경우는 사용 가능하다.)
display의 기본값이 inline인 요소들과 아닌 요소들을 알아두는 것도 좋은데, <span>, <a>, <img> 태그는 display의 기본값이 inline이고 나머지는 대부분 diplay: block이다.
4. Cascading Style Sheet & 명시도
설정된 속성이 아닌 값으로 계속해서 덮어씌워진다면 CSS의 풀네임 중 Cascading이라는 키워드에 집중해보자. 기본적으로 페이지의 흐름상 '아래에' 선언된 스타일이 적용된다.
만약 하나의 요소에 적용되는 스타일이 중복으로 존재한다면 어떠한 우선순위를 갖는지도 확인해봐야 한다. ID Selector는 Class Selctor보다 우선순위를 갖게 되며 Class Selctor는 Type Selector보다 우선순위를 갖는다.
<div class="my_class">Hello</div>
.my_class {
background-color: blue;
}
div {
background-color: red;
}
위와 같이 Type Selector의 값이 더 아래에 설정되었더라도 Class Selector의 우선순위가 더 높기 때문에 <div class="my_class"> Hello </div>
요소는 배경으로 파란(blue) 색을 갖게 된다.
명시도와 관련하여 자세한 사항은 문서 참고 https://developer.mozilla.org/ko/docs/Web/CSS/Specificity