ありそうでなかったテキスト省略ライブラリ Eripusisu を作った

まえがき

長すぎるテキストを「…」のような文字を使って省略表現することがあります。この実装は通常 CSS プロパティを使って実現していましたが、問題も多くありました。

次に挙げるものは長年、不便を感じていたり、実装都合でデザイナーからの提案を退けざるをえなかったりして、改善したいと思っていた問題です。

省略対象のコンテンツが強く制約を受けてしまうことは特に、デザイナーを説得しづらく、解決したい問題でした。

そこで Eripusisu を作成しました。2020 年の今になってどれほど価値のあるライブラリなのかは未知数ですが、個人的には長年欲しかったヤツなので、刺さる人には刺さるのではないでしょうか。

特長

Eripusisu は次のような特長を備えています。

デモ

簡易的なデモを用意しました。

キャプチャを添えて少し解説してみます。

通常の省略

これまで display: -webkit-box を使ってモダンブラウザでは実現できていたパターンです。

通常の省略 省略中のキャプチャ

展開したところ。

通常の省略 展開中のキャプチャ

途中にリンクがある場合

これも特に驚きはありません。

途中にリンクがある場合 省略中のキャプチャ

展開したところ。

途中にリンクがある場合 展開中のキャプチャ

ブロック要素が含まれる場合

このあたりからは CSS や既存のテキスト省略系ライブラリでは対応できていなかった範囲です。インライン要素とブロック要素が混在していても、指定した行数のみ表示され、残りは省略されます。

ブロック要素が含まれる場合 省略中のキャプチャ

展開したところ。

ブロック要素が含まれる場合 展開中のキャプチャ

float した要素が含まれる場合

float した要素は float したままで、指定行より後が省略されます。float の左右方向は問いません。

float した要素が含まれる場合 省略中のキャプチャ

展開したところ。

float した要素が含まれる場合 展開中のキャプチャ

画像のみ含まれる場合

テキスト内に画像が含まれていても問題ありません。ここでは1行指定しています。

画像のみ含まれる場合 省略中のキャプチャ

展開したところ。

画像のみ含まれる場合 展開中のキャプチャ

inline-block な要素が含まれる場合

text-overflow プロパティを使用した場合、省略対象の要素はすべてインライン要素である必要がありますが、Eripusisu を使うと inline-block な要素が含まれていても省略表示ができます。使える領域を最大限に使うように表示文字数を決定します。

なお、inline-block な要素の外側に省略文字「…」を表示することには未対応です。

inline-block な要素が含まれる場合 省略中のキャプチャ

展開したところ。

inline-block な要素が含まれる場合 展開中のキャプチャ

RTL 言語の場合

アラビア語などの RTL 書字方向をもつ言語にも対応しています。

RTL 言語の場合 省略中のキャプチャ

展開したところ。

RTL 言語の場合 展開中のキャプチャ

インストール

script 要素で読み込む

<script src="https://unpkg.com/eripusisu@1.1.2/dist/eripusisu.umd.js"></script>

npm パッケージを利用する

npm install --save Eripusisu
var Eripusisu = require("eripusisu");

使いかた

次のような HTML を想定して解説しています。

<div class="container">
  <!-- 任意の省略対象の要素(群) -->
</div>
<button class="button">開閉</button>

<div class="container">
  <!-- 任意の省略対象の要素(群) -->
</div>
<button class="button">開閉</button>

:
:

シンプルな省略表示

省略表示をしたいコンテンツを含むコンテナー要素を取得し、Eripusisu コンストラクタ―の第1引数に渡します。第2引数には省略表示にする行数を指定します。

// 省略表示をしたいコンテンツを含むコンテナー要素を取得する
var container = document.querySelector(".container");

// Eripusisu を実行する(3行で省略)
new Eripusisu(container, 3);

クラス名から複数のコンテナーを省略表示

// 省略表示をしたいコンテンツを含むコンテナー要素を取得する
var containers = document.querySelectorAll(".container");

// ループを利用して Eripusisu を実行する
for (var i = 0; i < containers.length; i += 1) {
  new Eripusisu(containers[i], 3);
}

開閉ボタン

第3引数の toggleButton プロパティに要素を渡すことで開閉ボタンが動作します。

// 省略表示をしたいコンテンツを含むコンテナー要素を取得する
var container = document.querySelector(".container");

// ボタン要素を取得する
var button = document.querySelector(".button");

// Eripusisu を実行する
new Eripusisu(container, 3, { toggleButton: button });

幅の変化に追随させる

設計上、幅の変化には自動的に追随しません。必要があれば、resize イベントをハンドリングするなどして refresh() メソッドを呼び出します。

var eripusisu = new Eripusisu(container, 3);

window.addEventListener("resize", function () {
  eripusisu.refresh();
})

コンストラクタ、メソッド、イベントの定義

README をご覧ください。

サポートブラウザ

IE 11 以降のモダンブラウザに対応しています。

アクセシビリティへの配慮

大したことではありませんが、開閉をトグルするボタンに WAI-ARIA の属性を付与しています。スクリーンリーダー利用時には、開閉の状態が読み上げられるようになっています。

ときどき、大きなコンテンツを overflow プロパティを利用して視覚的にだけ隠している場合があります。このパターンをスクリーンリーダー等でアクセスすると、内容をすべて読み上げることになり、得られる情報に差が生まれるばかりか、場合によっては非常に使いにくいことがあります。Eripusisu ではあふれた部分は DOM から消えるため、情報の差異はなくなります。もこれも広義にはアクセシビリティへの配慮に含まれるかもしれません。

実行パフォーマンスについて

コンテンツが指定行内に収まるかどうかの判定はとても難しく、ブラウザに描画させた結果に対して行をまたぐかどうか判定する必要があります。テキスト長を変えながら繰り返し判定処理を行うため、処理は重くなりがちです。

できる限り軽量に動かすため、いくつかの対策をしています。

高速化の余地はまだあるかもしれません。お心当たりがあればぜひコントリビューションを。

コントリビューション歓迎

ぜひ使ってみて、使い心地をフィードバックください。GitHub プロジェクトへの issue, pull request 等も大歓迎です。