CSSで、長い文章を3行で「…」と省略する方法
長い文章を3行で切り、3行目の最後に「…」を付けるには、display: -webkit-box、-webkit-box-orient: vertical、-webkit-line-clamp: 3 の3つを組み合わせ、overflow: hidden で4行目から先を隠します。行数で切るので、要素の幅が変わっても3行のままです。切る要素に padding を付けると4行目が少し見えてしまうため、余白は外側の要素に付けます。
検証環境は Ubuntu 24.04、Node.js 22.23.4、Playwright 1.63.0、Chromium 153 です。HTML と CSS だけのページを Playwright で開き、要素の高さを測ったり、スクリーンショットを見て「…」が付いたかを確かめたりしました。文章は日本語で、幅 320px、文字の大きさ 16px、行の高さ 1.6(25.6px)です。Firefox と Safari、スマートフォンのブラウザ、英語の文章、スクリーンリーダーでの読み上げは試していません。
3つのプロパティを組み合わせて3行で切る
CSS は次のとおりです。
/* 長い文章を3行で切って、最後に「…」を付ける */
.clamp-3 {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden; /* 4行目から先を隠す */
}
<div class="clamp-3">猫の手を借りたいほど忙しい日に、やることを短いメモにまとめておくと、……</div>
MDN の line-clamp のページによると、-webkit-line-clamp は、display が -webkit-box(または -webkit-inline-box)で、-webkit-box-orient が vertical のときだけ働きます。どれも非推奨のプロパティですが、3つを組み合わせたときの動きは仕様で決められていて、今後も使えると書かれています。overflow: hidden がないと、中身は隠れないまま、決めた行数の後に「…」が表示されます。
検証環境で、そのままなら6行になる文章にこの CSS を付けたところ、要素の高さ(clientHeight)は 154px から 77px になりました。行の高さ 25.6px の3行分(76.8px)です。3行目の終わりは「よいかがす…」となり、4行目から先は見えません。幅を 200px に狭めると、全部で10行になる文章でも、高さは 77px の3行で、3行目の終わりに「…」が付きました。
1行に収まる短い文章に同じクラスを付けると、高さは1行分の 26px で、「…」は付きません。短い文章が混ざる一覧でも、同じクラスをそのまま使えます。
max-height や text-overflow では「…」が付かない
高さを3行分(max-height: 4.8em)にして overflow: hidden を付けても、3行で切れます。高さは同じ 77px です。ただし、文章が途中で切れるだけで、「…」は付きません。
text-overflow: ellipsis を足しても同じでした。MDN の text-overflow のページにあるとおり、text-overflow が働くのは、文章が横(行の進む方向)にあふれたときだけです。ボックスの下にあふれた文章には働きません。1行で省略するなら、overflow: hidden と white-space: nowrap を一緒に指定すれば使えますが、3行で省略するには使えません。

接頭辞の付かない line-clamp: 3 も試しました。overflow: hidden と組み合わせても、6行すべて見えたままです。検証環境の Chromium 153 では、CSS.supports("line-clamp", "3") は false、CSS.supports("-webkit-line-clamp", "3") は true でした。@mdn/browser-compat-data 8.1.8 の互換性データでも、接頭辞なしの line-clamp は Chrome・Firefox・Safari のどれも試験版(preview)やフラグを有効にしたときだけで、-webkit- 付きは Chrome 6、Firefox 68、Safari 5 から使えるとなっています。Safari は 18.2〜18.3 で接頭辞なしの line-clamp が誤って使える状態になり、18.4 で取り除かれた、という記録もあります。
padding は外側の要素に付ける
枠と余白を付けてカードのように見せるとき、切る要素そのものに padding: 12px を付けると、下の余白の部分に4行目の上半分が見えました。3行目の終わりには「…」が付いています。MDN の overflow のページにあるとおり、overflow: hidden は、あふれた中身を要素の padding ボックス(padding を含めた範囲)で切り取ります。padding の部分に入った4行目は、切り取られずに見えます。検証環境で、下の余白(12px)の中で、白より暗い画素を数えたところ、321 個ありました。
余白は、外側の要素に付けます。
/* 内側の余白は、外側の要素に付ける */
.card {
padding: 12px;
border: 1px solid #00c8e8;
}
<div class="card">
<div class="clamp-3">猫の手を借りたいほど忙しい日に、……</div>
</div>
こうすると、3行目の終わりに「…」が付き、下の余白の中の白より暗い画素は 0 個になりました。

中に段落がいくつあっても、まとめて3行で切る
切る要素の中に <p> が2つあるときも試しました。1つ目の段落が1行、2つ目が6行の文章です。
<div class="clamp-3">
<p>猫の手を借りたいほど忙しい日のメモです。</p>
<p>猫の手を借りたいほど忙しい日に、……</p>
</div>
高さは 77px で、1つ目の段落の1行と、2つ目の段落の2行を合わせた3行で切れました。「…」は、2つ目の段落の2行目の終わりに付きます。段落ごとに3行ずつではなく、要素の中の行を上から数えて3行です。
切れているかどうかを JavaScript で調べる
「続きを読む」のボタンを、文章が切れているときだけ出したいときは、要素の scrollHeight と clientHeight を比べます。MDN の scrollHeight のページにあるとおり、scrollHeight は、あふれて見えない部分も含めた中身の高さです。検証環境では、3行で切れた要素は scrollHeight が 154px、clientHeight が 77px でした。1行の短い文章は、どちらも 26px です。ボタンで開け閉めする作り方は、このブログの記事『Reactで、長い文章を「続きを読む」で折りたたむ方法』にまとめています。
const el = document.querySelector(".clamp-3");
const clamped = el.scrollHeight > el.clientHeight; // 切れていれば true





