No.188
MICRO CSSJS

Auto-Grow Textarea

文字を打つと入力欄の高さが1行ずつ伸び、6行を超えたらスクロールに切り替わる入力欄。CSS の field-sizing: content の1行で作り、未対応のブラウザだけ JavaScript で高さを合わせます。

MY COLLECTION RANDOM ↗

DEMO

0 / 400

CODE

HTML
<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>
CSS
.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; }
JS
(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

Claude Code Cursor v0
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

📖 なかしまぁ先生のCSSアニメーション入門 📖 マイクロインタラクション ―UI/UXデザインの神が宿る細部 📖 Fundamentals of Web Animation with GSAP

※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。

学びを止めない · AMAZONサブスク

📚 Kindle Unlimited — 技術書・デザイン書が読み放題。30日無料体験 → 🎧 Audible — 移動中に耳で学ぶオーディオブック。30日無料体験 → 📦 Amazon Prime — Prime Reading・配送特典つき。30日無料体験 → 🎵 Music Unlimited — 作業用BGMに。1億曲が聴き放題・30日無料体験 →

※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。

CREATOR TOOLS · スクール(PR)

🎬 Adobe Creative Cloud — After Effects / Photoshop 業界標準ツール → 💻 SkillHacks — プログラミング・動画編集オンラインスクール → 🚀 デイトラ — Web制作スクール・実案件レベルまで習得 →

※本サイトはアフィリエイトリンクを含みます。リンク経由のご購入・お申し込みで運営者が紹介料を受け取る場合があります。

RELATED EFFECTS

↗ MORE
→ FLOATING LABEL INPUT → OTP INPUT → PASSWORD STRENGTH METER

field-sizing(中身に合わせて大きさが変わる入力欄)とは

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プロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。