置換要素(imgなど)に対する :before, :after疑似要素の指定について

CSSのセレクターのひとつ :before, :after疑似要素では、contentプロパティを組み合わせて要素の内容の前後にコンテントを挿入することができます。

たとえばこんな記述をすることによって、新着であることを分かりやすく表現できます。

.new:before {
  content: "New!";
  color: #e00;
  background: #fff;
}

IE7以前は :before, :after疑似要素に対応していません。

しかし、img要素やobject要素などの置換要素(Replaced element)[1]に指定する場合の動作については、仕様が何度か変わったこともあり、ブラウザによって挙動が異なります。たとえばimg要素にtitle属性を設定してその値を画面表示したい場合、

img:after {
  content: attr(title);
}

と書けば実現できそうですが、ほとんどのブラウザでは表示されず、また仕様的にもその挙動は正しいものとなります。

まず、CSSの仕様を再確認してみます。

CSS2(1998年勧告)の場合

:before, :after 疑似要素は1998年に勧告されたCSS2で追加されたものですが、当初の仕様書にはimg要素に指定する例が載っていました。

The next rule inserts the text of the HTML "alt" attribute before the image. If the image is not displayed, the reader will still see the "alt" text.

IMG:before { content: attr(alt) }

Generated content, automatic numbering, and lists(www.w3.org)

例示の記述をした場合、画像が表示されないときはalt属性値が表示されるようです。

CSS2.1(2011年勧告)の場合

ところが、先のimg要素の記述例はCSS2.1で削除され、h1要素の例に置き換えられてしまいました。代わりに、「12.1 The :before and :after pseudo-elements」にこんな注釈が追加されています。

Note. This specification does not fully define the interaction of :before and :after with replaced elements (such as IMG in HTML). This will be defined in more detail in a future specification.

Generated content, automatic numbering, and lists(www.w3.org)

置換要素については、CSS2.1ではその作用を定義しないという扱いのようです(将来的に定義されるかもしれないという含みを残しつつ)。

CSS3の場合

CSS3はモジュール化が行われていますが、contentプロパティはCSS3 Generated and Replaced Content Module(www.w3.org)で定義されており、現在の最新バージョンである2003年5月14日版は Working Draft(草案)の状態にあります。

置換要素に関する記述は「12. Replaced content」に記述されています。

If the computed value of the part of the 'content' property that ends up being used is a single URI, then the element or pseudo-element is a replaced element. The box model defines different rules for the layout of replaced elements than normal elements. Replaced elements do not have '::before' and '::after' pseudo-elements; the 'content' property in the case of replaced content replaces the entire contents of the element's box.

To insert text around replaced content, '::outside::before' and '::outside::after' may be used.

CSS3 Generated and Replaced Content Module(www.w3.org)

置換要素の場合は::outside疑似要素(www.w3.org)を使えと言うことですね。ただ、主要ブラウザの最新版(Firefox13, Google Chrome19, IE9, Opera12, Safari5.1)はいずれも未対応なので、現段階ではHTML構造を変えるか、JavaScriptで制御するしかなさそうです。

ブラウザの挙動を見る

では、実際のブラウザはどんな挙動をするのか、次のコードでテストしてみました。

<!DOCTYPE html>
<html lang="ja">
<head>
<title>img:afterでcontentを生成してみる</title>
<style>
img:after {
  content: attr(title);
  color: #e00;
  background: #fff;
}
</style>
</head>
<body>
<p><img src="img01.png" alt="画像1" title="画像1のタイトル" /></p>
<p><img src="img02.png" alt="画像2" title="画像2のタイトル" /></p>
</body>
</html>

img要素に対して、:after疑似要素で title属性値を表示するよう指定しています(区別できるよう色も変えています)。またimg要素は2つありますが、 img02.png は意図的に用意しておらず 404 となります。

結果は次の3パターンでした。

  • :after疑似要素で生成した内容は表示されない。(Google Chrome19, IE8~9, Opera11.6以降, Safari5.1)
  • 画像が存在しない場合(img02.png)のみ、:after疑似要素で生成した内容が表示される。(Firefox13)
  • :after疑似要素で生成した内容は表示される。(Opera11.5以前)
オリジナル画像
図1Internet Explorer 9 の表示
オリジナル画像
図2Firefox 13 の表示
オリジナル画像
図3Opera 11.5 の表示

Operaは少し前まで、画像の表示可否に関わらず :before, :after疑似要素の生成内容を表示するというおかしな動作でしたが、2011年12月にリリースされた 11.6 で修正されています。

FirefoxはCSS2の記述 If the image is not displayed, the reader will still see the "alt" text. に従ったものですね。CSS3的にはこの動作は正しくないので[2]、いずれ他のブラウザに合わせられるのではないかと思います。

  • [1]置換要素(Replaced element)の定義は、CSS2.1仕様書の3.1 Definitions(www.w3.org)に書かれています。
  • [2]現段階では草案なので、仕様が変わる可能性もありますが。