ブラウザーがCSSセレクターを右から左に一致させるのはなぜですか?


560

CSSセレクターは、ブラウザーエンジンによって右から左にマッチングされます。したがって、まず子供を見つけ、次に親をチェックして、ルールの残りの部分と一致するかどうかを確認します。

  1. どうしてこれなの?
  2. それは仕様が言っているからというだけですか?
  3. 左から右に評価した場合、最終的なレイアウトに影響しますか?

私にとって最も簡単な方法は、要素数が最も少ないセレクターを使用することです。したがって、最初にIDを使用します(1つの要素のみを返す必要があるため)。次に、おそらくノードまたはノードの数が最も少ないクラスまたは要素です。たとえば、ページにスパンが1つしかない場合があるため、スパンを参照するルールを使用してそのノードに直接移動します。

ここに私の主張を裏付けるいくつかのリンクがあります

  1. http://code.google.com/speed/page-speed/docs/rendering.html
  2. https://developer.mozilla.org/en/Writing_Efficient_CSS

親でなければならない子のすべての親ではなく、親の子(多くの場合)をすべて見る必要がないように、このように行われているようです。DOMが深い場合でも、RTLマッチングでは複数のノードではなく、レベルごとに1つのノードのみを参照します。CSSセレクターLTRまたはRTLを評価する方が簡単/高速ですか?


5
3.いいえ-どのように読んでも、セレクターは常に同じ要素のセットと一致します。
サイムVIDAS

39
それだけの価値があるため、ブラウザはIDが一意であると想定できません。同じid = "foo"をDOM全体に貼り付けることができ、#fooセレクターはそれらすべてのノードに一致する必要があります。jQueryには、$( "#foo")が独自のルールを使用して独自のAPIを定義しているため、常に1つの要素のみを返すというオプションがあります。しかし、ブラウザはCSSを実装する必要があり、CSSはドキュメント内のすべてのものを指定されたIDに一致させると言っています。
Boris Zbarsky、2011

4
@Quentin「非準拠」(HTMLに対して)のドキュメントIDは一意でない可能性があり、それらのドキュメントではCSSはすべての要素をそのIDと一致させる必要があります。CSS自体は、IDが一意であることに対する規範的な要件を課していません。あなたが引用するテキストは有益です。
Boris Zbarsky、2011

5
@Boris Zbarsky jQueryの機能は、jQuery内のコードパスによって異なります。場合によっては、jQueryはNodeSelector API(ネイティブquerySelectorAll)を使用します。他の場合では、シズルが使用されます。Sizzleは複数のIDに一致しませんが、QSAは一致します(AYK)。使用されるパスは、セレクター、コンテキスト、ブラウザーとそのバージョンによって異なります。jQueryのQuery APIは、私が「ネイティブファースト、デュアルアプローチ」と呼んでいるものを使用しています。私はそのことについて記事を書いたが、それはダウンしている。ここにあるかもしれませんが、fortybelow.ca
Garrett

5
だれかさえわかりませんが、あなた方2人は、この長い会話で何が起こっているのかを理解できます。これらの拡張ディスカッションにはチャットがあります。特に情報を明確にする場合は、どうしても残したいものはすべて質問または回答に含める必要があります。Stack Overflowはコメントでの議論をうまく処理しません。
ジョージストッカー2013年

回答:


824

ブラウザーがセレクターマッチングを実行している場合、ブラウザーには1つの要素(スタイルを決定しようとしている要素)とすべてのルールとそのセレクターがあり、どのルールが要素に一致するかを見つける必要があることに注意してください。これは、通常のjQueryとは異なります。たとえば、セレクターが1つしかなく、そのセレクターに一致するすべての要素を見つける必要がある場合です。

セレクターが1つだけで、そのセレクターと比較する要素が1つしかない場合は、左から右の方が意味がある場合があります。しかし、それは明らかにブラウザの状況ではありません。ブラウザはGmailなどをレンダリングしようとしていて、<span>スタイルを設定しようとしているものを持っています。Gmailがスタイルシートに設定している10,000以上のルール(私はその数値を上げていません)。

特に、ブラウザは、問題の要素と一致しないと見なしいるほとんどのセレクタを調べています。したがって、問題は、セレクターができるだけ速く一致しないことを決定することの1つになります。それが一致する場合に少し余分な作業が必要な場合でも、一致しない場合に保存したすべての作業のために、引き続き勝利します。

セレクターの右端の部分を要素と照合することから始める場合は、一致しない可能性があり、完了します。それが一致する場合、より多くの作業を行う必要がありますが、ツリーの深さに比例するだけで、ほとんどの場合それほど大きくありません。

一方、セレクターの左端の部分を一致させることから始める場合、何と一致しますか?DOMを調べ、それに一致する可能性のあるノードを探す必要があります。左端の部分に一致するものが何もないことに気づくだけで、しばらく時間がかかる場合があります。

