❝原文地址: https://medium.com/better-programming/10-best-practices-for-improving-your-css-84c69aac66e 作者:Ferenc Almasi ❞
正文从这里开始~
首先,决定是否真的需要使用 CSS 框架。现在,有许多替代轻量级健壮(robust)框架的方法。通常,你不需要使用框架中的所有选择器,所以你的包中会包含死代码(dead code)。
如果你只对按钮使用样式,可以将它们加入到你的 CSS 文件,并去掉其余的样式。另外,你可以通过使用 DevTools 的 coverage 标识未使用的 CSS 规则。
可以在 Chrome 控制面板中搜索 Coverage 来打开它。你可以通过快捷键 Ctrl
+ Shift
+ P
来打开 Chrome 控制面板。打开后,通过点击重新加载(reload)Icon 开始记录。所有表现为红色,则代表未使用。
从上面的例子可以看出,表示有 98% 的 CSS 是未使用的。需要注意的是,事实并非如此,一些 CSS 样式只有在用户在网页上产生交互后才会被应用。移动设备未使用的样式也会标为为使用的字节。所以,在你移除所有这些之前,请你确认在没有任何地方使用它。
考虑在你的项目中使用 CSS 方法。CSS 方法用于在 CSS 文件中建立一致性。它们有助于扩展和维护你的项目。下面是一些我推荐的流行的 CSS 方法。
BEM ——Block、Element、Modifier ——是最流行的 CSS 方法之一。它是以一个命名约定的集合,你可以用它轻松地构建可复用的组件。命名约定遵循以下模式:
.block { ... }
.block__element { ... }
.block--modifier { ... }
.block
: Block 代表组件。它们是独立的实体,本身就有意义。.block_element
: 它们是 .block
的一部分。它们没有独立的意义,必须绑定到块(block)上。.block--modifier
: 它们被用作块或元素上的标志。我们使用它们来改变元素的外观、行为或状态。例如,使用 hidden 标志,我们可以称它为 .block-hidden
。倒三角 CSS 通过在不同的层引入不同的特性来帮你更好地组织你的文件。并且,你越深入,它也将变得越具体。
Object-oriented CSS, 简称 OOCSS,它有两个主要行为准则。这在实践中意味着什么?
/* Instead of */
.box {
width: 250px;
height: 250px;
padding: 10px;
border: 1px solid #CCC;
box-shadow: 1px 2px 5px #CCC;
border-radius: 5px;
}
/* Do */
.box {
width: 250px;
height: 250px;
padding: 10px;
}
.elevated {
border: 1px solid #CCC;
box-shadow: 1px 2px 5px #CCC;
border-radius: 5px;
}
这意味着你需要将视觉效果和结构代码分开定义。这在实践中意味着什么?
/* Instead of */
.box {
width: 250px;
height: 250px;
padding: 10px;
border: 1px solid #CCC;
box-shadow: 1px 2px 5px #CCC;
border-radius: 5px;
}
/* Do */
.box {
width: 250px;
height: 250px;
padding: 10px;
}
.elevated {
border: 1px solid #CCC;
box-shadow: 1px 2px 5px #CCC;
border-radius: 5px;
}
这意味着你不需要任何元素依赖于它的位置。相同的元素应该看起来相同,而不是它们在页面的哪个地方。
/* Instead */
.main span.breadcumb { ... }
/* Do */
.breadcrumb { ... }
安装预处理器会让你在多个方面受益。预处理器是一个可以让你使用在 CSS 中不存在的先进特性的工具。这些可以是循环的变量或函数。
现今,有很多预处理器。最著名的三种可能还是 Sass、Less 和 Stylus。
所以,预处理器是如何帮助你的?
预处理器可以帮你更好地组织样式。它们能把你的文件变成更小的、可复用的片段。文件间可以互相导入,或者稍后单独导入你的应用。
// Import different modules into one SCSS file
@import 'settings';
@import 'tools';
@import 'generic';
@import 'elements';
@import 'objects';
@import 'components';
@import 'trumps';
另一种增加可读性的好方法如果嵌套你的选择器。这是 CSS 缺少的一个简单、强大的功能。
.wrapper {
.sidebar {
&.collapsed {
display: none;
}
.list {
.list-item {
...
&.list-item--active {
...
}
}
}
}
}
层级结构使我们更容易看到不同的元素是如何联系在一起的。
一些非标准的或试验性的特性在 CSS 中需要添加前缀。不同的浏览器会使用不同的前缀,例如:
webkit-
: 基于 WebKit 的浏览器,例如 Chrome、Safari 或者新版本的 Opera。-moz-
: Firefox 火狐。-o-
: 旧版本的 Opera。-ms-
: IE 和 Edge。为了支持所有主流浏览器,我们需要多次定义某些属性:
.gradient {
background: rgb(30,87,153);
background: -moz-linear-gradient(top, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%, rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%);
background: -webkit-linear-gradient(top, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%, rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%);
background: linear-gradient(to bottom, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%, rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#1e5799', endColorstr='#7db9e8', GradientType=0);
}
预处理器可以帮助我们使用 mixin
来解决这个问题,即可以代替硬编码(hard-code)指的函数。
@mixin gradient() {
background: rgb(30,87,153);
background: -moz-linear-gradient(top, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%, rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%);
background: -webkit-linear-gradient(top, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%);
background: linear-gradient(to bottom, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#1e5799', endColorstr='#7db9e8', GradientType=0);
}
.gradient {
@include gradient();
}
而不是一遍又一遍地写相同的代码,你只需要在需要它们的地方写入这个 minxin
。
一个更好的选择是 post-processor。一旦 pre-processor 生成 CSS 后,post-processor 可以运行额外的优化步骤。最流行的 post-processors 之一是 PostCss
。
你可以使用 PostCss
来自动为你的 CSS 打上前缀,所以你不用担心遗漏主流浏览器。它们使用 Can I use 中的值,所以总是最新的。
另外一个很好的 post-processor 是 autoprefixer
。有了 autoprefixer
,当你想要支持最后四个版本时,你就不用在 CSS 文件中写如何厂商前缀了!
const autoprefixer = require('autoprefixer')({
browsers: [
'last 4 versions',
'not ie < 9'
]
});
作为 minxin
的一部分,你还可以选择使用变量,与 linter 结合使用,你可以强制执行设计规则。
// Font definitions
$font-12: 12px;
$font-21: 21px;
// Color definitions
$color-white: #FAFAFA;
$color-black: #212121;
现在,让我们来看看现实中的 CSS。这经常会被忽视。通常,你可以通过简单地使用正确的 HTML 元素来减少你的 CSS 包的大小。假设你有一个标题,其中包含以下规则:
span.heading {
display: block;
font-size: 1.2em;
margin-top: 1em;
margin-bottom: 1em;
}
你使用 span
元素作为标题。你可以重写默认的显示,间距或字体样式。这可以通过使用 h1
、h2
或者 h3
来避免。默认情况下,它们具有你试图使用其他元素实现的样式,你可以直接摆脱这四个不必要的规则。
为了更进一步地减少 CSS 规则的数量,请始终尝试使用速记属性。对于上面的例子,我们可以这样:
.heading {
margin: 1em 0;
}
其他属性(如 padding
、borders
或者 background
)也是如此。
这和前一点(速记属性)是一致的。有时,我们很难发现冗余 CSS 规则,尤其是在两个选择器的重复规则顺序不一致的时候。但是,如果你的类选择器只是一个或两个规则不同,最好将这些规则提取出来,作为一个额外的类选择器来使用,而不是这样:
<style>
.warning {
width: 100%;
height: 50px;
background: yellow;
border-radius: 5px;
}
.elevated-warning {
width: 100%;
height: 50px;
font-size: 150%;
background: yellow;
box-shadow: 1px 2px 5px #CCC;
border-radius: 5px;
}
</style>
<div class="warning">⚠️</div>
<div class="elevated-warning">?</div>
尝试使用类似的方法:
<style>
.warning {
width: 100%;
height: 50px;
background: yellow;
border-radius: 5px;
}
.warning--elevated {
font-size: 150%;
box-shadow: 1px 2px 5px #CCC;
}
</style>
<div class="warning">⚠️</div>
<div class="warning warning--elevated">?</div>
使用复杂的选择器有两个主要的问题。首先,你增加的特性不仅使得后期很难去重写存在的规则,而且增加了浏览器去匹配选择器的时间。
.deeply .nested .selector span {
...
}
浏览器将会先从 span
开始。这将会匹配所有 span
标签,然后接着去找下一个。它将会过滤掉 .selector
类里面的 span
,以此类推。
这不仅很难让机器去解析(parse),而且也很难让人去理解。以下面这个为例:
[type="checkbox"]:checked + [class$="-confirmation"]::after {
...
}
你认为上面这个规则会在什么时候应用?这可以通过创建一个自定义类选择器以及使用 JavaScript 实现切换来简化它。
.confirmation-icon::after {
...
}
现在它看起来舒服多了。如果你仍然觉得需要一个过于复杂的选择器,并且你认为没有其他选择。请在上面写上注释来解释你的方案。
/**
* Creates a confirmation icon after a checkbox is selected.
* Select all labels ending with a class name of "-confirmation"
* that are preceeded by a checked checkbox.
* PS.: There's no other way to get around this, don't try to fix it.
**/
.checkbox:checked + label[class$="-confirmation"]::after {
...
}
这是开发者在写 CSS 的时候最常见的错误之一。虽然,你可能会认为移除轮廓线造成的 highlight 不会有问题,但是实际上,你将使得网站无法访问。通常的做法是将这个规则作为重置添加到你的 CSS 中。
:focus {
outline: none;
}
然而,通过这种方式,只使用键盘导航的用户将不知道他们正在关注你的网站。
如果默认的样式看起来不适合你的品牌,你可以自定义轮廓线。你只需要确保在聚焦元素时有某些提示。
当你需要处理媒体查询(media queries)时,一定要先考虑移动端。将移动端作为首选意味着你首先从移动设备写 CSS 和小屏幕的方法开始。这也被称为渐进式增强(progressive enhancement)。
这确保你可以添加更多额外的规则来满足大屏幕设备的需求,而不是重写现有的 CSS 规则。这可以减少你最终使用的规则数。
你怎么知道你的媒体是不是先写的移动端?如果你的媒体查询使用了 min-width
,则说明你是正确的。
/* Mobile-first media query, everything above 600px will get the below styles */
@media (min-width: 600px) {
/* your CSS rules */
}
/* Non mobile-first media query, everything below 600px will get the below styles */
@media (max-width: 600px) {
/* your CSS rules */
}
最后,压缩你的包来减少它的大小。压缩会删除注释和空白,这样你的包只需要较少的带宽来获取。
如果你还没启用,请在服务器端启用压缩。
另一种更进一步地减少你的 CSS 的大小的好方法是混淆类选择器名。
要实现这一点,你可以根据项目设置提供两个选项:
css-loader
module。gulp-minify-cssnames
插件。