div 사이에 생기는 공백의 정체
(Sub-Pixel Rendering Bug)

div에만 국한되는 문제가 아니지만, 쉽게 문제점을 구현하기 위해 이번 포스트에서는 div로 설명을 드리겠습니다. div 요소 2개를 부모와 자식 관계로 포개어 생성할 때, 두 개 div 요소 사이에 가끔 공백이 생성되는 것을 볼 수 있습니다. 위의 사각형의 border와 content 사이를 자세히 보면, 위쪽과 왼쪽 테두리선에 하얀 실선의 공백이 보일 것입니다. 이런 공백이 발생하는 것은 우리가 잘못한 것이 아니라, 현재 브라우저들이 가지고 있는 Sub-Pixel Rendering 버그에 의해서 발생하는 것입니다. Sub-Pixel Rendering 버그는 미세한 크기의 선(~1px)들을 출력할 때, 그 위치와 크기를 완벽하게 제어할 수 없는 버그입니다. 이번 포스트에서는 문제점을 확인 한 후, 해결 방법까지 다뤄보겠습니다. 참고로 span 사이에 발생하는 빈 공간은 또 다른 이슈에 해당하는데, 이 부분도 마지막 부분이 살짝 언급하겠습니다.
[1] 문제점 확인하기
<style> .wrapper { margin: 0 auto; max-width: 1180px; padding: 0 10px; display: flex; justify-content: center; } .box { width: 100px; height: 100px; border: 2px solid black; } .content { width: 100%; height: 100%; background-color: coral; } </style> <div class=“wrapper”> <div class=“box”> <div class=“content”></div> </div> |
- 예제 목표
- div 사이에 생성되는 공백의 문제점을 구현해보고, 브라우저마다 어떻게 다르게 출력하는지 보겠습니다
- HTML 파트
- 먼저 코드 아래 부분에 위치한 HTML 파트부터 보겠습니다.
- <div class=”wrapper”></div> 래퍼 요소를 만들어 줍니다. 래퍼 요소를 먼저 만들어 주고, 그 안에 원하는 HTML 들을 넣어주면, 복잡한 코드를 작성할 때 정렬 면에서 편리해집니다. 관련 내용은 [CSS] 래퍼의 기본 개념 및 CSS 기본설정] 포스에서 자세히 다루고 있습니다.
- <div class=”box”></div> 래퍼 요소 안에 div.box 요소를 만들어 줍니다. 이 요소의 테두리선을 CSS로 설정할 예정입니다.
- <div class=”content”></div> div.box 요소 안에 자식 요소로 div.content 요소를 만들어 주고, content 부분을 오렌지 색깔로 표시할 예저입니다.
- CSS 파트
- 코드 위로 올라와서 CSS 파트를 보겠습니다.
- .wrapper의 CSS
- – margin: 0 auto; 여기서 margin은 2개의 값을 받았는데, 0은 위/아래의 여백에 해당하고, auto는 좌/우의 여백에 해당합니다. 여기서 auto의 의미는 좌/우 여백의 크기를 동일하게 설정하는 것이고, 결국 div.wrapper는 가로 방향 가운데 정렬을 하게 됩니다.
- – max-width: 1180px; 래퍼 요소가 최대로 커질수 있는 너비를 1180px로 설정합니다. 이렇게 설정하는 이유는 가독성을 높이기 위해서 입니다. 만약 max-width를 설정하지 않은 경우, 큰 모니터나 디바이스를 사용 할 때, 래퍼 요소의 너비가 너무 넓게 표시되어, 사람의 눈이 한번에 인지할 수 있는 영역을 벗어나게 되어 가독성이 크게 떨어집니다. 이것을 방지하기 위해 래퍼 요소를 생성하고 max-width를 필수적으로 설정합니다. 이 외에 래퍼 요소에 설정해야 하는 프로퍼티들은 [CSS] 래퍼의 기본 개념 및 CSS 기본설정] 포스에서 자세히 다루고 있습니다.
- – padding: 0 10px; 래퍼 요소에 안쪽 여백 padding을 좌/우로 10px 설정합니다.
- – display: flex; 자식 요소(div.box)를 정렬하기 위해 flex로 설정합니다.
- – justify-content: center; 자식 요소(div.box)를 가로 방향 가운데 정렬합니다.
- .box의 CSS
- – width: 100px; height: 100px; div.box의 크기를 100 x 100 px로 설정합니다.
- – border: 2px solid black; div.box의 테두리선을 2px 검정 실선으로 설정합니다.
- .content의 CSS
- – width: 100%; height: 100%; div.content 요소의 크기를 100 % x 100%로 설정하여 부모 요소(div.box)의 content 부분을 채웁니다.
- – background-color: coral; content 부분을 표시하기 위해, 배경색을 coral 색깔로 표시합니다.
- 구현 결과
- 인터넷 브라우저마다 구현 결과가 다를 수 있습니다. 테스트한 브라우저는 Chrome(버젼: 96.0.4664.45), Edge(버젼: 96.0.1054.29), Whale(버젼: 2.11.126.23 ), Opera(버젼: 81.0.4196.60)이며, 모두 div.box와 div.content 사이에 예기치 못한 흰색 공백이 생김을 확인하였습니다. Firefox (버젼: 94.0.2)가 제일 sub-pixel rendering 문제를 잘 해결하였는데, 현재 예제가 정상적으로 잘 나왔을 뿐만 아니라, 화면을 확대했을 때도 테두리선이 깨지는 현상도 발생하지 않았습니다. 요즘 파이어 폭스가 잘하고 있군요. 다시 말하지만, 이러한 이미지 깨짐 문제는 우리가 CSS를 잘못 설정한 것이 아니라, 인터넷 브라우저가 가지는 sub-pixel rendering 버그 때문에 발생합니다. (이 버그에 대해서 모르셨다면, 아마 내가 뭘 잘못한거지 한참 찾고 계셨을 것입니다.???? 이눔의 브라우저들!) 또한 브라우저들마다 출력하는 메커니즘이 다르기 때문에 공백의 위치도 다 다르게 표시됩니다. 예를 들어 같은 크로미움 브라우저인 네이버 웨일과 구글의 크롬의 아래 구현 결과을 보면, 공백 위치가 서로 다르다는 것을 확인할 수 있습니다.


