16
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

before, after 擬似要素の使いどころを改めて考える。

Last updated at Posted at 2018-11-13

擬似要素とは

まるで要素のように振舞うが、実際には要素ではないもののこと。
擬似要素を使うと、本来は 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 が書けるようになっていきたい。

  1. えっ? Holly ハック?overflowプロパティ?ここは魔法学校ではない。それに、その 2 つの解決策は副作用が強いので、使用箇所が限定される。前者に至っては遺物だし。

  2. Cascading Style Sheets Level 2 Revision 2 - § 5.10 Pseudo-elements and pseudo-classes

  3. Cascading Style Sheets Level 2 Revision 2 - § 12 Generated content, automatic numbering, and lists

  4. Cascading Style Sheets Level 2 Revision 2 - § 12.2 The 'content' property

  5. なお、動的擬似クラスには記述が存在する。

  6. CSS Generated Content Module Level 3 - § 1.1. Accessibility of Generated Content

  7. ん? CSS Speech Module はどうだって?冗談はよせよ、そんなやつはいなかっただろ。

  8. CSS Generated Content Module Level 3 - § 1.2. Alternative Text for Speech

16
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?