DEMO
CODE
<div class="demo-stage fsz-stage">
<form class="fsz-card" id="fsz-form" action="#">
<label class="fsz-label" for="fsz-text">メッセージ</label>
<textarea class="fsz-text" id="fsz-text" rows="1" maxlength="400" placeholder="改行すると伸びます" aria-describedby="fsz-count"></textarea>
<div class="fsz-row">
<label class="fsz-tag"><span aria-hidden="true">#</span><input class="fsz-input" id="fsz-tag" type="text" value="motion" maxlength="24" aria-label="タグ"></label>
<span class="fsz-count" id="fsz-count">0 / 400</span>
</div>
</form>
</div>
.fsz-stage { position:relative; overflow:hidden; display:flex; align-items:center; justify-content:center; padding:2rem 1.25rem; background:#0B0B10; min-height:300px; }
.fsz-card { width:100%; max-width:420px; box-sizing:border-box; display:flex; flex-direction:column; gap:.6rem; padding:1rem; border-radius:14px; background:#16161D; border:1px solid rgba(255,255,255,.1); }
.fsz-label { color:#EDEDED; font-size:.82rem; font-weight:600; }
.fsz-text {
field-sizing: content; /* 中身に合わせて高さが変わる */
min-height: calc(1lh + 1.4rem + 2px); /* 1行分+上下の padding+border(box-sizing:border-box のため) */
max-height: calc(6lh + 1.4rem + 2px); /* 6行を超えたらスクロール */
overflow-y: auto;
resize: none;
box-sizing: border-box; width:100%; padding:.7rem .85rem; border-radius:10px;
border:1px solid rgba(255,255,255,.18); background:#0F0F15; color:#EDEDED;
font:inherit; font-size:.92rem; line-height:1.6;
transition: border-color .2s, box-shadow .2s;
}
.fsz-text::placeholder { color:#8B8B96; }
.fsz-text:focus-visible { outline:none; border-color:#F472B6; box-shadow:0 0 0 3px rgba(244,114,182,.25); }
.fsz-row { display:flex; align-items:center; justify-content:space-between; gap:.75rem; flex-wrap:wrap; }
.fsz-tag { display:inline-flex; align-items:center; gap:.15rem; padding:.2rem .55rem; border-radius:999px; background:rgba(209,23,122,.18); color:#F9A8D4; font-size:.82rem; }
.fsz-input {
field-sizing: content; /* 横幅も中身に合わせる */
min-width: 3ch; max-width: 16ch;
border:0; background:transparent; color:inherit; font:inherit; padding:.15rem 0;
}
.fsz-input:focus-visible { outline:2px solid #F472B6; outline-offset:2px; border-radius:3px; }
.fsz-count { color:#A1A1AA; font-size:.75rem; font-variant-numeric:tabular-nums; }
.fsz-count.is-near { color:#FCA5A5; }
(function(){
var ta = document.getElementById('fsz-text');
var tag = document.getElementById('fsz-tag');
var count = document.getElementById('fsz-count');
var form = document.getElementById('fsz-form');
if (!ta || !tag || !count || !form) return;
form.addEventListener('submit', function(e){ e.preventDefault(); });
var native = window.CSS && CSS.supports && CSS.supports('field-sizing', 'content');
function fit(){
if (native) return; /* 対応ブラウザは CSS だけで伸びる */
ta.style.height = 'auto';
ta.style.height = ta.scrollHeight + 2 + 'px'; /* 2 = 上下の border */
tag.style.width = Math.max(3, Math.min(16, tag.value.length + 1)) + 'ch';
}
function update(){
var n = ta.value.length;
count.textContent = n + ' / ' + ta.maxLength;
count.classList.toggle('is-near', n >= ta.maxLength - 40);
fit();
}
ta.addEventListener('input', update);
tag.addEventListener('input', fit);
update();
})();
AI PROMPT
文字を打つと高さが1行ずつ伸びて、6行を超えたらスクロールに切り替わる入力欄を作って。textarea に field-sizing: content を指定し、box-sizing:border-box のまま、min-height を calc(1lh + 上下の padding と border の合計)、max-height を calc(6lh + 上下の padding と border の合計) にして(border を足し忘れると6行目でスクロールバーが出る) overflow-y:auto・resize:none を付ける(lh は行の高さの単位)。placeholder は短くする(field-sizing: content では placeholder が収まる大きさまで広がるため)。横に #タグ の input も置き、同じく field-sizing: content と min-width:3ch・max-width:16ch で入力に合わせて幅を変える。文字数を「n / 400」で表示し、残り40文字で色を変える(font-variant-numeric: tabular-nums で数字の幅を揃える)。CSS.supports('field-sizing','content') が false のブラウザだけ、input のたびに textarea の height を auto に戻してから scrollHeight+上下の border に合わせ、タグの input は文字数から ch 単位の幅を付ける。フォーカス時は枠の色と薄い外側の影で示し、outline を消す場合は必ず代わりの表示を付ける。
Acceptance criteria: works with prefers-reduced-motion (animation disabled), zero console errors, zero layout shift
AIエージェントでの実装ガイド → Claude Code でWebアニメーションを実装する
BOOKS · PR · AMAZON
※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。
学びを止めない · AMAZONサブスク
※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。
CREATOR TOOLS · スクール(PR)
※本サイトはアフィリエイトリンクを含みます。リンク経由のご購入・お申し込みで運営者が紹介料を受け取る場合があります。
field-sizing は、入力欄のように最初から決まった大きさを持つ要素の、大きさの決まり方を変える CSS のプロパティです。MDN では「フォームコントロールのように既定の大きさを持つ要素の大きさの振る舞いを制御できる」と説明され、値を content にすると入力した文字に合わせて欄が伸び縮みします。以前は JavaScript で scrollHeight を測って高さを付け直すのが定番でしたが、CSS の1行で同じことができるようになりました。
当サイトの Floating Label Input はフォーカスするとラベルが上へ縮みながら移動する入力欄、OTP Input は6桁のコードを1桁ずつの枠に入力する欄、Password Strength Meter は入力に合わせて強度のメーターが伸びる表示です。本ページは入力欄そのものの大きさを中身に合わせる別テーマです。
チャットの送信欄、コメント欄、タグの入力のように、短い入力が多く時々長くなる場所に向いています。一方で上限を決めないと長文で画面が押し出されるため、max-height で行数の上限を決め、そこからはスクロールにするのが扱いやすい形です。
field-sizing が使えないブラウザではどうなりますか?
MDN の互換性データ(browser-compat-data 2026-09-24 版)では、field-sizing は Chrome・Edge 123、Firefox 152、Safari 26.2 から使えます。それより古いブラウザでは指定が無視されて普通の大きさのままになるため、本実装は CSS.supports で対応を調べ、未対応の時だけ JavaScript で高さを scrollHeight に合わせています。対応ブラウザでは JavaScript は高さに関わりません。
max-height を付けているのはなぜですか?
field-sizing: content だけだと、長い文章を貼り付けた時に入力欄がどこまでも伸び、送信ボタンやページの下の部分が画面の外へ押し出されます。6行分の max-height と overflow-y: auto を付けると、それ以上は欄の中でスクロールするようになります。行数は lh という行の高さの単位で書くと、文字の大きさを変えても6行のまま保てます。
コードは無料で使えますか?
はい。Motion LabのコードスニペットとAIプロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。