본문 바로가기

FrontEnd

[번역] CSS margin(마진)에 대한 모든 것(with 마진 겹침)

반응형

CSS 마진은 언뜻 보기에 단순해 보입니다.

요소 주변에 공간을 형성하여 다른 요소를 밀어냅니다.

하지만 마진에는 당신이 모르는 몇가지 함정이 숨어있습니다.

해당 게시물에서는 CSS 마진과 마진에 숨어있는 함정을 다룹니다.

아래 게시물의 번역입니다.

https://www.smashingmagazine.com/2019/07/margins-in-css/

 

Everything You Need To Know About CSS Margins — Smashing Magazine

Margins in CSS seem simple enough at first glance. Applied to an element it forms a space around the element, pushing other elements away. However, there is more to a margin than you might think.

www.smashingmagazine.com

마진은 CSS BOX 모델의 구성 요소 중 하나로, 박스 주변의 투명한 여백으로서, 박스 컨텐츠로부터 다른 요소를 밀어냅니다.

margin 속성은 margin-top, margin-right, margin-bottom, margin-left의 속기(shorthend) 형식으로,

CSS1부터 존재했습니다.

 

마진은 언뜻 단순해 보이지만 사람들을 놀라게 하는 몇 가지 사항이 존재합니다
이 기사에서는 마진이 서로 어떻게 상호 작용하는지, 마진 겹침이 어떻게 동작하는지 살펴볼 것입니다.

CSS Box Model

박스 모델은 상자의 다양한 부분(컨텐츠, 패딩, 보더 및 마진)이 배치되고 서로 상호 작용하는 방법을 나타냅니다.
CSS1에서 Box Model은 아래 이미지에 표시된 ASCII 아트 다이어그램으로 자세히 설명되었습니다.
 
CSS1 스펙에서 설명하는 BOX 모델의 아스키 아트 다이어그램

상자의 각 모서리에 해당하는 네 가지 마진 속성과 마진 속기 표현 속성 모두 CSS1에서 정의되었습니다.

CSS2.1 사양에는 박스 모델을 설명하는 그림이 있으며, 박스 모델 내 존재하는 상자를 설명하는 용어는 이전과 동일합니다.
사양은 content box, padding box, border box, and margin box를 설명하며 각각
콘텐츠의 가장자리, 패딩, 테두리 및 마진으로 정의됩니다.
CSS2의 박스 모델 묘사

CSS3(Level 3 Box Model specification)은 CSS2 박스 모델과 거의 동일합니다.

CSS3 박스 모델 이미지

마진 겹침(Margin Collapsing)

마진을 처음으로 정의한 CSS1 사양은 세로 방향 마진 겹침도 정의합니다.
초기에 CSS가 디자인 용도보단, 문서 서식을 위한 언어로 사용되었다는 점을 고려하면 마진 겹침이 의미가 있습니다.
마진 겹침은 아래쪽 마진이 있는 제목 다음에 위쪽 마진이 있는 단락이 올 때 두 단락 사이에 너무 큰 간격이 생기는 것을 예방해줍니다.
 

마진이 겹치면 두 요소 사이의 마진은, 더 큰 쪽을 따르게 됩니다.
즉, 작은 마진은 더 큰 마진 내부에서 끝나게 됩니다.

 

다음 상황에서 마진 겹침이 발생합니다.

  • 인접한 형제와 마진 겹침
  • 완전히 비어있는 박스와의 마진 겹침
  • 부모와 첫번째 자식, 마지막 자식 간의 마진 겹침
각 시나리오를 하나씩 살펴보겠습니다.

인접한 형제와 마진 겹침(ADJACENT SIBLINGS)

인접한 형제 사이의 마진은 겹칠 수 있습니다.
아래에 언급된 상황을 제외하고,
일반적인 흐름에서 두 개의 요소가 차례로 표시되는 경우
첫 번째 요소의 아래쪽 마진이 다음 요소의 위쪽 마진과 겹칩니다.
 
아래 CodePen 예제에는 3개의 div 요소가 있습니다.
  • 첫 번째는 위쪽 및 아래쪽 마진이 50px입니다.
  • 두 번째는 상단 및 하단 마진이 20px입니다.
  • 세 번째는 위쪽 및 아래쪽 마진이 3em입니다.
처음 두 요소 사이의 마진은 50픽셀입니다. 작은 위쪽 마진이 큰 아래쪽 마진과 결합되기 때문입니다.
두 번째 요소와 세번째 요소 사이의 마진은 3em 입니다. 3em이 20px보다 크기 때문입니다.

완전히 비어있는 박스와의 마진 겹침(ADJACENT SIBLINGS)

박스가 비어 있으면 위쪽 및 아래쪽 마진이 서로 겹칠 수 있습니다.
아래 CodePen 예제에서 클래스가 empty인 div의 위쪽 및 아래쪽 마진은 50픽셀인데요,
첫 번째 항목과 세 번째 항목 사이의 간격은 100픽셀이 아니라 50픽셀입니다.
이는 empty div의 위쪽, 아래쪽 요소의 두 마진이 겹치기 때문입니다.
해당 박스에 패딩, 보더 혹은 어떤 컨텐츠라도 추가하면, 위쪽 및 아래쪽 마진이 사용되며 마진 겹침이 발생하지 않습니다.
<div class="wrapper">

