《CSS 揭秘》中的 CSS 技巧

3,052 阅读7分钟

“你瞅啥”

“瞅你咋地”

本文旨在记录《CSS揭秘》这本书中出现的CSS经典技巧

1. 半透明边框

假设我们想给一个容器设置一层白色背景和一道半透明的边框,我们最初的尝试可能是这样的:

CSS
border: 10px solid hsla(0, 0%, 100%, .5)
background: #fff

除非你对背景和边框的工作原理非常地熟悉,否则展示出来的结果可能让你摸不着头脑,因为我们的背景会从它的半透明边框透上来。如下图所示:

CSS半透明边框

解决方案

默认情况下,背景会延伸到边框所在的区域下层,即使你使用的是不透明的实色边框。幸运的是,在CSS3中,我们可以通过bakcground-clip属性来调整上述默认行为。这个属性的初始值是border-box,如果不希望背景侵入到边框所在的范围,我们可以把它的值设为padding-box,即:

CSS
border: 1px solid hsla(0, 0%, 100%, .5);
background: #fff;
background-clip: padding-box

试一试:dabblet.com/gist/012289…

2. 多重边框

box-shadow方案

目前为止,我们大多数人可能用过(或滥用过)box-shadow来生成投影。不太为人所知的是,它还接受第四个参数(叫做扩张半径),通过指定正值和负值,可以让投影面积加大或减小。一个正值的扩张半径加上两个为零的偏移量以及为零的模糊值,得到的投影其实就像一道实线边框:

CSS
background: yellowgreen;
box-shadow: 0 0 0 10px #655;

使用box-shadow的另一个好处是它支持逗号分隔语法,我们可以创建任意数量的投影(边框)

CSS
background: yellowgreen;
box-shadow: 0 0 0 10px #655, 0 0 0 15px deeppink;

需要注意的是,box-shadow是层层叠加的,第一层投影位于最顶层。因此,需要按照此规律调整扩张半径

试一试:dabblet.com/gist/525eb8…

outline方案

在某些情况下,你可能只需要两层边框,那就可以先设置一层普通的边框,再加上outline属性来产生外层的边框。这种方法的一大优点在于边框样式十分灵活,不像box-shadow方案只能模拟实线边框

CSS
background: yellogreen;
border: 10px solid #655;
outline: 5px solid deeppink;

另一大优点是你可以通过outline-offset属性设置来控制它跟元素边缘之间的距离,甚至可以是负值。不过这个方案有一些需要注意的地方:

  1. 只适用于双层边框场景
  2. 边框不一定会贴合border-radius属性产生的圆角,这种行为被CSS工作组认为是一个bug,因此未来可能会改动
  3. 描边在不同的浏览器中不一定是矩形

3. 灵活的背景定位

很多时候,我们想针对容器某个角对背景图片做偏移定位,如右下角。在CSS2.1中,我们只能指定距离左上角的偏移量,或者干脆对齐到其他三个角。但是,我们有时希望图片和容器的边角之间流出一定的距离。对于固定尺寸的容器来说,可以计算出距离左上角的偏移量,然后设置background-position,对于尺寸不固定的容器这就不可能做到了,只能设置为某个接近100%的百分比值

背景定位

background-position扩展方案

在CSS3中,background-position属性得到扩展,允许我们指定背景图片距离任意角的偏移量

CSS
background: url(code-pirate.svg) no-repeat #58a;
background-position: right 20px bottom 10px;
/*兼容旧浏览器*/
background: url(code-pirate.svg) no-repeat  bottom right #58a;
background-position: right 20px bottom 10px;

试一试:dabblet.com/gist/0f226e…

background-origin方案

在给背景图片设置某个角的偏移量时,有一种情况极为常见:偏移量与容器内边距(padding)一致,即(背景图片相对于padding定位):

CSS
padding: 10px;
background: url(code-pirate.svg) no-repeat #58a;
background-position: right 10px bottom 10px;

上面代码虽然能够起作用,但是不够DIY。每次改动padding值时,需要在三个地方更新这个值。

