CSSで、長い文章を3行で「…」と省略する方法

​​CSS​HTML,Playwright

長い文章を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 は次のとおりです。

css
/* 長い文章を3行で切って、最後に「…」を付ける */
.clamp-3 {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden; /* 4行目から先を隠す */
}
html
<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行で省略するには使えません。

上から順に、-webkit-line-clamp: 3 では3行目の終わりが「よいかがす…」になる。max-height: 4.8em だけと、max-height と text-overflow: ellipsis では、3行目の終わりが「よいかがすぐに」で切れて「…」は付かない
3つの書き方で、同じ文章を3行分の高さにした。「…」が付いたのは -webkit-line-clamp だけ

接頭辞の付かない 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 個ありました。

余白は、外側の要素に付けます。

css
/* 内側の余白は、外側の要素に付ける */
.card {
  padding: 12px;
  border: 1px solid #00c8e8;
}
html
<div class="card">
  <div class="clamp-3">猫の手を借りたいほど忙しい日に、……</div>
</div>

こうすると、3行目の終わりに「…」が付き、下の余白の中の白より暗い画素は 0 個になりました。

上の枠は、切る要素に padding を付けたもの。3行目の「付ければ…」の下に、4行目の上半分が見えている。下の枠は、padding を外側の要素に付けたもの。3行目の「付ければ…」で終わり、4行目は見えない
切る要素に padding を付けると4行目が見える。外側の要素に付けると見えない

中に段落がいくつあっても、まとめて3行で切る

切る要素の中に <p> が2つあるときも試しました。1つ目の段落が1行、2つ目が6行の文章です。

html
<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で、長い文章を「続きを読む」で折りたたむ方法』にまとめています。

js
const el = document.querySelector(".clamp-3");
const clamped = el.scrollHeight > el.clientHeight; // 切れていれば true

​Posted by 86