【CSS / JavaScript】インラインテーブル要素を、行に対してぴったり配置する。
ruby_enabler2.jsでは、ruby要素を正しくレンダリングしてくれないウェブブラウザに対して、
- ruby要素:インラインテーブル(display:inline-table;)
- 内包するrb, rt, rtc要素:テーブル構成要素(display:table-row;だとかdisplay:table-header-groupだとか)
…というスタイル指定をして、ルビに見えるように表示しています。で、前後の文字列とインラインテーブルとを綺麗に配置するために、インラインテーブルに適切な vertical-align の値を設定したいのだけれど、これが一筋縄ではいきません。
簡単のために、rubyタグたちを使わずに、以下のような例を見てみます。
【CSS】
.test { font-size:25px; line-height:1.5em; }
.itable { display:inline-table; line-height:1em; }
.row { display:table-row; background-color:rgba(255,0,0,0.3); }
.head { display:table-header-group; font-size:50%; text-align:center; line-height:1em; background-color:rgba(0,0,255,0.3); }
【HTML】
.itable { display:inline-table; line-height:1em; }
.row { display:table-row; background-color:rgba(255,0,0,0.3); }
.head { display:table-header-group; font-size:50%; text-align:center; line-height:1em; background-color:rgba(0,0,255,0.3); }
<div class="test">
テスト一<span class="itable">
<span class="row">一一</span>
<span class="head">ルビ</span>
</span>一
</div>
テスト一<span class="itable">
<span class="row">一一</span>
<span class="head">ルビ</span>
</span>一
</div>
これをブラウザで表示させるとこんな感じ。
class="itable" なブロックに vertical-align 値を設定して上下のズレを修正します。いろいろ試してみると "vertical-align:0.95em;" とすれば、行と綺麗に揃います。ちなみにこのスクリーンショットは、Ubuntu + Firefox + Takao Pゴシック という環境での表示。
よし、クラス .itable に vertical-align:0.95em; を指定すればよいのだな…と思いきや、そうすると、
- Win 7 + ( IE11 or Firefox ) + メイリオ の場合は上に 1px〜2px ズレる。
- Win 7 + IE11 + MS ゴシック の場合にも上にズレる。
- Win 7 + Firefox + MS ゴシックのときはきっちり表示される。
- フォントサイズを変えてみると、上手く行ったり行かなかったり。
…という具合で、おそらく原因はフォントデザインの違いや数値の丸め誤差等々だと思うのですが、全く上手くない。
OSやウェブブラウザやフォントの種類・サイズに応じて、vertical-align の値を JavaScript できっちり計算することも可能だとは思うのだけれど、もう面倒くさい。
なので、こんなスクリプトを組んでみる。
- 標的のインラインテーブル要素の vertical-align を 初期値(0px)に設定。
- 標的の直前に line-height:1em; なインラインブロック要素(id="_reference")を挿入。この _reference は、何時でも行にピッタリと嵌って配置されます。
- ページ最上部から _reference までの距離(= _reference のy座標)を取得。
- 取得したら、もう用済みなので _refernce を削除。
- ページ最上部から 標的内の class="row" 要素(=今回、行にピッタリと合わせたい要素)までの距離(y座標)を取得。
- (5) と (3) の差分を取れば、それが 標的の vertical-align の値となりますね。
- その値を標的に設定して終了。
これでどんな閲覧環境でもキッチリ配置できます。
【CSSに追加】
#_reference{ display:inline-block; line-height:1em; }
【HTML】
<div class="test">
テスト一<span class="itable">
<span class="row">一一</span>
<span class="head">ルビ</span>
</span>一
</div>
【JavaScript】:今回はいろいろ決め打ちなので、以下のような感じでよかろう。
テスト一<span class="itable">
<span class="row">一一</span>
<span class="head">ルビ</span>
</span>一
</div>
<script>
var target = document.getElementsByClassName('itable')[0], ref, r_top, t_top ;
target.style.verticalAlign = '0px';//(1)
ref = document.createElement('SPAN');
ref.setAttribute('id','_reference');
ref.innerHTML = '一';
target.parentNode.insertBefore( ref , target );//(2)
r_top = ref.getBoundingClientRect().top + window.pageYOffset;//(3)
target.parentNode.removeChild( ref );//(4)
t_top = target.getElementsByClassName('row')[0].getBoundingClientRect().top + window.pageYOffset;//(5)
va = t_top - r_top + 'px';//(6)
target.style.verticalAlign = va ; //(7)
</script>
var target = document.getElementsByClassName('itable')[0], ref, r_top, t_top ;
target.style.verticalAlign = '0px';//(1)
ref = document.createElement('SPAN');
ref.setAttribute('id','_reference');
ref.innerHTML = '一';
target.parentNode.insertBefore( ref , target );//(2)
r_top = ref.getBoundingClientRect().top + window.pageYOffset;//(3)
target.parentNode.removeChild( ref );//(4)
t_top = target.getElementsByClassName('row')[0].getBoundingClientRect().top + window.pageYOffset;//(5)
va = t_top - r_top + 'px';//(6)
target.style.verticalAlign = va ; //(7)
</script>
ということで。
コメント