したがって、ブラウザーは右から一致します。これは明らかな出発点を提供し、ほとんどの候補セレクターを非常に迅速に取り除くことができます。一部のデータはhttp://groups.google.com/group/mozilla.dev.tech.layout/browse_thread/thread/b185e455a0b3562a/7db34de545c17665(表記はわかりにくいですが)で確認できますが、特にGmailの場合の結果がわかります2年前、(ルール、エレメント)ペアの70%で、ルールの右端のセレクターのタグ/クラス/ IDの部分を調べただけでは、ルールが一致しないと判断できました。Mozillaのページロードパフォーマンステストスイートに対応する数は72%でした。そのため、すべてのルールの2/3をできるだけ早く取り除き、残りの1/3とのみ一致させることを心配する価値があります。

また、確実に一致しないルールに一致させようとすることを回避するために、ブラウザーがすでに行っている他の最適化があることにも注意してください。たとえば、右端のセレクターにIDがあり、そのIDが要素のIDと一致しない場合、Geckoではそのセレクターをその要素とまったく一致させる試みは行われません。試行される「ID付きセレクター」のセット要素のIDのハッシュテーブル検索から取得されます。したがって、これはルールの70%であり、右端のセレクターのタグ/クラス/ IDだけを考慮して、一致しない可能性がかなりあります。


5
小さなボーナスとして、英語でもLTRよりもRTLを読む方が理にかなっています。例:stackoverflow.com/questions/3851635/css-combinator-precedence/...
BoltClock

6
RTLマッチングはコンビネーター全体にのみ適用されることに注意してください。単純なセレクタレベルまではドリルダウンしません。つまり、ブラウザは右端の複合セレクタまたは一連の単純なセレクタを受け取り、それをアトミックに一致させようとします。次に、一致がある場合は、コンビネーターを左方向にたどり、次の複合セレクターまで進み、その位置にある要素をチェックします。ブラウザが複合セレクタRTLの各部分を読み取るという証拠はありません。実際、最後の段落はそれ以外の場合を正確に示しています(idチェックが常に最初に来る)。
BoltClock

5
実際、少なくともGeckoでは、セレクターを一致させるときまでに、タグ名と名前空間が最初に来ます。id(およびtagnameとclassnames)は、セレクターを実際に一致させようとせずにほとんどのルールを排除する事前フィルタリングのステップで考慮されます。
Boris Zbarsky 2012

これ、UAが実行している最適化によって役立つ場合がありますが、上記で説明したGeckoの事前フィルタリング手順には役立ちません。ただし、子孫コンビネーターに使用されるIDとクラスで機能する2番目のフィルター処理ステップがありますが、それが役立つ可能性があります。
Boris Zbarsky 2012

@Benito Ciaro:特異性の問題は言うまでもありません。
BoltClock

33

右から左への解析は、ボトムアップ解析とも呼ばれ、ブラウザにとって実際には効率的です。

以下を検討してください。

#menu ul li a { color: #00f; }

ブラウザのために最初にチェックしa、その後、li、そしてul、その後#menu

これは、ブラウザがページをスキャンしているときに、現在の要素/ノードと、それがスキャンした以前のすべてのノード/要素を調べる必要があるためです。

注目すべきことは、ブラウザーが完全なタグ/ノード取得した瞬間にブラウザーが処理を開始し、スクリプトが見つかった場合を除いてページ全体を待つ必要がないことです。この場合、一時停止してスクリプトの実行が完了してから、進む。

逆の場合は、ブラウザが最初のチェックでスキャンしている要素を見つけたため、効率が悪くなりますが、その後、すべての追加のセレクターについてドキュメントを調べ続ける必要がありました。このため、ブラウザーはHTML全体を持っている必要があり、CSSペイントを開始する前にページ全体をスキャンする必要がある場合があります。

これは、ほとんどのlibがdomを解析する方法とは逆です。そこでdomが構築され、ページ全体をスキャンする必要はありません。最初の要素を見つけて、その中の他の要素を照合するだけです。


20

より具体的なものからそれほど具体的でないものへとカスケードすることができます。また、アプリケーションでの短絡も可能です。より具体的なルールが親ルールが適用されるすべての側面に適用される場合、すべての親ルールは無視されます。親に他のビットがある場合、それらが適用されます。

逆の場合は、親に従ってフォーマットし、子に何か異なるものがあるたびに上書きします。長い目で見れば、これはすでに処理されているルールの項目を無視するよりもはるかに多くの作業です。


11
それは別の問題です。カスケードを行うには、ルールを特異性でソートし、次にそれらを特異性の順序で照合します。しかし、ここでの問題は、特定のルールでセレクタを特定の方法で一致させる理由です。
Boris Zbarsky、2011
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.