한 줄 요약display는 요소가 줄을 따라 흐를지(inline), 한 줄을 통째로 차지할지(block)를 정한다. inlinewidth·height가 안 먹고, block은 다 먹지만 줄을 새로 시작한다. 둘의 장점을 합친 게 inline-block(줄 안에 앉는 박스)이고, none은 요소를 자리째 지운다.

학습 목표#

  • blockinline이 줄을 차지하는 방식이 어떻게 다른지 설명할 수 있다.
  • inline 요소에 width·height가 안 먹는 이유를 안다.
  • inline-block을 언제 쓰고, 어떤 한계가 있는지 안다.
  • display: nonevisibility: hidden이 자리를 다루는 차이를 구분할 수 있다.

오늘의 비유 — 줄공책에 글을 쓰는 일#

공책 한 페이지에 글을 쓴다고 떠올려 보자. 글자 하나하나는 왼쪽에서 오른쪽으로 줄을 따라 이어진다. 글자는 제 폭만큼만 자리를 차지하고, 줄 끝에 닿으면 다음 줄로 넘어간다. 글자 한 개만 두 배로 키워 줄 높이를 무시하고 우뚝 세울 수는 없다 — 줄의 흐름을 따라야 하니까. 이게 inline이다.

반대로 한 줄을 통째로 차지하는 것도 있다. 큼직한 제목을 한 줄에 적거나 페이지를 가로지르는 구분선을 죽 긋는 경우다. 그 줄은 통째로 그 요소의 것이고, 다음 내용은 무조건 아랫줄로 내려간다. 이게 block이다. 그리고 문장 중간에 끼워 넣은 작은 네모 스티커를 떠올려 보자. 글자들 사이 줄 안에 얌전히 앉아 있지만, 스티커 자체는 가로세로 크기를 가진 박스다. 줄도 깨지 않고 크기도 갖는 이 절충이 inline-block이다.

핵심 개념#

브라우저의 모든 요소는 기본 display 값을 하나씩 갖고 태어난다. div·p·h1·sectionblock으로, span·a·stronginline으로 태어난다. display는 이 타고난 성질을 바꾸는 속성이다.

block — 한 줄을 통째로 차지한다#

block 요소는 가로로 쓸 수 있는 자리를 전부 차지하고(width를 안 주면 부모 너비만큼), 다음 요소를 아랫줄로 민다. width·height·상하 margin·padding이 모두 정상으로 먹는다.

.notice {
  width: 240px;
  height: 80px;
  background: #e0e7ff;
}

div에 이렇게 주면 240×80 박스가 한 줄을 차지하고 다음 요소는 그 아래로 내려간다.

inline — 글자처럼 줄을 따라 흐른다#

inline 요소는 글자처럼 줄을 따라 옆으로 흐른다. 줄을 새로 시작하지 않고, 제 콘텐츠 폭만큼만 차지한다. 핵심은 widthheight가 무시된다는 점이다.

.tag {
  width: 240px;  /* inline에서는 무시된다 */
  height: 80px;  /* 이것도 무시된다 */
  background: #fde68a;
}

span에 위처럼 줘도 배경은 글자 폭에만 딱 붙고, 240×80은 적용되지 않는다. 좌우 padding·margin은 먹지만, 위아래 margin은 줄 간격에 영향을 주지 못한다. 글자가 줄을 따라야 하기 때문에 생기는 자연스러운 제약이다.

inline-block — 줄 안에 앉는 박스#

inline-block은 두 성질을 합친다. 줄 안에 다른 요소와 나란히 앉되(줄을 깨지 않음), block처럼 width·height·상하 여백이 모두 먹는다.

.tag {
  display: inline-block;
  width: 240px;
  height: 80px;
  background: #fde68a;
}

이제 240×80 박스가 줄 안에 그대로 앉는다. 버튼이나 배지처럼 "글 흐름 안에 있으면서 크기는 갖고 싶은" 요소에 오래 쓰였다. 다만 한계가 있다 — 여러 개를 나란히 정렬하거나 간격을 고르게 주는 일은 까다롭다(아래 흔한 실수 3번). 요즘은 그런 배치를 flexgrid로 푸는 쪽이 훨씬 깔끔해서, inline-block의 자리는 많이 좁아졌다.

display: none과 visibility: hidden — 숨기는 두 방법#

요소를 안 보이게 하는 방법은 둘인데, 자리를 어떻게 다루느냐가 다르다.

.gone {
  display: none;       /* 자리째 사라진다 */
}

.invisible {
  visibility: hidden;  /* 안 보이지만 자리는 남는다 */
}

display: none은 요소를 레이아웃에서 완전히 들어낸다. 자리도 차지하지 않아 뒤 요소가 그 빈자리를 메운다. visibility: hidden은 글자만 지운 셈이라 그 자리는 빈 채로 그대로 남는다. 공책으로 치면 none은 지우개로 지워 다음 글자가 자리를 메우는 것이고, hidden은 수정테이프로 덮어 글자는 안 보여도 흰 자리가 그대로 남는 것이다.

참고로 둘 다 화면 낭독기(스크린리더)에서도 읽히지 않는다. 눈에는 안 보이되 보조기기로는 읽혀야 하는 정보라면, none/hidden 대신 별도의 "시각적으로만 숨기기" 기법을 써야 한다.

함께 따라하기#

span 하나의 display 값만 바꿔 가며 세 가지를 직접 비교해 보자.

