每当我给客户和研讨班学生提出下面这个建议时,他们都会非常震惊:
我推荐使用 !important
。
大多数情况下,大家的第一反应是厌恶—— !important
通常是坏消息——不过,“大多数情况”并不等于“所有情况”……
和其他很多事情一样,总会有某些例外情况,在这种情况下遵守规定并不是什么好事,恰恰相反,我们需要破坏规定。
举个例子,英国的限速是 70 英里每小时(很不幸,我们还在使用“英里”)。你的车速不能超过 70,那是不合法的,就这么简单。
但是……如果你的朋友正在后座上飙血,你必须在他失血过多之前到达医院,那就别犹豫了,有多快开多快!
在 90% 的情况下,规则都是好的,我们最好遵守。但是一定有某些场合不属于这 90%。
开发者也不例外。我们必须明白,程序中的各种规则总会有不适用的场景。
随着年龄(或者说时间)的增长,我们会拥有更多知识。我经常告诫出血者不要使用 !important
,但是当初学者们成长起来之后,他们就会意识到这个世界并非非黑即白,这时我们就可以更进一步介绍如何用好这个特性。
不过别着急,在我们介绍例外情况之前,先来研究一下规则本身。
!important
随便使用 !important
是一种极具危险性并且极其愚蠢的行为。使用 !important
来摆脱现有 CSS 毫无疑问是很不明智的。这样做的后果就是越来越多的 !important
。
不要下意识地使用 !important
,不要用 !important
去解决冲突,不要冲动地使用 !important
。
如果你确实遇到了冲突,比如某些已经存在的样式覆盖了新样式,那有很多更加安全的解决方法。
如果需要提高某个 class 的优先级,可以把它和它自己串联起来(比如 .btn.btn{}
)。如果需要提高某个 ID 的优先级,可以用属性选择器重写(比如 [id="header"]{}
)。更多内容可以阅读文章解决冲突的技巧。
大多数情况下,你都不需要使用 !important
。
那什么情况下我们可以用它?
!important
实现不变性我真的非常喜欢不变性。一个东西在创建之后就再也不会发生改变,听起来超棒!如果我们知道某个东西永远保持不变,那写起代码来不就轻松多了吗?我真的超级喜欢不变性!
不过在 CSS 中想实现不变性难度很大,因为 CSS 是基于继承设计的,其中大量应用到可变性。不过有一种特殊的类型能充分利用不变性,并且不会带来任何问题:工具类(utility class)。
工具类是一些非常简单的类,用于解决非常具体、非常明确的问题。比如:
.u-text-center { text-align: center; }
.u-float-left { float: left; }
.u-text-large { font-size: 48px; }
它们都以 u-
开头,告诉开发者它们是做什么用的,并且它们只包含一条样式。
上面这段代码中,所有的声明都不包含 !important
,但是它们真的真的应该这样做。原因如下:
在 HTML 中使用 u-text-center
这样的类时,我们做了一个非常确定、清晰的决定,那就是我们想让一段文字居中显示。毫无疑问是这样的。然而, .u-text-center{}
选择器的优先级相对比较低,因此其他选择器可能会在无意中覆盖它。看看下面的例子:
.sub-content h2 {
...
text-align: left;
}
.u-text-center {
text-align: center;
}
<div class="sub-content">
<h2 class="u-text-center">...</h2>
</div>
不幸的是, .sub-content h2{}
的优先级比 .u-text-center{}
高,所以 h2
最后还是左对齐,虽然我们设置了 text-align:center;
。这里就有问题了, u-text-center
无法让某些内容居中。
简而言之,这就是为什么我们应该在工具样式中使用 !important
。我们希望工具样式是不变的;无论在什么情况下,当我们使用 u-text-center
的时候,一定是想要让文字居中。
给工具类加上 !important
,让它们不可变。
当然了,在一个完美世界中(无论是什么世界),我们可以杜绝 .sub-content h2{}
这样的选择器出现在 CSS 中,但是我们无法避免:
具备适应性和防御性的系统的设计目标并不是完美世界,而是现实世界。在现实世界中,人们就是会写出各种各样的 CSS。使用 !important
实现不变性会避免其他人带来的各种冲突。
我觉得最好再简单介绍一下各种常见的工具类。
如果你使用的不是Tachyons/Basscss/Atomic CSS这样的函数式 CSS(这些完全是另一个话题),那你一定不想在 HTML 中看到大量工具类。
不过,如果我们使用了更加模块化和组件化的 CSS 组织方法(我们确实可能这样做),那大多数类都会是这样的:
.c-carousel {}
.o-media__body {}
.c-nav-primary {}
.c-btn--large {}
它们会有一个作用域(也就是BEM中的一个块),并且被封装起来。这样做的好处是在 HTML 中可以清楚地看出类之间的关系(在函数式 CSS 中这很难——或者说不可能——办到),如下所示:
<blockquote class="o-media c-testimonial">
<img class="o-media__img c-testimonial__photo" ... />
<p class="o-media__body c-testimonial__text">...</p>
</blockquote>
这里我们可以轻松看出两种完全不同的样式。
但!是!假设我们想让某一个 testimonial 有更大的 margin-bottom
,该怎么做?显然并不是所有的 testimonial 都需要它,只有页面中某个特定位置的 testimonial 需要。这种需求需要用一种特殊的实现方式。
这里我们用工具类实现:
<blockquote class="o-media
c-testimonial
u-margin-bottom-large">
我们之所以使用工具类,是因为额外的 margin-bottom
其实和 testimonial 没什么关系;它只和上下文相关,并且只需要用那么几次,所以我们不需要把它写到 testimonial 的 CSS 中。
恰恰相反,如果我们有一种字体更大的 testimonial,那网站上的其他 testimonial 也可能会用到它,那就不能写成工具类了。这并不是一个临时应急用的类,而是属于 testimonial 本身,所以需要把它封装到 BEM 中:
<blockquote class="o-media
c-testimonial c-testimonial--large">
总结一下:
如果这个样式会长期存在,那就正式把它加到 CSS 中。如果只是临时使用或者只是一个特例,那就是用工具类。
工具类可能是我“最不喜欢”的一种类,因为它们和行内样式(inline style)其实差不太多。谨慎使用工具类,只用它实现临时改动或者某些极其特殊的改动。
往期精选文章 |
---|
使用虚拟dom和JavaScript构建完全响应式的UI框架 |
扩展 Vue 组件 |
使用Three.js制作酷炫无比的无穷隧道特效 |
一个治愈JavaScript疲劳的学习计划 |
全栈工程师技能大全 |
WEB前端性能优化常见方法 |
一小时内搭建一个全栈Web应用框架 |
干货:CSS 专业技巧 |
四步实现React页面过渡动画效果 |
让你分分钟理解 JavaScript 闭包 |
小手一抖,资料全有。长按二维码关注京程一灯,阅读更多技术文章和业界动态。