> 原文出处:http://www.w3cplus.com/css3/css-secrets/complex-background-pattern.html
## 问题
在[上一节中](http://www.w3cplus.com/css3/css-secrets/striped-backgrounds.html),我们学习了如何使用 CSS 渐变创建各种类型的条纹。不过,条纹并不能代表所有的背景图案,最多只能算是背景中的几何图案。此外,我们还会常常用到许多类型的背景,比如网格、波尔卡圆点、棋盘格等等。
值得庆幸的是,CSS 的渐变属性就可以帮我们创建这些背景图案。虽然几乎可以使用 CSS 的渐变创建各种类型的几何图案,但是这些背景图案的效果并不具有实用性。如果开发中稍不注意,那么代码就会迅速变得冗杂和繁琐。CSS 的背景图案也是非常适合使用 CSS 预处理器来处理的问题之一,比如可以使用 [Sass](http://www.w3cplus.com/blog/tags/302.html) 来减少重复背景图案中的重复工作。
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdd8e37903.png "复杂背景图案")
> 在 2011 年的时候,我的 [CSS3 图案集](http://lea.verou.me/css3patterns/) 就展示了大量的 CSS 渐变图案。之后在 2011 年和 2012 年期间,有大量和 CSS 渐变相关的文章、书籍和会议引用了它们,甚至会被浏览器厂商拿来调整浏览器在渐变方面的功能。不过,并不是每一个模式都是可以用于线上产品的,有一些只是用来演示 CSS 渐变的能力,但是具体的代码往往过于冗杂。对于这些情况,SVG 显然是个更好的选择。如果你想了解更多的 SVG 信息,可以查看 [SVG Patterns](http://philbit.com/svgpatterns/),该网站展示了大量 SVG 版本的 CSS 图案集。
在本章中,我们将会着重创建简单且实用的图案。
## 网格
当我们只能使用一次渐变时,往往就限制了背景图案的种类。下面将要展示给各位的魔幻效果就是要组合多个渐变,让它们交叉重叠。最简单的图案就是使用交叉重叠的水平和垂直条纹创建各种类型的网格。比如,下面的代码就是用来创建怀旧风格的桌布图案:
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdd8fcd69d.png "复杂背景图案")
*图注:由两个渐变组成的桌布图案(这里的透明色就是传统的灰色棋盘格)*
~~~
background: white;
background-image: linear-gradient(90deg,
rgba(200,0,0,.5) 50%, transparent 0),
linear-gradient(
rgba(200,0,0,.5) 50%, transparent 0);
background-size: 30px 30px;
~~~
在某些情况下,我们会想要调整网格中单元格内部的尺寸,而又不影响单元格整体的大小。这也是一种很好地情境,让我们使用固定长度代替百分比来设置过渡点的位置:
~~~
background: #58a;
background-image:
linear-gradient(white 1px, transparent 0),
linear-gradient(90deg, white 1px, transparent 0);
background-size: 30px 30px;
~~~
效果如图所示
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdd900e8e4.png "复杂背景图案")
*图注:一个基础的蓝图网格图案,每个单元格的边框为`1px`,边框的宽度和整个单元格的宽度无关*
上图是一个具有 `1px` 白线的网格,网格中的每个单元格保持了 `30px` 的大小。就像在上一节的 “[灵活可扩展的精致斜纹](http://www.w3cplus.com/css3/css-secrets/striped-backgrounds.html)” 部分所说,最初设定的背景色也是一种降级处理的技巧。
总体来看,这个网格图案是高可维护性代码(虽然其中仍然有一些重复代码)的典范:
* 当需求变更时,可以迅速定位到需要更改的网格尺寸、宽度和颜色
* 需改样式时无需过多编辑,只需一两处修改即可实现
* 短小简洁,只需要四行代码,大约 `170b`的代码量,如果使用 SVG 的话是远远无法如此精简的
> 将 CSS 图案的文件黏贴到 [bytesizematters.com](http://bytesizematters.com/) 这个网站,就可以计算出文件大小
我们甚至可以交叉多层不同宽度和颜色的网格来创建一个更真实的网格(类似蓝图图纸,如下图):
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdd954f756.png "复杂背景图案")
*图注:更复杂的蓝图图案,主要由两个网格组成,每个网格都有不同的样式*
~~~
background: #58a;
background-image:
linear-gradient(white 2px, transparent 0),
linear-gradient(90deg, white 2px, transparent 0),
linear-gradient(hsla(0,0%,100%,.3) 1px,
transparent 0),
linear-gradient(90deg, hsla(0,0%,100%,.3) 1px,
transparent 0);
background-size: 75px 75px, 75px 75px,
15px 15px, 15px 15px;
~~~
## 波尔卡圆点
到目前为止,我们只是使用了线性渐变来创建背景图案。在此之外,径向渐变通常非常有用,它可以帮助我们创建圆形、椭圆形,或者是这些图形的部分。使用径向渐变创建的最简单图案就是大量的圆点,如下图:
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdd95b4752.png "复杂背景图案")
*图注:一个点集;虚线框内是用来平铺的图案*
~~~
background: #655;
background-image: radial-gradient(tan 30%, transparent 0);
background-size: 30px 30px;
~~~
诚如所见,这种图案往往用处不大。不过,接下来我们可以使用两个径向渐变的组合,通过设定不同的 `background-size` 来创建类似波尔卡圆点的图案:
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdd9b1175f.png "复杂背景图案")
*图注:波尔卡圆点图案;虚线框内的两个图案都是是用来平铺的图案*
~~~
background: #655;
background-image: radial-gradient(tan 30%, transparent 0),
radial-gradient(tan 30%, transparent 0);
background-size: 30px 30px;
background-position: 0 0, 15px 15px;
~~~
值得注意的是,为了实现这种效果,就必须让第二个渐变的 `background-position` 为 `background-size` 的一半。不幸的是,这意味着当我们需要修改背景大小时,就至少只需在四个地方进行修改。虽然无法定论这样的代码已经混乱了,但可以确信的说,我们的代码已经接近混乱边缘了。如果你正在使用预处理器,那么你就可以将它转换成一个混合宏:
~~~
@mixin polka($size, $dot, $base, $accent) {
background: $base;
background-image:
radial-gradient($accent $dot, transparent 0),
radial-gradient($accent $dot, transparent 0);
background-size: $size $size;
background-position: 0 0, $size/2 $size/2;
}
~~~
现在,当我们再次创建波尔卡圆点时,只需像下面这样做就可以了:
~~~
@include polka(30px, 30%, #655, tan);
~~~
## 棋盘格
棋盘格图案在现实世界中有大量的应用。比如,轻质的棋盘格可以用来替换古板的纯色背景,让页面显得更有趣。此外,在众多的 UI 设计中,灰色的棋盘格背景已经被广泛地理解为了透明效果。使用 CSS 创建一个棋盘格图案是可能的,但是其中的艰辛将会超出我们的想象。
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdda04c6a3.png "复杂背景图案")
*图注:灰色棋盘格图案往往用来表示透明区域;如果使用图片平铺的方式实现这种效果,那么虚线框内的图案就是要平铺的图案*
正如上图所示,一个典型的棋盘格格子,有两个不同颜色的正方形不断重复组成的。乍看之下,好像很容易就可以创建出来:只需要创建两个位置不同的矩形嘛。这样做对吗?显然并没有那么简单。虽然我们可以使用 CSS 渐变创建矩形,但是如果矩形周围没有可用空间的话,最终的效果就会变成一个纯色背景。实际上,我们是无法使用 CSS 渐变创建具有额外空间的矩形。如果你对此有所疑问,可以动手试一试,当你让渐变平铺时,就会生成类似下图的效果。
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdda082e00.png "复杂背景图案")
*图注:平铺一个四周有空白的正方形;虚线框内是用于平铺的图案*
实现这种效果的技巧就是,使用两个直角三角形拼接成正方形。在前面的集结中,我们已经知道了如何创建直角三角形。如下图所示:
![](https://box.kancloud.cn/2015-10-01_560cdda0b34a6.png)
为了让你回忆起来,你可以看看下面的代码:
~~~
background: #eee;
background-image:
linear-gradient(45deg, #bbb 50%, transparent 0);
background-size: 30px 30px;
~~~
这个时候你可能疑惑了,这样做有什么用吗。当然有用,如果我们想合成类似下图效果:
![](https://box.kancloud.cn/2015-10-01_560cdda0b34a6.png)
那样的正方形,我们就会得到一个纯色。不过,如果我们将三角形的长度减半,那么它们就会占有原来空间的八分之一,而不是现在的二分之一,这种情况下又会是怎样的效果呢?我们只需将颜色过渡点的位置从 `50%` 调整为 `25%`,即可完成这一调整。最后的效果就是下图这样的直角三角形了。
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdda11536c.png "复杂背景图案")
*图注:周围有大量空白的直接三角形*
与上面道理相同,只需翻转颜色过渡点即可创建反方向的直接三角形:
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdda13a0ff.png "复杂背景图案")
*图注:翻转颜色过渡点之后,得到相反方向的三角形*
~~~
background: #eee;
background-image:
linear-gradient(45deg, transparent 75%, #bbb 0);
background-size: 30px 30px;
~~~
> 展望:锥形渐变(Conical gradients) 未来,我们创建棋盘格背景将不再需要费心地交叉覆盖三角形。在 [CSS Image Values Level 4](http://w3.org/TR/css4-images) 中,定义了一系列新的渐变函数来生成锥形渐变(又名,“angle gradients”)。这些渐变从俯视的角度来看就像一个圆锥,所以得名锥形渐变。锥形渐变由一系列的颜色过渡点组成,并且从一个固定点开始旋转变化。比如,使用下面的代码就可以创建一个色调取色盘: ```background: conic-gradient(red, yellow, lime, aqua, blue, fuchsia, red); `` 锥形渐变在很多情况下都非常有用,比如星群、金属拉丝等效果,当然也包括棋盘格效果。未来,创建一个类似棋盘格只需使用一个渐变就可以实现:``` background: repeating-conic-gradient(#bbb 0, #bbb 25%, #eee 0, #eee 50%); background-size: 30px 30px; ``` 不幸的是,本书写作的时候的还没有任何浏览器实现了这一渐变。
如果我们创建两个渐变,猜猜看会有什么结果呢?
~~~
background: #eee;
background-image:
linear-gradient(45deg, #bbb 25%, transparent 0),
linear-gradient(45deg, transparent 75%, #bbb 0);
background-size: 30px 30px;
~~~
首先,结果就像下图所示一般,它并不像我们所要实现的效果。不过,我们只需要将第二个渐变的位置移动 `background-size`的一半,就可以将它们合并成正方形了:
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdda17f4de.png "复杂背景图案")
*图注:合并两个三角形图案*
~~~
background: #eee;
background-image:
linear-gradient(45deg, #bbb 25%, transparent 0),
linear-gradient(45deg, transparent 75%, #bbb 0);
background-position: 0 0, 15px 15px;
background-size: 30px 30px;
~~~
你能猜到最终的结果会是什么样子吗?它就是我们想要实现的棋盘格:
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdda1b5231.png "复杂背景图案")
*图注:三角形合并后变成了正方形,并且在周围保持了空白区域;虚线框内的两个图案是用于平铺的图案,第二个渐变用深色标志*
请注意,这只是棋盘格的一半。如果想创建一个完整的正方形棋盘格,只需重复一下上面的两条渐变,然后调整一下位置即可,有点类似创建波尔卡圆点的操作:
~~~
background: #eee;
background-image:
linear-gradient(45deg, #bbb 25%, transparent 0),
linear-gradient(45deg, transparent 75%, #bbb 0),
linear-gradient(45deg, #bbb 25%, transparent 0),
linear-gradient(45deg, transparent 75%, #bbb 0);
background-position: 0 0, 15px 15px,
15px 15px, 30px 30px;
background-size: 30px 30px;
~~~
最终的结果就是和下图所示的棋盘格了。
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdda04c6a3.png "复杂背景图案")
此外,通过合并对立的三角形(比如,第一个对第二个,第三个对第四个)、添加暗色半透明的基色,可以提高代码的可维护性,无需调整顶层的颜色,只需更改基色即可应对新的需求:
~~~
background: #eee;
background-image:
linear-gradient(45deg,
rgba(0,0,0,.25) 25%, transparent 0,
transparent 75%, rgba(0,0,0,.25) 0),
linear-gradient(45deg,
rgba(0,0,0,.25) 25%, transparent 0,
transparent 75%, rgba(0,0,0,.25) 0);
background-position: 0 0, 15px 15px;
background-size: 30px 30px;
~~~
现在,我们用两个渐变替换了四个渐变,代码总体简练多了。如果需要改变颜色或者单元格大小,则至少需要修改四处地方。在这一个问题上,使用预处理器的混合宏显然是一个明智之举。比如,可以在 Sass 中这样处理:
~~~
@mixin checkerboard($size, $base, $accent: rgba(0,0,0,.25) {
background: $base;
background-image: linear-gradient(45deg,
$accent 25%, transparent 0,
transparent 75%, $accent 0),
linear-gradient(45deg,
$accent 25%, transparent 0,
transparent 75%, $accent 0);
background-position: 0 0, $size $size,
background-size: 2*$size 2*$size;
}
/* Used like... */
@include checkerboard(15px, #58a, tan);
~~~
在任何情况下,当我们需要这么代码解决问题的时候,那么使用 SVG 将会更合适。使用 SVG 格子的效果的话,代码就会变得很简单:
~~~
<svg xmlns="http://www.w3.org/2000/svg"
width="100" height="100" fill-opacity=".25" >
<rect x="50" width="50" height="50" />
<rect y="50" width="50" height="50" />
</svg>
~~~
有人可能会质疑说:“如果使用 CSS 的话,就可以节省 HTTP 请求了!”不过,在现代浏览器中,我们可以将 SVG 文件嵌入到样式中,作为一个数据 URI,我们甚至不需要使用 base64 和 URLencode:
~~~
background: #eee url('data:image/svg+xml,\
<svg xmlns="http://www.w3.org/2000/svg" \
width="100" height="100"
fill-opacity=".25">\
<rect x="50" width="50" height="50" /> \
<rect y="50" width="50" height="50" /> \
</svg>');
background-size: 30px 30px;
~~~
SVG 版本的棋盘格不仅仅是小到了只有 40 个字符,更棒的是减少了重复性的工作。比如,我们只需修改一处地方,就可以更改颜色,只需修改两处地方,就可以更改大小。
**注意,你可以通过使用反斜线(`\`)将 CSS 字符串分解到多行,从而提高可读性。**
## 相关链接
* [CSS Image Values](http://www.w3cplus.com/css3/css-secrets/w3.org/TR/css-images)
* [CSS Backgrounds & Borders](http://www.w3cplus.com/css3/css-secrets/w3.org/TR/css-backgrounds)
* [Scalable Vector](Graphics w3.org/TR/SVG)
* [CSS Image Values Level 4](http://www.w3cplus.com/css3/css-secrets/w3.org/TR/css4-images)
可以通过 [叠加模式](http://w3.org/TR/compositing-1)(也被称为[CSS混合模式](http://www.w3cplus.com/blog/tags/409.html)) 来组合这些技巧,使用 `background-blend-mode` 的时候,使用除 `normal` 之外的其他属性值作用到一个或多个图层,会产生非常有趣的效果,就像是 [bennettfeely.com的gradients示例](http://bennettfeely.com/gradients/) 里所展示的一样。这些图案大多只使用了 `multiply` 的叠加模式,在此之外`overlay`,`screen` 或者是 `difference` 都非常有用。
![复杂背景图案](https://box.kancloud.cn/2015-10-01_560cdda7330ac.png "复杂背景图案")
## 总结
[上一节](http://www.w3cplus.com/css3/css-secrets/striped-backgrounds.html)主要介绍了使用CSS3的渐变配合`background-size`制作简单的条纹纹理图案效果。但实际上,将CSS3的渐变和`background-size`配合的好的话,不仅仅可以制作简单的条纹效果,还可以制作一些复杂的纹理效果。虽然这些纹理在实际中不十分实用,但让你练手和熟悉CSS3的强大功能是足以。