CSS技巧(三):视觉效果

源代码可访问仓库地址

视觉效果

1. 单侧投影

1.1 单侧投影

大多数人使用box-shadow的方法是,制定三个长度和一个颜色值。

      
1
      
box-shadow: 2px 3px 4px rgba(0, 0, 0, .5);

box-shadow第一个长度表示水平方向投影,第二个为垂直方向投影,第三个为模糊半径。

投影绘制步骤:

  • 以该元素的尺寸和位置画一个rgba(0,0,0,.5)的矩形
  • 把它向右移2px,向下移3px
  • 使用高斯模糊算法将它进行4px的模糊处理。这在本质上表示在阴影边缘发生阴影色和纯透明色之间的颜色过度长度近似模糊半径的两倍(这里为8px)
  • 接下来,模糊后的矩形与原始元素的交集部分会被剪切掉,因此看起来像是在该元素后面。所以这里跟我们所理解的元素叠在模糊后矩形上层不同。所以说如果我们给元素设置一层半透明的背景,就看不到任何投影

使用4px的模糊半径意味着投影的尺寸会比元素本身的尺寸大约8px,因此投影的最外圈会从元素的四面向外显露出来。

  • 设置偏移量,就可以把投影的顶部和左边隐藏起来,只要这两个方向上的偏移量不小于4px就行,不够会导致外漏的投影过于浓重

  • 最终解决方案是使用box-shadow的第四个长度参数,排在模糊半径参数之后,称作扩张半径。这个参数会根据你指定的值去扩张或缩小(负值)投影的尺寸。比如一个-5px的扩张半径会把投影宽度和高度各减少10px(每边5px)

所以我们使用一个负的扩张半径,而他的值正好等于模糊半径

      
1
      
box-shadow: 0 5px 4px -4px black;

现在只有底部才有一道投影了。

1.2 邻边投影

可以使用之前说的设置偏移量,要么使用设置第四个长度参数

  • 我们不应该把阴影缩的太小,而是把阴影藏进一侧,另一侧自然露出就好,因此,扩张半径不应该设为模糊半径的相反值,而是这个相反值的一半
  • 需要指定两个偏移量,因为希望投影在水平和垂直方向上同时移动。它们的值需要大于或等于模糊半径的一半
      
1
      
box-shadow: 3px 3px 6px -3px black;

1.3 双侧投影

用上面的单侧投影(每边个一块)来达到目的。基本上就是把”单侧投影”中的技巧运用两次

      
1
2
      
box-shadow: 5px 0 5px -5px black,
-5px 0 5px -5px black;

2. 不规则投影

当元素添加了伪元素或半透明背景的时候,box-shadow会变得力不从心,出现一些问题,有些原理之前已经讲到过。

对下面三种情况的元素都使用了box-shadow: .1em .1em .3em rgba(0, 0, 0, .5);

比如,用伪元素生成气泡的小尾巴后,再对气泡使用投影,投影效果不会在小尾巴上显现。

对元素使用了透明背景,投影会忽视透明部分。

切角效果

等等。

使用filter属性来解决,目前为止IE11还不支持,其他基本支持。filter实行从SVG借鉴过来的。我们使用其中一个函数drop-down(),跟box-shadow很相像,但不包括扩张半径和inset值。

可以这样改写

      
1
      
filter: drop-shadow(.1em .1em .1em rgba(0,0,0,.5));

最终效果

3. 染色效果

使用<canvas>也可以实现,这里探讨css方法的实现。

3.1 基于滤镜的方案

由于没有一种现成的滤镜是专门为这个效果而设计的,所以需要使用多个滤镜组合起来。

第一个滤镜是sepia(),它会给图片增加一种饱和度的橙黄色染色效果,几乎所有的色相值都被收敛在35~40之间。

      
1
      
filter: sepia();

如果想要主色调的饱和度比这个高,可以用staturate()l滤镜来给每个像素提升饱和度。具体多少可以根据实际情况。

      
1
      
filter: sepia() saturate(4);

但是我们想要一种亮粉色的,则还需要再添加一个hue-rotate()滤镜,把每个像素的色相以指定的度数进行偏移。为了把原来的色相值40提升至335,需要增大(335 - 40)= 295度

      
1
      
filter: sepia() saturate(4) hue-rotate(295deg);

添加一个hover来触发切换

      
1
2
3
4
5
6
7
8
9
      
img {
max-width: 250px;
filter: sepia() saturate(4) hue-rotate(295deg);
transition: 1s filter;
}
img:hover,img:focus {
filter:none
}

3.2 基于混合模式的方案

当两个元素叠加时,“混合模式”控制了上层元素的颜色与下层颜色进行混合的方式。用它来实现染色效果,需要用到的混合模式是luminosity,这种模式会保留上层元素的HSL亮度信息,并从它的下层吸取色相的饱和度信息。所以如果我们将主色调放在下层,待处理的图片放在上层,就相当于进行染色了。当然IE11肯定是不支持的

对一个元素设置混合模式,有两个属性可以用:mix-blend-mode可以为整个元素设置混合模式,background-blend-mode可以为每层背景单独指定混合模式。所以有两种选择

  • 需要把图片包裹在一个容器中,并把容器的背景设置为我们想要的主色调
  • 不用图片元素,而用div元素,把这个元素的第一层背景设置为要染色的图片第二层的背景设置为我们想要的主色调
      
1
2
3
      
<a href="#">
<img src="dog.jpg">
</a>

几行声明就可以解决

      
1
2
3
4
5
6
7
8
9
10
      
a {
display: block;
max-width: 250px;
background: hsl(335, 100%, 50%);
}
img {
width: 100%;
mix-blend-mode: luminosity;
}

mix-blend-mode是把整个元素向下进行混合,而不管下面是什么。因此只要把这个属性设置为luminosity混合模式,那图片总会跟某些东西进行混合。此外,使用background-blend-mode属性则可以让每层背景跟它的下层背景进行混合,但不关心元素之外是什么情况。所以,当我们只有一个背景图像以及一个透明的背景色时,就不会出现任何混合效果。利用此特点可以制作动画

      
1
2
      
<div class="dog" style="background-image: url('dog.jpg')">
</div>
      
1
2
3
4
5
6
7
8
9
10
11
      
.dog {
width: 640px; height: 440px;
background-size: cover;
background-color: hsl(335, 100%, 50%);
background-blend-mode: luminosity;
transition: .5s background-color;
}
.dog:hover {
background-color: transparent;
}

两种方法都不够理想

  • 图片的尺寸需要在css中写死
  • 在语义上,这个元素不是一张图片

4. 毛玻璃效果

使用半透明颜色作为背景,然后将其放在图片或花哨的背景之上,会产生不错的效果。不过也可能导致文字很难阅读。

      
1
2
3
4
5
6
7
8
      
<main>
<blockquote>
“The only way to get rid of a temptation is to yield to it. Resist it, and your soul grows sick with longing for the things it has forbidden to itself, with desire for what its monstrous laws have made monstrous and unlawful.”
<footer>-
<cite>Oscar Wilde, The Picture of Dorian Gray</cite>
</footer>
</blockquote>
</main>

关键css代码可能是

      
1
2
3
4
5
6
7
      
body {
background: url("http://csssecrets.io/images/tiger.jpg") 0 / cover fixed;
}
main {
background: hsla(0,0%,100%,.25) border-box;
}

最后效果

上面的fixed表示background-attachment:fixed,设置背景图像固定,不会随着页面的其余部分滚动。

效果图文字有些难以看清,背景图过于花哨。可以通过提升背景色的不透明度来则增加文本的可读性,不过效果就那么生动。下面的图是将不透明度调整为.5,一点都不好看。

解决这个问题的方案通常是将覆盖的那部分图片区做模糊处理。在css中可以使用滤镜,blur()对元素进行模糊处理。

