내 CSS가 자꾸 깨지는 이유

A mug written CSS IS AWESOME

내 CSS는 왜 자꾸 깨지는 걸까?

매번 원치 않게 CSS가 깨지는 이유가 뭘까? 우선 ‘깨진다’는 것의 정의를 새롭게 해보자. 깨진다는 것은 다음과 같이 세분화할 수 있다.

  • 의도치 않게 영역을 벗어나는 경우
  • 의도하지 않은 좌우 위치
  • 의도하지 않은 상하(z-index) 위치

의도치 않게 영역을 벗어나는 경우

이런 경우를 오버플로우라고 부른다. 오버플로우는 왜 일어나는 걸까? 당연히 오버플로우를 허용했기 때문이다. 이를 해결하려면 부모 엘리먼트가 자식 엘리먼트들을 모두 감싸도록 만들어주면 된다. 이렇게 정의된 레이아웃 영역을 Block Formatting Context라 부른다.

MDN: Block Formatting Context

BFC를 정의하려면, 가장 간단하게는 overflow: auto 를 지정해주면 된다. BFC는 레이아웃에 속한 작은 레이아웃이다. 이 속에서는 모든 요소들이 해당 블록 안에 속하게 된다. (내부 요소의 마진까지도 속한다)

BFC를 만드는 방법

  • position: absolute, position: fixed
  • display: inline-block, display: table-cell, display: table-caption
  • overflow: auto
  • display: flow-root는 기존의 방법들은 모호한 감이 있어서 (왜 그 속성을 지정한 것인지 맥락을 이해하기 힘들다) 새롭게 제안된 속성이다.

BFC와 관련된 내용

  • Margin collapsing: 같은 BFC 내의 엘리먼트들의 마진이 겹치는 경우, 더 큰 마진 하나만 적용된다.
  • Inline overflow
    • text-overflow의 경우 white-space: nowrap; 속성을 통해서 overflow 가 일어난다. 이를 content box의 overflow: hiddentext-overflow: ellipsis;로 해결할 수 있다. (css3)

의도하지 않은 좌우 위치

Box Model

HTML의 요소들은 박스 모델을 기준으로 배치된다. box-sizing 속성으로 박스 모델의 기준을 변경할 수 있다. 기본값은 content-box 인데, 이 값의 기준은 border 내부의 content-edge이다. border-box 로 지정을 하면 border까지를 기준으로 삼을 수 있다.

See the Pen CSS Box Model explained by kidkkr (@kidkkr) on CodePen.

위 예시는 모두 너비가 100%로 지정된 세 개의 박스이다.

  • #1은 기본 값인 content-box 기준으로 border 내부의 너비가 100%로 되어 boder가 삐져나왔다.
  • #2는 마찬가지로 content-box 기준으로 padding값을 지정해주어 padding 영역 내부의 너비가 100%로 되어 더 많이 삐져나왔다.
  • #3은 box-sizing으로 border영역까지 포함한 너비가 100%가 되었다.

이때 각 박스의 내부에서 자식 엘리먼트를 position: relative로 좌우 위치를 지정하면 어떻게 될까? 각 박스들의 자식 엘리먼트들은 content-box 영역에서 배치되기 시작한다. 어디까지가 박스의 content인지 알아야 좌우 위치를 예측할 수 있을 것이다.

의도치 않은 상하(z-index) 위치

z-index는 단위를 갖지 않는 상대적인 값이다. 따라서 BFC와 마찬가지로 z-index도 상대적인 값이 의미가 있는 context가 존재한다. 이를 z-index stacking context라 부른다.

See the Pen Z-index stacking context explained by kidkkr (@kidkkr) on CodePen.

위 예시에서 빨간색 동그라미는 겹치는 사각형들보다 낮은 z-index를 갖지만 서로 다른 context에 존재하기 때문에 사각형들 위에 위치한다. 따라서 의도한 대로 z-index를 위치시키려면 이런 stacking context를 만들어 주면 되는데, 가장 손쉬운 방법은 position: relative; z-index: 0; 으로 context를 만들어주는 것이다.

참고자료