CSS 编码技巧

在软件开发中,保持代码的 DRY 和可维护性是最大的挑战之一。

  • DRY:Don't Repeat Yourself 不要重复你自己

  • 可维护性:尽量减少改动时要编辑的地方

举一个例子:

html
1<button>Yes!</button>
css
1button {
2  padding: 6px 16px;
3  border: 1px solid #446d88;
4  background: #58a linear-gradient(#77a0bb, #58a);
5  border-radius: 4px;
6  box-shadow: 0 1px 5px gray;
7  color: white;
8  text-shadow: 0-1px 1px #335166;
9  font-size: 20px;
10  line-height: 30px;
11}

image-20210907174246793

这是一个 button 按钮,假设我想要修改它的字体大小,得到一个更大的按钮,我可以直接设置 font-size,但是仅仅设置了 font-size 显然不够,比如下面我将其设置为font-size:30px;

image-20210907174543159

这样行高和字号的比例就不正确了。

依赖关系表达

当某些值相互依赖的时候,我们应该把他们的相互关系用代码表达出来

这里的 line-height 和 font-size 是具有相互关系的,比例大概是 1.5 比 1。

所以我们可以这样写

css
1font-size: 30px;
2line-height: 1.5;

line-height 设置成数字或者百分比的时候,会自动根据该元素的字体大小进行计算。

设置 line-height 的推荐写法是设置成数字,不会在继承时产生不确定的结果。 ——MDN

尽量不写绝对值

绝对值写起来非常容易,但是如果要修改时,有可能会非常麻烦。比如在这个按钮上,我们有可能会遇到修改 padding、border-radius 的需求,如果全部用 px 这种绝对值单位书写,那需要修改的地方就非常多。

在 css 中,我们可以用 vw、vh、rem、em、百分比等单位替代绝对值。

css
1button {
2  padding: 0.3em 0.8em; /* 父盒子的 font-size 是16px */
3  border: 1px solid #446d88;
4  background: #58a linear-gradient(#77a0bb, #58a);
5  border-radius: 0.2em;
6  box-shadow: 0 0.05em 0.25em gray;
7  color: white;
8  text-shadow: 0-0.05em 0.05em #335166;
9  font-size: 125%;
10  line-height: 1.5;
11}

现在我们如果想要把按钮放大,那它的所有效果也都跟着放大了。

代码易维护 vs 代码量少

有时候,代码量少和代码易维护不可兼得。假设我们需要给元素添加一道 10px 的边框,但是左边不加边框

css
1border-width: 10px 10px 10px 0;

这样代码只需要一行就可以搞定,但是如果以后需要改成 20px 宽呢?就需要修改 3 个地方。

此时只要分开申明,就可以只修改一个地方,而且可读性更高。

css
1border-width: 10px;
2border-left-width: 0;

currentColor

currentColor 是 css 中第一个变量,它表示当前的标签所继承的文字颜色

举个例子:

css
1button {
2  padding: 0.3em 0.8em;
3  border: 1px solid currentColor; /* 看这里 */
4  color: white; /* 看这里 */
5  background: #58a linear-gradient(#77a0bb, #58a);
6  border-radius: 0.2em;
7  box-shadow: 0 0.05em 0.25em gray;
8  text-shadow: 0-0.05em 0.05em #335166;
9  font-size: 125%;
10  line-height: 1.5;
11}

此时字体的颜色是白色的,边框的颜色会跟着字体的颜色变成白色

image-20210907182820234

如果修改成黑色,那么边框就会变成黑色。

css
1color: black;

image-20210907182909489

currentColor 是很多属性的初始值(比如 border-color),它会自动根据文本颜色来获取到颜色。

inherit 继承

尽管 inherit 很常见,但是我们还是很容易遗忘它。inherit 可以用在任何 css 属性上,它会绑定到父元素的对应值。

举个例子:当我的 a 标签希望颜色跟页面的其他部分(父元素等)相同时,可以考虑使用 inheirt的特性

