
这篇文章就是新手的“CSS优先级急救包”:我们把复杂的权重规则拆成“人话”——行内样式、ID、类、标签的权重怎么比?计算优先级有没有简单公式?哪些情况会让样式“插队”?甚至帮你避开新手最常踩的3个误区。不管你是刚学CSS的小白,还是总被样式冲突搞疯的新手,看完都能快速“拎清”优先级,再也不用瞎调代码,让你的CSS终于“听话”!
你有没有过这种情况?写CSS的时候,明明给按钮加了.color-red的类,结果页面上按钮还是蓝色;或者好不容易把导航栏的样式调对了,刷新一下,footer的文字突然变成了奇怪的大小?我去年帮刚学前端的小夏改博客样式时,她就坐在我旁边拍桌子:“这CSS是不是故意跟我作对?”其实根本不是CSS调皮,是她没搞懂“优先级”——这玩意儿就像CSS里的“排队规则”,你不守规则,样式肯定不听话。今天我把自己踩过的坑、翻烂MDN才搞懂的逻辑,揉成最接地气的话讲给你听,保证你看完之后,再也不用对着CSS文件叹气。
先搞懂:CSS优先级到底是啥?为什么它能管着你的样式?
我刚开始学CSS的时候,也以为“后面写的样式会覆盖前面的”,直到有一次我用#header设置了字体大小为16px,后面又用.header类改成14px,结果页面上header的字体还是16px——我盯着代码看了三分钟,差点把电脑关掉。后来查谷歌开发者文档才明白,优先级是CSS给不同选择器的“权重分”,权重分高的样式会“插队”,不管你写在代码的前面还是后面。就像你去奶茶店买奶茶,VIP客户肯定比普通客户先拿到,不是谁来得晚谁先拿。
那不同选择器的权重分是多少呢?我做了个简化版的表格,你一看就懂:
选择器类型 | 简化权重分 | 例子 |
---|---|---|
行内样式(style属性) | 1000 |
…
|
ID选择器 | 100 | #header |
类/伪类/属性选择器 | 10 | .nav、:hover、[type=”text”] |
标签/伪元素选择器 | 1 | div、p、::before |
你看,行内样式的权重分最高,因为它是直接“贴”在元素上的,就像你对着服务员说“我要加双倍珍珠”,肯定比菜单上的默认选项管用;ID选择器是唯一的,比如#header只能对应页面上一个元素,针对性强,所以权重分第二;类选择器是一群元素的“标签”,比如.nav可以对应所有导航栏的元素,权重分第三;标签选择器是最大的群体,比如div对应所有div元素,权重分最低。
那权重分是怎么用的呢?其实是“累加”的——比如你写了一个选择器div.nav.active,那它的权重分就是“标签(1)+类(10)+类(10)=21”;如果另一个选择器是#header.nav,权重分就是“ID(100)+类(10)=110”,那后者的权重分更高,会覆盖前者的样式。我之前写过一个博客的文章列表样式,用了.post-item a(标签+类,权重分11),后来想给置顶的文章加特殊样式,写了.top-post a(类+标签,权重分11),结果完全没反应——后来我改成.top-post .post-item a(类+类+标签,权重分21),才终于生效。你看,不是谁写在后面谁赢,是权重分高的赢。
还有个小细节要注意:通配符()和继承的样式,权重分是0。比如你写了 { color: gray; },然后给p写了color: black;,那p的颜色是black,因为通配符的权重分是0,比p的权重分(1)低。我之前帮朋友改简历页面的样式,他用设置了margin: 0; padding: 0;,结果所有元素的边距都没了,后来他想给h1加margin-top: 20px;,直接写h1 { margin-top: 20px; }就行,因为h1的权重分比通配符高。
新手最容易踩的3个优先级坑,我踩过2个,你别再犯
我学CSS的前三个月,踩过的坑能绕我家小区三圈,其中有三个坑是新手最常犯的,我帮你列出来,你千万别再跳进去。
我刚开始学的时候,只要遇到样式不生效,第一反应就是加!important——“反正加了这个,肯定能覆盖所有样式”。结果有一次我给.button加了color: red!important,后来想改hover状态的颜色(.button:hover { color: blue; }),不管怎么刷新,hover的时候还是红色。我盯着代码看了半小时,才想起自己加了!important——这玩意儿会跳过所有权重计算,直接变成“最高优先级”,就像你在排队的时候突然喊“我有急事”,虽然能插队,但会打乱整个队伍的秩序。
后来我查MDN才知道,!important的正确用法只有两种:一是覆盖第三方插件的默认样式(比如Bootstrap的.btn类),二是修复某些特殊的继承问题。而且用的时候一定要加备注,比如:
.button {
color: red!important; / 覆盖Bootstrap的.btn默认颜色 /
}
我现在的原则是:能不用!important就不用,实在要用,写完一定要记着删——不然等你后面想改样式的时候,得一个个找!important的位置,比找掉在沙发缝里的遥控器还麻烦。
小夏之前问我:“为什么我给body设置了font-family: ‘微软雅黑’,h1的字体却还是宋体?”其实h1的字体是“继承”自body的,但浏览器默认给h1设置了font-family: serif(宋体)——继承的样式优先级比直接设置的样式低,就像你爸妈给你买了件外套,但你自己又买了一件,肯定穿自己买的。
我教她的解决办法是:如果想让继承的样式生效,可以用inherit关键词。比如:
h1 {
font-family: inherit; / 让h1继承body的字体 */
}
这样h1就会用body的“微软雅黑”,而不是浏览器的默认样式。 你要记住:只有某些样式能继承(比如字体、颜色、行高),而像width、height、border这些样式是不会继承的——我之前想让所有div都继承body的width,结果完全没反应,后来才知道width是“非继承属性”,得自己设置。
我之前帮朋友改电商网站的样式,他给.product-list设置了font-size: 14px,然后给.product-item写了font-size: 16px,结果.product-item的字体还是14px——他急得直拍桌子:“我明明给子元素设置了更大的字体,为什么没用?”我打开开发者工具一看,原来他给.product-list加了!important,所以覆盖了.product-item的样式。其实这个问题的本质是:父元素的样式不会覆盖子元素的样式,除非父元素的样式加了!important。
正常情况下,子元素的样式会覆盖父元素的继承样式——比如你给div设置了color: red,然后给div p设置了color: blue,那p的颜色是blue,因为div p是直接选择p元素的样式,比继承自div的样式优先级高。我再举个例子:如果你给.nav设置了background-color: #f8f8f8,然后给.nav .active设置了background-color: #fff,那.active的背景色是#fff,因为.nav .active是直接选择.active元素的样式,优先级更高。
还有个新手常犯的错误是:用父元素的ID选择器,覆盖子元素的类选择器。比如你给#header设置了color: gray,然后给.header-link设置了color: black,结果.header-link的颜色是gray——因为#header的权重分(100)比.header-link的权重分(10)高,所以覆盖了子元素的样式。我教朋友的解决办法是:给子元素的选择器加更高的权重分,比如写成#header .header-link(ID+类,权重分110),这样就能覆盖#header的样式(权重分100)。
最后再跟你说个小技巧:遇到样式冲突时,打开浏览器的开发者工具(F12)——选中那个不听话的元素,看“Styles”面板,被划掉的样式就是被覆盖的,旁边会显示“被更高优先级的样式覆盖”,你跟着找对应的选择器就行。比如你看到.color-red被划掉了,旁边写着“被#header .color-red覆盖”,那你就知道是#header的权重分更高,要么给.color-red加更高的权重分(比如改成#header .color-red.bold),要么调整选择器的组合。
其实CSS优先级没那么可怕,就是“守规则”——你懂了它的“排队逻辑”,样式就会乖乖听你的话。我帮小夏改完样式的那天,她盯着电脑屏幕笑:“原来不是CSS跟我作对,是我之前没懂它的规矩。”你看,有时候不是技术难,是我们没把“专业术语”翻译成“人话”。
如果你按我讲的办法试了,欢迎回来告诉我效果!比如你之前有个样式总是不生效,现在搞定了,或者你踩过什么奇怪的优先级坑,都可以在评论区留言—— 学CSS的路上,谁不是一边踩坑一边成长呢?
为什么我写的CSS样式没生效,是不是优先级的问题?
大概率是优先级在“搞鬼”。CSS优先级就像“排队规则”,权重分高的样式会“插队”,不管你写在代码前面还是后面。比如你用类选择器(.color-red)设置了红色,但之前用ID选择器(#header)设置了蓝色,ID的权重分(100)比类(10)高,你的类样式就会被覆盖,看起来像“没生效”。还有继承的样式优先级更低,如果子元素自己有直接设置的样式,父元素的继承样式也会“没生效”。
你可以先算选择器的权重分——比如div.nav是标签(1)+类(10)=11分,#header.nav是ID(100)+类(10)=110分,后者权重更高。不确定的话,打开浏览器开发者工具(F12),选中元素看“Styles”面板,被划掉的样式就是被覆盖的,旁边会提示原因,跟着找对应的选择器就行。
行内样式、ID、类、标签这些选择器的优先级怎么比?
有个“简化权重分”的办法很好记:行内样式(写在元素style属性里)权重最高,是1000;然后是ID选择器(比如#header),100分;接下来是类、伪类或属性选择器(比如.nav、:hover),10分;最后是标签或伪元素选择器(比如div、::before),1分。
优先级是累加的——比如div.nav.active是1+10+10=21分,#header.nav是100+10=110分,后者权重更高,会覆盖前者。我之前写文章列表样式,用.post-item a(11分)没生效,改成.top-post .post-item a(21分)才管用,就是因为权重分提高了。
我加了!important怎么还是没覆盖原来的样式?
!important能跳过权重计算,但有两种情况会“失效”:一是对方的样式也加了!important,这时候得比权重分——比如你写.button { color: red!important; },对方写#header .button { color: blue!important; },后者权重分更高,还是蓝色;二是你加的位置不对,比如想改hover状态,只给原样式加了!important,hover的样式没加,那hover时还是原样式。
我之前踩过坑:给.button加了color: red!important,后来想改hover为蓝色,写了.button:hover { color: blue; },结果没反应——后来给hover的样式也加了!important才生效。所以用!important时,要注意“对应场景”,别只加在原样式上。
父元素的样式为什么覆盖不了子元素的?
因为父元素的样式大多是“继承”给子元素的,继承的样式优先级特别低(权重分0),子元素自己直接设置的样式优先级更高,所以父元素的样式覆盖不了。比如你给body设置了微软雅黑,h1自己有默认的宋体,那h1还是宋体,因为h1的直接样式优先级比继承的高。
还有一种情况是父元素加了!important,比如#header设置了color: gray!important,子元素.header-link设置了color: black,这时候父元素的!important会覆盖子元素的样式——因为!important跳过了权重计算。我帮朋友改电商样式时遇到过,后来给子元素的选择器加了更高的权重分(比如#header .header-link),才覆盖了父元素的样式。
遇到样式冲突时,怎么快速找出问题在哪儿?
最有效的办法是用浏览器开发者工具(按F12)。选中“不听话”的元素,看右侧“Styles”面板——被划掉的样式就是被覆盖的,旁边会显示“被更高优先级的样式覆盖”。比如我之前改博客文章列表,用.post-item a没生效,打开工具一看,原来被#main .post-item a覆盖了,后者权重分更高。
这个技巧比“瞎试代码”管用一百倍:比如你看到.color-red被划掉,旁边写着“被#header .color-red覆盖”,就知道是#header的权重分更高,要么给.color-red加更高的权重分(比如改成#header .color-red.bold),要么调整选择器组合。新手一定要学会用开发者工具,能省很多时间。