IE8 と Opera 9.5 以降で :active 疑似クラスは親要素に伝搬しない

ものすごく久しぶりに Blog 書いてるなぁ……。書こうと思えば書けたのだが。さて、ここから本題。「IE8 & Opera 9.5 以降」と「Firefox & Safari & Google Chrome & Opera 9.2x」を比較すると、:active 疑似クラスが親要素にも伝搬するか否かがそれぞれ異なっている。

結論からいえば、次の状況になっている。

UA 別 hover/active 疑似クラス親要素伝搬有無一覧
UA :hover :active
Firefox 3.0.8
Firefox 3.5 Beta 4
Safari 3.2.3
Safari 4 Beta
(AppleWebKit/528.18)
Opera 9.27
IE8 ×
Opera 9.52 ×
Opera 9.64 ×
Opera 10.00
(Build 1497)
×

:active 疑似クラスは UA によって挙動が異なっているのがわかる。

対照的に、:hover 疑似クラスはどの UA でも常に親要素へ伝搬している。

この現象は、UA によって :active:hover の伝搬に差異があるという問題につながっている。

テストケース

次の div 要素には、各々に :hover 疑似クラスと :active 疑似クラスが定義されている。各要素は「疑似クラスが割り当てられた」ことを認識すると :before 疑似要素にてその旨を表示するようになっている。

hover
active

考察

この問題はかなり根が深いようで、CSS 2 ではそもそも挙動自体が言及されていなかったようだ。

CSS 2 では次のように記述されている。

CSS doesn't define which elements may be in the above states, or how the states are entered and left. Scripting may change whether elements react to user events or not, and different devices and UAs may have different ways of pointing to, or activating elements.

5.11.3 The dynamic pseudo-classes: :hover, :active, and :focus

CSS 2.1 では強調部分が追記されている。

CSS doesn't define which elements may be in the above states, or how the states are entered and left. Scripting may change whether elements react to user events or not, and different devices and UAs may have different ways of pointing to, or activating elements.

CSS 2.1 doesn't define if the parent of an element that is ':active' or ':hover' is also in that state.

5.11.3 The dynamic pseudo-classes: :hover, :active, and :focus

Selectors Level 3(CSS 3 のセレクタ仕様)にも強調部分のように、CSS 2.1 と同様の表現が存在している。

There may be document language or implementation specific limits on which elements can become :active or acquire :focus.

These pseudo-classes are not mutually exclusive. An element may match several pseudo-classes at the same time.

Selectors doesn't define if the parent of an element that is ':active' or ':hover' is also in that state.

6.6.1. Dynamic pseudo-classes

つまるところ、CSS 2、CSS 2.1、CSS 3 のどれにも :active 及び :hover 疑似要素の挙動が明示されていない。この現状が、各 UA 間で挙動が異なってしまっている原因のひとつだと考えられる。

本サイトのメインナビゲーション(現時点では右上)は、:active 疑似クラスを多用している。つまり、前述してきた UA 間で起こる挙動の差異に巻き込まれてしまう。現に、IE8 & Opera 9.5 以降では意図した通りの挙動を起こさない。該当 UA でメニューボタンを押下してみてほしい。ボタンの一部しか押下の挙動を示さず、レイアウトが崩れてしまっているはずだ。これは a 要素で発生した :active 疑似クラスが、親要素である li 要素に伝搬していないために、li:active が解釈されないために起きている。

Opera 9.5 時代からこの問題は把握していたが、原因の特定までは行っていなかった。ところが IE8 でも同様の挙動をとることが判明し、慌てて調査してみたというわけである。何とも情けない話であるが、有益な情報を得ることができたと思う。

DOM 2 Events の概念に照らしていえば、:active 疑似クラスの挙動は次のようにまとめることもできる。

IE8 & Opera 9.5 以降

active イベントが bubbing しない

Firefox & Safari & Google Chrome & Opera 9.2x

active イベントが bubbing する

IE8 & Opera 9.5 以降の bubbling しない 挙動は、ある意味で非常に直感的でないともいえる。CSS と DOM の仕様は別々に策定されているため、こういった差異が生じるのはわからなくもないが、せめて仕様書には正となる挙動を明示して欲しかった。

こういった「非明示による差異」問題は、他にも細かいところでありそうだ。ただ、細部を意図的に明示しないのは W3C の意図という話をどこかで聞いたことがある。HTML/XHTML も例外ではない。その反動が WHATWG による HTML 5 の細かさに繋がっていたりするらしい、という話もどこかで聞いた。

しかし、この :active の問題は、どうみても不利益しか生まないような気がする。どうして不明瞭な文面にしたのだろう。意図が知りたいなぁ……。

2009-05-16