<div class="box">
  A box
</div>

<div class="box empty"></div>

<div class="box">
  Another box
</div>
  
</div>

<style>
.wrapper {
  border: 5px dotted black;
}

body {
  font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
  margin: 2em 3em;
}

.box {
  background-color: rgb(55,55,110);
  color: white;
  border-radius: .5em;
}

.empty {
  margin: 50px 0 50px 0;
}
</style>

부모 요소와 첫번째 자식, 마지막 자식 간 마진 겹침(PARENT AND FIRST OR LAST CHILD ELEMENT)

특히 직관적이지 않아 사람들을 골치아프게 만듭니다.
다음 CodePen에는 wrapper 클래스가 포함된 div가 있으며
해당 div의 위치를 ​​볼 수 있도록 해당 div에 빨간색 윤곽선을 지정합니다.
 
세 개의 자식 요소 모두 위 아래 마진이 50px 입니다만,
요소와 래퍼 사이에 50px 마진이 없습니다.

이는 자식의 마진이 부모의 마진과 겹쳐 결국 부모의 외부에서 끝나기 때문입니다.
DevTools를 사용하여 첫 번째 자식을 검사하면 이를 볼 수 있습니다.
강조 표시된 노란색 영역이 마진입니다.

마진이 끝나는 지점

오직 블록 방향의 마진만 겹칩니다

즉, 가로 쓰기 모드에 있는 경우 요소의 위쪽 및 아래쪽 마진만 겹칩니다.
참고: 마진은 단락 사이와 같이 블록 방향으로만 겹친다는 점을 기억하세요

마진 겹침 예방하기 

절대 위치 지정되거나 플로팅되는 경우 마진 겹침이 적용되지 않습니다.
또한, 두 요소 사이에 존재하는 무언가에 패딩, 보더, 컨텐츠가 존재하면 마진이 겹치지 않습니다.

 

예를 들어, 아래와 같이 내용이 완전히 비어 있는 박스에 테두리나 패딩이 적용된 경우 상단 및 하단 마진이 겹치지 않습니다.

아래 예에서는 박스에 1px의 패딩을 추가했습니다.

이제 박스 위 아래에 50px의 마진이 존재합니다.

See the Pen Smashing: empty boxes with padding do not collapse margins by rachelandrew (@rachelandrew) on CodePen.

 

이러한 마진 겹침에는 이유가 있습니다.
박스가 테두리나 패딩 없이 완전히 비어 있으면 시각적으로 나타나지 않습니다.
이는 CMS에 의해 마크업에 포함된 빈 단락 요소일 수 있습니다.
CMS가 (실수로 혹은 의도적으로) 비어있는 단락 요소를 중복으로 추가하는 경우 
마진이 적용되어 다른 단락 사이에 큰 간격이 생기는 것을 원하지 않을 것입니다.
 
부모와 마진이 겹치는 첫 번째 또는 마지막 자식의 마진에서도 유사한 동작을 볼 수 있습니다.
부모에 테두리를 추가하면 자식의 마진은 내부에 유지됩니다.
 
 
이러한 마진 겹침이 발생하는데도 이유가 있습니다.
시각적인 목적이 없는, 구조, 의미론적 목적을 가진 wrapper 요소가 큰 간격을 만드는 것을 뭔하지 않을 수 있습니다.
예를 들어 wrapper를 여러개 사용한다고 마진이 여러개 생긴다면 별로 좋지 않을 것읍니다.
이것은 웹 요소 대부분이 텍스트였을 때 많은 의미가 있었습니다.
오늘날 웹 요소를 디자인 목적으로 활용할 땐 덜 유용합니다.

블록 서식 컨텍스트 만들기(CREATING A BLOCK FORMATTING CONTEXT)

블록 서식 컨텍스트 BFC(Block Formatting Context) 또한 모든 요소를 박스 안에 포함하여 마진 겹침을 방지합니다.
(BFC는 블록 바깥으로 안에 존재하는 무언가가 삐져나가는 것을 막습니다.)
 
첫 번째와 마지막 자식의 예를 재구성하여,
wrapper에 display: flow-root를 지정하여 새 BFC를 생성하면
자식의 마진이 내부에 포함됩니다.

플렉스 컨테이너와 그리드 컨테이너 사용하기(FLEX AND GRID CONTAINERS)

Flex 및 Grid 컨테이너는 자식에 대해 Flex 및 Grid 서식 컨텍스트를 설정하여,
블록 레이아웃에 대해 다른 동작을 수행합니다.
일반적인 흐름에서와의 차이점 중 하나는 마진 겹침이 발생하지 않는다는 것입니다.