默认情况下background-positionpadding-box为定位原点,如果把它的值改成content-box那么就会以内容去的边缘为基准。

CSS
padding: 10px;
background: url(code-pirate.svg) no-repeat #58a bottom right;
background-origin: content-box;

试一试:dabblet.com/gist/0f19ac…

calc()方案

现在我们仍然以左上角偏移的思路来考虑,其实希望它有个100% – 20px的水平偏移量,以及100% – 10px的垂直偏移量。幸运的是,calc()函数允许我们执行此类运算

CSS
background: url(code-pirate.svg) no-repeat;
background-position: calc(100% - 20px) calc(100% -10px);

试一试:dabblet.com/gist/b5fcb4…

4. 内框与圆角

内框与圆角

传统方案

使用两个div元素实现

CSS
<div class="something">
    <div>
        I have a ...
    </div>
</div>

.something {
    background: #655;
    padding: .8em;
}
.something > div {
    background: tan;
    border-radius: .8em;
    padding: 1em;
}

outline方案(hack方案)

其实上面的方案更灵活一些,因为它允许我们充分运用背景的能力。例如,如果我们希望这一圈“边框”不只是纯色的,而是要加一层淡淡的纹理,我们也可以很容易的做到。不过,如果只要达成简单的实色效果,我们还有另一条路可走。

CSS
background: tan;
border-radius: .8em;
padding: 1em;
box-shadow: 0 0 0 .6em #655;
outline: .6em solid #655;

outline并不会跟着元素的圆角走(因而显示出直角),但box-shadow却是会的。因此,我们把这两者结合到一起,box-shadow会刚好填补描边和容器圆角之间的空隙。

不过要注意的是,我们为box-shadow属性指定的扩张值并不一定等于outline的宽度。事实上,扩张值等于描边宽度在某些浏览器中可能会得到渲染异常,因此我推荐一个稍小一点的扩张值。那么多大的扩张值合适呢?

如下图,在我们的例子中,border-radius是.8em,那么最小的扩张值是0.8(√2- 1)= 0.33137085em

最小扩张半径

试一试:dabblet.com/gist/170fe4…

5. 条纹背景

假设我们有一条基本的垂直线性渐变,颜色从#fb3过渡到#58a

CSS
background: linear-gradient(#fb3, #58a);

现在,我们把这两个坐标拉近一点:

CSS
background: lnear-gradient(#fb3 20%, #58a 80%);

渐变

现在真正的渐变只出现在容器60%的高度区域。如果我们把两个色标继续拉近,那真正的渐变区域就更窄了。如果我们把两个色标重合在一起,会发生什么?

CSS
background: linear-gradient(#fb3 50%, #58a 50%);

如果多个色标具有相同的位置,它们会产生一个无限小的过渡区域,过渡的起止色分别是第一个和最后一个指定值。从效果上看,颜色会在哪个地方突变,而不是一个平滑的过程。

因为渐变是一种由代码生成的图像,我们能够像对待其他背景图像那样对待它,而且可以通过background-size来调整其尺寸。

CSS
background: linear-gradient(#fb3 50%, #58a 50%);
background-size: 100% 30px;

最终效果

我们可以用同样的方法来创建不等宽条纹,只需调整色标的位置值即可。

CSS
background: linear-gradient(#fb3 30%, #58a 30%);
background-size: 100% 30px;

为了避免每次修改条纹宽度时都要修改两个数字,我们可以从规范那里找到捷径。

“如果某个色标的位置值比整个列表中在它之前的色标的位置值都要小,则该色标的位置值会被设置为它前面所有色标位置的最大值。”

这就意味着,如果我们把第二个色标值设为0,那它总是会被浏览器调整为前一个色标值:

CSS
background: linear-gradient(#fb3 30%, #58a 0);
background-size: 100% 30px;

要创建超过两种颜色的条纹,也是很容易的。

CSS
background: linear-gradient(#fb3 33.3%, #58a 0, #58a 66.6%, yellowgreen 0);
background-size: 100% 45px;

试一试:dabblet.com/gist/119dbf…

知识共享许可协议
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可