目标
需要实现如下的效果
要求
- 要求内容能够自适应,比如添加步骤5、步骤6, 内容能够自动等宽,而不是手动修改width;
- 步骤之间的横线也要自适应,能够随着页面宽度的拉伸而伸长;
- 步骤数字能够自动计算,而不是手动修改添加;
- 良好的语义化
思路
- 页面布局使用 ul li;
- 步骤圆的效果使用 box-shadow ,或者 使用 两个标签叠加,或者 使用 渐变( radial-gradient ,但这种实现方式锯齿很严重,放弃),这里用 box-shadow实现;
- 内容自适应使用 flex 的 flex-grow;
- 步骤数字自动计算使用 counter;
- 步骤内的数字、步骤下面的文字、圆形状以及横线都使用伪类实现;
提示:下面展现的代码是基于上一步骤的代码进行累加的。
实现
-
基本布局,实现内容自适应
1 <ul> 2 <!-- 第一步 --> 3 <li> 4 </li> 5 <!-- 第二步 --> 6 <li> 7 </li> 8 <!-- 第三步 --> 9 <li> 10 </li> 11 <!-- 第四步 --> 12 <li> 13 </li> 14 </ul>
首先整体的内容自适应 css 如下
1 ul { 2 list-style: none; /* 取消默认样式 */ 3 display: flex; /* 使用flex */ 4 } 5 6 ul li { 7 flex-grow: 1; 8 }
设置上面的CSS后,不管添加多少个 li ,都会均匀分布。
-
实现步骤圆
因为 li 标签的宽度是等分的,并且没有高度,如果直接给 li 设置 box-shadow 以及 border-radius,就会出现下面的效果。
li 不仅 宽度太大,也没有高度,如果手动设置widht 以及 height 就会打破内容自适应的效果,所以需要在 li 下添加额外的标签或者使用伪类来实现。
为了html结构的精简,这里使用伪类实现。如下:
1 ul li::before { 2 content: ""; 3 width: 3rem; /* 步骤圆的宽 */ 4 height: 3rem; /* 步骤圆的高 */ 5 background: #bcbcbc; /* 里面的小圆 */ 6 box-shadow: 0 0 0 0.5rem #bcbcbc, 0 0 0 1rem transparent; /* 两层投影 改变投影颜色就可以实现步骤的不同状态 这里默认未完成状态 */ 7 border-radius: 50%; /* 设置形状为原型 */ 8 margin: 1rem; /* 没有设置margin的话,会位置不正确,因为投影不占用位置,而这里投影确实需要占用,所以手动给margin */ 9 display: block; /* 需要设置为块级 不然不生效*/ 10 }
效果有了,但貌似圆不是在中心位置,需要在伪类的父级元素设置 ,使伪类居中,这里使用 felx的当时居中,如下:
/* 在 ul li 中添加 */ display: flex; justify-content: center; /* 现阶段 ul li 完整如下 */ ul li { flex-grow: 1; display: flex; justify-content: center; }
已经居中了。
-
实现步骤内的数字
数字自动计算使用 counter,所以需要在 li 的 父级,也就是 ul , 声明一个counter变量,在 ul 中 添加 counter-reset: steps; ,并且在 li 的伪类 before 中使用counter,代码如下:
/* ul 现阶段完整样式*/ ul { list-style: none; /* 取消默认样式 */ display: flex; /* 使用flex */ counter-reset: steps; /* 声明counter变量,名为 steps */ } /* ul li::before 中使用counter */ counter-increment: steps; /* 使 steps 自增 */ content: counter(steps); /* 修改content的内容为steps的值 */ /* ul li::before 现阶段完整样式*/ ul li::before { width: 3rem; /* 步骤圆的宽 */ height: 3rem; /* 步骤圆的高 */ background: #bcbcbc; /* 里面的小圆 */ box-shadow: 0 0 0 0.5rem #bcbcbc, 0 0 0 1rem transparent; /* 两层投影 改变投影颜色就可以实现步骤的不同状态 这里默认未完成状态 */ border-radius: 50%; /* 设置形状为原型 */ margin: 1rem; /* 没有设置margin的话,会位置不正确,因为投影不占用位置,而这里投影确实需要占用,所以手动给margin */ display: block; /* 需要设置为块级 不然不生效*/ counter-increment: steps; /* 使 steps 自增 */ content: counter(steps); /* 修改content的内容为steps的值 */ /* 使 步骤数字水平垂直居中,并设置字号 */ display: flex; color: white; justify-content: center; align-items: center; font-size: 1.5rem; }
-
实现步骤横线
同样使用伪类实现,样式如下:
ul li:nth-child(n+2):after { content: ''; height: .3rem; width: 100%; background: #bcbcbc; }
ul li:nth-child(n+2) : 选择除了第一个li标签以外的所有 li。
这还不够,会发现效果相差极大
横线与步骤圆挤在一起,需要将横线脱离出来,并且定位到中间。使用 position,样式如下:
ul li:nth-child(n+2):after { content: ''; height: .3rem; width: 100%; background: #bcbcbc; position: absolute; left: -50%; /* 刚好以圆中心从右往左 */ } /* 并且需要以 li 为相对位置,所以需要在 ul li 中 添加 position: relative; */ ul li { flex-grow: 1; display: flex; justify-content: center; position: relative; }
上述实现后,横线不是垂直居中,这里直接在 ul li 中直接使用 align-items: center; 进行垂直居中
/* ul li 现阶段完整样式 */ ul li { flex-grow: 1; display: flex; justify-content: center; position: relative; align-items: center; }
这里横线覆盖了数字,在before那里设置z-index即可。就不展示样式了。
-
实现步骤文字
这里同样使用伪类实现,但需要在 li 下添加额外标签,html 如下:
<ul> <!-- 第一步 --> <li> <div></div> </li> <!-- 第二步 --> <li> <div></div> </li> <!-- 第三步 --> <li> <div></div> </li> <!-- 第四步 --> <li> <div></div> </li> </ul>
样式如下:
ul li div { color: black; /* 设置文字颜色 */ } ul li div:before { content: "第"counter(steps)"步"; /* 使用counter */ color: inherit; position: absolute; /* 定位位置 */ bottom: -2rem; left: 50%; transform: translateX(-50%); /* 水平居中 */ }
-
步骤的不同状态
这里直接改变 box-shadow的颜色即可, 给完成状态的样式单独一个类(active),在html 中添加相应class,再修改样式即可,样式如下:
ul li.active:nth-child(n+2)::after { background: #00bc9b; } ul li.active::before { background: #00bc9b; box-shadow: 0 0 0 0.5rem rgb(255 255 255), 0 0 0 1rem #00bc9b; }
完整代码
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 7 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 8 <title>步骤条</title> 9 <style> 10 *{ 11 padding: 0; 12 margin: 0; 13 } 14 15 ul { 16 list-style: none; /* 取消默认样式 */ 17 display: flex; /* 使用flex */ 18 counter-reset: steps; 19 } 20 ul li { 21 flex-grow: 1; 22 display: flex; 23 justify-content: center; 24 position: relative; 25 align-items: center; 26 } 27 28 ul li::before { 29 width: 3rem; /* 步骤圆的宽 */ 30 height: 3rem; /* 步骤圆的高 */ 31 background: #bcbcbc; /* 里面的小圆 */ 32 box-shadow: 0 0 0 0.5rem #bcbcbc, 0 0 0 1rem transparent; /* 两层投影 改变投影颜色就可以实现步骤的不同状态 这里默认未完成状态 */ 33 border-radius: 50%; /* 设置形状为原型 */ 34 margin: 1rem; /* 没有设置margin的话,会位置不正确,因为投影不占用位置,而这里投影确实需要占用,所以手动给margin */ 35 display: block; /* 需要设置为块级 不然不生效*/ 36 counter-increment: steps; /* 使 steps 自增 */ 37 content: counter(steps); /* 修改content的内容为steps的值 */ 38 39 /* 使 步骤数字水平垂直居中,并设置字号 */ 40 display: flex; 41 color: white; 42 justify-content: center; 43 align-items: center; 44 font-size: 1.5rem; 45 position: relative; 46 47 z-index: 1; 48 } 49 50 ul li:nth-child(n+2):after { 51 content: ''; 52 height: .3rem; 53 width: 100%; 54 background: #bcbcbc; 55 position: absolute; 56 left: -50%; 57 } 58 59 ul li div { 60 color: black; 61 } 62 ul li div:before { 63 content: "第"counter(steps)"步"; 64 color: inherit; 65 position: absolute; 66 bottom: -2rem; 67 left: 50%; 68 transform: translateX(-50%); 69 } 70 71 ul li.active:nth-child(n+2)::after { 72 background: #00bc9b; 73 } 74 75 ul li.active::before { 76 background: #00bc9b; 77 box-shadow: 0 0 0 0.5rem rgb(255 255 255), 0 0 0 1rem #00bc9b; 78 } 79 </style> 80 </head> 81 82 <body> 83 <ul> 84 <!-- 第一步 --> 85 <li class="active"> 86 <div></div> 87 </li> 88 <!-- 第二步 --> 89 <li class="active"> 90 <div></div> 91 </li> 92 <!-- 第三步 --> 93 <li class="active"> 94 <div></div> 95 </li> 96 <!-- 第四步 --> 97 <li> 98 <div></div> 99 </li> 100 </ul> 101 </body> 102 103 </html>