플렉스 컨테이너는 콘텐츠에 대한 새로운 플렉스 서식 컨텍스트를 설정합니다.
이는 블록 레이아웃 대신 플렉스 레이아웃이 사용된다는 점을 제외하면 블록 서식 컨텍스트를 설정하는 것과 동일합니다.
예를 들어 float 요소는 플렉스 컨테이너를 침범하지 않으며,
플렉스 컨테이너의 마진은 콘텐츠의 마진과 겹치지 않습니다.
 Flexbox Level 1
 
wrapper를 플렉스 컨테이너로 만들고 flex-direction: column을 설정하면
이제 자식의 마진이 부모와 겹치지 않는 것을 볼 수 있습니다.
또한 인접한 플렉스 항목 사이의 마진 또한 서로 겹치지 않습니다.
따라서 플렉스 항목 사이에 100픽셀의 마진, 즉 항목의 위 아래에 총 50픽셀의 합이 됩니다.
 

마진 전략(Margin Strategies For Your Site) 

마진 겹침을 고려하면,
사이트의 마진을 다루는 일반적인 방법을 사용하는 것이 좋습니다.
가장 간단한 방법은 요소의 상단 또는 하단에만 여백을 정의하는 것입니다.
항상 마진이 있는 면이 마진이 없는 면과 인접하므로 마진 겹침 문제가 자주 발생하지 않습니다.
(참고 : 왜 이 방법이 좋은 방법인가 - Harry Roberts has an excellent post)
 
하지만 솔루션은 부모와 자식 간 마진 겹침 문제를 해결하지 못합니다.
이러한 문제는 자주 발생하진 않지만,
위에서 배운 display: flow-root를 활용하여 모든 것을 블록 안에 포함하도록 할 수 있습니다.
 
위의 해결 방법들을 사용할 경우, 주석을 통해 이유를 명시하는 것을 추천합니다.

퍼센트 마진(Percentage Margins)

CSS의 퍼센트는 항상 어떤 기준에 대한 퍼센트 입니다.
퍼센트 마진(및 패딩)은 항상 부모의 인라인 크기(가로 쓰기 모드의 너비)의 퍼센트입니다.
 

아래의 CodePen 예제에는 너비가 200픽셀인 wrapper가 있으며
내부에는 margin이 10%인 상자가 있습니다.
margin은 4면 모두에서 20px이며, 이는 200의 10%입니다.


흐름에 상대적인 마진(Margins In A Flow-Relative World) 

우리는 지금까지 세로 방향 마진에 대해 이야기해 왔지만
현대 CSS는 요소를 물리적인 고정 위치에 있는것이 아닌,
상대적인 흐름에 존재하는 것으로 생각합니다.
즉, 수직 마진에 대해 이야기한 것은 실제로는 블록 차원의 마진에 대해 이야기한 것입니다.
이러한 마진은 가로 쓰기 모드인 경우 위쪽과 아래쪽이 되지만
세로 쓰기 모드에서는 왼쪽에서 오른쪽 방향이 됩니다.
 
논리적이고 상대적인 흐름 방향으로 작업하면
블록 시작과 블록 끝 관점에서 작업하기 쉬워집니다.
이를 위해 CSS는 논리적 속성 및 값 사양(Logical Properties and Values specification)을 도입했습니다.
이는 흐름 관련 속성을 물리적 속성에 매핑합니다.
 
마진의 경우 다음 매핑을 제공합니다. (가로쓰기 경우의 매핑)
  • margin-top = margin-block-start
  • margin-right = margin-inline-end
  • margin-bottom = margin-block-end
  • margin-left = margin-inline-start
또한 두 블록을 한 번에 설정하거나 인라인으로 설정할 수 있는 두 개의 새로운 속기 속성이 있습니다.

다음 CodePen 예제에서는 이러한 흐름 관련 키워드를 사용하여 다음 상자의 쓰기 모드를 변경했습니다.
마진이 물리적인 위쪽, 오른쪽, 아래쪽 및 왼쪽에 연결되지 않고 텍스트 방향을 따르는 것을 볼 수 있습니다.

아래 게시물에서 논리적 속성 및 값에 대해 자세히 알아보세요


요약

이제 마진에 대해 알아야 할 대부분의 내용을 알게 되었습니다!

배운 내용을 요약하자면

  • 마진 겸침이 왜 발생하고 언제 발생하지 않는지 이해해야 원하지 않는 레이아웃 문제를 해결할 수 있습니다.
    • BFC 만들기
    • 마진을 한 방향으로 설정하기
    • 중간의 빈 div에 테두리, 패딩 추가하기
  • 마진을 한 방향으로 설정하면 많은 마진 관련 문제가 발생하지 않습니다.
    • 모든 CSS와 마찬가지로 결정 사항을 팀과 공유하고 코드에 주석을 추가하세요.
  • 물리적인 위, 아래, 왼쪽, 오른쪽 방향으로 사고하는 것보다, 인라인 방향, 블록 방향 관점에서 사고하는 것이 좋습니다.

 

 

 

 

반응형