首页 《CSS揭秘》笔记1 — 背景与边框
文章
取消

《CSS揭秘》笔记1 — 背景与边框

此篇博客是学习《CSS 揭秘》一书的学习笔记。

1. 半透明边框

假设我们想给一个容器设置一道半透明白色边框,父元素的颜色会透过其边框。 HTML 如下:

1
2
3
<div class="box-100">
  <div class="box-100 translucence-border"></div>
</div>

CSS 代码如下:

1
2
3
4
5
6
7
8
.box-100 {
  width: 100px;
  height: 100px;
}
.translucence-border {
  border: 10px solid hsla(0, 0%, 100%, 0.5);
  background: #ff7875;
}

实际效果如下,子元素的红色背景(#ff7875)延伸到了边框下面,所以父元素的白色背景被遮住了。

CSS3 中的 background-clip 属性可以解决上述问题。此属性设置了元素的背景(背景图片或颜色)是否延伸到边框下面。

1
2
3
4
5
.translucence-border {
  border: 10px solid hsla(0, 0%, 100%, 0.5);
  background: #ff7875;
  background-clip: padding-box;
}

background-clip 有如下几个值:

  • border-box: 默认值,背景延伸至边框外沿(但是在边框下层)。
  • padding-box: 背景延伸至内边距(padding)外沿。不会绘制到边框处。
  • content-box: 背景被裁剪至内容区(content box)外沿。

修改后的效果如下,我们现在能够看到父元素的背景色了。

2. 多重边框

box-shadow 方案

我们可以通过 box-shadow 来实现多重边框,而不需要使用额外的元素。

它支持逗号语法,使我们可以创建任意数量的投影。

HTML:

1
<div class="box-100 multi-border"></div>

CSS:

1
2
3
4
5
6
.multi-border {
  margin: 30px;
  background: #ff7875;
  /* x偏移量 | y偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */
  box-shadow: 0 0 0 10px #69c0ff, 0 0 0 20px #ffc069, 0 0 0 30px #95de64;
}

outline 方案

当我们只需要两层边框时,使用 outline (描边) 更方便。

CSS:

1
2
3
4
5
6
7
.multi-border {
  margin: 10px;
  background: #ff7875;
  border: 10px solid #69c0ff;
  /* 宽度 | 样式 | 颜色 */
  outline: 10px solid #ffc069;
}

3. 灵活的背景定位

CSS 2.1 中,我们只能指定背景图片距离左上角的偏移量,或者干脆完全靠齐到其他三个角。

CSS 3 中,我们可以灵活地定位背景图片了。

background-position 扩展语法方案

有如下 div 元素,内边距 10px ,现在我们想把此元素的背景图片定位到距右下角 10px 处。
HTML:

1
<div class="box-100 padding-10 bg-position">css 3</div>

CSS:

1
2
3
4
.bg-position {
  background: url("/svg/css3.svg") no-repeat right bottom #ff7875;
  background-position: right 10px bottom 10px;
}

其中,前一个 background 中的 right bottom 为回退方案,对于不支持 CSS3 的浏览器,背景将定位至右下角处。
效果如下:

css 3

background-origin 方案

background-origin 规定了 background 的原点。

其可用的属性如下:

  • border-box: 背景图片的摆放以 border 区域为参考;
  • padding-box: 背景图片的摆放以 padding 区域为参考;
  • content-box: 背景图片的摆放以 content 区域为参考;

CSS:

1
2
3
4
.bg-position {
  background: url("/svg/css3.svg") no-repeat right bottom #ff7875;
  background-origin: content-box;
}

效果如下:

css 3

calc() 方案

我们仍然以左上角偏移的思路来考虑,calc(100% - 10px) 的水平向左偏移等价于 10px 的水平向右偏移。

CSS:

1
2
3
4
.bg-position {
  background: url("/svg/css3.svg") no-repeat right bottom #ff7875;
  background-position: calc(100% - 10px) calc(100% - 10px);
}

效果如下:

css 3

4. 边框内圆角

我们先用两个元素实现边框内圆角。
HTML:

1
2
3
<div class="outer">
  <div class="inner">边框内圆角</div>
</div>

CSS:

1
2
3
4
5
6
7
.outer {
  padding: 5px;
}
.inner {
  padding: 5px;
  border-radius: 5px;
}

效果如下:

边框内圆角

我们再用一个元素实现边框内圆角。
HTML:

1
<div class="inner-rounding">边框内圆角</div>

CSS:

1
2
3
4
5
6
.inner-rounding {
  padding: 5px;
  border-radius: 5px;
  box-shadow: 0 0 0 5px #69c0ff;
  outline: 5px solid #69c0ff;
}

重点: outline 不会跟着元素的圆角走,而 box-shadow 会。

效果如下:

边框内圆角

5. 条纹背景

水平条纹

使用 linear-gradient() 线性渐变生成如下几个条纹:

HTML:

1
2
3
4
5
6
7
<div class="box-500-100 flex-around">
  <div class="box-100 stripe-1">stripe-1</div>
  <div class="box-100 stripe-2">stripe-2</div>
  <div class="box-100 stripe-3">stripe-3</div>
  <div class="box-100 stripe-4">stripe-4</div>
  <div class="box-100 stripe-5">stripe-5</div>
</div> 

CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.stripe-1 {
  background: linear-gradient(#ff7875, #69c0ff);
}
.stripe-2 {
  background: linear-gradient(#ff7875 40%, #69c0ff 60%);
}
.stripe-3 {
  background: linear-gradient(#ff7875 50%, #69c0ff 50%);
}
.stripe-4 {
  background: linear-gradient(#ff7875 50%, #69c0ff 50%);
  background-size: 100% 20px;
}
.stripe-5 {
  background: linear-gradient(#ff7875 50%, #69c0ff 0);
  background-size: 100% 20px;
}

效果如下:

stripe-1
stripe-2
stripe-3
stripe-4
stripe-5
  • stripe-1: 从红色渐变至蓝色;
  • stripe-2: 在 40% - 60% 区域内从红色渐变至蓝色;
  • stripe-3: 无渐变效果,红蓝各占一半;
  • stripe-4: 配合 background-size 来调整尺寸;
  • stripe-5: 当第二个色标的位置为 0 时,会自动取前一个色标位置的值。

垂直条纹

HTML:

1
<div class="box-100 vertical-stripe">垂直条纹</div>

我们只需要在开头加上一个额外的参数来指定渐变的方法,默认为 to bottom ,此处我们的方向为 to right ,或者使用 90deg。 CSS:

1
2
3
4
5
.vertical-stripe {
  background: linear-gradient(to right, /* 或 90deg */
              #ff7875 50%, #69c0ff 0);
  background-size: 20px 100%;
}

效果如下:

垂直条纹

斜条纹

斜条纹我们使用了 repeating-linear-gradient() ,它与 linear-gradient() 类似,有一点不同:它是无限循环的,直到填满整个背景。

HTML:

1
2
3
4
<div>
  <div class="diagonal-stripe-1">斜条纹1</div>
  <div class="diagonal-stripe-2">斜条纹2</div>
</div>

CSS:

1
2
3
4
5
6
7
8
9
10
11
12
.diagonal-stripe-1 {
  background: repeating-linear-gradient(45deg, #ff7875, #69c0ff 20px);
}
.diagonal-stripe-2 {
  background: repeating-linear-gradient(
    45deg,
    #ff7875,
    #ff7875 10px,
    #69c0ff 0,
    #69c0ff 20px
  );
}

效果如下:

斜条纹1
斜条纹2

6. 复杂的背景图案

网格

HTML:

1
<div class="box-110 grid"></div>

CSS:

1
2
3
4
5
6
.grid {
  background: #fff;
  background-image: linear-gradient(rgba(200, 0, 0, 0.5) 50%, transparent 0),
    linear-gradient(90deg, rgba(200, 0, 0, 0.5) 50%, transparent 0);
  background-size: 20px 20px;
}

效果如下:

波点

HTML:

1
<div class="box-100 polka"></div>

CSS:

1
2
3
4
5
6
7
.polka {
  background: #fff;
  background-image: radial-gradient(#ff7875 30%, transparent 0),
                    radial-gradient(#ff7875 30%, transparent 0);
  background-size: 20px 20px;
  background-position: 0 0, 10px 10px;
}

效果如下:

棋盘

HTML:

1
<div class="box-100 checkerboard"></div>

CSS:

1
2
3
4
5
6
7
8
9
10
11
.checkerboard {
  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, 10px 10px;
  background-size: 20px 20px
}

效果如下:

7. 伪随机背景

利用多层 background-image 生成随机背景:

  • 通过 background 设置一层底色;
  • 通过 background-image 设置三个条纹;
  • 通过 background-size 设置不同的尺寸使条纹错开。

HTML:

1
<div class="container height-100 random-stripes"></div>

CSS:

1
2
3
4
5
6
7
.random-stripes {
  background: #ff7875;
  background-image: linear-gradient(90deg, #69c0ff 10px, transparent 0),
                    linear-gradient(90deg, #ffc069 20px, transparent 0),
                    linear-gradient(90deg, #95de64 20px, transparent 0);
  background-size: 80px 100%, 60px 100%, 40px 100%;
}

效果如下:

我们可以发现,图案每隔 240px 就会重复一次。见图中的虚线方框。

240px 就是所有 background-size 的最小公倍数

为了最大化最小公倍数,我们把这些数字改成质数,并且这些质数之间互质

修改后的 CSS 如下:

1
2
3
4
5
6
7
.cicada-stripes {
  background: #ff7875;
  background-image: linear-gradient(90deg, #69c0ff 11px, transparent 0),
                    linear-gradient(90deg, #ffc069 23px, transparent 0),
                    linear-gradient(90deg, #95de64 41px, transparent 0);
  background-size: 41px 100%, 61px 100%, 83px 100%;
}

现在这三个 background-size 的最小公倍数为 41 X 61 X 83 = 207583px。这个数值远大于常规屏幕的分辨率。

这个技巧被称为”蝉原则“。

效果如下:

8. 连续的图像边框

有时我们想把图案或图片应用为边框,而不是背景。

两个 HTML 元素

最简单的办法是使用两个 HTML 元素,父元素的背景设为指定的图片(左图),子元素用来放内容,效果如下(右图):

使用两个 HTML 元素实现连续的图像边框

HTML:

1
2
3
<div class="outer">
  <div class="inner">使用两个 HTML 元素实现连续的图像边框</div>
</div>

CSS:

1
2
3
4
5
6
7
8
9
10
11
12
.outer {
  width: 200px;
  height: 132px;
  padding: 10px;
  background: url('/images/2019-06-01-css-secrets/book.jpg');
  background-size: cover;
}
.inner {
  width: 100%;
  height: 100%;
  background: #fff;
}

一个 HTML 元素

使用一个 HTML 元素的思路如下:

  • 给元素设置一个透明的 border
  • 设置两层背景,一层是白色背景(白色背景写在前面),下面一层是图片;
  • 白色背景的 background-clip 的值为 padding-box ,图片背景则为 border-box
  • 最后设置 border-origin 的值为 border-box (默认值为 padding-box ),否则就会出现左图背景图片有拼接的情况。

注:产生拼接的原因是图片显示的尺寸不仅取决于 padding box 的尺寸,而且被放置在了 padding box 的原点(左上角)。我们看到的实际上就是背景图片以平铺的方式蔓延到了border box 区域的效果。因此需要指定 border-origin 的值为 border-box

仅使用一个 HTML 元素实现连续的图像边框(背景图片有拼接情况)
仅使用一个 HTML 元素实现连续的图像边框

HTML:

1
<div class="continuous-image-borders">仅使用一个 HTML 元素实现连续的图像边框</div>

CSS:

1
2
3
4
5
6
7
8
9
10
11
.continuous-image-borders {
  width: 200px;
  height: 132px;
  padding: 10px;
  border: 10px solid transparent;
  background: linear-gradient(#fff, #fff),
              url('/images/2019-06-01-css-secrets/book.jpg');
  background-clip: padding-box, border-box;
  background-size: cover;
  background-origin: border-box;
}

为减少代码量,我们可以把背景属性整合到 background 这个简写属性中:

1
2
3
4
5
6
7
8
.continuous-image-borders {
  width: 200px;
  height: 132px;
  padding: 10px;
  border: 10px solid transparent;
  background: linear-gradient(#fff, #fff) padding-box,
              url('/images/2019-06-01-css-secrets/book.jpg') border-box 0 0 / cover;
}

注:

  1. background 属性被指定多个背景层时,使用逗号分隔每个背景层。
  2. background-size 只能仅接着 background-position ,并以 / 分割,如 0 0 / cover
  3. <box> 最多可以出现两次;出现两次时,前一个设置 background-origin ,后一个设置 background-clip ;出现一次时,同时设置这两个值。
  4. background-color 只能被包含在最后一层。

最终出现与前面一样的效果:

仅使用一个 HTML 元素实现连续的图像边框(减少代码量)

我们可以使用这个技巧实现老式信封样式的边框:

老式信封样式边框

CSS 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
.vintage-envelope {
  width: 200px;
  height: 132px;
  padding: 1em;
  border: 1em solid transparent;
  background: linear-gradient(#fff, #fff) padding-box,
              repeating-linear-gradient(-45deg, 
              red 0, red 12.5%, 
              transparent 0, transparent 25%,
              #58a 0, #58a 37.5%,
              transparent 0, transparent 50%
              ) 0 / 4em 4em;
}

注:

  1. 0 / 4em 4em 等价于 0 center / 4em 4em ,因为对于 background-position 属性,如果只指定了一个值,另外一个值将为 center
  2. repeating-linear-gradient 中的颜色宽度为:
    • 0 - 12.5%: 红色;
    • 12.5% - 25%: 透明;
    • 25% - 37.5%: 蓝色;
    • 37.5% - 50% : 透明;
  3. 然后剩下的 50% 区域会自动重复,这样他才能与其他 4em X 4em 方形背景以相同的颜色拼接起来。

我们还可以使用这个技巧实现蚂蚁行军边框,此效果在图像编辑软件中很常见:

蚂蚁行军边框

CSS 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@keyframes ants {
  to { background-position: 100%; }
}
.marching-ants {
  width: 200px;
  height: 132px;
  padding: 1em;
  border: 1px solid transparent;
  background: linear-gradient(#fff, #fff) padding-box,
              repeating-linear-gradient(-45deg, 
              #fff 0, #fff 12.5%, 
              transparent 0, transparent 25%,
              #000 0, #000 37.5%,
              transparent 0, transparent 50%
              ) 0 / .6em .6em;
  animation: ants 12s linear infinite;
}

要点如下:

  1. 边框宽度减少至 1px此时斜向条纹转变成了虚线边框
  2. background-size 改为一个合适的值,如 .6em .6em
  3. 定义动画 ants ,改变其 background-position 的值;
  4. 通过 animation 使用动画,此时黑白虚线框就会动起来了。
本文由作者按照 CC BY 4.0 进行授权