不过直接处理也不行,会导致文字无法阅读。需要另找办法

由于不能直接对元素本生进行模糊处理,可以选择对一个伪元素进行处理,然乎将它定位到元素下层。

下面是主要代码

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
      
main {
position: relative;
/*其他样式*/
}
body,main::before {
background: url("http://csssecrets.io/images/tiger.jpg") 0 / cover fixed;
}
main::before {
content: '';
position: absolute;
top: 0;right: 0;bottom: 0;left: 0; /*设置全部偏移量为0,可以将它完整覆盖在宿主元素上*/
z-index: -1;
filter: blur(20px);
}

将伪元素的背景图设置成body的一致,z-index: -1是将它置于main元素之下,然后对伪元素惊醒模糊处理。

大部分效果可以出来了,不过仔细可以看出来,模糊效果在接近边缘处会逐渐消退。因为模糊效果会削减实色像素所能覆盖的范围,削减的半径正是模糊半径的长度。可以对伪元素设置成红色背景,方便看清真像。

可以让伪元素相对其宿主元素的尺寸再向外扩大至少20px(即模糊半径),可以通过-20px的外变局来实现。保险起见,用一个更大的绝对值(-30px).

但是周边又出现一圈模糊效果,因为超出了容器,使用hidden即可

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
      
main {
position: relative;
overflow: hidden;
background: hsla(0,0%,100%,.3) border-box;
}
body,main::before {
background: url("http://csssecrets.io/images/tiger.jpg") 0 / cover fixed;
}
main::before {
content: '';
position: absolute;
top: 0;right: 0;bottom: 0;left: 0;
z-index: -1;
filter: blur(20px);
margin: -30px;
}

现在毛玻璃效果完美了。

5. 折角效果

背景知识:css变形,css渐变、切角效果

5.1 45°折角

第一步实现一个切角效果

      
1
2
3
4
      