[2] 해결 방법
<style> .wrapper { display: flex; justify-content: center; margin: 0 auto; max-width: 1180px; padding: 0 10px; } .box { width: 100px; height: 100px; border: 2px solid black; /* 아래 코드를 추가 */ display: flex; justify-content: center; align-items: center; } .content { /* 아래 코드를 수정 */ width: calc(100% – 4px); height: calc(100% – 4px); background-color: coral; } </style> <div class=“wrapper”> <div class=“box”> <div class=“content”></div> </div> </div> |
- 예제 목표
- content와 border 사이에 발생하는 공백을 깔끔하게 해결할 수 있는 방법은 없습니다. 아쉬운 대로, width를 1px를 넓히는 식의 방법으로 공백을 메꾸기도 하는데, 여기서는 outline을 이용한 방법에 대해서 알아보겠습니다.
- 앞 섹션에서 확인했듯이, 빈 공간 문제를 해결할 때 가장 까다로운 부분은 인터넷 브라우저마다 공백의 위치가 다르다는 것입니다. 예를 들어 크롬에서 왼쪽에 빈 공간이 생겨서 왼쪽 빈공간을 메꿨는데, Opera 브라우저에서는 오른쪽에 빈 공간이 보일 수도 있다는 것입니다. 따라서 가장 먼저 해야할 조치는 content 부분을 가운데로 위치시키는 것입니다.
- HTML 파트
- 앞 섹션의 예제와 동일하게 래퍼 요소를 만들고, 아래에 div.box 요소와 div.content 요소를 넣어줍니다. 코드가 완전 동일함으로 중복 설명은 생략합니다.
- CSS 파트
- .wrapper의 CSS
- 앞 섹션의 예제와 동일함으로 중복 설명은 생략합니다.
- .box의 CSS
- 새로 추가한 프로퍼티들만 설명하겠습니다.
- – display: flex; 자식 요소(div.content)를 가운데 정렬을 하기 위해 flex를 설정해줍니다.
- – justify-content: center; 자식 요소(div.content)를 수평 가운데 정렬을 시킵니다.
- – align-items; 자식 요소(div.content)를 수직 가운데 정렬을 시킵니다.
- .content의 CSS
- – width: calc(100% – 4px); width를 전체 100%에서 4px를 감소시킵니다. calc는 다른 단위끼리 계산을 할 수 있는 함수인데, 띄어쓰기에 유의하여 작성해야 합니다. 그렇지 않으면 동작하지 않습니다. 빼기 부호(-) 좌우로 띄어쓰기를 해야함에 유의하세요
- – height: calc(100% – 4px); height를 전체 100%에서 4px를 감소시킵니다.
- .wrapper의 CSS
- 구현 결과
- div.content 요소(오렌지 박스)의 상하좌우로 일정한 크기의 흰색 공백이 생성되었음을 확인할 수 있습니다. 만약 가로와 세로 방향 모두 가운데로 일정하게 위치했다면 첫 번째 단계를 성공적으로 설정한 것입니다. 다음 단계에서는 일정한 두께로 설정된 흰색 공백을 outline으로 메꿀 것입니다. 다음 페이지에서 다루겠습니다.
- 왜 4px 빼주는가?
- 모든 경우에 4px를 빼주는 것이 아니라, 실험적으로 얼마를 빼줘야 하는지를 본인이 찾아야 합니다. 다시 말해서 width와 height를 1px씩 빼주면서 [예: width: calc(100% – 1px)], sub-pixel rendering 문제가 없어지는 순간을 찾아야 합니다. 이해를 돕기 위해 1px 빼주면서 어떻게 결과가 달라지는지 아래에 출력 결과물들을 배치했습니다. (A)는 width와 height를 각각 1px 빼줬을 때에 해당하는데, 윗쪽, 오른쪽, 아랫쪽의 공백의 두께는 같아지지만, 왼쪽의 공백이 여전히 크므로 여전히 문제가 있습니다. (B) 2px를 빼줬을 때를 보면, 이번에는 오른쪽 공백이 더 얇은 것을 확인할 수 있습니다. (C) 3px를 빼줬을 때는, 윗쪽/왼쪽과 아랫쪽/오른쪽의 두께가 다릅니다. 그리고 마침내 4px를 빼줬을 때, 위의 구현 결과와 같이 상하좌우 모든 흰색 공백의 두께가 일치하게 됩니다. 따라서 4px로 설정해주었습니다.



