text-indent: hanging / each-line — padding-left + 음수 text-indent 트릭을 걷어내기

  • 7th September 2026
  • 6 min read

참고문헌 목록, 용어 정의, 시, 대본, 주소. 첫 줄은 왼쪽 끝에 붙고 둘째 줄부터 들여쓰는 내어쓰기(hanging indent)가 필요한 자리는 많다. 그리고 CSS에는 오랫동안 이걸 바로 말하는 문법이 없었다. 대신 모두가 같은 트릭을 썼다.

.ref {
  padding-left: 2em;
  text-indent: -2em;
}

블록 전체를 2em 밀어 넣고, 첫 줄만 2em 도로 당긴다. 결과는 내어쓰기처럼 보인다. 20년 넘게 쓰인 트릭이고 지금도 검색하면 이게 나온다.

이제 이 두 줄을 한 줄로 바꿀 수 있다.

.ref {
  text-indent: 2em hanging;
}

2026년 3월에 크롬이 마지막으로 합류하면서 모든 브라우저에서 된다. 이 글은 hangingeach-line이 정확히 무엇을 하는지, 트릭이 어디서 어긋났는지, 그리고 트릭으로는 아예 못 만들던 것이 무엇인지에 대한 것이다.

text-indent는 원래 "첫 줄"만 건드린다

text-indent의 정의는 이렇다. 블록 안 인라인 콘텐츠의 첫 번째 서식 줄(first formatted line) 시작 쪽에 여백을 준다. 그 뒤의 줄은 손대지 않는다. 문단 첫 줄을 들여쓰는 인쇄 관행을 그대로 옮긴 속성이다.

"첫 번째 서식 줄"이 무엇인지가 중요하다. <br>로 강제로 줄을 바꾼 다음 줄은 첫 줄이 아니다. 그래서 주소나 시처럼 <br>가 들어간 블록에서는 맨 첫 줄만 들여써지고 나머지는 전부 왼쪽에 붙는다. 이 성질이 뒤에서 each-line의 존재 이유가 된다.

CSS Text Level 3가 이 속성에 키워드 둘을 붙였다.

text-indent: [ <length-percentage> ] && hanging? && each-line?
  • hanging — 명세 원문은 한 문장이다. "적용되는 줄을 반전한다(Inverts which lines are affected)." 첫 줄에 주던 여백을 첫 줄을 제외한 나머지에 준다.
  • each-line — "각 블록 컨테이너의 첫 줄, 그리고 강제 줄바꿈 뒤의 각 줄에 적용된다. 소프트 랩 뒤의 줄에는 적용되지 않는다." 즉 <br>로 나뉜 줄마다 새 문단처럼 취급한다.

둘은 같이 쓸 수 있다. 조합이 넷이니 그림으로 보는 편이 빠르다.

같은 마크업 — 줄 넷, 가운데에 <br> 하나, 첫째·셋째 줄은 길어서 소프트 랩 text-indent: 2em 첫 줄만 br text-indent: 2em hanging 첫 줄 빼고 전부 — 참고문헌 br text-indent: 2em each-line br 뒤 줄도 첫 줄로 — 문단 들여쓰기 br text-indent: 2em hanging each-line 소프트 랩 이어짐 줄만 — 시·코드·대본 br 진한 줄은 원래 줄, 연한 줄은 폭이 모자라 이어진 줄(소프트 랩). 오른쪽 아래 조합은 트릭으로 만들 수 없다.
기본값 · hanging · each-line · hanging each-line.

오른쪽 아래가 핵심이다. hanging each-line은 "내가 줄을 바꾼 곳은 왼쪽에 붙이고, 폭이 모자라 저절로 이어진 줄만 들여쓴다"는 뜻이다. 시, 가사, 대본, 줄바꿈이 있는 코드 — 사람이 정한 줄 구조를 유지하면서 화면 폭에 밀려 넘어간 부분만 표시하는 것. 이게 이 속성의 진짜 쓸모이고, 트릭으로는 못 만든다.

트릭이 어긋나는 곳

padding-left + 음수 text-indent는 참고문헌 하나만 놓고 보면 완벽하다. 문제는 그 주변에서 난다.

값이 둘이라 어긋난다

트릭은 같은 값을 두 번 쓴다. 하나를 고치고 하나를 안 고치면 첫 줄이 튀어나오거나 덜 들어간다. 반응형으로 폭에 따라 들여쓰기를 줄일 때 미디어 쿼리마다 두 줄씩 고쳐야 하고, CSS 변수로 묶어도 "왜 이 변수가 두 속성에 들어가는가"를 다음 사람이 알아야 한다. text-indent: 2em hanging은 값이 하나다.

padding은 상자를 움직인다

padding-left는 텍스트만 미는 것이 아니라 상자의 콘텐츠 영역을 옮긴다. 배경, 테두리, ::before로 붙인 장식, 그리고 list-style의 불릿 위치가 전부 영향을 받는다. 목록 항목에 내어쓰기를 걸었더니 불릿과 텍스트 사이가 벌어지고, 배경색을 준 블록에서는 텍스트가 배경 왼쪽 끝에 붙지 않는다. text-indent는 줄 상자 안에서만 움직여서 상자는 그대로다.

overflow: hidden 이 첫 줄을 자른다

