当文書は、CSS を用いてドロップキャップを実現する手法についての解説です。
皆さんはドロップキャップという言葉を何処かで見聞きした事があるでしょうか? これは印刷物によく使われる手法で、段落の先頭一文字のフォントサイズを大きくして、それを段落の内部へ落ち込ませるように配置するというものです。章などが変わる時、読者の目を先頭段落に向けやすくする効果を持ちます。濫用すると非常にうざくて見苦しいものになってしまいますが、適所にさり気なく使用してやれば文書が少し華やかになり、当然見易くなります。
Web 上での基本的な情報伝達手段は文書です。そして現在最も多く使用されている文書フォーマットが HTML であり、その XML 再定義版である XHTML であるわけです。それらもまた、人が「見る」というものに違いありません。そうするとおのずと「見易さ」が求められてきます。
CSS は、そのようなマークアップ言語に対して「体裁」を与える為に作られた、スタイルシート言語の一種です。現在、最も多く利用されているスタイルシート言語であるでしょう。
CSS を使えば、ドロップキャップが簡単に実現できてしまいます。
ドロップキャップを使って、自分の作った Web サイトにちょっとした彩りと心遣いを添えてみませんか?
当文書は、HTML や XML、CSS の基礎解説書ではありません。最低限、HTML 4.01 と CSS Level2 について言語仕様と実用方法について知識がある人を対象にしています。
これらについて詳しく知りたい方は、参考文献にあるサイトを参考にして下さい。
ここでは、「どうやって実現するか」について簡単に解説します。
実は、CSS Level2 の勧告書に ドロップキャップの実装方法(日本語訳)が実例 & 表示例付きで載っています。
当文書の実装方法も、基本は全く同じです。
ドロップキャップのカギとなるのが、「文字の落ち込み」です。段落中へ埋め込むように文字を配置することは、一見難しそうに思えます。
しかし、img 要素が答えを与えてくれます。
img 要素は、しばしば p 要素の行内置換要素として利用します。ですが、それでは画像が段落から大きくはみ出して、とても見苦しいものになります。
こんな時、あなたならどうしますか?
ひとつの答えとして、そうした img 要素の周りに文字を回り込ませると、歪な配置を綺麗にする事ができます。これは、文字の回り込みと呼ばれたりします。Microsoft Word 等のワープロソフトにも、画像配置指定の一つに回り込みを持っています。
さて、回り込みを実現する CSS プロパティは何だったでしょうか?
それは、float です。
ドロップキャップの対象になっている文字を、今一度思い出してみて下さい。一つの文字の回りに、その他の文字が回りこんでいるように見えませんか?
事実、そうなっています。よって、次のように考えることができます。
画像の代わりに文字へ float を適用すれば、その文字の周囲へ他の文字が回り込む。
もうお分かりでしょう。段落中に文字を落ち込ませるには、float プロパティを使用すればよいのです。
では、何故そうした事が可能なのか、少し突っ込んだ解説をしましょう。
float プロパティは、その名の通り、要素ボックスが浮動するかしないか、また、もし浮動するならば左右どちらなのかを指定します。浮動すると決められたボックスは浮動ボックスと呼ばれ、その親要素が決定する一連の流れに含まれなくなります。すると、浮動ボックスの次から生成される行ボックスは、浮動ボックスの為の空間を作る為に短くされます。要するに、後に続く文字やインライン要素がその浮動ボックスの左もしくは右へ回り込むというわけです。
ドロップキャップについてだけ言うなら、親要素は p です。それが決定する一連の流れとは、即ちテキストの流れになります。
float プロパティには、大きな特徴があります。それは、適用する要素を選ばないことです。つまり、img 要素だろうが p 要素だろうが浮動ボックスにすることができます。float プロパティの解説にはしばしば img 要素が引き合いに出されますが、何も浮動ブロックにできるのは img 要素だけではありません。
それは、擬似要素であろうと変わりません。詳細は後述しますが、p:first-letter に float プロパティを適用すると、先頭一文字だけが浮動ブロックになるのです。これを利用して文字に float プロパティを適用すれば、文字に文字を回り込むのです。
実装例を挙げます。
次のような HTML 断片を大元にして話を進めます。
<h2>見出し要素</h2> <p>ドロップキャップが適用される段落。</p> <p>ドロップキャップが適用されない段落。</p>
次のような条件が付けられたドロップキャップ段落を作ります。
次に、CSS の完成形を載せます。
p { line-height : 1.5; } h2 + p:first-letter { float : left; color : #393; /* 目立たせているだけ */ font-size : 2em; line-height : 1.0; margin : 0 0.1em 0 0; padding : 0.125em 0; } h2 + p + * { clear : left; }
このスタイルをレンダリングすると、次図のようになります。
以下、先の実装例で示した CSS 断片について解説を加えていきます。この文書の中核を成す部分です。
CSS の選択子と擬似要素を利用して、特定の部位にだけドロップキャップ効果を付与します。この場合の条件は「h2 要素直下の p 要素が持つテキストノードの、一番最初の一文字」となります。
「一番最初の一文字」を示すのが first-letter 擬似要素です。これは、次のようなマークアップと等価であるといえます。
<h2>見出し要素</h2> <p><p:first-letter>ド</p:first-letter>ロップキャップが適用される段落。</p> <p>ドロップキャップが適用されない段落。</p>
このことから、first-letter 擬似要素をサポートしていない UA でもドロップキャップを実現するには、次のようにマークアップします。
<h2>見出し要素</h2> <p><span class="first-letter">ド</span>ロップキャップが適用される段落。</p> <p>ドロップキャップが適用されない段落。</p>
勿論、CSS もそれに対応して書き換える必要があります。
ドロップキャップ効果を実現する要です。先頭一文字を浮動ブロックとし、他の行ブロックを回り込ませます。
フォントサイズは、ドロップキャップ実現において重要な要素の一つです。この例では 2em、即ち元の段落のフォントサイズに対して二倍の大きさに設定しています。あまり小さすぎても目立たなく、大きすぎても場所をとるだけなので、大体このくらいが適当でしょう。
この指定は、フォントの高さを揃えドロップキャップを美しく見せるという点で欠かすことができないものです。
親要素である p 要素に、line-height : 1.5;
というスタイルが与えられているとしましょう。継承規則によって、このスタイルは first-letter 擬似要素にも適用されます。
line-height の指定値が数値である場合、子孫要素へ継承されるのは、その数値そのものになります。では、first-letter 擬似要素の行高さを計算してみましょう。
親要素である p 要素のフォントサイズを 1em として、p 要素の line-height 計算値を導いてみましょう。font-size 指定値 × line-height 指定値 = line-height 計算値
という計算式から、p 要素の line-height 計算値は 1em × 1.5 = 1.5em
となります。
次に、first-letter 擬似要素の line-height 計算値を導いてみましょう。前と同様に、first-letter 擬似要素の line-height 計算値は 2em × 1.5 = 3em
となります。
ここで重要になるのがリーディングの概念です。
リーディング・半リーディングという語は、CSS Level2 の仕様書にあります。あまり聞いた事のない語だとは思いますが、ドロップキャップを綺麗に実現するにはどうしても欠かせない概念なので、詳しく解説することにします。
行内ボックスの高さは、その内部に存在するテキストの font-size 値と異なっていてもよいことになっています。例えば font-size : 1em
に対し、line-height : 1.5
という状態も、line-height : 0.5
という状態も許されます。line-height : 0
なんていう値ですら OK なのです。
font-size 計算値よりも line-height 計算値の方が大きい時、レンダリングされる文字の上下にスペースが存在してもよいとされています。この時、font-size 計算値と line-height 計算値との差を リーディング と呼びます。そして、リーディングの半分の値を 半リーディング と呼びます。リーディングは line-height 計算値 - font-size 計算値 = リーディング
という式で示され、先に示した p 要素の場合、リーディングは 1.5em - 1em = 0.5em
となり、半リーディングは 0.5em ÷ 2 = 0.25em
となります。
半リーディング分のスペースはフォントの上下にそれぞれ付与され、行ボックスの高さは line-height 計算値と同じになります。
フォント上方に生成される半リーディングについて考えましょう。先の計算式によれば、p 要素の半リーディングは 0.25em、同じようにして first-letter 擬似要素の半リーディングは (3em - 2em) ÷ 2 = 0.5em
になります。
このままでは、first-letter 擬似要素のフォント上辺が段落内に押し込まれすぎて、歪になってしまいます。
そこで、first-letter 擬似要素の line-height 値を明示的に指定します。それが line-height : 1.0 なのです。これで、行ボックスの高さは font-size と同じ 2em になります。
しかし、このままでは見た目が汚いままです。何故なら、p 要素のフォント上方に生成される半リーディング分のスペースを全く考慮していないからです。次節では、もう少しだけドロップキャップ文字を押し下げる方法について述べます。
このプロパティによって、前述の line-height 計算値だけでは修正しきれない半リーディング分の押し込みを実現します。
先にも述べましたが、first-letter 擬似要素のフォント上方には、p 要素のフォント上方に生成される半リーディング分のスペースが存在せず、このままでは微妙にドロップキャップ文字だけが上にズレているように見えてしまいます。
そこで、first-letter 擬似要素のフォント上方に、p 要素のフォント上方に生成される半リーディング分のスペースと同じ大きさのスペースを作ってやりましょう。
ここで padding の出番です。first-letter 擬似要素が持つべき半リーディングの値を計算して、それを上下 padding 指定値とします。
first-letter 擬似要素の font-size が 2em である為、親要素である p 要素の半分であると考えればよいことになります。先の計算から、半リーディング値は親要素で 0.25em、親要素の 2em = first-letter 擬似要素の 1em
ですから、first-letter 擬似要素での半リーディング値は 0.125em になります。
これを padding に指定してやれば、半リーディング分のスペースを与え、不揃いだった上辺を調整することができるのです。
因みに、これを line-height で実現しようとしても、Mozilla では line-height が効力を持たない為、敢えて padding を用いました。
小技です。文字やフォントによっては、ドロップキャップされた文字と隣接する文字との間が極端に狭い場合があります。このプロパティによって隙間を作ってやり、文字が接触しているように見える事を解消します。
また、親要素からの継承を無効化する目的もあります。
これは、h2 直下の p 要素に適用された float による回り込みの防止措置です。
ドロップキャップの対象となる p 要素が、一行にレンダリングされた場合を考えてみましょう。margin、padding、line-height 指定値等の列方向幅指定値にもよりますが、ドロップキャップ効果を与えられている要素の列方向幅 + その直下に存在する要素の列方向幅 ≤ ドロップキャップ文字の縦幅
という関係が成立してしまう場合、直下に存在する要素の行ボックスがドロップキャップ文字に回り込んでしまう事があります。これは、CSS Level2 の勧告書で次のように記述されているからです(強調筆者)。
通常のフローでは、浮動体は他のボックスと重なることができる。(中略)行内ボックスが浮動体と重なる場合、行内ボックスの内容、背景及び境界は、浮動体の前面でレンダリングされる。ブロックボックスが重なる場合は、ブロックボックスの背景及び境界は、浮動体の背面でレンダリングされ、ボックスが透過的な部分でだけ見える。ブロックボックスの内容は、浮動体の前面でレンダリングされる。
Cascading Style Sheets, Level 2 9.5 浮動体
これを回避する方法は、勿論 clear プロパティで回り込みを解除してやる事です。h2 + p:first-letter
の float 指定値は left なので、clear : left
とすればよいでしょう。
如何でしたか? ドロップキャップ一つとっても、これだけの工夫と理論武装が必要になってきます。
CSS Level2 の勧告書に載っていたドロップキャップの実装例を見て、実際に自分で実装を行ってみてからというもの、どうすればより見た目が美しいドロップキャップを作り上げることができるかを考え続け、試行錯誤を重ねてきました。
そしてようやくある程度納得できるものを実現することができた時には、実装例のコードより格段に行数が増えていました。それはそれで当たり前の事でしたが、当文書で触れたように仕様の詳細を知らないと「何故そうなるのか」が分からないものばかりでした。line-height の奥深い継承規則や半リーディングの概念などは、その最たるものです。
初めに実装ありき。それから不十分な点を試行錯誤で修正し、最終的には理論的考察を得る。その結果が、このドロップキャップ実装です。
例え理論は確固たるものであっても、現実がそれを許すかどうかは定かでないのも考慮に入れなければなりませんでした。line-height の指定値はパーセンテージよりも数値である方が汎用性が高く、継承も良い感じになることを実践的に納得し、半リーディング処理の所では、旧版で line-height だけを利用して親要素である p 要素の半リーディングを含めさせるような実装を施していましたが、それでは Gecko で何故か first-letter 擬似要素の line-height が無視されるという問題に対処できず、表示が意図しないものになっていました。
そして、ようやく今のところのベストなものができた時、思わず「やった」という言葉が口をついて出ました。
この文書が、ドロップキャップの衆知に貢献しますように。
2005-03-26
参考までに、筆者は first-letter 擬似要素を使用して実装を行っている事を述べておきます。当文書も、first-letter 擬似要素を用いた実装についてのものです。
筆者としては、span 要素を用いた「擬似要素の擬似的な」マークアップを推奨しません。
恐らく、span 要素を用いた「擬似要素の擬似的な」マークアップを施したいと思っている方は、IE6 の CSS 実装に愕然としたのではないでしょうか? 何しろこのじゃじゃ馬は、CSS2 のサポートが非常に貧弱なのですから。
IE が比較的性能の良い UA であった時代は、最早過去の話です。現在では非常に優秀なレンダリング能力を持つ Gecko レンダリングエンジン(NGLayout)や Opera といったソフトウェアが存在しています。特に Gecko は、Firefox の登場により一気にユーザ数を伸ばしています。
IE6 は first-letter 擬似要素を実装していません。それは、IE が時代遅れの代物であり、最早 Mozilla や Opera といった最先端の視覚系 UA に追いつく事が困難であるか、Microsoft にそれらを実装する気が無い事を示しているのかもしれません。
しかしながら、このじゃじゃ馬は騎手が尋常ならざらぬ実力と権力を持っているが故に、視覚系 UA シェアの約八割程度を占めているという調査結果もあります。
そこから導き出される結論は、「IE は、実装状況では少数派、使用状況では多数派」という、常識とはかけ離れたアプリケーションであることです。
筆者はこの理由から、「実装状況の多数派」である Mozilla や Opera が実装済みである擬似要素を使用したに過ぎません。
え? それじゃあ逆だって? そんなことはありません。長期的に考えれば、性能の良い方に合わせた方が後々も現在も苦労せずに済むんですから。
筆者はまず、全ての文書に対して span 要素指定を施すのが非常にめんどくさいから first-letter 擬似要素を利用しています。span による方法は全ての文書に対して手を加えなければならないのに対し、first-letter 擬似要素を利用すればファイル一つで済みます。これは、CSS を利用する利点そのものです。一々 span で個別指定などしていたら、それこそ大量の文書があると時間がいくらあっても足りません。Perl か何かで自動書き換えさせるにしても同じです。first-letter 擬似要素は、それを実装していない処理系では無視されるものです。ですからあっても無くても閲覧に支障は無いドロップキャップ効果については、敢えて span による指定を施す必要が全く無いという結論に達しました。
そもそも HTML 等で文法的にもアクセシビリティ的にも適切なマークアップを施された文書が、そうした視覚的な補助無くとも読めないなどということは無い筈です。
もし、貴方が「使用状況の多数派」にも適合するように span 要素を使用した擬似要素の擬似的用法を使うのであれば、その前にそれが利点を持つかどうかをよく考えていただきたいものです。
それをやるな、とは言えません。かといって、それをやれ、とも言えません。
だから、筆者としては「実装状況でも、使用状況でも多数派」という、夢のような条件を満たした UA を欲して止みません。
尤も、当文書に示したテクニックはどちらの場合にも有効です。仮に読者が span を用いた擬似要素の擬似実装を行うとしても、適宜読み替えてもらえればいいでしょう。
当文書を執筆するうえで参考にした文献です。
.blockcode
マークアップに変更