이전 포스팅에서 다뤄봤던 Jank 현상은 앞서 말했던 방법으로 해결 가능하다.
그러나 더 간단한 방법이 있었으니...
jank 현상이 일어났던 진짜 원인은 다른 데 있었다.
결론
결론 먼저 말하자면 여백 상쇄 현상을 제거하니
기존 코드에서도 jank가 발생하지 않았다.
...그런데 여백상쇄가 무엇일까?
이번에도 어렵게 돌아가기 스타트
margin collapse (마진 상쇄, 여백상쇄)
margin collapse(이하 여백 상쇄)란, 수직으로 맞닿은 블록의 마진은 가장 큰 값으로 수렴한다는 뜻이다.
말이 더 어려운 것 같은데, 그림으로 살펴보면 다음과 같다.
위의 예시는 형제끼리 맞닿아 있을 때를 나타낸 것이고, 부모 자식 간에도 여백 상쇄가 일어난다.
부모와 자식이 맞닿아 있을 때에는 조금 특이한 현상이 발생하는데, 바로 부모 요소가 자식 요소의 마진값만큼 아래로 내려온다는 것.
부모 요소의 높이값이 따로 정해져 있지 않다면 높이(height) 자체가 줄어드는 것을 볼 수 있다.
블록 레벨 요소의 height 값을 결정할 때 부모와 자식 요소간에 여백 상쇄가 발생하면 브라우저 렌더링할 때 자식 요소의 margin-top이나 margin-bottom값을 부모 요소의 높이 계산에 고려하지 않는다.
따라서 부모와 자식 요소의 마진이 하나로 합쳐져 같은 경계에서 시작하고 끝난다. 실제 화면에서는 확인할 수 없지만, 개발자도구를 이용해 경계를 그려보면 알 수 있다.
여백 상쇄 또한 브라우저 layout(혹은 reflow) 과정에서 상위 요소와 자식 요소 사이의 마진에 대하여 연산이 들어가기 때문에, 여백 상쇄가 일어난 요소에 애니메이션이 들어가면 jank가 일어날 가능성이 있다. 애니메이션이 필요한 경우에는 렌더링 최적화를 위해 여백 상쇄 현상도 고려하는 것이 좋겠다.
여백 상쇄 해결하기
그렇다면 여백 상쇄를 어떻게 해결하면 좋을까?
w3c의 여백 상쇄 명세를 보고 하나씩 타파해보자!
w3c 여백상쇄 관련 내용
https://www.w3.org/TR/CSS2/box.html#collapsing-margins
- 둘 다 동일한 블록 서식 맥락(block format context)이고, 플로우(in-flow)에 속하는 블록 모델
- 두 요소를 나누는 line box, 클리어런스X, padding, border 등이 없어야함
- 수직으로 만나야 함
- top-margin이 있는 부모와 자식 요소
- bottom-margin이 있는 요소와 top-margin이 있는 형제 요소
- bottom-margin이 있는 마지막 자식 요소와 bottom-margin이 있는 부모요소 (부모 높이값은 auto계산)
- 블록서식맥락을 설정하지 않은 박스(min-height가 0, height가 0이거나 auto, 그리고 플로우에 속하는 자식 없음)
명세서라 그런가 단어 자체가 생소하고 명확하게 파악하기 쉽지가 않다.
어떤 뜻인지 간단하게 살펴보고 많이 사용하는 여백 상쇄 타파 방법을 알아보자
둘 다 같은 블록 서식 맥락(block format context)이고,
플로우(in-flow)에 속하는 블록 모델
블록 서식 맥락(block format context)
CSS가 화면에 렌더링 할 때 미니 레이아웃으로, 블록 상자를 배치하고 플로트 요소가 다른 요소와 상호작용하는 하나의 영역. 우리가 명시적으로 볼 수 없지만 CSS 내부적으로 화면에 있는 요소들을 묶는 방식이라 생각 하면 될 것 같다.
아래 mdn링크에서 나오는 것처럼 블록 서식 맥락을 새로 생성하는 방법은 많다. 여러 가지 방법 중 가장 많이 사용한 건 아래와 같다.
⇒ overflow 옵션을 주거나 position값을 absolute로 변경
블록 서식 맥락 참고
https://developer.mozilla.org/ko/docs/Web/Guide/CSS/Block_formatting_context
https://www.smashingmagazine.com/2017/12/understanding-css-layout-block-formatting-context/
플로우에 속하는 모델(in-flow block-level boxes)
CSS는 일반적으로 블록요소는 수직으로 쌓이고 인라인 요소는 가로로 쌓인다. 이 일련의 흐름을 flow라고 하고 이 흐름에 몸을 맡기는 것들을 in-flow box라고 하는 것. flow에서 벗어나는 예를 들어보자면 float 옵션이 있는 아이템, position:absolute(and fixed) 루트 요소(html) 등이 있다.
⇒ 플로우에서 벗어나기 위해 float를 준다, position을 absolute로 변경 등
두 요소를 나누는 line box, clear, padding, border 등이 없어야함
두 요소 사이에 아무것도 없어야 여백 상쇄가 일어난다. 그런데, 이걸 해결하자고 없던 텍스트를 넣거나 없는 보더를 넣을 순 없으니
⇒ 그래서 보통 margin 대신 padding을 이용해서 여백을 조절.
line box
텍스트요소를 렌더링 할 때 생성되는 line-height높이의 박스.
라인 박스 참고 : https://ohgyun.com/572
수직으로 만나야 함
⇒ 가로로 만날 때는 안생긴다! 끝!
..이면 좋겠지만 농담이고 인접하는 경우를 명세와 아래 참고자료에서는 더 자세하게 분류했다. 자료들을 보고 위에서 제시한 방법들 중 어떤 것을 어떨 때 사용해야 효울적일지 확인해보자.
여백 상쇄가 일어나는 다양한 관계에 대한 참고
https://velog.io/@raram2/CSS-마진-상쇄Margin-collapsing-원리-완벽-이해
여백 상쇄를 없애는 대표적인 여러 방법
- overflow:auto;
- margin 대신 padding
- position:absolute;