今までtext-overflowで1行の文章に省略する方法やline-clampで複数行の文章に省略する方法を試しましたが、今回はJavaScriptで指定した行数に省略する方法を実装してみました。
サンプルコード
まずHTMLにダミーの文章を用意します。
<p class="omit js-omit">ヘルエスタ王国の第二皇女。文武両道学園主席、真面目で誰にでも優しくかなりの人望がある。王位継承の資格者として日々鍛錬や人とのコミュニケーションを大事にしている。</p> <p class="omit js-omit">ボロボロの小屋で時間を忘れて錬金術の研究に明け暮れている。大人っぽい女性的な体に憧れており、実はその研究をしているとかしていないとか。</p> <p class="omit js-omit">寂れた和風喫茶で働く女の子。店長の趣味でメイド服を着せられている。足下に見え隠れする尻尾が本物かどうかは、触れた人のみぞ知る。満月の夜は何か不思議な事が起きるらしい?</p> <p class="omit js-omit">いぬいどんどんすきになる</p> <p class="omit js-omit">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dapibus consectetur nisi, vel efficitur purus congue sit amet.</p>
.js-omitに対して省略処理を実行する想定です。
次にJavaScriptですが、関数を用意して任意のタイミングで処理を実行する形で実装しました。
// 省略対象のclassを指定
var omit = document.getElementsByClassName('js-omit');
window.onload = function() {
// 元の文章をdata-origintextに退避
omit_init();
// 文章を省略する処理。引数に行数を指定。
omit_sentence(2);
};
/**
* 文字省略の初期設定
*/
function omit_init() {
for (var i = 0; i < omit.length; i++) {
if(omit[i].dataset.origintext === undefined) {
var sentence = omit[i].textContent;
omit[i].dataset.origintext = sentence;
}
}
}
/**
* 文字省略の実行
* @param {number} line - 省略する行数
*/
function omit_sentence(line) {
// 対象の文章を1文字ずつspanで区切る
for (var i = 0; i < omit.length; i++) {
omit[i].innerHTML = divide_sentence(omit[i].dataset.origintext);
}
// 区切った文字の行数(座標)を調べる
for (var i = 0; i < omit.length; i++) {
var s = omit[i].getElementsByTagName('span');
// 省略する位置を調べる
var omitIndex = check_character_row_count(s, line);
// 省略した文章を反映
var sentence = omit[i].dataset.origintext;
if(omitIndex !== undefined) {
sentence = sentence.slice(0, omitIndex) + '…';
}
omit[i].textContent = sentence;
}
}
/**
* 文章を1文字ずつspanで括って返す
* @param {string} text - 分割する文字列
*/
function divide_sentence(text) {
var textArr = text.split('');
var divideText = '';
for (var i = 0; i < textArr.length; i++) {
divideText += '<span>' + textArr[i] + '</span>';
}
divideText += '<span>' + '…' + '</span>';
return divideText;
}
/**
* 省略する位置を調べて返す
* @param {object} text - spanで区切った文字群
* @param {number} line - 省略する行数
*/
function check_character_row_count(text, line) {
var lineCount = 0;
var beforeTop = text[0].getBoundingClientRect().top - 1;
var omitIndex = undefined;
for (var i = 0; i < text.length - 1; i++) { // 文章の最後に確認用の省略文字が入っているので、最後の文字はチェックから除外
var currentTop = text[i].getBoundingClientRect().top;
// 今回の文字の座標が前回の文字の座標より先に進んでいる時
if(currentTop > beforeTop) {
beforeTop = currentTop;
lineCount++;
}
// 調べている文字が省略行数を過ぎた時
if(lineCount > line) {
// 省略の記号を入れるため、文字の幅から切り取り位置の調整
var ellipsisWidth = text[text.length - 1].getBoundingClientRect().width + 1;
var c = 0;
var w = 0;
do {
c++;
w += text[i - c].getBoundingClientRect().width;
} while(w < ellipsisWidth);
omitIndex = i - c;
break;
}
}
return omitIndex;
}
これで文章の2行目で省略されるようになりました。
複数行で省略するデモページ
注意点として、文章内にspanやリンクなどのHTMLタグが無い想定で作成しています。
大まかな処理の流れは以下のようになります。
- 元の文章をdata属性に退避(omit_init())
- 文章を1文字ずつspanタグで囲う(divide_sentence())
- 各文字の位置から省略位置を調べる(check_character_row_count())
- 省略した内容で反映
上記デモではページ読み込み時のみ省略処理を行っていますが、それ以外のタイミングで省略の調整を行いたい場合、省略の初期設定を行う omit_init() と、省略処理を行う omit_sentence() の2つを使います。
例えばリサイズに合わせて省略位置の調整、PCとSPで省略位置を変更したい場合、以下のように記述を追加します。
window.onresize = function() {
if(window.matchMedia('(max-width: 767px)').matches) {
omit_sentence(3);
}
if(window.matchMedia('(min-width: 768px)').matches) {
omit_sentence(2);
}
};
omit_sentence()の引数で省略する行数を指定できます。
リサイズ時に省略位置を調整するデモページ
これでリサイズ毎に省略の調整が行えますが、文章量や省略する要素数によっては処理が重くなってしまいます。
そのため、リサイズ後に1度だけ省略処理を実行されるように調整する、元の文章量を制限するなどの対応を適宜行うようにしてください。
ページ読み込み後に追加された文章を省略したい場合、omit_init()で初期化を行ってからomit_sentence()で省略を行います。
// ボタンクリック時に文章を追加
document.getElementById('add').addEventListener('click', function() {
// 文章追加
document.body.insertAdjacentHTML('beforeend', '<p class="omit js-omit">魔界学校所属の和装鬼娘。いたずら好きで、よく鬼火を飛ばして他人をからかって遊んでいる。こう見えて実は生徒会長。</p>');
// 省略の初期設定
omit_init();
// 省略処理を実行
omit_sentence(2);
}, false);
コメントが承認されるまで時間がかかります。