css
1a {
2  color: inherit;
3}

对于伪元素来说,inherit会取生成该伪元素的宿主元素。

同时,这个 inherit 关键字对于背景颜色和边框等同样有效。

html
1<div>这是一个框</div>
css
1div {
2  position: relative;
3  max-width: 200px;
4  border: 1px solid black;
5}
6div::before {
7  content: '';
8  display: block;
9  width: 0;
10  height: 0;
11  border: 10px solid transparent;
12  border-bottom-color: inherit; /* 看这里 */
13  border-top: none;
14  position: absolute;
15  top: -40%;
16  left: 0.5em;
17}

image-20210907200022678

把媒体查询当做最后的优化手段

响应式网页设计非常重要,但不应过多采用媒体查询,每个媒体查询都会增加成本,这种成本会随着代码的提升,在后期维护时突显出来。

媒体查询不能以一种连续的方式来修复问题,它能做的只是修补某个特定分辨率下的特定问题。

不妨考虑在媒体查询中使用 em 等非绝对单位来取代像素单位。这能让文本缩放在必要时触发布局的变化。

响应式网页设计的建议

下面是响应式网页设计的一些建议,它能够帮助我们避免不必要的媒体查询

  • 使用百分比长度来取代固定长度,或者使用与视口相关的单位(vw、vh、vmin、vmax)等解析视口宽度或高度的百分比

  • 当需要在较大分辨率下得到固定宽度时,使用 max-width 而不是 width,它能适应较小的分辨率。

  • 为替换元素(img、video、iframe 等)设置一个 max-width,值为 100%

  • 背景图片需要完整地平铺一个容器,不管容器的尺寸如何变化,使用 background-size:cover可以做到

  • 当图片或者其他元素以行列式进行布局时,让视口的宽度来决定列的数量,可以用弹性盒子布局(FlexbOX)

  • 在使用多列文本时,指定 column-width(列宽)而不是指定 column-count(列数),这样它可以在较小的屏幕上自动显示为单列布局。

总得来说,我们的思路是尽可能实现弹性可伸缩的布局,并且在媒体查询的各个区间内指定响应的样式。

当网页的设计足够灵活时,让它变成响应式只需要用到一些简短的媒体查询。

想让网页在一堆不同的设备上合理展示,只需要在最终产品上添加一点 CSS 媒体查询就可以了。这件事情之所以这么简单,关键在于我们的布局原本就是弹性可伸缩的。因此,优化网页在小屏幕上的表现,其实只意味着把一些外边距收拢到最小程度,然后把因为屏幕太窄而无法显示成双列的侧栏调整为单列布局而已。——在 Iterations 中实践响应式设计

合理使用简写

下列两行 css 代码并不是等价的

css
1background: red;
2background-color: red;

前面是简写,它可以确保我们得到红色的背景颜色。

后者是展开式单个属性,它并不能帮助我们清空其他相关的所有属性,有可能会干扰我们得到想要的效果。

合理使用简写,是一种良好的防卫性编码方式。当然,如果我们明确需要覆盖某个属性的展开式属性并保留其他样式,那就需要用展开式属性来书写代码。

展开式属性和简写属性的配合使用也非常有用,比如以下代码

css
1background: url(tr.png) no-repeat top right / 2em /2em, url(tr.png) no-repeat top left / 2em /2em,
2  url(tr.png) no-repeat bottom right / 2em /2em;

background-size 和 background-repeat 的值被重复了三遍,尽管每层背景的这两个值确实是相同的。

CSS 扩散规则表明:如果只为某个属性提供一个值,那它就会扩散并应用到列表中的每一项。

因此,我们可以抽离出重复的内容

css
1background: url(tr.png) top right, url(tr.png) top left, url(tr.png) bottom right;
2background-size: 2em 2em;
3background-repeat: no-repeat;

现在,我们只需要改一个地方就可以控制 background-size 和 background-repeat 了