【複数行にも対応】長過ぎる文字列を省略して末尾を三点リーダー(…)にする方法いろいろ

wakamsha
1322

ランディングページといったコンテンツもレイアウトも全て決め打ちで成立するようなものはさておき、多くの Web サイトおよびアプリケーションは、いかなる分量のコンテンツであろうと柔軟に受け入れて表示出来るように設計・デザインされなくてはなりません。

しかし、全ての文字列を表示するには長過ぎてレイアウトが崩れてしまうといった場合には、何らかの方法で文字列を省略する必要があります。一昔であれば Ruby や PHP、Java などサーバーサイドで文字列を切り捨てるなどの加工をしてからフロントエンドに返すという方法が常套手段として用いられていました。しかし、これでは昨今のワンソースによるレスポンシブデザインといったスクリーンサイズに応じて動的に表示領域が変わるようなデザインに対応しきる事が出来ません。PCサイズの表示領域に適した文字数を返したとしてもモバイルサイズの表示領域がそれと同じとは限りません。表示領域がより小さくなればたちまちはみ出したり不自然な見切れ方をするなどのレイアウト崩れが発生してしまいます。

そんな訳で、サーバーサイドに頼らずフロントエンドで表示領域からはみ出した文字列を動的に省略し、末尾に三点リーダー(…)をつける方法をいくつかご紹介するとします

text-overflow を使う

最も簡単かつ確実な方法です。

text-overflow CSS プロパティは、テキストが表示領域をオーバーフローしていることを、ユーザに知らせる方法を決めます。クリップするか、省略記号 ('…'、U+2026、…) を表示するか、ウェブ著作者の定義した文字を表示させることができます。

text-overflow - CSS | MDN

text-overflow プロパティを指定することで、文字列が表示領域からはみ出した時に末尾を三点リーダーにした状態で省略することが出来ます。これを使うには、以下の設定と組み合わせる必要があります。

  • widthプロパティを設定する (※%emといった単位でもOK)
  • overflowプロパティをvisible 以外に設定する
  • white-spaceプロパティをnowrapに設定する

text-overflow は CSS3 の機能の一つとして定義されていますが、元々は Internet Explorer6 の独自仕様として策定されたものであり、それが後に CSS3 に採用されたものなので現状全ブラウザで使用することが出来ると言えます

ブラウザ実装状況
IE Chrome Firefox Safari Opera Safari (iOS) Android
6.0 ~ 4.0 ~ 7.0 ~ 3.1 ~ 9.6 ~ 3.2 ~ 2.1 ~

Can I use... Support tables for HTML5, CSS3, etc

HTML
<div class="container">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
</div>
SCSS
// Text with ellipsis
.container {
  background: #eee;
  overflow: hidden;
  width: 100%;

  p {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}
DEMO

とはいえこの手法、コードを見てすぐにお気づきかと思いますが、white-spaceプロパティを指定していることから、一行表示でしか使うことが出来ません。ヘッダーやナビゲーション・バーといった箇所などと、一行で表示するのに違和感が無いと思われる箇所での用途に限られてしまうのが難点です。

-webkit-line-clamp を使ってみる

指定した行にクランプ文字(…)を付与するというプロパティです。クランプを直訳すると締め具ですが、書類にクリップをつけるといった意味合いなんでしょうか…1)英語圏では三点リーダーのことをクランプと言うんでしょうか。かっこいいですね。明日から僕たちも使っていきましょう(適当)。-webkitというプレフィックスが付いている通り Chrome や Safari 限定ですが、これを使うことでとてもシンプルに複数行に対応した文字列省略を実現することが出来ます。

SCSS
// Reset
p {
  margin: 0;
}

// Multiline text with ellipsis
.container {
  background: #eee;
  overflow: hidden;
  width: 100%;
  p {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
  }
}
DEMO