음수 text-indent는 첫 줄을 콘텐츠 영역 밖으로 내보낸다. 패딩이 그 자리를 마련해두니 보통은 괜찮지만, 어떤 이유로 패딩이 사라지거나 줄어들면(다른 규칙이 padding: 0으로 덮거나, 축약 속성 padding이 뒤에 오거나) 첫 줄의 왼쪽 2em이 잘려 나간다. overflow: hidden이 걸린 컨테이너에서 이 사고가 잦다. 텍스트 숨김용으로 text-indent: -9999px를 쓰던 시절이 남긴 습관인데, 같은 원리로 내어쓰기 첫 줄도 잘릴 수 있다.

물리 방향이라 RTL에서 깨진다

padding-left왼쪽이다. 아랍어·히브리어처럼 오른쪽에서 시작하는 문서에서는 반대쪽에 여백이 생기고, text-indent는 시작 쪽(inline-start)에 적용되니 둘이 서로 다른 쪽을 가리킨다. padding-inline-start로 바꾸면 되지만, 그걸 아는 사람만 고친다. hanging은 처음부터 논리 방향이다.

상속되는 것은 text-indent다

이건 트릭과 새 문법 모두에 해당한다. text-indent상속된다. 명세가 따로 주의를 준다 — 블록에 지정하면 자손 inline-block에도 적용되므로, inline-block 요소에는 text-indent: 0을 주는 것이 현명하다고. 내어쓰기한 문단 안에 inline-block 배지를 넣었더니 배지 안 텍스트가 밀린다면 이것이다.

어디에 쓰나

참고문헌·인용 목록2em hanging. 학술 양식의 표준 내어쓰기다. 저자명이 왼쪽에 붙어 훑기 쉽다.

.references li {
  text-indent: 2em hanging;
  list-style: none;
}

정의 목록의 dd — 용어를 첫 줄 시작에 두고 설명이 길어지면 이어지는 줄을 들여쓴다. dtdd를 한 줄에 놓는 스타일에서 특히 유용하다.

시·가사·대본hanging each-line. <br>로 나눈 행은 전부 왼쪽에 붙고, 폰에서 폭이 모자라 넘어간 부분만 들여써서 "이건 새 행이 아니라 이어진 것"을 보여준다. 대본이라면 화자 이름이 왼쪽에 서고 대사가 길어지면 이어지는 줄이 들어간다.

.lyrics, .script {
  text-indent: 1.5em hanging each-line;
}

줄바꿈되는 코드pre { white-space: pre-wrap }로 긴 코드 줄을 접을 때, 접힌 이어짐 줄에 hanging each-line을 주면 원래 줄과 이어진 줄이 구분된다. 터미널과 에디터가 하는 방식이다. 코드에서 줄바꿈은 전부 강제 줄바꿈이니 each-line이 정확히 맞는다.

pre.wrap {
  white-space: pre-wrap;
  text-indent: 2ch hanging each-line;
}

주소·연락처 블록<address> 안의 여러 줄. 첫 줄 라벨을 왼쪽에 두고 나머지를 맞춘다.

브라우저 지원과 폴백

브라우저 버전 출시일
Safari152021-09-20
Firefox1212023-12-19
Chrome · Edge1462026-03-10

Baseline Newly available 2026-03-13. 출처: webstatus.dev, 2026-09-07 조회. hangingeach-line은 지원 시점이 같다.

순서가 평소와 반대다. 사파리가 5년 먼저 했고 크롬이 올해 3월에야 붙었다. 그래서 "이제 된다"는 최근이지만, 안 되는 브라우저는 6개월 안 된 크롬뿐이라는 뜻이기도 하다. 크롬은 자동 갱신이라 실제 방문자 중 146 미만은 빠르게 줄어든다.

그래도 폴백은 둔다. 이 속성은 폴백이 쉽다. 키워드를 모르는 브라우저는 선언 전체를 무시하기 때문에, 트릭을 먼저 쓰고 새 문법을 @supports로 덮으면 된다.

.ref {
  padding-inline-start: 2em;
  text-indent: -2em;
}

@supports (text-indent: 1em hanging) {
  .ref {
    padding-inline-start: 0;
    text-indent: 2em hanging;
  }
}

@supports 없이 text-indent: -2em; text-indent: 2em hanging;으로 겹쳐 쓰는 것은 안 된다. 두 번째 줄이 무시되면 첫 줄이 남아 음수 인덴트는 걸리는데 패딩을 어디서 없앨지 정할 수 없다. 패딩과 인덴트를 같이 바꿔야 하니 @supports 블록이 필요하다.

정리

  • text-indent는 원래 첫 번째 서식 줄만 건드린다. <br> 뒤 줄은 첫 줄이 아니다.
  • hanging은 적용 대상을 반전한다 — 첫 줄 빼고 전부. 참고문헌·정의 목록.
  • each-line은 강제 줄바꿈 뒤 줄을 첫 줄로 친다. 둘을 합친 hanging each-line이 시·대본·접힌 코드에 맞고, 트릭으로는 만들 수 없다.
  • 트릭의 문제: 값 둘 동기화, 패딩이 상자를 움직임, overflow: hidden에서 첫 줄 잘림, 물리 방향.
  • 지원: Safari 15 → Firefox 121 → Chrome 146(2026-03). 폴백은 @supports로 패딩과 인덴트를 함께 바꾼다.
  • text-indent는 상속된다. inline-block 자손에 text-indent: 0.

참고: CSS Text Module Level 3 — 8.1 text-indent