CSSセレクタ優先度の計算を深く理解する

18006 ワード

選択の優先度は、要素がどのスタイルを適用するかに関係します.CSS 2.1の仕様(http://www.w3.org/TR/2009/CR-CSS2-20090908/cascade.html#specificity)では、
  • 宣言が「スタイル」属性であって、セレクタ付きの規則ではなく、0(=a)(HTML要素のスタイル属性もスタイルルールであり、これらのスタイル規則はセレクタがないので、a=1,b=0,c=0,d=0)
  • と記載されている.
  • は、セレクタにおけるID属性の個数(=b)
  • を計算する.
  • は、セレクタにおける他の属性(クラス、属性セレクタ)と疑似種類の個数(=c)
  • を計算する.
  • は、セレクタにおける要素名と疑似要素の個数(=d)を計算する
  • .
    4つの数字をa-b-c-dのように接続し(大数進のデジタルシステムにおいて)、セレクタの優先度を構成する.
     
    最新のSelector Level 3仕様では、 
  • は、セレクタにおけるID属性の個数(=a)
  • を計算する.
  • は、セレクタにおける他の属性(クラス、属性セレクタ)と疑似種類の個数(=b)
  • を計算する.
  • は、セレクタにおける要素名と疑似要素の個数(=c)
  • を計算する.
  • 汎用セレクタ*
  • を無視する.
    3つの数字をa-b-cのように接続し(大数進法のデジタルシステムにおいて)、セレクタの優先度を構成する.style属性計算はcss 2.1仕様を参照してください.
     
    問題:
    1、選択器の全体優先度はどう計算しますか?ネットで言っているa*1000+b*100+c*10+dのようですか?
           いいえ、違います.この答えは明らかに望文生義である.四級(a、b、c、d)の間は簡単な加算関係ではありません.同じレベル(例えば、a対a)の方が比較可能な関係があります.
     
    分析:
    以下はwebkitのwebCoreの優先度計算に関するコードです.
    )
    unsigned CSSSelector::specificity() const
    
    {
    
        // make sure the result doesn't overflow
    
        static const unsigned maxValueMask = 0xffffff; //          ,     :idMask + classMask + elementMak = 16777215
    
        static const unsigned idMask = 0xff0000; // ID       ,     :(16*16+16)*16^4=16711680
    
        static const unsigned classMask = 0xff00; // class(  、 )       ,     :(16*16+16)*16^2=65280
    
        static const unsigned elementMask = 0xff; //          ,     :16*16+16=255
    
    
    
        if (isForPage())
    
            return specificityForPage() & maxValueMask;
    
    
    
        unsigned total = 0;
    
        unsigned temp = 0;
    
    
    
        for (const CSSSelector* selector = this; selector; selector = selector->tagHistory()) {
    
            temp = total + selector->specificityForOneSelector();
    
            // Clamp each component to its max in the case of overflow.
    
            if ((temp & idMask) < (total & idMask)) //      ID   
    
                total |= idMask; //   ID            ID        ,  
    
            else if ((temp & classMask) < (total & classMask))
    
                total |= classMask;
    
            else if ((temp & elementMask) < (total & elementMask))
    
                total |= elementMask;
    
            else
    
                total = temp;
    
        }
    
        return total;
    
    }
    
    
    
    inline unsigned CSSSelector::specificityForOneSelector() const
    
    {
    
        // FIXME: Pseudo-elements and pseudo-classes do not have the same specificity. This function
    
        // isn't quite correct.
    
        switch (m_match) {
    
        case Id:
    
            return 0x10000; // ID     
    
    
    
        case PseudoClass:
    
            // FIXME: PsuedoAny should base the specificity on the sub-selectors.
    
            // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0530.html
    
            if (pseudoClassType() == PseudoClassNot && selectorList())
    
                return selectorList()->first()->specificityForOneSelector();
    
            FALLTHROUGH;
    
        case Exact:
    
        case Class:
    
        case Set:
    
        case List:
    
        case Hyphen:
    
        case PseudoElement:
    
        case Contain:
    
        case Begin:
    
        case End:
    
            return 0x100; // class     
    
    
    
        case Tag:
    
            return (tagQName().localName() != starAtom) ? 1 : 0; //        
    
        case Unknown:
    
            return 0;
    
        }
    
        ASSERT_NOT_REACHED();
    
        return 0;
    
    }
     
          上のコードから分かるように、webkitでは、aレベルセレクタ(「style」属性のスタイルルール)に対して優先演算にはまったく関与していません.bレベル(IDセレクタ)、cレベル(クラスセレクタ)、dレベル(要素セレクタ)については、各ステージごとに最大値(最大数255)があり、それを超えると最大値(最大数)が適用されます.bレベルの最大値は0 xff0000(16711680)であり、重み付けは0 x 1000(65536)であり、数が256を超える時も最大値を使用する.c級、d級は似ています.したがって、下位レベルが一定の数を超えて、高いレベルが上書きされることはありません.一つのセレクタグループ(em:铉a.d div)において、すべてのセレクタの合計は16777215を超えないことを保証している(各クラスのセレクタは最大値を超えないことを保証している).デモ:http://trac.webkit.org/browser/trunk/Source/WebCore/css/CSSSelector.cpp.そうですimpotant、webkitは歩くもう一つの経路(持っています!importentのスタイル規則はないより大きいです!importentのスタイル規則は、同時に!import属性を持っている場合のみ選択の全体優先度を比較します.)全体的には、webkitの中で、!impotant>inline style>ID>class.
          webkitは
    http://jsbin.com/duker/2今回の改訂では、優先度オーバーフローの処理(chromeリリースバージョンが速いので、今年はblinkに変更されました.chromeは特殊性(優先度)計算の基準を守っていると考えられます.
    タイムスタンプ:2012-10-04 19:04:44(
    http://trac.webkit.org/changeset/130444/trunk/Source/WebCore/css/CSSSelector.cpp前)作者:[email protected]メッセージ:
    セレクタの特殊カテゴリが高カテゴリ20ヶ月にオーバーフローしました.
    Patch by Tab Atkins<​https://bugs.webkit.org/show_bug.cgi?id=98295>on 201-10-04 Review by Eric Seiddel.
    今回追加したパッチはCSSセレクタの特殊性にオーバーフローポリシーを追加するためです.
    以前は各カテゴリの特殊性オーバーフロー問題を検出しませんでした.元のポリシーは、各カテゴリを1バイト(2^8=256)に格納し、全体として符号なし整数が存在する.このようにすると256個の同じカテゴリの単一セレクタが1つの高カテゴリのセレクタに等しいという結果になります.しかし、これはセレクタの特別な規則に違反して、スタイル規則の並べ替え問題を引き起こします.
    Tests:/fast/selectors/specifinity-overflow.
  • css/CSSSelector.cpp:
  • (WebCore:CSSSelector::specifinity):
     
     
          mozilaで優先度計算に関するコード(アドレスは
    [email protected](472行-537行):
    int32_t nsCSSSelector::CalcWeightWithoutNegations() const
    
     {
    
       int32_t weight = 0;
    
     
    
     #ifdef MOZ_XUL
    
       MOZ_ASSERT(!(IsPseudoElement() &&
    
                    PseudoType() != nsCSSPseudoElements::ePseudo_XULTree &&
    
                    mClassList),
    
                  "If non-XUL-tree pseudo-elements can have class selectors "
    
                  "after them, specificity calculation must be updated");
    
     #else
    
       MOZ_ASSERT(!(IsPseudoElement() && mClassList),
    
                  "If pseudo-elements can have class selectors "
    
                  "after them, specificity calculation must be updated");
    
     #endif
    
       MOZ_ASSERT(!(IsPseudoElement() && (mIDList || mAttrList)),
    
                  "If pseudo-elements can have id or attribute selectors "
    
                  "after them, specificity calculation must be updated");
    
     
    
       if (nullptr != mCasedTag) {
    
         weight += 0x000001;
    
       }
    
       nsAtomList* list = mIDList;
    
       while (nullptr != list) {
    
         weight += 0x010000;
    
         list = list->mNext;
    
       }
    
       list = mClassList;
    
     #ifdef MOZ_XUL
    
       // XUL tree pseudo-elements abuse mClassList to store some private
    
       // data; ignore that.
    
       if (PseudoType() == nsCSSPseudoElements::ePseudo_XULTree) {
    
         list = nullptr;
    
       }
    
     #endif
    
       while (nullptr != list) {
    
         weight += 0x000100;
    
         list = list->mNext;
    
       }
    
       // FIXME (bug 561154):  This is incorrect for :-moz-any(), which isn't
    
       // really a pseudo-class.  In order to handle :-moz-any() correctly,
    
       // we need to compute specificity after we match, based on which
    
       // option we matched with (and thus also need to try the
    
       // highest-specificity options first).
    
       nsPseudoClassList *plist = mPseudoClassList;
    
       while (nullptr != plist) {
    
         weight += 0x000100;
    
         plist = plist->mNext;
    
       }
    
       nsAttrSelector* attr = mAttrList;
    
       while (nullptr != attr) {
    
         weight += 0x000100;
    
         attr = attr->mNext;
    
       }
    
       return weight;
    
     }
    
     
    
     int32_t nsCSSSelector::CalcWeight() const
    
     {
    
       // Loop over this selector and all its negations.
    
       int32_t weight = 0;
    
       for (const nsCSSSelector *n = this; n; n = n->mNegations) {
    
         weight += n->CalcWeightWithoutNegations();
    
       }
    
       return weight;
    
     }
          webkitと同じで、inline style要素は計算に含まれません.b級(ID)、c級、d級の最大値と最小値もwebkitと一致しています.異なるのは、mozilaでは同じカテゴリのセレクタを最大値で制御するのではなく、直接加算することです.このようにすると、同じレベルのセレクタの数が255よりも高いレベルになる、つまり、結果がオーバーフローするという問題が発生します.また、セレクタグループ全体の優先度計算は、webkitのようなビットと演算によって結果がオーバーフローしないことを保証するため、簡単に加算するだけで、mozilaにオーバーフローが発生する可能性があります.
     
          IEはコードを読めませんので、IEシリーズに対してはデモテストの方法でしか確認できません.すべてのIEシリーズ(q、s)において、表現はすべてmozilaと一致している.最新のIE 11を含む.
     
    注:CSSセレクタにはもう一つの継承性があります.
    <>JS Bin