久々に発行される Folio Vol.7 ですが、準備期間の余裕を活かし過ぎて(?)やたらめったらコンテンツが多い。いつもは Folio で読むのに一番時間のかかる記事として悪名高い「"いろは"の先のCSS」ですが、今回はテクニック紹介に話題を絞って軽く仕上げました。しかもテーマは「角丸テーブル」を再現する方法……興味ある方、多いんじゃないでしょうか。最後までよろしくお付き合いいただければ幸いです。
Folio Vol.7 のデザインは、編集のししまるさんが完成図を描き、私がそれを Movable Type のテンプレートに落とし込むという手順で作られています。私がコーディングを担当するからには、当然 CSS でレイアウトすることに。結果はご覧の通りで、デフォルト設定の IE などでご覧の方は、角の丸い枠線が多用されていることに気付かれたはず。
私はこれまであまり角丸の枠線を使わずにきました。理由は多々ありますが、根本的に現状の CSS には向かない表現手法だから、というのが大きい。ふつう、角の丸い枠線を実現するには、「角丸テーブル」と呼ばれる手法を用います。
上図をご覧いただければお分かりの通り、角丸テーブルは最低3×3のテーブルと8つの画像(4辺と4角)を必要とします。一方、CSS には重大な制約があることを思い出さねばなりません。
CSS では1つの要素に背景画像は1つしか指定できない。
したがって、角丸テーブルを CSS で再現するためには、要素を8重の入れ子とすればよいわけです。ところが、これが簡単でない。
<div id="a">
<div id="b">
<div id="c">
<div id="d">
<div id="e">
<div id="f">
<div id="g">
<div id="main">
本文
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
#a
{background:#cff url(a.png) repeat-x left top;}
#b
{background:#cff url(b.png) repeat-y right top;}
(中略)
#g
{background:#cff url(g.png) no-repeat right bottom;}
#main
{background:#cff url(main.png) no-repeat left bottom; padding:30px;}
ポイントは、背景画像指定の順番です。まず4辺の背景画像を配置し、続いて4角の画像を重ねます。基本的に、内側にある要素が、描画においては上層に配置されます。したがって、内側の4要素(e,f,g,main)が4角の背景画像を担当します。
他に引っかかりやすいのは背景画像の繰り返しの指定ミスと、配置基準の指定ミス。躓いたら作例をじっくり読み返してください。なお div#main は本文領域ですから、最後にきちんと内側の余白を指定しましょう。そうしないと角を丸めたところに文字が重なってみっともないことになります。
HTML なんかどうでもいい、ということであれば、要素を8重の入れ子にして一件落着なのですが、私はそれでよいとは思いません。過去の連載で繰り返し指摘してきた通り、CSS は HTML に表現されている作者の意図を、きちんと表現するための技術です。
つまり、角丸の枠をつけたい要素が、単なる段落なのであれば、HTML は
<p>角丸の枠をつけたい文章</p>
これで過不足ないわけで、どれだけ屁理屈を付加してみても、8重の入れ子は出てきません。無論、根本的に無理をいっているんだから仕方ないじゃないか、といってしまえば話は簡単で、いつもの結論「諦めなさい」が導かれます(HTML と CSS を正しく使おうとするならば)。でもそれではあんまりですから、もう少し頑張ってみましょう。
多くの背景画像が必要になるのは、現状、Web で使える画像形式がピクセル固定なので、縦横の伸縮に対応するために無理をしていることが原因です。
横方向の伸縮に対応するために上下の辺に repeat-y を指定した背景画像を置かねばならず、縦方向の伸縮に対応するために左右の辺に(以下略)。
そこで、背景画像の繰り返しを用いない手を考えてみましょう。
<div id="a">
<div id="b">
<div id="c">
<div id="main">
本文
</div>
</div>
</div>
</div>
#a
{background:#cff url(a.png) no-repeat left top;}
#b
{background:#cff url(b.png) no-repeat right bottom;}
#c
{background:#cff url(c.png) no-repeat right top;}
#main
{background:#cff url(main.png) no-repeat left bottom padding:30px;}
あらかじめ4辺の繰り返しを見越して長く伸びた画像を用意しておくことで、入れ子が半減します。
4重入れ子でもやっぱり、無理があるといえばあるのですが、例えばこんな解決法が考えられます。
<div class="diary_date">
<dl>
<dt>日付</dt>
<dd>本文</dd>
</dl>
</div>
3重入れ子ですが、じつはこれでも作例2と同じ結果が得られます。右上の画像を dt 要素に、左下の画像を dd 要素に割り振ればよいわけです。全体にまたがる大きな背景画像は div.diary_date と dl 要素の2つあれば足りますから、じつは最低3重の入れ子構造があればよいというわけ。
これ以上、入れ子構造を減らそうとするのはさすがに不可能で、伸縮の自由度を犠牲にする他ありません。
ヒントだけ書きますと、高さを固定すれば背景画像は左右だけあれば足ります。幅を固定すれば、上下だけでいい。背景画像は2つでよいので、2重構造であればよく、リストに対しては簡単に角丸の枠線を実現できるというわけです。あるいは p 要素と div.section でも OK です。
というわけで、縦横の長さを指定すれば、背景画像はひとつで足ります。
<div id="main">
本文
</div>
#main
{width:60px; height:60px; padding:30px; background:#cff url(main.png) no-repeat left top overflow:auto;}
以上、お粗末さまでした。