<style> .wrapper { display: flex; justify-content: center; margin: 0 auto; max-width: 1180px; padding: 0 10px; } .box { width: 100px; height: 100px; border: 2px solid black; display: flex; justify-content: center; align-items: center; } .content { width: calc(100% – 4px); height: calc(100% – 4px); background-color: coral; /* 아래 코드를 추가 */ outline: 3px solid coral; } </style> <div class=“wrapper”> <div class=“box”> <div class=“content”></div> </div> </div> |
- 예제 목표
- 두 번째 단계로 outline을 이용하여 빈 공간을 메꿉니다.
- HTML 파트
- 앞 예제와 동일함으로 중복 설명은 생략합니다.
- CSS 파트
- 앞 예제와 동일한 코드에 대한 설명은 생략합니다.
- .content의 CSS
- – outline: 3px solid coral; box.content 요소의 outline을 3px 두께의 coral색 실선으로 만들어 줍니다.
- 구현 결과
- box.content 요소 주위에 생겼던 빈 공백이 outline에 의해서 잘 메꿔졌습니다. Sub-pixel rendering 버그는 브라우저가 가지는 버그이기 때문에, 사용자가 직접 해결할 수는 없지만, 이번 포스트에서 다뤘던 2단계 (가운데 정렬, outline)의 방법으로 임시적으로 해결할 수 있습니다.
[3] span 사이에 발생하는 빈 공간 / 공백
혹시 위에서 다룬 sub-pixel rendering 버그가 아니라, span과 같은 인라인 (inline) 요소 또는 인라인 블록 (inline-block) 요소 사이에 발생하는 빈 공간의 문제라면 다르게 접근하셔야 합니다. 아래 예제에서 문제를 확인하고 해결 방법을 알아보겠습니다.
<style> .wrapper { margin: 0 auto; max-width: 1180px; } .child { border: 1px solid black; font-size: 50px; } </style> <div class=“wrapper”> <span class=“child”>1</span> <span class=“child”>2</span> <span class=“child”>3</span> </div> |
1
2
3
- 문제점
- 출력 결과를 보면, span 요소들 사이에 원치 않는 빈 공간이 존재함을 확인할 수 있습니다. 이러한 문제는 단순히 span 요소에서만 발생하는 것이 아니라, 모든 인라인(inline) 요소과 인라인-블록(inline-block) 요소들 사이에서 발생합니다. 이 문제는 위에서 다룬 Sub-Pixel Rendering 버그랑은 다른 문제입니다. 관련 내용은 현재 포스트의 주제를 벗어 나기 때문에, [CSS] 인라인 또는 인라인 블록 요소들 사이에 발생하는 빈 공간 문제 해결방법 포스트에서 자세히 다루겠습니다.
명쾌하게 알려주셔서 감사합니다! 덕분에 해결했습니다ㅠㅠ 만수무강하세요…
댓글 달아주셔서 감사합니다. 저의 블로그 글이 도움이 되었다니 감사합니다. 라빈님도 앞으로 좋은 일들만 가득하시길 바랍니다 🙂