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時にボックス表示させてあげたりとかの方が良さそう。

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

|   

marginとline-heightによる"真の余白"について考える

まだまだWeb制作においては、デザイナーがデザインしたものをコーダーがコーディングする、というような流れが多いように思う。

デザイナーは1pxにもこだわる人たちなので、コーダーもそれに応えるように、きちんとデザイン通りに表現する。ようにがんばっている。

「ここは20px、ここは40px、ここは60px」というような具合に、余白の指示書などがあるとありがたい。デザイナーによっては、余白がそれぞれバラバラだったりして、なかなか骨が折れることもあるので…。

例えば、「見出しの下の余白を20px空けたい」という指示があったとする。margin-bottom: 20px;でOKだけど、実はそれ、下の文章のline-heightなどによっては、きちんと20px空いてなかったりすることもある。

以下の例で考える。

:root {
    font-family: meiryo;
    font-size: 10px;
}

h1 {
    font-size: 3rem;
    line-height: 1;
    margin: 0;
}

p {
    font-size: 1.5rem;
    line-height: 1.8;
    margin: 0;
}
<body>
    <h1>margin調整について</h1>
    <p>margin調整について書きます。<br>margin調整について書きます。<br>margin調整について書きます。</p>
</body>

これの結果が以下。

margin調整について1

これのh1の下に20pxの余白を空けるため、margin-bottom: 20px;と入れてみる。で、Chromeのインスペクタで要素を確認してみる。と、若干20pxより余白が大きいように見える。

margin調整について2

そう、これは兄弟要素であるpline-height: 1.8;分の余白が追加されているためである…。

margin調整について3

じゃあ実際にそのline-height分の余白を20pxから引いてあげればいいよね!つまり、20pxから6px引いた、14pxをh1margin-bottomにしてあげればOK!

でも、それらをいちいち計算するのも面倒…。そこで、みんな大好きcalc()関数ですよ。

h1 {
    margin-bottom: calc(20px - (((1.5rem * 1.8) - 1.5rem) / 2));
}

1.5rem(今回の場合は15px)のline-height: 1.8;なので1.8倍で27pxがp要素の行の高さ。そこから自身のテキスト分1.5remを引いてあげた12px分が、均等に上下に割り振られているから、2で割った6pxがテキストの上の部分の余白になる。これを20pxから引いた数字(つまり14px)をh1margin-bottomに指定してあげれば、余白をぴったり20pxにできるという計算。

margin調整について4

margin調整について5

ね。

ただ今度は、それぞれフォントサイズや行の高さに合わせて数値を一つ一つ変えるのは面倒臭い!って思いますよね?そこで、みんな大好きSassですよ。SCSS形式で書きます。

$baseMargin: 20px;
$pFontSize: 1.5rem;
$pLineHeight: 1.8;
@mixin marginBottom($baseMargin: 20px, $pFontSize: 1.5rem, $pLineHeight: 1.8) {
    margin-bottom: calc(#{$baseMargin} - (((#{$pFontSize} * #{$pLineHeight}) - #{$pFontSize}) / 2));
}

h1 {
    @include marginBottom;
}

p {
    font-size: $pFontSize;
    line-height: $pLineHeight;
}

こうやって@mixinしてやれば初期値とかも指定できるし便利。h2の時は下の余白は40pxにしたい!しかも、次の要素の行の高さは2.2だった!なんてときも大丈夫。

$baseMargin: 20px;
$pFontSize: 1.5rem;
$pLineHeight: 1.8;
@mixin marginBottom($baseMargin: 20px, $pFontSize: 1.5rem, $pLineHeight: 1.8) {
    margin-bottom: calc(#{$baseMargin} - (((#{$pFontSize} * #{$pLineHeight}) - #{$pFontSize}) / 2));
}

h1 {
    @include marginBottom;
}

h2 {
    @include marginBottom($baseMargin: 40px, $pLineHeight: 2.2);
}

p {
    font-size: $pFontSize;
    line-height: $pLineHeight;
}

コンパイル結果。

h1 {
  margin-bottom: calc(20px - (((1.5rem * 1.8) - 1.5rem) / 2)); }

h2 {
  margin-bottom: calc(40px - (((1.5rem * 2.2) - 1.5rem) / 2)); }

p {
  font-size: 1.5rem;
  line-height: 1.8; }

何も考えずにmargin-bottom: 20px;とやったときの余白の差はこんな感じ。

margin調整について6

View Demo: margin and line-height adjustment

こうやって、きっちり20pxなら20pxの余白になってた方がいいよね!と、この記事の例を見せながらデザイナーのKくんに聞いたら、「そこまでやってくれると嬉しいけど…(;^ω^)」、後輩のMくんに聞いたら、「わ…(;^ω^)」との感想をいただきました。

|   

スタイルをシンプルなものに変更

スタイルをよりシンプルなものに変更した。1カラムにすることで、よりスッキリした印象を与えるのが狙い。

結構前から、白い背景に黒いテキストのサイトにハマっていて(そのサイトが有益なものなら尚更)、余計なものをとことん省いているストイックさに痺れる。だけど自分がそれをやると何故か味気ないので、なんとかフォントや色味や配置やホワイトスペースを駆使して”Design”に昇華させたいのだけど、それが難しい…。

とりあえず以前のスタイルはDocumentsページにぶち込んだ。その作業をしている途中で、さらに以前のスタイルを見つけて懐かしんでいた。やっぱり何かを残すっていうのは後で振り返るときに良い。そしてそれを発見しやすい・残りやすいのがWebの良いところだと思う。

ところで、以前からトップページがクソ重かったのだけど、多分広告のせいだと思うので、1つだけの表示にした。別に広告で稼いでいるわけではないのだけど、表示していると「ぽい」ので。収益は1年経っても1,000円行ってないし(´;ω;`)

なるべくCMSの恩恵を受けられるように、何かを変えたら全部が変わるように、またPHPをちょこちょこ弄った。今さっきの1記事目のみ広告表示とか、個別ページ(ディレクトリ)の子ページは個別に書いたHTML(DOCTYPEから)を適用させるとかとか。一応例を書いてみる。

if (is_page('about') or is_page('documents') or is_page('link')) {
    // headerとかfooterとか予め用意してあるテンプレを読み込む
} else {
    // 1から書けるように、headerとかfooterなどを読み込まない
    // Web(WordPress)上から編集できるように
    if ( have_posts() ) :
    while ( have_posts() ) : the_post();
    the_content();
    endwhile;
    endif;
}

何の事は無い、このサイトにはAbout、Documents、Linkの個別ページがあるので、それ以外を個別にHTMLが書けるようにしただけ。これ、親である個別ページが膨大になってきたらどうするんだろうね。or連発するのだろうか…。もっとスマートなやり方があるだろうけど、ひとまずこれで。

○記事目で条件分岐させるやり方は、「投稿記事の○件目」で条件分岐させるWordPress カスタマイズまとめを参考にした。

他にも次ページ・前ページの部分とか、検索結果ページとか、カテゴリインデックスページとか、修正したいところがいくつかあるのだけど、ちょっともう今日は体力の限界なので、これから少しずつこっそり修正していこうと思う。仕事でもさんざんやってるのに、プライベートでも2~3日徹夜とか、ホントWeb制作って楽しいなぁ。