jQuery:フィルターについての疑問
jQueryのセレクタを指定するフィルターのfirst-childを使っていた時に、その指定の仕方によって、動作が違った。少しそのフィルターに関して実験してみたので、メモのためにエントリー。
:first-child
この:first-childは例えば「div p:first-child」のように、divの子要素pの中から、最初のpだけを指定するフィルターである。通常はタグやclass名に続けて書いて指定するのだが、「離して書いたらどうなる?」なんて疑問に思ったのがきっかけで、試しに離して指定してみた。
また、全てを指定する「*」を子要素を指定する「parent > child」とあわせて「parent > *」として指定した時、さらに:first-childを指定したらどのような動作をするのか、チェックしてみた。
使用するHTML
今回利用するHTMLは以下の通り
■サンプルHTML
<div class="preview"> <p>階層1 <em>階層2 </em> <em>階層2 <span>階層3 </span> <span>階層3 </span> </em> <em>階層2 </em> </p> <p>階層1 <em>階層2 </em> <em>階層2 <span>階層3 </span> <span>階層3 </span> </em> <em>階層2 </em> </p> <p>階層1 <em>階層2 </em> <em>階層2 <span>階層3 </span> <span>階層3 </span> </em> <em>階層2 </em> </p> </div>
このHTMLにそれぞれ指定をしてみた。その結果か下記の通り。
1:div#test1 :first-child
■スクリプト
$('div#test1 :first-child').css({ backgroundColor:'#ff00ff', color:'#ffffff'} );
■プレビュー
階層1 階層2 階層2 階層3 階層3 階層2
階層1 階層2 階層2 階層3 階層3 階層2
階層1 階層2 階層2 階層3 階層3 階層2
2:div#test2 > *:first-child
■スクリプト
$('div#test2 > *:first-child').css({ backgroundColor:'#ff00ff', color:'#ffffff' });
■プレビュー
階層1 階層2 階層2 階層3 階層3 階層2
階層1 階層2 階層2 階層3 階層3 階層2
階層1 階層2 階層2 階層3 階層3 階層2
3:div#test3 > * :first-child
■スクリプト
$('div#test3 > * :first-child').css({ backgroundColor:'#ff00ff', color:'#ffffff' });
■プレビュー
階層1 階層2 階層2 階層3 階層3 階層2
階層1 階層2 階層2 階層3 階層3 階層2
階層1 階層2 階層2 階層3 階層3 階層2
4:div#test4 > * > *:first-child
■スクリプト
$('div#test4 > * > *:first-child').css({ backgroundColor:'#ff00ff', color:'#ffffff' });
■プレビュー
階層1 階層2 階層2 階層3 階層3 階層2
階層1 階層2 階層2 階層3 階層3 階層2
階層1 階層2 階層2 階層3 階層3 階層2
5:div#test5 > * > * :first-child
■スクリプト
$('div#test5 > * > * :first-child').css({ backgroundColor:'#ff00ff', color:'#ffffff' });
■プレビュー
階層1 階層2 階層2 階層3 階層3 階層2
階層1 階層2 階層2 階層3 階層3 階層2
階層1 階層2 階層2 階層3 階層3 階層2
結果を見ての疑問
1から5までの指定の仕方の違いをみて、1は子要素全ての最初の要素に適応されているのがわかる。最初のpとその中の最初のem、そしてその中の最初のspanにそれぞれ適応されている。
2は「*」がpの指定と同じ動作をしていることがわかる。一階層内側の最初の要素に(divの一つ内側のp)対して適応されているのである。これも理解した。
3をとばして4、これも、「*」がemの指定と同じ動作をして、さらに一階層内側の最初の要素に(divの二階層内側のem)たいして適応されている。
5は、em内部のすべての要素を対象に、その最初の要素に適応していると考えられるのはわかる。問題は3の動作である。じつはこの3の動作、ブラウザによって動作が違うことがわかった(jQuery1.3.2現在)。IE6,IE7,Firefox3,Opera9のブラウザでは、pの一つ内側のemの最初にしか適応されていないのだが、Safari3とChromeではpの一つ内側のemの最初と、emの一つ内側のspanの最初にも適応されているのだ。この違いはなんだろう?
1の動作から推測すると、pに対しての内側の要素全てに対して適応されるはずだと思われるので、Safari3とChromeの動作のほうが正しいのではないかと思う。ところが、IE6,IE7,Firefox3,Opera9ではemに対して:first-childのフィルターを指定したのと同じになっている。うーむ、バグなのかどうなのだろう…
もう少し検証したほうがいいのかな?なんて結果になってしまった。近いうちにまた実験してみようと思う。あ、原因知っている方いましたら教えていただけたら嬉しいです。