HTML
CSS
JavaScript
HTML5
js

[javascript]任意のバイト数で3点リーダー

今回の課題

スクリーンショット 2017-12-18 15.13.46.png
この画像のように幅が決まってる要素の中で大量のテキストが書かれている場合にこれを3行とか4行とかで末尾に「...」と三点リーダーがつくようにしたい。

方法

3行とか4行にするのであればテキストのfont-sizeやらline-heightやらを計算して高さを取得し、
どーのこーのしようと思ったが、文字のバイト数で判断すればいいのではということになった。

コード

HTML

<div>
  <p data="">
    ここにテキストが入る。ここにテキストが入る。ここにテキストが入る。ここにテキストが入る。ここにテキストが入る。
    ここにテキストが入る。ここにテキストが入る。ここにテキストが入る。ここにテキストが入る。ここにテキストが入る。
    ここにテキストが入る。ここにテキストが入る。
  </p>
</div>

CSS

div {
  width: 200px;
  border: 1px solid #333;
  word-break: break-all
}

js

const data = document.querySelector('[data]'); //要素を取得

function getByteLength(str){ // バイトに変換してくれる関数?(ちょっと曖昧)
  str = (str==null)?"":str;
  return encodeURI(str).replace(/%../g, "*").length;
}

const a = getByteLength(data.innerText);

if (a >= 144) { //もし、バイト数が144バイト以上だったら
  data.innerText = data.innerText.substring(0, 47);  // 文字列の取得開始位置と取得終了位置を設定
  data.innerText += "..."; //最後に3点リーダー
}

定数dataで要素を取得し、
data.innerTextでdataの文字列を取得する。
その文字列のバイト数が144以上だったらdata.innerTextで取得してきた文字列の取得開始位置と、終了位置を設定し、最後の1文字を3点リーダーに置き換える。

テキストの要素が複数個ある場合

テキストの要素が複数個ある場合は、上のコードでは一番最初の要素しかならない(はず。。。)
その場合はquerySelectorAllで取得し、forで回せば全部対応できる。

const data = document.querySelectorAll('[data]');

function getByteLength(str){
  str = (str==null)?"":str;
  return encodeURI(str).replace(/%../g, "*").length;
}

for (let i = 0; i < data.length; i += 1) {
  a = getByteLength(data[i].innerText);

  console.log(a);

  if (a >= 144) {
    data[i].innerText = data[i].innerText.substring(0, 47);
    data[i].innerText += "...";
  }
}

まとめ

本当はcssで完結したかったが色々探してみてjsの方が早そうという結果になった。
ちなみに
text-overflow: ellipsis;とline-clamp: 3;の複数行対応のcssのみで完結できるものもあるが、
IEとfirefoxでは使えないらしく断念しました。