게시판 글쓰기 화면의 <textarea>는 늘 두 줄 높이로 시작한다. 세 줄째부터 스크롤바가 생기고, 사용자는 자기가 쓴 글의 윗부분을 못 보면서 계속 쓴다. 그래서 어느 프로젝트에나 이런 코드가 하나씩 있다.
textarea.addEventListener('input', function () {
this.style.height = 'auto';
this.style.height = this.scrollHeight + 'px';
});
키를 누를 때마다 높이를 0으로 눌렀다가 scrollHeight만큼 다시 편다. 동작은 하지만 이 코드는 브라우저가 원래 해줘야 할 일을 스크립트가 흉내 내는 것이다. 다른 요소는 전부 내용만큼 커지는데, 폼 컨트롤만 그러지 않아서 생긴 우회다.
2026년 6월부터 이 우회를 CSS 한 줄로 걷어낼 수 있게 됐다. field-sizing: content다.
폼 컨트롤은 왜 내용을 무시하는가
<div>에 글을 넣으면 글만큼 커진다. <span>도, <td>도 그렇다. 그런데 <input>과 <textarea>는 내용과 상관없이 미리 정해진 크기로 그려진다. 입력란은 size 속성(기본 20자), 텍스트 영역은 rows·cols(기본 2줄·20자)가 그 크기를 정한다.
이건 버그가 아니라 설계다. 폼 컨트롤은 비어 있는 상태로 사용자에게 보여지는 요소라, 내용 기준으로 크기를 잡으면 처음에는 크기가 0이 된다. 그래서 브라우저는 "내용은 무시하고 정해진 폭으로 그린다"를 기본값으로 삼아왔다.
field-sizing은 이 기본값을 속성으로 끌어낸 것이다. 값은 둘뿐이다.
fixed— 지금까지의 동작. 기본값이다.content— 다른 요소처럼 내용만큼 커진다.
즉 새 기능을 켜는 속성이라기보다, 폼 컨트롤만 예외로 두던 규칙을 해제하는 스위치다.
content로 바꾸면 무엇이 달라지나
textarea, input, select {
field-sizing: content;
}
요소별로 달라지는 것이 다르다.
<textarea> — 줄 수만큼 높아진다. 네 줄을 쓰면 네 줄 높이가 되고, 지우면 줄어든다. 위에 있던 scrollHeight 스크립트가 하던 일 그대로다.
<input> — 글자만큼 넓어진다. text·email·number·password·search·tel·url처럼 직접 입력하는 타입에 적용된다. 파일 입력도 선택된 파일명 길이에 맞춰 폭이 바뀐다.
<select> — 드롭다운은 지금 선택된 항목의 폭이 된다. 기본값에서는 가장 긴 항목에 맞춰 폭이 정해지는데, 그러면 짧은 항목을 골랐을 때 오른쪽이 텅 빈다. multiple이나 size가 붙은 리스트박스는 항목을 전부 보여줄 만큼 높아진다.
한 가지 더. 플레이스홀더도 내용으로 친다. 값이 비어 있으면 플레이스홀더 글자가 다 보일 만큼의 크기로 그려진다. 값도 플레이스홀더도 없으면 min-width까지 줄어든다 — 이 지점은 뒤에서 다시 다룬다.
지금까지 스크립트로 하던 것들
이 속성이 대체하는 코드가 어떤 것들인지 짚어두면, 어디에 넣을지가 보인다.
scrollHeight로 높이 맞추기
글 첫머리의 그 코드다. 문제가 세 가지 있다.
- 스크립트가 돌기 전에는 두 줄이다. 서버가 값을 채워서 내려준 수정 화면은 페이지가 뜬 직후 잠깐 두 줄로 보였다가 스크립트가 돌면서 늘어난다. 화면이 한 번 덜컥인다.
value를 코드로 바꾸면input이벤트가 안 난다. 임시저장 불러오기, 템플릿 삽입, 폼 초기화 뒤에는 높이를 손으로 다시 맞춰야 한다. 빠뜨리면 내용은 열 줄인데 상자는 두 줄이다.box-sizing과 어긋난다.scrollHeight는 패딩을 포함하고 테두리는 뺀 값이라,border-box인지 아닌지에 따라 매번 몇 픽셀씩 남거나 모자란다. 그래서 대개+ 2같은 보정 상수가 붙어 있다.
거울 요소로 폭 재기
입력란 폭을 글자에 맞추는 것은 더 번거롭다. <input>은 scrollWidth가 믿을 만하지 않아서, 같은 글꼴을 준 숨은 <span>에 값을 복사해 넣고 그 offsetWidth를 읽는다. 아니면 캔버스의 measureText로 재기도 한다. 어느 쪽이든 글꼴·크기·자간을 입력란과 똑같이 맞춰야 하고, 웹폰트가 늦게 로드되면 잰 값이 틀린다.
field-sizing: content는 이 둘을 전부 레이아웃 엔진 안으로 옮긴다. 이벤트도, 측정도, 보정 상수도 없다. 값이 어떤 경로로 바뀌든 크기는 따라온다.
한도를 거는 법
내용만큼 커진다는 것은 곧 끝없이 커진다는 뜻이다. 게시글 본문을 200줄 쓰면 텍스트 영역이 200줄 높이가 되고, 페이지 전체가 그만큼 길어진다. 한도가 필요하다.
한도는 평범한 CSS로 건다.
textarea {
field-sizing: content;
min-height: 3lh; /* 최소 세 줄 */
max-height: 20lh; /* 스무 줄까지 늘고, 그 뒤는 스크롤 */
}
input[type="text"] {
field-sizing: content;
min-width: 8ch;
max-width: 100%;
}
세 가지를 알아두면 된다.
rows·cols·size 속성은 무시된다. 최소값으로도 쓰이지 않는다. rows="5"를 뒀다고 다섯 줄에서 시작하지 않는다. 최소 높이를 원하면 min-height로 옮겨야 한다. 위 예시의 lh 단위는 줄 높이 하나라, rows를 옮기기에 딱 맞는다.
width·height를 고정값으로 주면 도로 고정된다. height: 80px이 있으면 field-sizing이 할 일이 없다. 한도는 반드시 min-·max-로 건다.
maxlength에 닿으면 성장이 멈춘다. 글자 수 제한이 있는 입력란은 그 길이에서 폭이 고정되므로, 별도의 max-width가 없어도 된다.
브라우저 지원
2026년 6월 16일에 Baseline Newly available이 됐다. 주요 브라우저 전부가 지원하기 시작한 날이다.
| 브라우저 | 버전 | 출시일 |
|---|---|---|
| Chrome · Chrome Android | 123 | 2024-03-19 |
| Edge | 123 | 2024-03-22 |
| Safari · iOS Safari | 26.2 | 2025-12-12 |
| Firefox · Firefox Android | 152 | 2026-06-16 |
출처: webstatus.dev, 2026-09-04 조회.
크롬은 2년 넘게 됐고, 사파리가 작년 말, 파이어폭스가 올여름에 합류했다. 그래서 "이제 쓸 수 있다"가 된 것은 최근이지만, 실제 방문자 브라우저 기준으로는 대부분이 이미 지원하는 상태다.
폴백은 따로 필요 없다
이 속성의 좋은 점은 미지원 브라우저에서 아무것도 망가지지 않는다는 것이다. 모르는 속성은 무시되고, 기본값 fixed가 남는다. 즉 지금 모양 그대로다. @supports로 감쌀 이유가 없다.
기존 스크립트를 당장 지우기 어렵다면, 반대로 지원되는 브라우저에서 스크립트를 끄는 쪽이 맞다.
if (!CSS.supports('field-sizing', 'content')) {
// 미지원 브라우저에서만 scrollHeight 리사이저를 붙인다
attachAutoResize(textarea);
}
둘 다 켜두면 스크립트가 height를 고정값으로 박아버려서 field-sizing이 무력화된다. 앞 절의 "고정값을 주면 도로 고정된다"가 바로 이 경우다.
부트스트랩과 부딪히는 곳
부트스트랩의 .form-control은 이렇게 돼 있다.
.form-control {
display: block;
width: 100%;
...
}
<textarea>는 이대로 괜찮다. 폭이 100%로 고정돼도 field-sizing이 건드리는 것은 높이라, 서로 방해하지 않는다. 클래스는 그대로 두고 field-sizing: content와 max-height만 얹으면 된다.
<input>은 안 된다. 글자만큼 넓어지려면 폭이 자유로워야 하는데 width: 100%가 못 박고 있다. 폭 자동을 원하는 입력란에만 덮어쓴다.
.form-control.is-fit {
display: inline-block;
width: auto;
min-width: 8ch;
max-width: 100%;
field-sizing: content;
}
실제로는 입력란 폭을 글자에 맞추고 싶은 자리가 생각보다 적다. 폼의 입력란은 세로로 정렬돼 있고 왼쪽 끝을 맞추는 것이 중요해서, 폭이 제각각이면 오히려 지저분하다. 폭 자동이 어울리는 곳은 문장 사이에 끼는 입력란, 표 안의 짧은 값, 태그 입력처럼 인라인으로 흐르는 자리다. 텍스트 영역의 높이 자동은 거의 어디서나 이득이지만, 입력란의 폭 자동은 골라서 써야 한다.
주의할 것
빈 입력란은 사라진다. 값도 플레이스홀더도 없으면 min-width까지 줄어드는데, min-width를 안 줬으면 거의 0이다. 폭 자동을 켤 때는 min-width가 사실상 필수다. 플레이스홀더를 넣는 것도 방법인데, 그러면 플레이스홀더 길이가 초기 폭이 된다.
타이핑마다 레이아웃이 바뀐다. 폭이 자라면 옆에 있던 것이 밀린다. 표 안의 입력란이면 열 폭이 흔들리고, 플렉스 줄 안이면 줄바꿈 위치가 바뀐다. 텍스트 영역의 높이 변화는 아래로만 밀어서 대개 괜찮지만, 입력란의 폭 변화는 주변을 살펴야 한다.
rows를 믿고 있던 코드를 찾아야 한다. 속성이 무시되므로, 마크업에 rows="10"이 있고 그걸로 "이 영역은 넉넉하게" 를 표현하던 곳은 min-height로 옮기지 않으면 두 줄짜리가 아니라 한 줄짜리가 된다. 기본 최소가 없어지기 때문이다.
정리
field-sizing: content는 새 기능이라기보다 폼 컨트롤만 예외로 두던 규칙을 푸는 스위치다. 텍스트 영역이 줄 수만큼, 입력란이 글자만큼, 셀렉트가 선택된 항목만큼 커진다.
- 대체하는 것:
scrollHeight리사이저, 거울span·measureText폭 측정 - 같이 쓸 것:
min-height·max-height·min-width·max-width.rows·cols·size는 무시된다 - 지원: Chrome 123 · Edge 123 · Safari 26.2 · Firefox 152. Baseline 2026-06-16
- 폴백: 필요 없음. 미지원이면 지금 모양. 기존 스크립트는
CSS.supports로 미지원 브라우저에서만 켠다 - 부트스트랩: 텍스트 영역은 그대로, 입력란은
width: auto를 덮어써야 한다
가장 먼저 넣을 곳은 게시판·댓글·메모의 <textarea>다. 리사이저 스크립트를 지우고 두 줄을 넣는 것으로 끝난다.