深入理解CSS选择器优先级的计算 - jerrylsxu
选择器的优先级关系到元素应用哪个样式。在CSS2.1的规范(http://www.w3.org/TR/2009/CR-CSS2-20090908/cascade.html#specificity)中是这样描述的:
- 如果声明来自于“style”属性,而不是带有选择器的规则,则记为 1,否则记为 0 (= a)(HTML元素的style属性也是样式规则,因为这些样式规则没有选择器,因此记为a=1,b=0,c=0,d=0)
- 计算选择器中 ID 属性的个数 (= b)
- 计算选择器中其他属性(类、属性选择器)和伪类的个数 (= c)
- 计算选择器中元素名称和伪元素的个数 (= d)
将四个数字按 a-b-c-d 这样连接起来(位于大数进制的数字系统中),构成选择器的优先级。
在最新的Selector Level 3规范中:
- 计算选择器中 ID 属性的个数 (= a)
- 计算选择器中其他属性(类、属性选择器)和伪类的个数 (= b)
- 计算选择器中元素名称和伪元素的个数 (= c)
- 忽略通用选择器*
问题:
1、选择器的整体优先级如何计算,是像网上说的a*1000+b*100+c*10+d吗?
unsigned CSSSelector::specificity() <span style="color: #0000ff;">const</span><span style="color: #000000;"> { </span><span style="color: #008000;">//</span><span style="color: #008000;"> make sure the result doesn't overflow</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">const</span> unsigned maxValueMask = <span style="color: #800080;">0xffffff</span><span style="color: #000000;">; // 整个选择器的最大值,十进制表示:idMask + classMask + elementMak = <span>16777215</span> </span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">const</span> unsigned idMask = <span style="color: #800080;">0xff0000</span><span style="color: #000000;">; // ID选择器的最大值,十进制表示:(16*16+16)*16^4=<span>16711680</span> </span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">const</span> unsigned classMask = <span style="color: #800080;">0xff00</span><span style="color: #000000;">; // class(伪类、类)选择器的最大值,十进制表示:(16*16+16)*16^2=65280 </span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">const</span> unsigned elementMask = <span style="color: #800080;">0xff</span><span style="color: #000000;">; // 元素选择器的最大值,十进制表示:16*16+16=255 </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (isForPage()) </span><span style="color: #0000ff;">return</span> specificityForPage() &<span style="color: #000000;"> maxValueMask; unsigned total </span>= <span style="color: #800080;">0</span><span style="color: #000000;">; unsigned temp </span>= <span style="color: #800080;">0</span><span style="color: #000000;">; </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">const</span> CSSSelector* selector = <span style="color: #0000ff;">this</span>; selector; selector = selector-><span style="color: #000000;">tagHistory()) { temp </span>= total + selector-><span style="color: #000000;">specificityForOneSelector(); </span><span style="color: #008000;">//</span><span style="color: #008000;"> Clamp each component to its max in the case of overflow.</span> <span style="color: #0000ff;">if</span> ((temp & idMask) idMask)) // 判断是否为ID选择器 total |=<span style="color: #000000;"> idMask; // 保证ID选择器的同类叠加不会超过ID选择器的总最大值,下同 </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> ((temp & classMask) classMask)) total |=<span style="color: #000000;"> classMask; </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> ((temp & elementMask) elementMask)) total |=<span style="color: #000000;"> elementMask; </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> total </span>=<span style="color: #000000;"> temp; } </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> total; } inline unsigned CSSSelector::specificityForOneSelector() </span><span style="color: #0000ff;">const</span><span style="color: #000000;"> { </span><span style="color: #008000;">//</span><span style="color: #008000;"> FIXME: Pseudo-elements and pseudo-classes do not have the same specificity. This function </span><span style="color: #008000;">//</span><span style="color: #008000;"> isn't quite correct.</span> <span style="color: #0000ff;">switch</span><span style="color: #000000;"> (m_match) { </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> Id: </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">0x10000</span><span style="color: #000000;">; // ID选择器权重 </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> PseudoClass: </span><span style="color: #008000;">//</span><span style="color: #008000;"> FIXME: PsuedoAny should base the specificity on the sub-selectors. </span><span style="color: #008000;">//</span><span style="color: #008000;"> See </span><span style="color: #008000; text-decoration: underline;">http://lists.w3.org/Archives/Public/www-style/2010Sep/0530.html</span> <span style="color: #0000ff;">if</span> (pseudoClassType() == PseudoClassNot &&<span style="color: #000000;"> selectorList()) </span><span style="color: #0000ff;">return</span> selectorList()->first()-><span style="color: #000000;">specificityForOneSelector(); FALLTHROUGH; </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> Exact: </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> Class: </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> Set: </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> List: </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> Hyphen: </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> PseudoElement: </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> Contain: </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> Begin: </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> End: </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">0x100</span><span style="color: #000000;">; // class选择器权重 </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> Tag: </span><span style="color: #0000ff;">return</span> (tagQName().localName() != starAtom) ? <span style="color: #800080;">1</span> : <span style="color: #800080;">0</span><span style="color: #000000;">; // 元素选择器权重 </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> Unknown: </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">0</span><span style="color: #000000;">; } ASSERT_NOT_REACHED(); </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">0</span><span style="color: #000000;">; }</span>
时间戳:2012-10-04 19:04:44 (20个月前)作者:commit-queue@webkit.org消息:选择器特殊性类别溢出到高类别
https://bugs.webkit.org/show_bug.cgi?id=98295Patch by Tab Atkins jackalmage@gmail.com> on 2012-10-04
Reviewed by Eric Seidel.这一次添加的补丁是为了对于CSS选择器的特殊性添加溢出策略。
以前我们并不会检测每个类别的特殊性溢出问题。原始的策略是:把每个类别存储为一个字节(2^8=256),然后整体存在一个无符号整型数中。这样的话就会导致256个同一类别的单选择器等于1个高类别的选择器。但是这违反了选择器的特殊性规则,导致样式规则排序问题。
Tests: /fast/selectors/specificity-overflow.html
- css/CSSSelector.cpp:
(WebCore::CSSSelector::specificity):
int32_t nsCSSSelector::CalcWeightWithoutNegations() <span style="color: #0000ff;">const</span><span style="color: #000000;"> { int32_t weight </span>= <span style="color: #800080;">0</span><span style="color: #000000;">; #ifdef MOZ_XUL MOZ_ASSERT(</span>!(IsPseudoElement() &&<span style="color: #000000;"> PseudoType() </span>!= nsCSSPseudoElements::ePseudo_XULTree &&<span style="color: #000000;"> mClassList), </span><span style="color: #800000;">"</span><span style="color: #800000;">If non-XUL-tree pseudo-elements can have class selectors </span><span style="color: #800000;">"</span> <span style="color: #800000;">"</span><span style="color: #800000;">after them, specificity calculation must be updated</span><span style="color: #800000;">"</span><span style="color: #000000;">); </span><span style="color: #0000ff;">#else</span><span style="color: #000000;"> MOZ_ASSERT(</span>!(IsPseudoElement() &&<span style="color: #000000;"> mClassList), </span><span style="color: #800000;">"</span><span style="color: #800000;">If pseudo-elements can have class selectors </span><span style="color: #800000;">"</span> <span style="color: #800000;">"</span><span style="color: #800000;">after them, specificity calculation must be updated</span><span style="color: #800000;">"</span><span style="color: #000000;">); </span><span style="color: #0000ff;">#endif</span><span style="color: #000000;"> MOZ_ASSERT(</span>!(IsPseudoElement() && (mIDList ||<span style="color: #000000;"> mAttrList)), </span><span style="color: #800000;">"</span><span style="color: #800000;">If pseudo-elements can have id or attribute selectors </span><span style="color: #800000;">"</span> <span style="color: #800000;">"</span><span style="color: #800000;">after them, specificity calculation must be updated</span><span style="color: #800000;">"</span><span style="color: #000000;">); </span><span style="color: #0000ff;">if</span> (nullptr !=<span style="color: #000000;"> mCasedTag) { weight </span>+= <span style="color: #800080;">0x000001</span><span style="color: #000000;">; } nsAtomList</span>* list =<span style="color: #000000;"> mIDList; </span><span style="color: #0000ff;">while</span> (nullptr !=<span style="color: #000000;"> list) { weight </span>+= <span style="color: #800080;">0x010000</span><span style="color: #000000;">; list </span>= list-><span style="color: #000000;">mNext; } list </span>=<span style="color: #000000;"> mClassList; #ifdef MOZ_XUL </span><span style="color: #008000;">//</span><span style="color: #008000;"> XUL tree pseudo-elements abuse mClassList to store some private </span><span style="color: #008000;">//</span><span style="color: #008000;"> data; ignore that.</span> <span style="color: #0000ff;">if</span> (PseudoType() ==<span style="color: #000000;"> nsCSSPseudoElements::ePseudo_XULTree) { list </span>=<span style="color: #000000;"> nullptr; } </span><span style="color: #0000ff;">#endif</span> <span style="color: #0000ff;">while</span> (nullptr !=<span style="color: #000000;"> list) { weight </span>+= <span style="color: #800080;">0x000100</span><span style="color: #000000;">; list </span>= list-><span style="color: #000000;">mNext; } </span><span style="color: #008000;">//</span><span style="color: #008000;"> FIXME (bug 561154): This is incorrect for :-moz-any(), which isn't </span><span style="color: #008000;">//</span><span style="color: #008000;"> really a pseudo-class. In order to handle :-moz-any() correctly, </span><span style="color: #008000;">//</span><span style="color: #008000;"> we need to compute specificity after we match, based on which </span><span style="color: #008000;">//</span><span style="color: #008000;"> option we matched with (and thus also need to try the </span><span style="color: #008000;">//</span><span style="color: #008000;"> highest-specificity options first).</span> nsPseudoClassList *plist =<span style="color: #000000;"> mPseudoClassList; </span><span style="color: #0000ff;">while</span> (nullptr !=<span style="color: #000000;"> plist) { weight </span>+= <span style="color: #800080;">0x000100</span><span style="color: #000000;">; plist </span>= plist-><span style="color: #000000;">mNext; } nsAttrSelector</span>* attr =<span style="color: #000000;"> mAttrList; </span><span style="color: #0000ff;">while</span> (nullptr !=<span style="color: #000000;"> attr) { weight </span>+= <span style="color: #800080;">0x000100</span><span style="color: #000000;">; attr </span>= attr-><span style="color: #000000;">mNext; } </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> weight; } int32_t nsCSSSelector::CalcWeight() </span><span style="color: #0000ff;">const</span><span style="color: #000000;"> { </span><span style="color: #008000;">//</span><span style="color: #008000;"> Loop over this selector and all its negations.</span> int32_t weight = <span style="color: #800080;">0</span><span style="color: #000000;">; </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">const</span> nsCSSSelector *n = <span style="color: #0000ff;">this</span>; n; n = n-><span style="color: #000000;">mNegations) { weight </span>+= n-><span style="color: #000000;">CalcWeightWithoutNegations(); } </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> weight; }</span>
test text
在所有浏览器中文字都会应用p {font-size:24px;}。如果把这句去掉的话,就会应用*{font-size:40px;},*包括p。(继承的样式没有优先级)
结论:
1、优先级计算时跨级相加应注意溢出问题;
2、优先级计算不包括inline style和!important;
3、优先级计算只有同一类别才具有可比性(一般也不会有人定义超出255个的同一选择器)。
I am currently using the book CSS Mastery: Advanced Web Standards Solutions.
Chapter 1, page 16 says:
To calculate how specific a rule is, each type of selector is assigned a numeric value. The specificity of a rule is then calculated by adding up the value of each of its selectors. Unfortunately, specificity is not calculated in base 10 but a high, unspecified, base number. This is to ensure that a highly specific selector, such as an ID selector, is never overridden by lots of less specific selectors, such as type selectors.
参考文章:

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

WebDevelovermentReliesonHtml,CSS和JavaScript:1)HTMLStructuresContent,2)CSSStyleSIT和3)JavaScriptAddSstractivity,形成thebasisofmodernWebemodernWebExexperiences。