<p>
  앞 글자
  <span class="badge">NEW</span>
  뒤 글자
</p>
.badge {
  width: 120px;
  height: 48px;
  padding: 8px;
  background: #fde68a;
  display: inline; /* 이 값을 inline-block, block으로 바꿔본다 */
}

display: inline일 때는 width: 120pxheight: 48px이 무시되어 NEW 배지가 글자 폭만큼만, 앞·뒤 글자와 같은 줄에 놓인다. inline-block으로 바꾸면 120×48 박스가 그대로 적용되면서도 여전히 같은 줄에 나란히 앉는다. block으로 바꾸면 그 박스가 한 줄을 통째로 차지해, 앞 글자와 뒤 글자가 위아래로 갈라진다. 값 하나만 바꿨는데 배치가 통째로 달라지는 걸 눈으로 확인할 수 있다.

흔한 실수 3가지#

1. inline 요소에 width/height를 적고 안 먹는다고 헤맨다#

aspan에 크기를 주려는데 꿈쩍도 안 하는 상황이다.

/* (이 width와 height는 적용되지 않습니다) */
.btn {
  width: 160px;
  height: 44px;
}
<span class="btn">구매하기</span>

spaninline이라 width·height를 무시한다. 줄을 따라 흐르는 글자에 가로세로를 못 박는 것과 같은 이치다. 크기를 주려면 display부터 바꿔야 한다.

.btn {
  display: inline-block; /* 또는 block */
  width: 160px;
  height: 44px;
}

2. display:none과 visibility:hidden을 같은 의미로 쓴다#

"안 보이게"만 떠올리고 자리를 생각하지 않으면 레이아웃이 의도와 어긋난다.

/* (자리를 남겨 두고 싶은데 자리째 사라집니다) */
.tooltip {
  display: none;
}

말풍선을 잠깐 숨겼다가 같은 자리에 다시 띄우고 싶다면, 자리가 사라지는 display: none은 주변 요소를 들썩이게 만든다. 자리를 유지한 채 숨기려면 visibility: hidden을 쓴다.

.tooltip {
  visibility: hidden;
}

반대로 목록에서 항목을 완전히 빼고 뒤 항목을 끌어올리고 싶다면 display: none이 맞다. 자리를 남길지 없앨지를 먼저 정하고 고르면 헷갈리지 않는다.

3. inline-block 사이의 공백 문제를 모른다#

inline-block 박스를 여러 개 나란히 두면, 박스 사이에 4px 안팎의 정체불명 틈이 생긴다.

<span class="card">하나</span>
<span class="card"></span>
<span class="card"></span>

박스 자체에는 margin을 안 줬는데도 사이가 벌어진다. inline-block은 글자처럼 취급되기 때문에, HTML에서 태그 사이에 넣은 줄바꿈과 띄어쓰기가 글자 사이 공백으로 렌더되는 탓이다. 급하면 부모에 font-size: 0을 줘 공백을 없애는 옛 기법도 있지만 부작용이 많다. 애초에 이런 나란한 배치는 flexgrid로 푸는 게 정답이다 — 공백 문제 자체가 생기지 않는다. 바로 다음 파트에서 배운다.

오늘 배운 것 체크리스트#

  • block은 한 줄을 통째로 차지하고 다음 요소를 아래로 민다.
  • inline은 줄을 따라 흐르고 width·height가 안 먹는다.
  • inline-block은 줄 안에 앉으면서도 크기를 가질 수 있다.
  • display: none은 자리째 사라지고, visibility: hidden은 자리를 남긴다.

자주 묻는 질문#

Q. display: nonevisibility: hidden은 뭐가 다른가요?

A. 둘 다 요소를 안 보이게 하지만 자리를 다루는 방식이 다릅니다. display: none은 요소를 레이아웃에서 완전히 들어내 자리까지 사라지므로 뒤 요소가 그 자리를 메웁니다. visibility: hidden은 안 보일 뿐 자리는 그대로 남아 주변 요소가 움직이지 않습니다. 숨겼다 같은 자리에 다시 보일 거라면 hidden, 아예 목록에서 뺄 거라면 none이 맞습니다.

Q. spanwidth를 줬는데 안 먹어요. 왜 그런가요?

A. span은 기본이 inline이라 width·height를 무시하기 때문입니다. inline 요소는 줄을 따라 흐르는 글자처럼 다뤄져서 가로세로 크기를 직접 정할 수 없습니다. 크기를 주고 싶다면 display: inline-block(줄 안에 두고 싶을 때)이나 display: block(한 줄을 차지해도 될 때)으로 바꾸면 됩니다.

Q. inline-block 박스 사이에 생기는 틈은 왜 생기나요?

A. inline-block은 글자처럼 취급되기 때문에, HTML 태그 사이의 줄바꿈·띄어쓰기가 글자 사이 공백처럼 렌더되어 4px 안팎의 틈으로 보입니다. 부모에 font-size: 0을 주거나 태그를 붙여 쓰면 없앨 수 있지만, 요즘은 이런 나란한 배치를 flex로 만들어 틈 문제 자체를 피하는 쪽이 깔끔합니다.

다음 시간 예고#

내일부터는 실습 파트로 들어간다. 첫 주제는 position 5종 — static, relative, absolute, fixed, sticky다. 요소를 보통 흐름에서 떼어내 원하는 자리에 고정하거나 띄우는 법을 한 번에 정리한다.

더 알아보기#