text-overflow: ellipsis;された時に元のテキストをどう表示させるか

text-overflow: ellipsisのためにtitle属性を仕込むのもバカバカしい。またそういった定義がある要素のクラス名を決め打ちで動的に仕込んでいくのもまたバカバカしい。

CSSの定義からHTMLの要素を取得するために – Weblog – Hail2u.net

上記の記事を読んで、面白そうだから自分で書いてみた。ユーザー的には、ellipsisで省略されたテキストがツールチップとかで表示されると結構便利かもね!実際にはどうやって書くんだろう?という興味。

以下HTMLとCSSのサンプル。

<ul class="ellipsis">
  <li>吾輩は猫である。名前はまだ無い。</li>
  <li>ほげほげほげほげほげ</li>
  <li>ふが</li>
  <li>ぴよぴよぴよぴよぴよぴよぴよぴよぴよぴよぴよぴよぴよ</li>
  <li>ほげら</li>
</ul>
.ellipsis {
  width: 5em;
}

.ellipsis li {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

これでli要素のテキストが5emを超えると、超えた分は省略されて三点リーダーになる。超えた時はtitle属性で中のテキストをツールチップなどで表示させて、超えてなければそのまま。ただ、超えるか超えないかはその要素の横幅やフォントサイズに依存するので、全部に最初からtitle属性を付けるのも微妙な感じ。しかもテキストだけの横幅って多分取れない。

なのでjQueryで動的に作った文字列の幅を取得してみるの方法パクって、テキストをダミーの要素に入れてそれの横幅を取得するやり方でやってみた。

var checkElm = $("*"),
    elmArray = [],
    i;

for (i = 0; i < checkElm.length; i++) {
  // text-overflow: ellipsis;が当たっている要素を配列に挿入
  if($(checkElm[i]).css("text-overflow") == "ellipsis") {
    elmArray.push(checkElm[i]);
  }
}

// 要素に当たっている横幅を"数値で"取得
var cssSetWidth = parseInt($(elmArray).css("width")),
    strArray = [];

for (i = 0; i < elmArray.length; i++) {
  // text-overflow: ellipsis;が当たっている要素の文字列を取得
  var getStr = $(elmArray[i]).text();

  // ダミーのspan要素に文字列を挿入し、横幅を取得
  $("body").append("<span class='dummy" + [i] + "'>" + getStr + "</span>");
  var strWidth = $(".dummy" + i).width();

  // 文字幅がCSS指定の横幅を超えたら、title属性(値: 取得した文字列)を挿入
  if (strWidth > cssSetWidth) {
    $(elmArray[i]).attr("title", getStr);
  }
  $(".dummy" + i).remove();
}

View Demo: how to behavior when it omission - Demo1

とは言えこれ、全要素取得してそこからtext-overflow: ellipsis;が当たってる要素抽出して文字列取って横幅取って…とかやってたらすごいパフォーマンス落ちそう。

ということで代替案として、hover時にoverflow: hidden;を解除して全文を表示するという方法はどうだろうか。一応言うと@nazomikanの案。

.ellipsis li:hover {
  overflow: visible;
}

View Demo: how to behavior when it omission - Demo2

ただこれだと、さまざまな因果関係によって全部表示されなかったりすることもあるので、position: absolute;で絶対位置で表示させる。さらにそうすると元の要素の高さが失われるので、hover時の兄弟要素のpaddingを若干調整してやる。

.ellipsis li:hover {
  overflow: visible;
  position: absolute;
}

.ellipsis li:hover + * {
  padding-top: 1em;
}

View Demo: how to behavior when it omission - Demo3

元のテキストがすごい長かったりして折り返して表示したい時とか横スクロールバー発生するし、高さが1emじゃないこともあるだろうし、全然汎用的じゃない。ボツ。それこそJSでhover時にボックス表示させてあげたりとかの方が良さそう。

というような感じで遊んでた。考えたりコード書いたりするの楽しかった!結果よく分からないものが生まれた!

←prev