CSS の field-sizing で input や textarea をコンテンツに合わせて自動リサイズする

フォームの <input><textarea> は、デフォルトではブラウザが決めた固定サイズで表示されます。ユーザーが長いテキストを入力しても幅は変わらず、<textarea> は高さが固定のままスクロールバーが出ます。これまで入力内容に応じたリサイズは JavaScript で scrollHeight を取得して高さを書き換える方法が定番でしたが、CSS の field-sizing プロパティを使えば 1 行で済みます。

field-sizing プロパティ

field-sizing はフォーム要素のサイズ決定方法を制御するプロパティです。

挙動
fixed従来どおりの固定サイズ(デフォルト)
content入力内容に応じてサイズが変わる

fixed がこれまでのブラウザのデフォルト挙動で、要素の幅や高さは CSS や HTML 属性(sizecolsrows)で決まります。content を指定すると、入力されたテキストの量に応じて要素のサイズが動的に変化します。

textarea での使い方

最も恩恵が大きいのは <textarea> です。従来は rows 属性で初期の行数を決めるしかなく、内容が増えると内部スクロールが発生していました。

textarea {
    field-sizing: content;
}

これだけで、入力された行数に応じてテキストエリアの高さが自動的に伸縮します。実際の動作を確認できます。

HTML
CSS
JavaScript
<div class="demo">
    <div class="group">
        <label>field-sizing: fixed(デフォルト)</label>
        <textarea class="fixed" rows="3" placeholder="テキストを入力してください..."></textarea>
    </div>
    <div class="group">
        <label>field-sizing: content</label>
        <textarea class="content" placeholder="テキストを入力してください..."></textarea>
    </div>
</div>
.demo {
    display: flex;
    gap: 24px;
    max-width: 600px;
}
.group {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
label {
    font-size: 13px;
    font-weight: bold;
    color: #555;
}
textarea {
    padding: 8px;
    border: 1px solid #ccc;
    border-radius: 6px;
    font-size: 14px;
    line-height: 1.6;
    font-family: inherit;
    resize: vertical;
}
.fixed {
    field-sizing: fixed;
}
.content {
    field-sizing: content;
}

右側のテキストエリアに文章を入力していくと、行数に合わせて高さが伸びていくのがわかります。改行を消せば縮みます。

input での使い方

<input type="text"> にも field-sizing: content は有効です。入力文字数に応じて横幅が伸縮します。

input[type="text"] {
    field-sizing: content;
}

タグ入力 UI やインラインの編集フィールドなど、入力内容の長さが事前にわからないケースで便利です。ただし、幅が動的に変わるとレイアウトシフトが起きるため、使いどころは限定的になります。

min・max との併用

field-sizing: content を単独で使うと、空の状態で要素が極端に小さくなったり、大量のテキストで際限なく広がったりします。min-height / max-height(または min-width / max-width)と併用するのが実用的です。

textarea {
    field-sizing: content;
    min-height: 80px;
    max-height: 400px;
}

この指定で、最初は 80px の高さがあり、入力に応じて伸びるものの 400px で止まります。400px を超えた分はスクロールになるため、ページ全体のレイアウトが崩れることを防げます。

input[type="text"] {
    field-sizing: content;
    min-width: 120px;
    max-width: 100%;
}

<input> の場合も同様に、最小幅を確保しつつ親要素からはみ出さないよう max-width を設定しておけば安全です。

select 要素への適用

<select> にも field-sizing: content が使えます。通常、<select> の幅は最も長い <option> のテキストに合わせて固定されますが、content を指定すると現在選択されている項目の幅に合わせて伸縮します。

select {
    field-sizing: content;
}
HTML
CSS
JavaScript
<div class="select-demo">
    <div class="group">
        <label>fixed(デフォルト)</label>
        <select class="fixed-select">
            <option>短い</option>
            <option>これは少し長めの選択肢です</option>
            <option>中くらい</option>
        </select>
    </div>
    <div class="group">
        <label>field-sizing: content</label>
        <select class="content-select">
            <option>短い</option>
            <option>これは少し長めの選択肢です</option>
            <option>中くらい</option>
        </select>
    </div>
</div>
.select-demo {
    display: flex;
    gap: 24px;
    max-width: 500px;
}
.group {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
label {
    font-size: 13px;
    font-weight: bold;
    color: #555;
}
select {
    padding: 6px 8px;
    border: 1px solid #ccc;
    border-radius: 6px;
    font-size: 14px;
    font-family: inherit;
}
.fixed-select {
    field-sizing: fixed;
}
.content-select {
    field-sizing: content;
}

選択肢を切り替えると、右側の <select> はテキストの長さに合わせて幅が変わります。コンパクトな UI を維持したい場面で役立ちます。

JavaScript による従来の方法との比較

field-sizing が登場する前は、<textarea> の自動リサイズに JavaScript が必須でした。

const textarea = document.querySelector('textarea');

textarea.addEventListener('input', () => {
    textarea.style.height = 'auto';
    textarea.style.height = textarea.scrollHeight + 'px';
});

この方法にはいくつかの問題があります。

JavaScript による方法

入力イベントのたびに height を書き換えるため、レイアウト再計算(リフロー)が毎回発生する。初期値のリセットに height: auto を挟む必要があり、ちらつきの原因にもなる。

field-sizing: content

ブラウザの内部処理でサイズが決まるため、リフローのコストが低い。CSS の 1 行で完結し、JavaScript への依存がなくなる。

パフォーマンス面でもコードの簡潔さでも field-sizing が有利です。ただし、ブラウザ対応がまだ限定的なため、当面は JavaScript によるフォールバックを併用する形になります。

フォールバック戦略

未対応ブラウザ向けには @supports で分岐する方法と、JavaScript フォールバックを組み合わせる方法があります。

/* 未対応ブラウザ向けに固定の行数を確保 */
textarea {
    rows: 4;
}

/* 対応ブラウザでは field-sizing を有効化 */
@supports (field-sizing: content) {
    textarea {
        field-sizing: content;
        min-height: 80px;
        max-height: 400px;
    }
}
// CSS の field-sizing が使えない場合のみ JS フォールバック
if (!CSS.supports('field-sizing', 'content')) {
    document.querySelectorAll('textarea').forEach(el => {
        el.addEventListener('input', () => {
            el.style.height = 'auto';
            el.style.height = el.scrollHeight + 'px';
        });
    });
}

CSS.supports() で機能検出できるので、対応ブラウザでは CSS だけで動作し、未対応ブラウザでは JavaScript に切り替わります。

ブラウザ対応状況

2024 年末時点の対応状況です。

ブラウザ対応バージョン
Chrome123+
Edge123+
Safari対応なし
Firefox対応なし

Chrome と Edge では 2024 年 3 月のバージョン 123 から対応しています。Safari と Firefox は未実装ですが、仕様自体は CSS Working Group で策定が進んでおり、将来的な対応が見込まれています。未対応ブラウザでは field-sizing プロパティが無視され、従来どおりの固定サイズで表示されるだけなので、既存のレイアウトが壊れることはありません。