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

## 擬似要素とは
**まるで要素のように振舞うが、実際には要素ではないもの**のこと。
擬似要素を使うと、本来は 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](https://www.w3.org/TR/CSS22/) において、**擬似クラス、擬似要素はドキュメントソースやドキュメントツリーに現われない**とされている[^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](https://drafts.csswg.org/selectors-3/) に、「擬似要素がドキュメントソースやドキュメントツリーに現われない」とする文が見当たらない[^5]。

さらに、草案段階の [CSS Generated Content Module Level 3](https://www.w3.org/TR/css-content-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](https://www.w3.org/TR/css-content-3/) から登場した解決策だ。この機能は、**音声出力用の代替テキストを`content`プロパティに指定できる**という、非常に強力な機能だ[^8]。ここに空文字列を指定することで、擬似要素の内容が音声出力されることを抑制する、といった動作も行える。

```CSS
.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](https://www.w3.org/TR/CSS22/selector.html#pseudo-elements)
[^3]: [Cascading Style Sheets Level 2 Revision 2 - § 12 Generated content, automatic numbering, and lists](https://www.w3.org/TR/CSS22/generate.html)
[^4]: [Cascading Style Sheets Level 2 Revision 2 - § 12.2 The 'content' property](https://www.w3.org/TR/CSS22/generate.html#content)
[^5]: なお、[動的擬似クラス](https://drafts.csswg.org/selectors-3/#dynamic-pseudos)には記述が存在する。
[^6]: [CSS Generated Content Module Level 3 - § 1.1. Accessibility of Generated Content](https://www.w3.org/TR/css-content-3/)
[^7]: ん？ [CSS Speech Module](https://www.w3.org/TR/css3-speech/) はどうだって？冗談はよせよ、そんなやつはいなかっただろ。
[^8]: [CSS Generated Content Module Level 3 - § 1.2. Alternative Text for Speech](https://www.w3.org/TR/css-content-3/#alt)