div {
background: #58a;
background: linear-gradient(-135deg, transparent 2em, #58a 0);
}

然后增加一个暗色的三角形来实现翻折效果。实现方法就是增加一层渐变来生成这个三角形并将其定位在右上角,可以通过background-size来控制折角的大小。折页部分三角形放在切角渐变之上。

      
1
2
3
4
5
6
      
div {
background: #58a;
background: linear-gradient(to left bottom,
transparent 50%, rgba(0, 0%, 0, .4) 0) no-repeat 100% 0 / 2em 2em,
linear-gradient(-135deg, transparent 2em, #58a 0);
}

并没有达到我们想要的效果,原因跟(二)中切角效果一样,第二层渐变中的2em折角尺寸是写在色标中的,因此是沿着渐变轴进行度量的,是对角线尺寸。然而在background-size中的2em长度是背景贴片的宽度和高,是在水平和垂直方向上度量的。

有两种方式调整:

  • 保留对角线的2em长度,将background-size乘以根号2
  • 保留水平和垂直方向上的2em,就要切角渐变的角标位置值除以根号2

但是推荐使用第二种方式,绝大多数的css度量都不是在对角线上的。所以色标的位置值为2除以根号2等于根号2,约等于1.414

      
1
2
3
4
5
6
      
div {
background: #58a;
background: linear-gradient(to left bottom,
transparent 50%, rgba(0, 0%, 0, .4) 0) no-repeat 100% 0 / 2em 2em,
linear-gradient(-135deg, transparent 1.5em, #58a 0);
}

5.2 其他角度

45度角的折角不是很常用,可以改变折角角度,比如-150deg可以产生30度的切角,但也意味着计算折角三角形的边长也要复杂点了。

使用三角函数计算边长,折角三角形为30-60-90的直角三角形,所以

      
1
2
3
4
      
background: #58a;
background: linear-gradient(to left bottom,
transparent 50%, rgba(0, 0, 0, .4) 0) no-repeat 100% 0 / 3em 1.73em,
linear-gradient(-150deg, transparent 1.414em, #58a 0);

这个折角并不真实,拿纸折一下就可以看出来了。

这个折角三角形需要旋转,但是背景不能旋转,可以使用伪元素。

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
      
div {
position: relative;
background: #58a;
background: linear-gradient(-150deg, transparent 1.414em, #58a 0);
}
div::before {
content: '';
position: absolute;
top: 0;right: 0;
background: linear-gradient(to left bottom,
transparent 50%, rgba(0, 0, 0, .4) 0) no-repeat 100% 0 / 3em 1.73em;
width: 3em;
height: 1.7em;
}

实现了跟上面相同的效果,然后旋转

下一步将把折页三角形的宽高对调,以此改变它 的方向,然后再逆时针30来旋转这个折页三角形。

      
1
2
3
      
height: 1.73em;
width: 3em;
transform: rotate(-30deg);

为了平移简单,将transform-origin设置为bottom right即三角形的右下角成为旋转的中心

通过图和上面数据可知,垂直偏量为x - y = 3 - √3 = 1.3.

      
1
2
3
4
5
      
div::before {
/*其他样式*/
transform: translateY(-1.3em) rotate(-30deg);
transform-origin: bottom right;
}

为了更真实一点,增加圆角,渐变以及投影。

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
      
div {
position: relative;
background: #58a;
background: linear-gradient(-150deg, transparent 1.414em, #58a 0);
border-radius: .5em;
}
div::before {
content: '';
position: absolute;
top: 0;right: 0;
background: linear-gradient(to left bottom,
transparent 50%, rgba(0, 0, 0, .2) 0, rgba(0, 0, 0, .4)) no-repeat 100% 0;
width: 1.73em;
height: 3em;
transform: translateY(-1.3em) rotate(-30deg);
transform-origin: bottom right;
border-bottom-left-radius: inherit;
box-shadow: -.2em .2em .3em -.1em rgba(0, 0, 0, .15);
}

为了方便复,可以使用scss

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
      
@mixin folded-corner($bg, $size, $angle:30deg){
position: relative;
background: $bg;
background: linear-gradient($angle - 180deg, transparent $size, $bg 0);
border-radius: .5em;
$x: $size / sin($angle);
$y: $size / cos($angle);
&::before {
content: '';
position: absolute;
top: 0;right: 0;
background: linear-gradient(to left bottom,
transparent 50%, rgba(0, 0, 0, .2) 0, rgba(0, 0, 0, .4)) no-repeat 100% 0;
width: $y
height: $x;
transform: translateY($y - $x) rotate(2*$angle - 90deg);
transform-origin: bottom right;
border-bottom-left-radius: inherit;
box-shadow: -.2em .2em .3em -.1em rgba(0, 0, 0, .2);
}
}

CSS技巧(二):形状

发表于 2017-03-27 | 分类于 前端技术 | 阅读次数 1172

形状

本章代码比较多,可以访问仓库获取源代码。

1. 自适应的椭圆

背景知识:border-radius属性的基本用法

使用border-radius制作一个圆很简单,只要给任何正方形元素设置固定宽高及一半长度以上的border-radius,就可以得到圆形

      
1
2
3
4
      
background: #fb3;
width: 200px;
height: 200px;
border-radius: 100px; /*>=正方形边长的一半*/

1.1 椭圆

在实际开发中可能更多的是让元素根据内容自动调增,而不是事先设置好宽高,因为很多时候内容是不定的。我们期望:如果宽高相等,就显示一个圆,不相等就显示一个椭圆。

上面代码实现不了,当宽度大于高度的时候,便会出现下面这种情况:

解决方案:

border-radius可以单独指定水平和垂直半径,只要用一个(/)分隔这两个值就行。还一个特性是,它可以接受长度值,还可以接受百分比,两种特性结合,就可以自适应了。

      
1
      
border-radius: 50% / 50%;

由于斜杠前后的两个值现在是一致的,可以简写

      
1
      
border-radius: 50%;

1.2 半椭圆

border-radius是一个简写属性,包含四个展开式属性,这样一来可以通过设置四个角的不同半径来达到效果。

  • border-top-left-radius
  • border-top-right-radius
  • border-bottom-right-radius
  • border-bottom-left-radius

通过属性名字可以很清楚的知道他们用于设置哪个角。

不过还是推荐使用简洁写法,因为可以向它一次性提供用空格分开的多个值。

  • 传四个值,这四个值就会被分别从左上角开始以顺时针顺序应用到各个角
  • 传三个值,则意味着第四个值与第二个值相同
  • 传两个值,意味着第三个值与第一个值相同,第四个值与第二个值相同。
  • 传一个值,全部相同。

我们甚至可以为所有四个角提供完全不同的水平和垂直半径,方法就是在斜杠前指定1~4个值,斜杠后指定1~4个值。这两组值是单独展开为四个值。

比如border-radius:10px / 5px 20px,
相当于10px 10px 10px 10px / 5px 20px 5px 20px;

两个例子:

      
1
      
border-radius:2em;

等同于

      
1
2
3
4
      
border-top-left-radius:2em;
border-top-right-radius:2em;
border-bottom-right-radius:2em;
border-bottom-left-radius:2em;
      
1
      
border-radius: 2em 1em 4em / 0.5em 3em;

等同于

      
1
2
3
4
      
border-top-left-radius: 2em 0.5em;
border-top-right-radius: 1em 3em;
border-bottom-right-radius: 4em 0.5em;
border-bottom-left-radius: 1em 3em;

我们要实现的效果

弄清了,border-radius的用法,开始分析上面半椭圆的实现

  • 这个形状是垂直对称的,意味着左上角和右上角的半径值应该相同,右下角和左下角半径也是相同
  • 顶部边缘没有平直的部分,意味着左上角和右上角半径之和应该等于整个形状的宽度,结合上一条,左半径和右半径在水平方向上是50%
  • 垂直方向,顶部的两个圆角占据了整个元素的高度,而且底部没有任何圆角,因此在垂直方向上值应该好似100% 100% 0 0
  • 因为底部两个角的垂直圆角是零,那么他们的水平圆角是多少就完全不重要了
      
1
      
border-radius: 50% / 100% 100% 0 0;

沿纵轴劈开的半椭圆

      
1
      
border-radius: 100% 0 0 100% / 50%;

1.3 四分之一椭圆

创建一个四分之一椭圆,其中一个角水平和垂直半径值都需要100%,而其他三个角都不能设为圆角

      
1
      
border-radius: 100% 0 0 0;

2. 平行四边形

背景知识:基本变形属性transform,属性很多,用到哪个讲哪个。

我们一般用skew属性来对矩形进行斜向拉伸,变成平行四边形,但是如果直接对元素使用的话,它里面的内容也会跟着斜向变动。

2.1 嵌套元素方案

对容器内容再应用一次反向的skewX()变形,从而抵消容器的变形效果

      
1
2
3
4
5
      
<a href="#" class="button">
<div>
click me
</div>
</a>

css

      
1
2
3
4
5
6
7
      
.button {
transform: skewX(-45deg);
}
.button > div {
transform: skewX(45deg);
}

skewX() 定义沿着 X 轴的 2D 倾斜转换。对应还有skewY(angle),skew(x-angle,y-angle)

2.2 伪元素方法

上面方法需要添加额外的HTML元素。这里提供一个不用添加额外的HTML元素的。

这种方法的思路是把所有的样式(背景、边框等)应用到伪元素上,然后对伪元素进行变形。

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
      
.button {
position: relative;
/* 其他的文字颜色、内外变局等样式*/
}
.button::before {
content: '';
position: absolute;
top: 0;right: 0;bottom: 0;left: 0;
z-index: -1;
background: #58a;
transform: skew(-45deg);
}

要注意几点,一是要给宿主元素设置position: relative,并给伪类元素设置position: absolute,且偏移量都为0,以便让它在水平和垂直方向上都被拉伸至宿主元素的尺寸。二是伪元素生成的方块是重叠在内容之上的,一旦设置背景,就会遮住内容,应该设置z-index: -1或者更小的数,宿主没有设置z-index默认为0;

3. 菱形图片

背景知识:css变形、“平行四边形”

3.1 基于变形的方案

思路:需要把图片用一个<div>包起来,然后对其应用相反的rotate()变形样式。

      
1
2
3
      
<div class="picture">
<img src="dog.jpg">
</div>

样式

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
      
.picture {
width: 200px;
height: 200px;
transform: rotate(45deg);
overflow: hidden;
}
.picture img {
max-width: 100%;
transform: rotate(-45deg);
}
```
并没有发生我们想象的那样,得到一个八角形,还挺好看的,哈啊。
{% asset_img 03-1.png %}
> `totate()`定义 2D 旋转,在参数中规定角度。
为了观察清楚,为容器添加边框
{% asset_img 03-2.png %}
出现这样的情况主要是`max-width:100%`,`100%`会被解析为容器(.picture)的边长,但是,我们想要图片的宽度与容器的对角线相等。通过计算可以很快计算出正方形的对角线的长度为`根号2` 乘以正方形的边长。因为`根号2`约等于`1.414`,那么可以设置max-width为`1.141 * 100%`,向上取整为142%。
但是更推荐使用scale属性把图片放大,更合理。
* 我们希望图片的尺寸保留100%这个值,这样当浏览器不支持变形样式时仍然可以得到一个合理的布局
* 通过scale变形样式来缩放图片,是以它的中心点进行缩放的。通过width属来放大图片时,只会以它的左上角为原点进行缩放,从容迫使我们动用额外的负边距来调整图片。
``` css
.picture {
width: 200px;
height: 200px;
margin: 100px;
transform: rotate(45deg);
overflow: hidden;
}
.picture img {
max-width: 100%;
transform: rotate(-45deg) scale(1.42);
}

3.2 裁剪路径方案

上面方案需要一层额外的HTML,不够简洁,还有就是如果处理一张非正方形的图片,就不会有这样的效果。

使用的属性为clip-path,裁剪路径。我们使用其中的一个属性值polygon()(多边形)来指定一个菱形。语法从SVG那借鉴过来的

clip-path还有很多强大的功能,可以自行研究,还有就是目前为止,IE11和Edge完全不支持,不过可以平稳退化。

      
1
      
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);

上面用逗号分隔,每组数据代表一个坐标点,最后连接起来,就组成一个菱形。效果和上面一样。

还可以增加动画,比如悬停的时候,让图片扩展为完整的面积。

      
1
2
3
4
5
6
7
8
9
10
11
12
      
img {
max-width: 250px;
margin: 20px;
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
transition: 1s clip-path;
}
img:hover {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}

4.切角效果

背景知识:css渐变、background-size、条纹背景

4.1 直角切角

先实现一个简单的,比如让一个矩形,右下角切掉。实现该功能可以使用强大的渐变功能,有了渐变基础,应该不难理解。

      
1
2
      
background: #58a;
background: linear-gradient(-45deg, transparent 15px, #58a 0);

background: #58a不是必须的,加上它是为了将其作为回退机制。

实现两个切角,左右下角各一个。一层渐变肯定不行,需要两层。按想法一步步实现,首先可能会这样写

      
1
2
3
      
background: #58a;
background: linear-gradient(-45deg, transparent 15px, #58a 0),
linear-gradient(45deg, transparent 15px, #655 0);

可以看到,效果并没有实现,原因是两层渐变都会填满整个元素,因此它们会相互覆盖。需要让它们缩小一点,使用background-size让每层渐变分别只占据整个元素的一半。

      
1
2
3
4
      
background: #58a;
background: linear-gradient(-45deg, transparent 15px, #58a 0) right,
linear-gradient(45deg, transparent 15px, #655 0) left;
background-size: 50% 100%;

依然没有达到效果,这是因为没有添加background-repeat属性,因而每层渐变图案各自平铺了两次。

      
1
2
3
4
5
      
background: #58a;
background: linear-gradient(-45deg, transparent 15px, #58a 0) right,
linear-gradient(45deg, transparent 15px, #655 0) left;
background-size: 50% 100%;
background-repeat: no-repeat;

好了,现在实现了。如果要四个角的话,就要四层渐变了。

      
1
2
3
4
5
6
7
      
background: #58a;
background: linear-gradient(135deg, transparent 15px, #58a 0) top left,
linear-gradient(-135deg, transparent 15px, #58a 0) top right,
linear-gradient(-45deg, transparent 15px, #58a 0) bottom right,
linear-gradient(45deg, transparent 15px, #58a 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;

注: 在chrome中运行,发现一个问题,中间会出现一条白线。其他浏览器没有,还没有找到原因,知道的话请点明一下。

上面代码的可维护性差,要改变背景的时候,需要修改好多处,可以使用预处理器。这里使用scss

      
1
2
3
4
5
6
7
8
9
      
@mixin beveled-corners($bg, $tl:0, $tr:$tl, $br:$tl, $bl:$tr) {
background: $bg;
background: linear-gradient(135deg, transparent $tl, $bg 0) top left,
linear-gradient(-135deg, transparent $tr, $bg 0) top right,
linear-gradient(-45deg, transparent $br, $bg 0) bottom right,
linear-gradient(45deg, transparent $bl, $bg 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;
}

调用的时候传入2~5个参数

      
1
      
@include beveled-corners(#58a, 15px, 5px);

4.2 弧形切角

还可以创建弧形切角(“内凹圆角”),使用径向渐变属性代替上面线性渐变。

      
1
2
3
4
5
6
7
      
background: #58a;
background:radial-gradient(circle at top left, transparent 15px, #58a 0) top left,
radial-gradient(circle at top right, transparent 15px, #58a 0) top right,
radial-gradient(circle at bottom right, transparent 15px, #58a 0) bottom right,
radial-gradient(circle at bottom left, transparent 15px, #58a 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;

上面代码中circle指定圆形的径向渐变以及位置。

效果

这里同样可以使用预处理器来封装,类似。

4.3 内联SVG与border-image方案

基于渐变的方法有几个缺点:

  • 代码繁琐冗长
  • 不能让各个切角的尺寸以动画的方式发生变化

这里提供另一种方案,使用border-image,之前有提到过基本用。

根据border-image工作原理,使用上面SVG图形就可以产生带有切角的边框。黑线是增加的辅助线,描述border-image工作原理,将背景图分成九宫格。

由于尺寸无关紧要(border-image会解决缩放问题,而SVG可以实现与尺寸完全无关的完美缩放–矢量图的好处)。每个切片的尺寸都可以设置为1,便于书写。上面就是放大的图。

      
1
2
3
4
5
      
border: 15px solid transparent;
border-image: 1 url('data:image/svg+xml,\
<svg xmlns="http://www.w3.org/2000/svg" width="3" height="3" fill="%2358a">\
<polygon points="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2" />\
</svg>');

注意:使用的切面尺寸为1,这并不代表1像素,所对应的是SVG文件的坐标系统,所以也不同单位。

切角效果出来了,但还缺少整片背景,可以指定一个背景色。还有就是切角没有之前大。原因是在渐变中,这个15px是沿着渐变轴来度量的,它的水平方向和渐变推进的方向一致。边框宽度并不是斜向度量的,而是以水平或垂直方向度量的。

和之前“条纹背景类似”,为了得到相同的尺寸,我们需要把渐变中的尺寸乘以根号2,然后才能用在边框宽度属性中。15*根号2约等于21px。

      
1
2
3
4
5
6
      
border: 21px solid transparent;
border-image: 1 url('data:image/svg+xml,\
<svg xmlns="http://www.w3.org/2000/svg" width="3" height="3" fill="%2358a">\
<polygon points="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2" />\
</svg>');
background: #58a;

啊偶,切角效果没了,换个背景色看看。

还挺好看的,切角还在。原来是因为背景色和切角边框混成一团了,使用background-clip修复。

      
1
2
3
4
5
6
7
      
border: 21px solid transparent;
border-image: 1 url('data:image/svg+xml,\
<svg xmlns="http://www.w3.org/2000/svg" width="3" height="3" fill="%2358a">\
<polygon points="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2" />\
</svg>');
background: #58a;
background-clip: padding-box;

效果出来了,还可以增加其他效果,比如背景渐变,切角动画。

4.3 裁切路径方案

boder-image也有局限。比如我们要么指定某个实色背景,要么指定一个边缘接近某个实色的背景图案。假如我们设置其他类型的背景(比如纹理、平铺图案或一道线性渐变)。

clip-path可以打破这种局限。

      
1
2
3
4
      
background: #58a;
clip-path: polygon(20px 0, calc(100% - 20px) 0, 100% 20px,
100% calc(100% - 20px), calc(100% - 20px) 100%,
20px 100%, 0 calc(100% - 20px), 0 20px);

可以使用任意背景,还可以是图片

5. 梯形标签页

背景知识:基本的3D变形,平行四边形

现实的三维世界中旋转一个矩形,由于透视的关系,我们最终看到的二维视图往往是一个梯形。

      
1
      
transform: perspective(.5em) rotateX(5deg);
  • perspective(.5em)为 3D 转换元素定义透视视图,不设置的话看不到3D效果
  • rotateX(5deg) 定义沿着 X 轴的 3D 旋转。

可以生成一个梯形,但是内部的内容不可逆转,不像2D变形。可以使用伪元素。

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
      
.tab {
margin: 3em;
position: relative;
display: inline-block;
padding: .5em 1em .35em;
color: white;
}
.tab::before {
content: '';
position: absolute;
top: 0;right: 0;bottom: 0;left: 0;
z-index: -1;
background: #58a;
transform: perspective(.5em) rotateX(5deg);
}

现在生成了一个基本的梯形,但是还有许多问题。当我们没有设置transform-origin属性时,应用变形效果会让这个元素以它自身的中心线为轴进行空间上的旋转。因此,元素投射到2D屏幕上的尺寸会发生变化。比如宽度会增加,所占位置会稍稍下移,高度会有少许缩减。

我们可以为它指定transform-origin:bottom,当在3D空间旋转的时候,可以把它的底边固定住。

      
1
2
      
transform: perspective(.5em) rotateX(5deg);
transform-origin: bottom;

这样一来只有高度会发生变化,但是高度缩水也非常明显,那么可以在垂直方向使用scaleY()进行放大。

      
1
2
      
transform:scaleY(1.3) perspective(.5em) rotateX(5deg);
transform-origin: bottom;

使用这个技巧随后为标签页添加样式就变得很方便,

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
      
nav > a {
position: relative;
display: inline-block;
padding: .3em 1em 0;
}
nav > a::before {
content: '';
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
z-index: -1;
border-bottom: none;
border-radius: .5em .5em 0 0;
background: #ccc linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,0));
box-shadow: 0 .15em white inset;
transform: scale(1.1, 1.3) perspective(.5em) rotateX(5deg);
transform-origin: bottom;
}

我们给它添加了背景、边框、圆角、投影等样式,都可以完美生效,我们还可以通过设置background-origin为bottom left或bottom right,就可以得到左倾斜或右倾斜的标签页。具体代码可以查看仓库。

6. 简单的饼图

背景知识:css渐变、基本的SVG、css动画、条纹背景、自适应椭圆

基于transform的解决方案

这个方案的解构层上是最佳选择,只需要一个元素作为容器,其余部分用伪元素、变形属性和css渐变完成。

      
1
      
<div class="pie"></div>

画一个简单饼图,展示比率是固定的20%。先画一个圆

      
1
2
3
4
5
6
      
.pie {
width: 100px;
height: 100px;
border-radius: 50%;
background:yellowgreen;
}

我们用yellowgreen#655两种颜色分别作为背景色和显示比率色,把圆形左右两部分指定为上述两种颜色,然后用伪元素覆盖上去,通过旋转来决定露出多大的扇形。

将右半部分设置为棕色,通过线性渐变

      
1
      
background-image: linear-gradient(to right, transparent 50%, #655 0);

设置伪元素,覆盖

      
1
2
3
4
5
6
      
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
}

给伪元素添加边框可以看到,伪元素现在相对于整个饼图进行了重叠。不过现在还没有设置样式,它起不到遮盖作用:暂时是个透明的矩形。

观察和分析:

  • 希望这个伪元素能遮盖住圆形中的棕色部分,应该制定绿色背景。使用background-color:inherit声明可以避免代码重复
  • 希望它是绕着圆形的圆心来旋转的,对它自己来说,这个点就是它左边缘的中心点。可以写成transform-origin:left
  • 不希望呈现出矩形的形状,否则它会突破整个饼图的圆形范围,于是给.pie设置overflow:hidden,要么给这个伪元素指定合适的border-radius来变成一个半圆。
      
1
2
3
4
5
6
7
8
9
      
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: inherit;
transform-origin: left;
}

好了,现在覆盖住了。现在我们可以通过一个rotate()变形属性来让这个伪元素转起来。如果我们要显示20%的比率,可以指定旋转的值为72deg(0.2*360=72),写成.2turn(圈)更加直观。

      
1
      
transform: rotate(.2turn);

可以显示了,我们在0到50%的比率时都可以正常,但是超过50%后,比如60%的时候,就会是这样

如果把50%~100%的比率看所另外一个问题,我们可以发现,可以使用上述技巧的一个反向版本来实现这个范围,设置一个棕色的伪元素,让它在0至.5turn的范围内旋转。因此要得到一个60%比率的饼图,可以这样

      
1
2
3
4
5
6
7
8
9
10
11
      
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background: #655;
transform-origin: left;
transform: rotate(.1turn);
}

由于找到了实现任意值比率的方法,我们可以用css动画来实现一个饼图从0变化到100%的动画,从而得到一个炫酷的进度指示器

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
      
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: inherit;
transform-origin: left;
animation: spin 3s linear infinite,
bg 6s step-end infinite;
}
@keyframes spin {
to { transform: rotate(.5turn); }
}
@keyframes bg {
50% { background: #655; }
}

但是怎么做出多个不同比率的静态饼图呢?

我们希望这种方式来书写结构

      
1
2
      
<div class="pie">20%</div>
<div class="pie">60%</div>

就能得到两个饼图,一个展示为20%和一个展示为60%。探索如何用内联样式来实现这个需求,再通过一小段脚本代码来解析文本内容并把内联样式添加到元素上去,以实现代码的优雅性、封装抽象性、可维护性以及最重要的可访问性。

用内联样式来控制饼图的比率有一个很大的挑战:这些负责设置比率的css代码最终要应用到伪元素身上,无法为伪元素设置内联样式。

用动画的方法来解决(眼珠子都掉下来,动画还有这功能),不过动画必须处于暂停状态。使用负的动画延时来直接调至动画中任意的时间点。看看负animation-delay的解释

“一个负的延时值是合法的,与0s的延时类似,它意味着动画会立即开始播放,但会自动前进到延时值的绝对定位处,就好像动画在过去已经播放了指定的时间一样。因此实际效果就是动画跳过指定的时间而从中间开始播放了”

我们动画是暂停的,所以动画的第一帧将是唯一显示出的那一帧。在饼图中显示出的比率就是我们animation-delay的值在总动画持续时间中所占比率。比如,如果动画持续时间是6s,只需要把animation-delay的值设为-1.2s,就能显示出20%的比率。为了简化计算过程,设置一个长达100s的持续时间。动画是暂停的,不会有影响。

最后一个问题:动画是作用在伪元素上的,但希望最终内联样式可以设置在.pie上,由于div上没有任何动画效果,我们可以用内联样式的方式为其设置animation-delay属性,然后伪元素inherit继承。

结构代码

      
1
2
      
<div class="pie" style="animation-delay: -20s">20%</div>
<div class="pie" style="animation-delay: -60s">20%</div>

.pie代码不变,变化的代码下面显示

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
      
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: inherit;
transform-origin: left;
animation: spin 50s linear infinite,
bg 100s step-end infinite;
animation-play-state: paused;
animation-delay: inherit;
}
@keyframes spin {
to { transform: rotate(.5turn); }
}
@keyframes bg {
50% { background: #655; }
}

脚本代码

      
1
2
3
4
5
      
const pie = document.querySelectorAll('.pie');
pie.forEach(pie => {
const p = parseFloat(pie.textContent);
pie.style.animationDelay = `-${p}s`;
})

结构代码

      
1
2
      
<div class="pie">20%</div>
<div class="pie">60%</div>

我们保留了文字,因为需要它来确保可访问性和可用性。可以通过color:transparent来把文字隐藏起来,同时还保证了可访问性,因为文字仍然是可以被选中和打印的,进一步优化,把文字比率放在饼图中心,方便选中

  • 把饼图的height换成line-height
  • 通过绝对定位来完成对伪元素尺寸的尺寸设置和定位操作,这样它就不会把文字推到下面了
  • 增加text-align:center来实现居中

最终代码

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
      
.pie {
margin: 50px;
position: relative;
line-height: 100px;
width: 100px;
border-radius: 50%;
background:yellowgreen;
background-image: linear-gradient(to right, transparent 50%, #655 0);
color: transparent;
text-align: center;
}
.pie::before {
content: '';
position: absolute;
top:0;left:50%;
width: 50%;height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: inherit;
transform-origin: left;
animation: spin 50s linear infinite,
bg 100s step-end infinite;
animation-play-state: paused;
animation-delay: inherit;
}
@keyframes spin {
to { transform: rotate(.5turn); }
}
@keyframes bg {
50% { background: #655; }
}

CSS技巧(一):背景与边框

发表于 2017-03-24 | 分类于 前端技术 | 阅读次数 1528

该系列为《css揭秘》读书笔记,归纳主要知识点,通过实战技巧深入css属性,加以巩固。

背景与边框

1.半透明边框

背景知识:rgba/hsla,在rgb/hsl的基础上增加了Alpha通道,用于设置颜色的不透明度(就是能透过多少背景)

  • rgba接受四个数值,即rgba(red, green, blue,a),rgb可以为数值(0 ~ 255),也可以为百分比(0 ~ 100%),a表示不透明度(0~1),1为完全不透明,0表示完全透明。
    rgba(0,255,0,1) 表示纯绿色,完全不透明

    rgba(100%,0,0,0.5)表示纯红色,半透明

  • hsla(色相, 饱和度%, 亮度%,透明度),格式为hsla(0, 0%,0%,0)
    hsla的第一个值表示色相,也就是一个实际的颜色,比如红色或者绿色。所有的颜色绕色相环(色轮)一周,色相值以圆周上的度数表示。

    色轮

    红色是0或360,青色是180.以下是彩虹七色在色轮中的大致色相值。
    红:0;橙:35;黄:60;绿:125;蓝:230;靛:280;紫:305;

  • 饱和度设定有多少颜色,灰色的饱和度低,而强烈的色彩饱和度高

  • 亮度设定颜色的明暗,0%就是黑色,100%就是白色

难题

设计一个带有半透明边框的容器,可能很多人会这样写

border: 10px solid hsla(0, 0%, 100%, 0.5);
background: white;

但是实际情况,半透明的边框并不会显现出来。在边框中使用半透明并没有想象中的那么容易

解决方案

出现这种情况是,背景会默认延伸到边框所在的区域下面。可以使用background-clip属性来处理。

background-clip 设置元素的背景(背景图片或颜色)是否延伸到边框下面,有三个可选值,默认为border-box

  • border-box
    背景延伸到边框外沿(但是在边框之下)。

  • padding-box
    边框下面没有背景,即背景延伸到内边距外沿。

  • content-box
    背景裁剪到内容区 (content-box) 外沿。

有了这个属性可以很快解决这个问题了

border: 10px solid hsla(0, 0%, 100%, 0.5);
background: white;
background-clip: padding-box;

2. 多重边框

背景知识:box-shadow 描述阴影效果

2.1 使用box-shadow来制作多重边框

background: yellowgreen;
box-shadow: 0 0 0 10px #655,0 0 0 15px deeppink,0 2px 5px 15px rgba(0, 0, 0, .6)
  • 第一个length参数设置水平偏移量,如果是负值则阴影位于元素左边;
  • 第二个设置垂直偏移量,如果是负值则阴影位于元素上面。
  • 第三个值越大,模糊面积越大,阴影就越大越淡。 不能为负值。
  • 第四个取正值时,阴影扩大;取负值时,阴影.收缩
  • 第五个参数为颜色
  • 还有一个参数用来设置阴影位置,默认在边框外,在最前面设置inset让阴影在边框内

用border同样可以达到此效果,只不过更麻烦。用box-shadow通过逗号分隔可以创建任意数量的投影。

2.2 通过outline制作

使用下面代码同样可以实现

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

outline还可以有一个好处就是可以制作虚线边框,还可以通过outline-offset属性来控制它跟元素边缘之间的距离,接受负值。

background: black;
outline: 1px dashed white;
outline-offset: -10px;

3. 灵活的背景定位

以往针对容器某个角对背景图片做偏移定位的时候,一般是这样写

      
1
      
background-position:bottom right

或者使用百分比数值代替bottom和right,但是还有更好的方案

3.1 background-position的扩展语法方案

允许我们指定背景图片距离任意角的偏移量,只要在偏移量前面指定关键字

      
1
2
3
      
background: url(http://csssecrets.io/images/code-pirate.svg)
no-repeat bottom right #58a;
background-position: right 20px bottom 10px;

上面的代码表示背景图片跟右边缘保持20px,同时跟底部保持10px;background属性里面的设置用于回退。

3.2 background-origin方案

此方案用于更好的解决背景图片偏移量和容器的内边距一样时的问题。

  • border-box
    背景将会延伸到延伸到外边界的边框

  • padding-box
    背景描绘在padding盒子,边框里不会有背景出现。同样,背景将会延伸到最外边界的padding.

  • content-box
    背景描绘在内容区范围.

background-origin设置成content-box即可

      
1
2
3
4
      
padding: 10px;
background: url(http://csssecrets.io/images/code-pirate.svg)
no-repeat bottom right #58a;
background-origin: content-box;

3.3 calc()方案

      
1
      
background-position: calc(100% - 20px) calc(100% - 10px)

4.边框内圆角

这个效果按自己的思路都可以实现。我的第一反应也是使用两个元素实现。

      
1
2
3
      
<div class="something-meaningful">
<div>I have a nice subtle inner rounding, don’t I look pretty?</div>
</div>
      
1
2
3
4
5
6
7
8
9
10
      
.something-meaningful {
background: #655;
padding: .8em;
}
.something-meaningful > div {
background: tan;
border-radius: .8em;
padding: 1em;
}

当然这本书上肯定要讲述比较独特的方法实现。利用outline和box-shadow属性,只需写一个html属性即可

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

分析其原理:

  • outline描边并不会跟着圆角走,当只是用outline的时候,圆角跟直角处有空隙

  • box-shadow会跟着圆角走,当只是用box-shadow的时候没有直角

于是正好可以使用box-shadow来填充那部分空隙

5. 条纹图案

背景知识: 线性渐变linear-gradientbackground-size

  • background-size 设置背景图片大小,有多种写法

    • 使用关键字:background-size: cover,表示缩放背景图片以完全覆盖背景区,可能背景图片部分看不见。还有background-size: contain,缩放背景图片以完全装入背景区,可能背景区部分空白。
    • 使用一个值:background-size: 3em;这个值指定图片的宽度,图片的高度隐式的为auto,还可以使用百分比。
    • 两个值:background-size: 3em 25%,第一个值指定图片的宽度,第二个值指定图片的高度。可为数值,可为百分比。
    • 逗号分隔的多个值:设置多重背景

5.1垂直条纹

尝试一个基本线性渐变

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

最终效果是从上到下,第一个颜色渐变到第二个颜色

添加数值,指定被填充的区域

      
1
      
background: linear-gradient(#fb3 20%, #58a 80%);

可以看到渐变的区域变小了

把区域设为50%

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

发现已经看不到渐变区域了,如果多个色标具有相同的位置,它们会产生一个无限小的过渡区域,过度的起止变化分别是第一个和最后一个指定值,从效果上看,颜色会在那突然变化,而不是一个平滑的过度。

那么知道这个就可以配合background-size

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

我们把两条条纹的高度设置成15px,由于背景默认是平铺的,整个容器也被填满了。

还可以创建不等宽的条纹

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

如果某个色标的位置值比整个列表中在它之前的色标的位置的值都要小,则该色标的位置值会被设置为它前面所有色标位置的最大值。所以利用这个特性,可以不用每次都修改两个数

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

创建超过两种颜色的条纹

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

5.2垂直条纹

原理一样,稍微调整即可

      
1
2
      
background: linear-gradient(to right, #fb3 50%, #58a 0);
background-size: 30px 100%;

通过 to right 改变渐变的起始位置,也可以写成角度,这里可以写90deg
另外background-size的数值也要调换

5.3 斜向条纹

使用repeating-linear-gradient快速构建

      
1
      
background: repeating-linear-gradient(45deg, #fb3, #58a 30px);

可以很方便的变换想要的图形

      
1
      
background: repeating-linear-gradient(60deg, #fb3, #fb3 15px, #58a 0, #58a 30px);

5.4 灵活的同色系条纹

很多情况下,我们想要的条纹图案是由同一系色组成,只是在明暗方面有些差异。

      
1
      
background: repeating-linear-gradient(30deg, #79b, #79b 15px, #58a 0, #58a 30px);

但是上面写法想要修改的时候需要修改四处颜色,改进的办法

      
1
2
3
4
5
      
background: #58a;
background-image: repeating-linear-gradient(30deg,
hsla(0,0%,100%,.1),
hsla(0,0%,100%,.1),15px,
transparent 0, transparent 30px);

这里把最深的颜色作为背景色,同时把半透明白色的条纹叠加在背景之上来得到浅色条纹。这样每次只要修改背景色就可以了。

6.复杂的背景图案

背景知识:css渐变, “条纹背景”

6.1 网格

把多个渐变图案组合起来,让它们透过彼此的透明区域显现时,就会得到意想不到的图案。

      
1
2
3
4
      
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;

有些时候我们希望网格中每个格子的大小可以调整,而网格线条的粗细同时保持固定。下面展示了使用长度而不是百分比作为色标的场景

      
1
2
3
4
      
background: #58a;
background-image: linear-gradient(white 1px, transparent 0),
linear-gradient(90deg, white 1px, transparent 0);
background-size: 30px 30px;

还可以把两幅不同线宽、不同颜色的网格图案叠加起来

      
1
2
3
4
5
6
      
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;

6.2 波点

波点是利用径向渐变知识。下面是一个简单的径向渐变

      
1
2
3
      
background: #655;
background-image: radial-gradient(tan 30%, transparent 0);
background-size: 30px 30px;

这里的径向渐变由每个小方块的中心向四周渐变,也就是background-size指定的大小。

下面是一种更加使用的图案:

      
1
2
3
4
5
      
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属性将两个背景位置错开,第一个值表示水平位置,第二个表示垂直位置,用逗号分隔设置多重。

因为为了达到效果,第二层背景的偏移定位值必须是平铺图案中的每个基本单元宽高的一半,每次修改要修改多处尺寸,可以使用scss

      
1
2
3
4
5
6
7
      
@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;
}
      
1
      
@include polka(30px, 30%, #655, tan)

6.3 棋盘

一步一步制作棋盘,首先回想一下制作三角形图案。要制作类似下面这张图案

      
1
2
3
      
background: #eee;
background-image: linear-gradient(45deg, #bbb 50%, transparent 0);
background-size: 30px 30px;

每个三角形占据每个单元的一般,修改色标位置为25%。

我们把色标的顺序反转,便可以创建相反方向的三角形了

      
1
2
3
      
background: #eee;
background-image: linear-gradient(45deg, transparent 75%, #bbb 0);
background-size: 30px 30px;

组合起来的图形

      
1
2
3
4
      
background: #eee;
background-image: linear-gradient(45deg, transparent 75%, #bbb 0),
linear-gradient(45deg, #bbb 25%, transparent 0);
background-size: 30px 30px;

现在只需要把第二层渐变在水平和垂直方向均移动每个单元的一半,就可以拼接起来。

      
1
2
3
4
5
      
background: #eee;
background-image: linear-gradient(45deg, #bbb 25%, transparent 0),
linear-gradient(45deg, transparent 75%, #bbb 0);
background-size: 30px 30px;
background-position: 0 0, 15px 15px;

产生出了一个正方形,本质上是棋盘的一半,复制一份再创建出另一组正方形。

      
1
2
3
4
5
6
7
      
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-size: 30px 30px;
background-position: 0 0, 15px 15px,15px 15px, 30px 30px;

代码进行优化,可以把这些处在单元顶角的三角形两两组合起来(即把第一组和第二组并为一层渐变,第三组和第四组为一层渐变)

      
1
2
3
4
5
6
7
      
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;

使用scss

      
1
2
3
4
5
6
7
8
9
      
@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: $size*2 $size*2;
}
      
1
      
@include checkerboard(15px, #58a, tan);

7. 伪随机背景

重复平铺的几何图案很美观,但是看起来和你呆板。用css实现图案的随机平铺。

      
1
2
3
      
background: linear-gradient(90deg, #fb3 15%, #655 0, #655 40%,
#ab4 0, #ab4 65%, hsl(20, 40%, 90%) 0);
background-size: 80px 100%;

上面通过background-size来控制图案每隔80px重复一次。规律比较明显,并不是真实的随机平铺。

接下来,把这组条纹从一个平面拆散为多个层面:一种颜色作为底色,另外三种颜色作为条纹,然后再让条纹以不同的间隔进行重复平铺。在色标中定好边框的宽度,用background-size来控制条纹的间距

      
1
2
3
4
5
6
      
background: hsl(20, 40%, 90%);
background-image:
linear-gradient(90deg, #fb3 10px, transparent 0),
linear-gradient(90deg, #ab4 20px, transparent 0),
linear-gradient(90deg, #655 20px, transparent 0);
background-size: 80px 100%, 60px 100%, 40px 100%;

但是这里还有一个问题,每隔240px还是会重复一次,红色箭头处。这里每次重复单元正好是background-size的最小公倍数,而40、60、80的最小公倍数就是240。

根据这个逻辑,可以把每个重复单元的尺寸最大化,也就是最小公倍数最大化。为了让最小公倍数最大化,这些数字最好是相对质数(比如,10和27不是质数,但他们是相对质数,最小公倍数为10乘以27)。要达成相对质数,尽量选择质数,于是下面代码

      
1
2
3
4
5
6
      
background: hsl(20, 40%, 90%);
background-image:
linear-gradient(90deg, #fb3 11px, transparent 0),
linear-gradient(90deg, #ab4 23px, transparent 0),
linear-gradient(90deg, #655 41px, transparent 0);
background-size: 41px 100%, 61px 100%, 83px 100%;

再想让它重复,早就超出屏幕的分辨率了。

这个技巧被Alex Walker定名为“蝉原则”,通过质数来增加随机真实性。还可以用于其他涉及有规律重复的情况

  • 在图片库中,为每幅图片用细微的伪随机旋转效果时,可以使用:neth-child(a)选择符,且让a是质数。
  • 如果要生成一个动画,而且让它看起来不是按照明显的规律在循环时,可以应用多个时长为质数的动画。

8. 连续的图像边框

背景知识:css渐变、border-image、条纹背景、基本的css动画

  • border-image:指定作为元素周围边框的图像。基本原理就是九宫格伸缩法,把图片切割成九块,然后把它们应用到边框相应的边和角。结合实例继续说明

有时候我们想把一幅图案或图片应用为边框,而不是背景。一个元素有一圈装饰性的边框,基本上就是一张图片被裁剪进了边框所在的方环区域,不仅如此,还希望这个元素的尺寸在扩大或缩小的时候,这幅图片都可以自动延伸并覆盖完整的边框区域。

最简单的办法就是使用连个HTML元素,一个元素用来把图片设为背景,另一个元素存放内容

      
1
2
3
4
5
      
<div class="something">
<div>I have a nice stone art border,
don't I look pertty?
</div>
</div>
      
1
2
3
4
5
6
7
8
9
10
11
      
.something {
background: url('http://csssecrets.io/images/stone-art.jpg');
background-size: cover;
padding: 1em;
}
.something > div {
background: white;
padding: 1em;
}

如何改进,使用一个元素?
思路:在背景图片之上,再叠加一层纯白的实色背景,为了让下层的图片背景透过边框区域显现出来,需要给两层背景指定不同的background-clip值,最后一个要点在于,我们只能在多重背景的最底层设置背景色,因此需要一道从白色过渡到白色的css渐变来模拟纯白实色背景的效果

      
1
2
3
4
5
6
      
padding: 1em;
border: 1em solid transparent;
background: linear-gradient(white, white),
url('http://csssecrets.io/images/stone-art.jpg');
background-size: cover;
background-clip: padding-box, border-box;

发现效果很接近,但是边框的图片有一种怪异的拼接效果。原因是background-origin的默认值是paddin-box,因此,图片的显示尺寸不仅取决于padding box的尺寸,而且被放置在了padding box的原点(左上角)。我们看到的实际上就是背景图片以平铺的方式蔓延到border box区域的效果。修改即可

      
1
2
3
4
5
6
7
      
padding: 1em;
border: 1em solid transparent;
background: linear-gradient(white, white),
url('http://csssecrets.io/images/stone-art.jpg');
background-size: cover;
background-clip: padding-box, border-box;
background-origin:border-box;

简写属性

      
1
2
3
      
background:
linear-gradient(white, white) padding-box,
url('http://csssecrets.io/images/stone-art.jpg') border-box 0 / cover;

这个技巧还可以运用到渐图案上,比如制作一个老式信封

      
1
2
3
4
5
      
padding: 1em;
border: 1em solid transparent;
background: linear-gradient(white,white) 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 / 5em 5em;

上面例子可以很容易的通过background-size属性来改变条纹的宽度,通过border属性来改变整个边框的厚度。还可以用border-image来实现。

      
1
2
3
4
      
padding: 1em;
border: 16px solid transparent;
border-image: 16 repeating-linear-gradient(-45deg, red 0, red 1em, transparent 0,
transparent 2em, #58a 0, #58a 3em, transparent 0, transparent 4em);

border-image也是一个复合属性,包含下面属性

  • border-image-source:用在边框的图片的路径
  • border-image-slice:图片边框向内偏移
  • border-image-width:图片边框的宽度
  • border-image-outset:边框图像区域超出边框的量
  • border-image-repeat:图像边框是否应平铺(repeated)、铺满(rounded)或拉伸(stretched)

上面例子使用border-image实现,存在一些问题

  • 每当我们改变border-image-slice时,都要同时修改border-width来让它们匹配
  • 由于不能在border-image-slice属性中使用em单位,只能把边框厚度指定为像素单位
  • 条纹的宽度需要在色标的位置信息中写好。

制作蚂蚁行军边框

将边框的宽度减少至1px,修改条纹颜色,便可以出现虚线边框,然后background-size改为某个合适的值。添加动画

      
1
      
@keyframes ants { to {background-position: 100%} }
      
1
2
3
4
5
6
      
padding: 1em;
border: 1px solid transparent;
background:
linear-gradient(white, white) padding-box,
repeating-linear-gradient(-45deg, black 0, black 25%, white 0, white 50%) 0 /.6em .6em;
animation: ants 12s linear infinite;

border-image也有它强大之处,尤其是在搭配渐变图案时。比如我们需要一个顶部边框被裁切的效果,就像一般的脚注一样。我们所需要的就是在border-image属性再加上一条由渐变生成的垂直条纹,并把要裁剪的长度在渐变中写好,边框的粗细由border-width来控制。

      
1
2
3
      
border-top: .15em solid transparent;
border-image: 100% 0 0 linear-gradient(90deg, currentColor 4em, transparent 0);
padding-top: .5em;

使用了currentColor属性,会根据color属性的变化而自动适应(假设我们希望这条边框跟文字保持相同颜色)

correntColor:这是css3中一个颜色的关键字,这个关键字并没有绑定到一个固定的颜色,而是一直被解析为color。

假如我们想要所有水平割线自动与文本颜色保持一致。可以这么写

      
1
2
3
4
      
hr {
height: .5em;
background: currentColor;
}

很多已有的属性也具有类似的行为。如果你没有给边框指定颜色,它会自动从文本颜色那里得到颜色。

仓库代码地址

Vue全家桶新手入门项目,简易版hacker-news

前言

学了一段时间的Vue.js,用起来感觉很顺手,于是用vue全家桶写了这个简单的项目,加以巩固自家的知识以及发现自己的不足。

由于是第一次分享代码,自己也没有什么项目经验,希望有大神可以指点一二,也希望通过这个项目给新人一点启发,共同进步。

功能介绍

  • 主要是通过获取hacker-news的api来实现数据的展示,当然只是简单的处理,没有深入。
  • 新闻的点赞,隐藏
  • 评论的展示
  • 本地存储实现简单登录,主要是为了体验在vuex下的数据双向绑定
  • 还有些功能没有做,比如查询等。用到了Vue的很多基础的常用方法来编写代码,代码可能不会很优美,但也是用我现在最大能力去编写的。

效果展示

界面展示

评论

简单登录

更多详情

github地址:源代码

注:转载自微博

CSS技巧之视觉效果相关推荐

  1. 学无止境的CSS(xHTML+CSS技巧教程资源大全)

    本文里面收集一些有关CSS的技巧.教程.工具和观点等,其中一些你也许早就运用的炉火纯青,也可能有的你听都没听说过.不管是新手还是高手,大家都继续学习吧. 一,Web 标准 要玩游戏,就得先了解规则.要 ...

  2. 【经典】CSS技巧教程资源大全

    一,Web 标准 要玩游戏,就得先了解规则.要学CSS,就应该先了解一下Web标准.尽管看上去不是必须的(我在学CSS之前,根本不知道也不想知道Web标准是 个啥玩意儿).应该说,你是否学Web标准, ...

  3. 60+CSS技巧教程资源大全

    一,Web 标准 要玩游戏,就得先了解规则.要学CSS,就应该先了解一下Web标准.尽管看上去不是必须的(我在学CSS之前,根本不知道也不想知道Web标准是个啥玩意儿).应该说,你是否学Web标准,跟 ...

  4. 你应该知道的25个非常有用的CSS技巧

    在我们的前端CSS编码当中,经常要设置特殊的字体效果,边框圆角等等,还要考虑兼容性的问题, CSS网页布局,说难,其实很简单.说它容易,往往有很多问题困扰着新手,在中介绍了非常多的技巧,这些小技巧与知 ...

  5. [css] 举例说明你知道的css技巧有哪些?

    [css] 举例说明你知道的css技巧有哪些? /* 等比例容器 */ .ratio { position: relative; display: block; } .ratio:before { c ...

  6. css label 居中布局_用好这20个css技巧快速提升你的CSS技能

    点击右上方红色按钮关注"web秀",让你真正秀起来 前言 随着前端开发越来越关注效率:通过选择器的使用和简化代码来快速加载渲染.像Less.SCSS这样的预处理器在工作的时候,需要 ...

  7. 如何提升你的CSS技能?掌握这20个css技巧即可[完整版]

    前言 随着前端开发越来越关注效率:通过选择器的使用和简化代码来快速加载渲染.像Less.SCSS这样的预处理器在工作的时候,需要绕的路较长,而直接使用css速度会更快.这里涵盖了20个css技巧来帮助 ...

  8. css设置按钮竖直方向居中_前端设计师必须知道的10个重要的CSS技巧

    对于一个初入门的前端设计师,在设计修改网站前端的时候,我们需要编写一些CSS.JS的内容达到界面效果.今天分享10个对于前端设计师来说重要的CSS技巧,这也是我在给许多客户做网站的过程当中总结出来的. ...

  9. 给商品评分效果,CSS技巧

    像这种给商品评分的效果,基本上所有电商网站都有.这里写这个效果的时候运用到了一些CSS技巧.结合posiiton,z-index,background-p_w_picpath,background-p ...

最新文章

  1. 精密单电源虚拟地芯片 TLE2426
  2. CKfinder2.0.2版本破解
  3. IIS环境下如何批量添加、修改、删除绑定的域名
  4. 随机数范围扩展方法总结
  5. 对python编程做介绍-python002-编程语言介绍
  6. android 消息列表,[Android]用LinearLayout 实现类微信消息列表项
  7. 本文介绍使用OpenCV-Python进行形态学处理
  8. 双层板在哪层覆铜_2020年中国印制电路板行业发展现状及发展趋势预测(图)...
  9. matlab中值滤波实现
  10. Dilated Convolution(空洞卷积、膨胀卷积)详解
  11. 锤子t1android驱动,锤子坚果R1驱动
  12. java pfx_如何在Java中读取.pfx文件的内容?
  13. 解决react native打包apk文件安装好之后进入应用闪退的问题
  14. 电脑一夜之间变卡的问题
  15. android实现多画面播放,Android实现炫酷播放效果
  16. Linux命令(13)——实时监控进程、监控网络
  17. 躲避雪糕刺客?通过爬虫爬取雪糕价格
  18. PMP第八章:项目质量管理
  19. 【安全狐】CVE-2016-3088_ActiveMQ任意文件写入漏洞
  20. PyCharm基本配置:设置绿色护眼绿豆沙背景等

热门文章

  1. 【JavaWeb】文件上传下载(213-221)
  2. 51LED呼吸灯(完整代码可附赠Proteus仿真)
  3. Node.js:浅析高并发与分布式集群
  4. 嵌入式顶级程序员_3D打印的顶级开放式创新
  5. h5背景音乐播放代码
  6. 51 信用卡管家 Android 客户端内部数据库文件可被盗取
  7. 【ABTest】一款简单易用的ABTest开源库
  8. 关于淘宝联盟的接口调用报错问题
  9. c语言管理系统开发,日记管理系统的开发(C语言版)
  10. CMake Error: The source directory “/~./opencv-4.5.0/build“ does not appear to contain CMakeLists.tx