複数行での文字列省略を実現するためにdisplay: -webkit-box;、さらに-webkit-box-orient: vertical;と指定します。display 属性を box とすることで HTML 要素はフレキシブルボックスという状態になり、-webkit-line-clamp で指定した行までを表示するようになります。box-orient はそのフレキシブルボックスの並び方向を指定します。vertical と指定します。

このテクニックの優れている点は、表示領域の高さを単純に行数を指定するだけでピッタリと合わせてくれるところにあります。普通であれば高さを指定するために font-size と line-height を元に高さを割り出したりしがちですが、その必要がないので非常にお手軽で美しいコードが書けてしまいます。しかもリキッドレイアウトにも対応。すごいぜ。

しかし、モバイル端末限定といった仕様であればこれで充分ですが、IE や Firefox 等も含めたPCも対象となると現時点でのブラウザサポートの状況を考えるとコレでは不十分です。何か他に手段はないものでしょうか?

【これで決まり(?)】IE、Firefox にも対応した複数行での文字列省略

いささかトリッキーな方法ですが、IE にも Firefox にも対応した方法をご紹介します。

SCSS
// Variables
$container-bg: #eee;
$font-size-base: 14px;
$line-height-computed: 1.4;
$lines-to-show: 3;

// Reset
p {
  margin: 0;
}

// Multiline text with ellipsis
// Supported IE and Firefox
.container {
  background: #eee;
  overflow: hidden;
  width: 100%;
  p {
    font-size: $font-size-base;
    height: $font-size-base * $line-height-computed * $lines-to-show;
    line-height: $line-height-computed;
    position: relative;
    &:before,
    &:after {
      background: #eee;
      position: absolute;
    }
    &:before {
      content: "...";
      top: $font-size-base * $line-height-computed * ($lines-to-show - 1);
      right: 0;
    }
    &:after {
      content: "";
      height: 100%;
      width: 100%;
    }
  }
}
DEMO

before と after 2つの擬似要素を駆使することで実現しています。before は三点リーダー、after はそれを隠すマスクとしての役割を果たしています。コードだけでは分かり辛いので順番に説明していきましょう。

1) 表示領域の高さを定義する

-webkit-line-clamp の時とは違い、この手法では明示的に領域の高さを指定します。文字サイズと行の高さ、表示したい行数を掛けた値を指定することで最適な高さに設定することができます。

2) 三点リーダーを定義する

before 要素を使って三点リーダーを作ります。まず表示領域と同じ背景色を指定して文字列の上に重なっても良いようにします。position: absolute; で絶対座標指定にし、top は表示する行数の位置と右端に設定します。こうすることで文字列が来る一番後ろの位置に配置することが出来ます。

3) 三点リーダーを隠すマスク要素を定義する

文字列が表示領域内に収まっているのに三点リーダーが見えてしまっては意味がありません。こういった状態では三点リーダーを隠さなくてはなりません。そんな訳で、after要素にその役目を担ってもらいます。こちらもまずは背景色を指定しましょう。height と width をそれぞれ100%に指定することで表示領域をちょうど覆い隠せるサイズにします。また position: absolute; と絶対座標とだけ指定してすることで文字列の直後に配置されるようになります。つまり文字列のすぐ後ろにはマスク要素が控えていることになります。もし文字列が領域内に収まる時はこのマスク要素も領域内に来ます。そして先ほどの三点リーダー要素である before 要素の上に覆いかぶさるため、三点リーダーは見えなくなります。

あえて欠点を挙げるなら、三点リーダーの位置が表示領域の右下に固定されてしまうことでしょうか。英文など半角文字列の場合、表示される文字列の最終位置と三点リーダーが離れてしまう場合があるため、そこは仕様として割り切る必要がありますが、それでも JavaScript を一切使わずに CSS だけで実現出来るのは充分に使えるテクニックだと思います。

脚注

脚注
1 英語圏では三点リーダーのことをクランプと言うんでしょうか。かっこいいですね。明日から僕たちも使っていきましょう(適当)。