擬似要素とは
まるで要素のように振舞うが、実際には要素ではないもののこと。
擬似要素を使うと、本来は CSS から得られない情報に対する装飾を行える(例. 要素内の最初の文字)。
この記事で扱うbefore
擬似要素とafter
擬似要素は、ある要素内の先頭、末尾にある子要素として振舞う擬似要素だ。また、この記事ではbefore
, after
擬似要素のことを指して擬似要素ということがある。
before
, after
擬似要素が使われる場面
before
, after
擬似要素を使う場面は、以下の2つが主だろうと思う。
HTMLに手を加えずに要素の内容より前、もしくは後に何かを置きたい時
このテクニックはかなり昔から使われていた。
代表的なところでいうと、clearfix
だろうか。clearfix
は、装飾において発生した「とある問題」を解決するための手法だ。clearfix
を行うためには、そのための要素が 1 つ必要になる。
before
, after
擬似要素を使うテクニックが生まれるまでは、汎用的な要素(span
要素、div
要素など)を使いclearfix
を行っていた1。
これは、デザインのために文書構造を汚していることになるため、あまり好ましくない。
そこで、before
, after
擬似要素の出番というわけだ。擬似要素を使うと、文書構造が一切変化しないため、構造とデザインの分離がより完全な形で実現するのだ。
また、before
, after
擬似要素は、とある要素でも活用されている。
それはq
要素だ。q
要素は、その要素の内容が引用したものであることを表す。
最近のブラウザのユーザーエージェントスタイルシートでは、q
要素内の文字列の周りに、自動的に引用符が追加される。これは、before
, after
擬似要素を使い表現されている。
文字をコピペさせたくないとき
before
, after
擬似要素で**content
プロパティを使い表示した文字列は、選択ができない**。
そのため、コピペ禁止の簡易版として機能する。
もし、コピペ禁止だけが目的であれば、user-select
プロパティでも良いだろうと思う。
before
, after
擬似要素の利点
さて、before
, after
擬似要素の使用場面を調べた結果、これらの擬似要素を使う2つの利点が発見できた。
だが、あともう一つ、これらの擬似要素を使う利点がある。
before
, after
擬似要素は、要素のような振る舞いをする。といっても、所詮デザインの一部だ。コンテンツの一部として見られている可能性は低い。
そのため、これらの擬似要素の内容が検索エンジンにインデックスされてしまう可能性を回避できる、らしい。
これはuser-select
プロパティなど、既存の CSS プロパティでは代替できない。
まとめると、before
, after
擬似要素の利点は、以下の3つになる。
- 文書構造が一切変化しないため、構造とデザインの分離がより完全な形で実現する
-
content
プロパティを使い表示した文字列は、選択ができないため、コピペ禁止の簡易版として機能する -
before
,after
擬似要素の内容は、検索エンジンにインデックスされる可能性が低い
良いことづくめだ。
before
, after
擬似要素の欠点
草案段階の仕様で擬似要素の扱いが変化した
擬似要素の利点として挙げられた点として、
-
content
プロパティを使い表示した文字列は、選択ができないため、コピペ禁止の簡易版として機能する -
before
,after
擬似要素の内容は、検索エンジンにインデックスされる可能性が低い
というものがある。
しかし今後、この利点が無くなってしまうかもしれないのだ。
現在の擬似要素の扱い
Cascading Style Sheets Level 2 Revision 2 において、擬似クラス、擬似要素はドキュメントソースやドキュメントツリーに現われないとされている2。
Neither pseudo-elements nor pseudo-classes appear in the document source or document tree.
また、before
, after
擬似要素でcontent
プロパティを用いたときに作成されるコンテンツは、「生成されたコンテンツ」として扱われる3。
In CSS 2.2, content may be generated by two mechanisms:
- The 'content' property, in conjunction with the :before and :after pseudo-elements.
- Elements with a value of 'list-item' for the 'display' property.
そして、「生成されたコンテンツ」は、ドキュメントツリーを一切変更しない4。文字の選択というのは、ドキュメントの一部を選択することだ。そのため、ドキュメントツリーに現われない「生成されたコンテンツ」は選択できない。また、それに倣って、検索エンジンが「生成されたコンテンツ」を解釈しないというのも、まあ妥当な挙動だと思う。
Generated content does not alter the document tree. In particular, it is not fed back to the document language processor (e.g., for reparsing).
来るべき未来の擬似要素の扱い
ところが、この摂理は密かに覆されようとしている。
まず、 Selectors Level 3 に、「擬似要素がドキュメントソースやドキュメントツリーに現われない」とする文が見当たらない5。
さらに、草案段階の CSS Generated Content Module Level 3 によれば、「生成されたコンテンツ」は、検索が行え、選択ができ、支援技術がコンテンツの情報を利用可能であるべきだというのだ6。
Generated content should be searchable, selectable, and available to assistive technologies. The content property applies to speech and generated content must be rendered for speech output.
もし、「生成されたコンテンツ」が選択可能になった場合、当然だが上で挙げた利点のひとつが砕け散る。また、「生成されたコンテンツ」の内容が検索可能で、支援技術が把握できるようになれば、検索エンジンが擬似要素内のコンテンツをインデックスするようになる可能性がある。
これを読んでいる人の中には、「まあ、これ草案段階だし?あと 5 億年くらいは勧告されへんやろ?ヘーキヘーキ!」と思っている人もいるだろう。確かにそうだ。選択可能になるならば、あらかじめ擬似要素にuser-select
プロパティを付与しておけば良い。ただし、そうもいっていられない点が 1 つだけある。
スクリーンリーダーが擬似要素を読み上げる
なんと、アクセシビリティツリーはとっくの昔から、「生成されたコンテンツ」の内容を把握しているのだ。
さて、あなたが書いてきたbefore
, after
擬似要素の内容は、本当にユーザに読まれるべき情報だったのだろうか?
もし、before
, after
擬似要素のcontent
プロパティで記述した文字列が、ユーザに読まれるためではなく、装飾のためだけの文字列で、読み上げられたときにアクセシビリティを阻害するような内容であれば、対処が必要だろう。
考えられる対策は 3 つある。
-
aria-hidden
ステートを付与した汎用的な要素を使う
span
要素のような汎用的な要素に対して、aria-hidden
ステートを指定すれば、その要素内の内容はスクリーンリーダーには読まれない。ただし、検索エンジンが WAI-ARIA にまで注意を払っているかというと微妙なので、インデックスされたくない、装飾目的のほうが強いものの場合、この方法は使わないほうが良いだろう。 -
スクリーンリーダーが認識できない文字を
content
プロパティに指定する
これは暗黒面に半身が突っ込んでしまっている解決策だ。非常に現実的ではないが、とりあえずスクリーンリーダー、検索エンジンのどちらにも配慮はできている。しかし、一部のスクリーンリーダーは自身が読み上げられない文字を「ふぇぇ、なにこれぇ>_<」みたいな感じで読み上げてしまう。また、もしcontent
プロパティに設定した値をユーザが発音辞書に登録していた場合、それが読み上げられてしまうことになる。おまけに、この解決策は使用箇所が限定されすぎている。所詮はブラックな解決策で、不完全なものなのだ7。 -
content
プロパティに代替テキストを指定する
これは、 CSS Generated Content Module Level 3 から登場した解決策だ。この機能は、音声出力用の代替テキストをcontent
プロパティに指定できるという、非常に強力な機能だ8。ここに空文字列を指定することで、擬似要素の内容が音声出力されることを抑制する、といった動作も行える。
.hoge::before {
content: "私は hoge なのだわ" / "私は huga なのだわ";
/* このとき、音声出力は「私は huga なのだわ」が読み上げられることになる */
}
そんなわけで、解決策は上の 3 つか、このまま擬似要素を使い続けるかなのだが、現状は以下の二択となるだろう。
- このまま擬似要素を使う
-
aria-hidden
ステートを付与した汎用的な要素を使う
まとめ
利点
- 文書構造が一切変化しないため、構造とデザインの分離がより完全な形で実現する
-
content
プロパティを使い表示した文字列は、選択ができないため、コピペ禁止の簡易版として機能する -
before
,after
擬似要素の内容は、検索エンジンにインデックスされる可能性が低い
欠点
-
content
プロパティの内容をスクリーンリーダーが読み上げる - まだ大丈夫だけど、
content
プロパティを使い表示した文字列が選択できるようになるかも - まだ大丈夫だろうけど、上の変更に伴って
before
,after
擬似要素の内容が検索エンジンにインデックスされるようになるかも
使いどころ
以下の内容と、利点、欠点を加味して使うかどうかを判断すると良い。もし擬似要素が不適切だと判断できる場合、aria-hidden
ステートを付与した汎用的な要素を使うこともできる。
- それが装飾なのか、文書の一部なのか
- 読み上げ時にアクセシビリティを阻害するのか、しないのか
いずれ代替テキストをcontent
プロパティに指定できるようになるし、そうなればあまり悩まなくても良くなるかもしれない。
おわりに
私たちは、before
, after
擬似要素を当たり前のように使うが、利点ばかりではなく、場合によってはユーザのアクセシビリティを阻害するとわかった。さらに、欠点を突き詰めていく中で、利点が脅かされていたことも判明した。
擬似要素で表現しようとしているものは何か、スクリーンリーダーによって認識されても良いものか、 Web ページを閲覧する人間のことを考慮した CSS が書けるようになっていきたい。
-
えっ? Holly ハック?
overflow
プロパティ?ここは魔法学校ではない。それに、その 2 つの解決策は副作用が強いので、使用箇所が限定される。前者に至っては遺物だし。 ↩ -
Cascading Style Sheets Level 2 Revision 2 - § 5.10 Pseudo-elements and pseudo-classes ↩
-
Cascading Style Sheets Level 2 Revision 2 - § 12 Generated content, automatic numbering, and lists ↩
-
Cascading Style Sheets Level 2 Revision 2 - § 12.2 The 'content' property ↩
-
CSS Generated Content Module Level 3 - § 1.1. Accessibility of Generated Content ↩
-
ん? CSS Speech Module はどうだって?冗談はよせよ、そんなやつはいなかっただろ。 ↩
-
CSS Generated Content Module Level 3 - § 1.2. Alternative Text for Speech ↩