目標
需要實現如下的效果
要求
- 要求內容能夠自適應,比如添加步驟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>