1. 前期准备工作
1.1 一个工具函数——$$()——获取所有匹配特定 CSS 选择器的 DOM 元素
function $$(selector, context) {
context = context || document;
var elements = context.querySelectorAll(selector);
return Array.prototype.slice.call(elements);
}
1.2 浏览器兼容性信息
有很多优秀的网站提供了及时有效的浏览器兼容性信息。推荐如下:
- Can I Use...?(caniuse.com)
- WebPlatform.org(webplatform.org)
- Mozilla Developer Network(developer.mozilla.org)
- 维基百科上的“浏览器排版引擎对比(CSS 兼容性)”词条(en.wikipedia.org/wiki/Compar…
1.3 检测某个CSS样式属性是否被浏览器支持
如果要检测某个样式属性是否被支持,核心思路就是在任一元素的 element.style 对象上检查该属性是否存在
function testProperty(property) {
var root = document.documentElement; // html
if (property in root.style) {
root.classList.add(property.toLowerCase());
return true;
}
root.classList.add("no-" + property.toLowerCase());
return false;
}
1.4 检测一个CSS样式属性是否支持设置某个具体的属性值
如果我们想要检测某个具体的属性值是否支持,那就需要把它赋给对应的属性,然后再检查浏览器是不是还保存着这个值。很显然,这个过程会改变元素的样式,因此我们需要一个隐藏元素:
function testValue(id, value, property) {
var dummy = document.createElement("p");
var root = document.documentElement;
dummy.style[property] = value;
if (dummy.style[property]) {
root.classList.add(id);
return true;
}
root.classList.add("no-" + id);
return false;
}
2. CSS编码技巧
2.1 尽量减少代码重复
在实践中,代码可维护性的最大要素是尽量减少改动时要编辑的地方。
这还不仅仅是后期修改的问题。灵活的 CSS 通常更容易扩展:在写出基础样式之后,只用极少的代码就可以扩展出不同的变体,因为只需覆盖一些变量就可以了。看一个例子:
button {
padding: 6px 16px;
border: 1px solid #446d88;
background: #58a linear-gradient(#77a0bb, #58a);
border-radius: 4px;
box-shadow: 0 1px 5px gray;
color: white;
text-shadow: 0 -1px 1px #335166;
font-size: 20px;
line-height: 30px;
}
在这个例子中,行高是字号的 1.5 倍。因此,把代码改成下面这样会更易维护:
font-size: 20px;
line-height: 1.5;
但是,把父级的字号加大之后,就得修改每一处使用绝对值作为字体大小的样式。如果改用百分比或 em 单位就好多了:
font-size: 125%; /* 假设父级的字号是 16px */
line-height: 1.5;
如果把所有长度值都改成 em 单位,那这些效果的值就都变成可缩放的了,而且是依赖字号进行缩放
em 单位可以看成是 CSS 中的一个变量,因为它引用了 font-size 的值
button {
padding: 0.3em 0.8em;
border: 1px solid #446d88;
background: #58a linear-gradient(#77a0bb, #58a);
border-radius: 0.2em;
box-shadow: 0 0.05em 0.25em gray;
color: white;
text-shadow: 0 -0.05em 0.05em #335166;
font-size: 125%;
line-height: 1.5;
}
按钮的边框粗细保持在 1px,不受按钮尺寸的影响。
把半透明的黑色或白色叠加在主色调上,即可产生主色调的亮色和暗色变体,这样就能导出其他颜色各自的亮色和暗色版本:
button {
padding: 0.3em 0.8em;
border: 1px solid rgba(0, 0, 0, 0.1);
background: #58a linear-gradient(hsla(0, 0%, 100%, 0.2), transparent);
border-radius: 0.2em;
box-shadow: 0 0.05em 0.25em rgba(0, 0, 0, 0.5);
color: white;
text-shadow: 0 -0.05em 0.05em rgba(0, 0, 0, 0.5);
font-size: 125%;
line-height: 1.5;
}
覆盖 background-color 属性,就可以得到不同颜色版本的按钮了
<!DOCTYPE html>
<html>
<head>
<style>
button {
padding: 0.3em 0.8em;
border: 1px solid rgba(0, 0, 0, 0.1);
background: #58a linear-gradient(hsla(0, 0%, 100%, 0.2), transparent);
border-radius: 0.2em;
box-shadow: 0 0.05em 0.25em rgba(0, 0, 0, 0.5);
color: white;
text-shadow: 0 -0.05em 0.05em rgba(0, 0, 0, 0.5);
font-size: 125%;
line-height: 1.5;
}
button.cancel {
background-color: #c00;
}
button.ok {
background-color: #6b0;
}
</style>
</head>
<body>
<button>Yes!</button>
<button class="ok">ok!</button>
<button class="cancel">cancel!</button>
</body>
</html>
2.1.1. 代码易维护 vs. 代码量少
有时候,代码易维护和代码量少不可兼得。比如在上面的例子中,最终采用的代码甚至比一开始的版本略长。
下面的代码片段,为一个元素添加一道 10px 宽的边框,但左侧不加边框。
border-width: 10px 10px 10px 0;
只要这一条声明就可以搞定了,但如果日后要改动边框的宽度,你需要同时改三个地方。
如果把它拆成两条声明的话,改起来就容易多了,而且可读性或许更好一些:
border-width: 10px;
border-left-width: 0;
2.1.2 currentColor——CSS变量
currentColor是从SVG 那里借鉴来的。这个关键字并没有绑定到一个固定的颜色值,而是一 直被解析为 color。
举个例子,假设想让所有的水平分割线(所有 <hr> 元素)自动与文本的颜色保持一致
hr {
height: 0.5em;
background: currentColor;
}
currentColor 是很多 CSS 颜色属性的初始值,比如border-color 和 outline-color,以及 text-shadow 和 box-shadow 的颜色值,等等。
2.1.3 inherit继承
- inherit 可以用在任何 CSS 属性中,而且它总是绑定到父元素的计算值
- 对伪元素来说,inherit则会取生成该伪元素的宿主元素。
举例来说,要把超链接的颜色设定为与页面中其他文本相同,还是要用 inherit:
a { color: inherit; }
inherit 关键字对于背景色同样非常有用。举个例子,在创建提 示框的时候,希望它的小箭头能够自动继承背景和边框的样式:
.callout {
position: relative;
background-color: yellowgreen;
border: 1px solid red;
height: 50px;
width: 300px;
}
.callout::before {
content: "";
position: absolute;
top: -0.4em;
left: 1em;
padding: 0.35em;
background: inherit;
border: inherit;
border-right: 0;
border-bottom: 0;
transform: rotate(45deg);
}
2.2 相信你的眼睛,而不是数字
人的眼睛并不是一台完美的输入设备。有时候精准的尺度看起来并不精准,而我们的设计需要顺应这种偏差。
2.3 响应式布局——避免不必要的媒体查询
总的来说,我们的思路是尽最大努力实现弹性可伸缩的布局,并在媒体查询的各个断点区间内指定相应的尺寸。当网页本身的设计足够灵活时,让它变成响应式应该只需要用到一些简短的媒体查询代码。
- 使用百分比长度来取代固定长度。如果实在做不到这一点,也应该尝试使用与视口相关的单位(vw、vh、vmin 和 vmax),它们的值解析为视口宽度或高度的百分比。
- 在较大分辨率下得到固定宽度时,使用
max-width而不是width,因为它可以适应较小的分辨率,而无需使用媒体查询。 - 为替换元素(比如 img、object、video、iframe 等)设置一个
max-width,值为 100%。 - 假如背景图片需要完整地铺满一个容器,不管容器的尺寸如何变化,
background-size: cover这个属性都可以做到。但是,在移动网页中通过 CSS 把一张大图缩小显示往往是不太明智的。 - 当图片(或其他元素)以行列式进行布局时,让视口的宽度来决定列的数量。弹性盒布局(即 Flexbox)或者 display: inline-block加上常规的文本折行行为,都可以实现这一点。
- 在 使 用 多 列 文 本 时, 指 定 column-width( 列 宽 ) 而 不 是 指 定column-count(列数),这样它就可以在较小的屏幕上自动显示为单列布局
2.4 合理使用CSS简写属性
background: url(tr.png) no-repeat top right / 2em 2em,
url(br.png) no-repeat bottom right / 2em 2em,
url(bl.png) no-repeat bottom left / 2em 2em;
可以把重复的值从简写属性中抽出来写成一个展开式属性:
background: url(tr.png) top right, url(br.png) bottom right,
url(bl.png) bottom left;
background-size: 2em 2em;
background-repeat: no-repeat;
2.5 使用CSS预处理器
Stylus(stylus-lang.com/)、Sass(http… LESS(lesscss.org/)等CSS 预处理器,为 CSS 的编写提供提供了,变量、mixin、函数、规则嵌套、颜色处理等