개발자들이 가장 자주 겪는 CSS 문제 중 하나가 바로 수직 정렬이다. vertical-align: middle을 써도 텍스트가 가운데 안 뜨고, 이미지와 텍스트 사이에 이상한 공백이 생기고, 버튼 안의 아이콘이 삐뚤어진다. 다만 대부분의 개발자들은 이 문제의 원인이 정확히 뭔지, 왜 vertical-align이 안 되는 건지 모른 채 인터넷에서 가져온 코드를 그냥 복사해 붙인다. 이번에는 vertical-align이 정확히 뭔지, 언제 작동하고 안 되는지, 그리고 모던 CSS에서 수직 정렬을 완벽하게 하는 방법을 정리해서 소개하겠다.

 

vertical-align은 인라인 요소에만 작동한다

vertical-align의 첫 번째 함정은 바로 이것이다. 많은 개발자들이 vertical-align: middle을 div나 p 같은 블록 요소에 적용하고도 안 된다고 한다. 하지만 vertical-align은 애초에 인라인(inline)과 인라인블록(inline-block) 요소, 그리고 테이블 셀(td)에만 작동한다.

vertical-align의 작동 원리를 이해하려면 라인박스(line box)라는 개념을 알아야 한다. 텍스트가 여러 줄로 흐를 때, 한 줄 한 줄이 차지하는 높이를 라인박스라고 부르는데, vertical-align은 이 라인박스 안에서 인라인 요소들의 수직 위치를 결정한다. 따라서 블록 요소는 라인박스의 개념이 없으므로 vertical-align이 작동하지 않는다.

 

인라인 요소에서 vertical-align이 안 되는 이유

그렇다면 인라인 요소에는 vertical-align: middle이 잘 작동할까? 답은 아니다. 여기에 또 다른 함정이 숨어있다.

✗ 잘못된 코드: vertical-align만으로 수직 정렬 시도
<div style="height: 100px; border: 1px solid #333;">
  <img src="icon.png" alt="icon" style="vertical-align: middle;" />
  텍스트
</div>

이 코드에서 이미지는 여전히 텍스트 밑줄(baseline)에 정렬된다. 왜냐하면 vertical-align: middle은 "라인박스의 중앙을 기준으로 정렬"하라는 뜻인데, 라인박스의 높이가 이미지 높이에 맞춰지기 때문이다. 결국 이미지는 라인박스 중앙에 정렬되지만, 그 라인박스 자체가 부모 요소의 중앙에 위치하지 않는다.

✓ 올바른 코드: line-height로 라인박스 높이 통제
<div style="height: 100px; line-height: 100px; border: 1px solid #333;">
  <img src="icon.png" alt="icon" style="vertical-align: middle;" />
  텍스트
</div>

부모 요소의 line-height를 height와 같게 설정하면, 라인박스의 높이가 부모 요소의 높이와 일치한다. 이 경우 vertical-align: middle을 적용한 인라인 요소는 부모 요소의 중앙에 정렬된다.

결과

이미지와 텍스트가 부모 요소의 중앙에 정렬된다. 다만 이 방법은 한 줄 텍스트에만 적합하다.

 

블록 요소를 수직 정렬하는 4가지 방법

현실적으로 대부분의 경우 div나 다른 블록 요소를 수직 정렬해야 한다. vertical-align이 안 되므로 다른 방법을 써야 한다.

방법 1: Flexbox 사용 (가장 추천)
.container {
  display: flex;
  height: 100px;
  align-items: center;        /* 수직 정렬 */
  justify-content: center;     /* 수평 정렬 */
  border: 1px solid #333;
}
<div class="container">
  <p>중앙 정렬된 텍스트</p>
</div>

Flexbox는 모던 CSS에서 가장 간단하고 안정적인 방법이다. align-items: center는 수직 정렬을, justify-content: center는 수평 정렬을 담당한다. 이 방법은 블록 요소, 인라인 요소, 이미지 모두에 작동한다.

방법 2: Grid 사용
.container {
  display: grid;
  height: 100px;
  place-items: center;  /* 수평·수직 동시 정렬 */
  border: 1px solid #333;
}

Grid의 place-items: center는 한 줄로 수평, 수직 정렬을 모두 설정한다. Flexbox와 거의 동일한 결과지만, 복잡한 레이아웃에는 Grid가 더 강력하다.

방법 3: 절대 위치 지정(Absolute Positioning)
.container {
  position: relative;
  height: 100px;
  border: 1px solid #333;
}

.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

position: absolute와 transform: translate()를 조합하면 부모 요소의 중앙에 정렬된다. 다만 부모가 position: relative여야 하고, 문서 흐름에서 벗어나는 단점이 있다.

방법 4: CSS Grid의 margin: auto 트릭
.container {
  display: grid;
  height: 100px;
  border: 1px solid #333;
}

.child {
  margin: auto;
}

Grid 컨테이너 안에서 자식 요소에 margin: auto를 적용하면 수평, 수직 정렬이 된다. 간결하지만 다른 마진 설정이 있으면 영향을 받을 수 있다.

 

주의사항: vertical-align과 inline-block의 숨겨진 공백

인라인블록 요소들을 나열하면 사이사이에 예상 못 한 공백이 생기는 경우가 있다. 이는 vertical-align의 기본값이 baseline이기 때문이다.

✗ 공백이 생기는 코드
<div style="border: 1px solid #333;">
  <span style="display: inline-block; width: 50px; height: 50px; background: #ddd;"></span>
  <span style="display: inline-block; width: 50px; height: 50px; background: #bbb;"></span>
</div>

결과: 두 블록 사이에 불필요한 공백이 생긴다.

✓ 공백을 없애는 코드
<div style="border: 1px solid #333; font-size: 0;">
  <span style="display: inline-block; width: 50px; height: 50px; background: #ddd; font-size: 16px;"></span>
  <span style="display: inline-block; width: 50px; height: 50px; background: #bbb; font-size: 16px;"></span>
</div>

부모의 font-size: 0으로 공백 문자를 제거하고, 자식 요소에 font-size를 다시 설정한다. 또는 vertical-align: top을 명시적으로 설정해도 된다.

 

실전 예제: 네비게이션 메뉴 수직 정렬
<nav style="display: flex; height: 60px; background: #333; align-items: center;">
  <a href="#" style="color: white; text-decoration: none; margin: 0 15px;">홈</a>
  <a href="#" style="color: white; text-decoration: none; margin: 0 15px;">소개</a>
  <a href="#" style="color: white; text-decoration: none; margin: 0 15px;">연락처</a>
</nav>

display: flex와 align-items: center로 메뉴 항목들이 네비게이션 바의 중앙에 정렬된다. 이 방법이 모던 웹개발에서 가장 표준적이다.

 

CSS 수직 정렬은 상황에 맞는 방법을 선택하는 것이 핵심이다

수직 정렬이 안 된다고 한탄하는 개발자들 대부분은 vertical-align의 작동 범위를 모르고 무조건 이 속성을 사용한다. 반복되는 수동 정렬 작업을 피하려면 Flexbox나 Grid 같은 모던 레이아웃 도구를 기본으로 사용하고, 특수한 경우에만 절대 위치나 다른 방법을 고려해야 한다. 이 글의 4가지 방법 중 프로젝트에 맞는 것을 선택해 적용하면, 수직 정렬로 인한 UI 오류를 완전히 없앨 수 있을 것이다.