HTML、CSS和JavaScript在Web開發中的作用分別是:1.HTML定義網頁結構,2.CSS控製網頁樣式,3.JavaScript添加動態行為。它們共同構建了現代網站的框架、美觀和交互性。

HTML的未來趨勢是語義化和Web組件,CSS的未來趨勢是CSS-in-JS和CSSHoudini,JavaScript的未來趨勢是WebAssembly和Serverless。 1.HTML的語義化提高可訪問性和SEO效果,Web組件提升開發效率但需注意瀏覽器兼容性。 2.CSS-in-JS增強樣式管理靈活性但可能增大文件體積,CSSHoudini允許直接操作CSS渲染。 3.WebAssembly優化瀏覽器應用性能但學習曲線陡,Serverless簡化開發但需優化冷啟動問題。

HTML的未來充滿了無限可能。 1)新功能和標準將包括更多的語義化標籤和WebComponents的普及。 2)網頁設計趨勢將繼續向響應式和無障礙設計發展。 3)性能優化將通過響應式圖片加載和延遲加載技術提升用戶體驗。

HTML、CSS和JavaScript在網頁開發中的角色分別是:HTML負責內容結構,CSS負責樣式,JavaScript負責動態行為。 1.HTML通過標籤定義網頁結構和內容,確保語義化。 2.CSS通過選擇器和屬性控製網頁樣式,使其美觀易讀。 3.JavaScript通過腳本控製網頁行為,實現動態和交互功能。

HTML是構建網頁結構的基石。 1.HTML定義內容結構和語義,使用、、等標籤。 2.提供語義化標記,如、、等,提升SEO效果。 3.通過標籤實現用戶交互,需注意表單驗證。 4.使用、等高級元素結合JavaScript實現動態效果。 5.常見錯誤包括標籤未閉合和屬性值未加引號,需使用驗證工具。 6.優化策略包括減少HTTP請求、壓縮HTML、使用語義化標籤等。

HTML的作用是通過標籤和屬性定義網頁的結構和內容。 1.HTML通過到、等標籤組織內容,使其易於閱讀和理解。 2.使用語義化標籤如、等增強可訪問性和SEO。 3.優化HTML代碼可以提高網頁加載速度和用戶體驗。

HTMLISNOTAPROGRAMMENGUAGE; ITISAMARKUMARKUPLAGUAGE.1)htmlStructures andFormatSwebContentusingtags.2)itworkswithcsssforstylingandjavascript for Interactivity,增強WebevebDevelopment。
