CSS 실무 노트

작은 속성 하나로 UI가 덜 깨지게 만드는 방법

자주 보이는 레이아웃 문제, 스크롤 전파, 텍스트 줄바꿈, z-index 충돌을 줄이는 CSS 속성 활용법을 정리했습니다.

display: contents

레이아웃 정리

마크업상 래퍼는 필요하지만, 그 래퍼가 flex나 grid 배치에는 끼어들면 안 될 때 씁니다.

  • 카드 리스트에서 링크 전체를 감싸되, 내부 요소는 부모 grid에 그대로 배치하고 싶을 때 유용합니다.
  • 컴포넌트 구조를 유지하면서 불필요한 중첩 박스가 만드는 간격 문제를 줄일 수 있습니다.
  • 접근성 트리에서 일부 브라우저 이슈가 있었던 속성이므로 버튼, 폼, 의미가 중요한 요소에는 신중하게 적용합니다.
.product-card-link {
  display: contents;
}

.product-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
추천 사용처: CMS나 템플릿 구조상 래퍼를 제거할 수 없지만, 시각적 레이아웃에서는 래퍼가 없는 것처럼 다뤄야 하는 상황.

isolation: isolate

쌓임 맥락

컴포넌트 내부의 배경, 딤, 장식 요소, absolute 요소가 바깥 레이어와 섞이지 않도록 독립된 stacking context를 만듭니다.

  • 카드 안의 장식 배경에 z-index: -1을 쓸 때 바깥 페이지 뒤로 사라지는 문제를 막습니다.
  • 히어로, 배너, 모달처럼 내부 레이어가 많은 UI에 기본값처럼 넣어두면 안전합니다.
  • 무작정 높은 z-index: 9999를 늘리는 대신, 충돌 범위를 컴포넌트 단위로 좁힙니다.
.hero-banner {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

.hero-banner::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
}

overscroll-behavior: contain

스크롤 제어

내부 스크롤 영역이 끝에 닿았을 때 바깥 페이지까지 같이 움직이는 현상을 막습니다.

  • 모달 본문, 사이드 패널, 드롭다운 목록, 코드 프리뷰 영역에 적합합니다.
  • 모바일에서 내부 패널을 스크롤하다가 배경 페이지가 같이 밀리는 느낌을 줄입니다.
  • 완전히 막아야 하면 overscroll-behavior: none도 가능하지만, 일반 UI는 contain이 덜 공격적입니다.
.modal-body,
.code-preview {
  max-height: min(70vh, 640px);
  overflow: auto;
  overscroll-behavior: contain;
}

text-wrap: balance

타이포그래피

제목이나 짧은 문구가 한 줄은 길고 마지막 줄은 한두 글자만 남는 식으로 깨질 때 줄 길이를 균형 있게 맞춥니다.

  • 히어로 제목, 카드 제목, 배너 문구, 섹션 헤딩처럼 짧은 텍스트에 좋습니다.
  • 긴 본문 전체에 적용하면 줄 계산 비용과 가독성 면에서 이점이 적습니다.
  • 지원하지 않는 브라우저에서는 일반 줄바꿈으로 동작하므로 점진적 향상으로 쓰기 좋습니다.
.section-title,
.card-title,
.banner-copy {
  text-wrap: balance;
}

같이 쓰면 좋은 CSS 패턴

추천

content-visibility: auto

아래쪽 긴 콘텐츠 렌더링을 늦춰 초기 화면 부담을 줄입니다. 긴 리스트, 문서형 페이지에 좋습니다.

contain: layout paint

독립적인 위젯이나 카드가 바깥 레이아웃에 주는 영향을 줄입니다. 애니메이션 카드에 특히 유용합니다.

scrollbar-gutter: stable

스크롤바가 생기고 사라질 때 페이지 폭이 흔들리는 문제를 줄입니다.

min-width: 0

flex/grid 자식의 긴 텍스트가 부모를 밀어내는 문제를 막는 실무 필수 보정입니다.

overflow-wrap: anywhere

긴 URL, 코드, 영문 파일명이 모바일 폭을 뚫고 나갈 때 사용합니다.

:where()

선택자 우선순위를 0으로 낮춰 공통 스타일을 덜 공격적으로 적용할 수 있습니다.

기본으로 넣어두기 좋은 스니펫

.ui-surface {
  isolation: isolate;
}

.scroll-panel {
  overflow: auto;
  overscroll-behavior: contain;
}

.balanced-title {
  text-wrap: balance;
}

.layout-pass-through {
  display: contents;
}

.grid-child,
.flex-child {
  min-width: 0;
}

.long-text {
  overflow-wrap: anywhere;
}