記錄--純CSS實現一個簡單又不失優雅的步驟條

来源:https://www.cnblogs.com/smileZAZ/archive/2023/06/07/17464192.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 步驟條是一種用於引導用戶按照特定流程完成任務的導航條,在各種分步表單交互場景中廣泛應用。先來看一下幾個主流前端 UI 框架中步驟條組件的樣子: ElementPlus AntDesign OpenTiny iView 我們可以發現,步驟條 ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

步驟條是一種用於引導用戶按照特定流程完成任務的導航條,在各種分步表單交互場景中廣泛應用。先來看一下幾個主流前端 UI 框架中步驟條組件的樣子:

我們可以發現,步驟條通常由編號、名稱和引導線三個基本要素組成。本文中要實現的是一個簡單的步驟條,包含上述三個基本要素,下麵是最終的效果圖:

5_72dc53815f27dbf472423a1e97bfc238_940x96.gif@900-0-90-f.gif

接下來將詳細介紹實現過程。

確定結構

對於步驟條這種呈現順序的列表結構,在 HTML 標簽選擇上,使用 ulol 標簽可以讓語義更加清晰,這裡我們使用了 ol 標簽,HTML 代碼如下:

<ol class="steps">
  <li>註冊</li>
  <li>域認證</li>
  <li>身份校驗</li>
  <li>風險等級評估</li>
  <li>開通賬號</li>
</ol>

由於步驟項需要水平排列,因此在 CSS 中用了 flex 佈局,代碼如下所示:

.steps {
  display: flex;
  justify-content: space-between;  /* 按水平均勻分佈,行首行尾兩端靠齊 */
  margin: 0;
}

現在,我們的“步驟條”已初步有那麼點兒意思了,讓我們繼續完善細節。

生成步驟編號

步驟編號可利用 CSS 的原生能力來自動生成,在上一步中,ol 標簽生成的編號並不好看,此處我們用 ::before 偽元素和 CSS 計數器來實現帶圈編號的樣式,讓步驟看起來更加清晰明瞭。

感興趣的小伙伴可移步《CSS實現有序列表編號方法知多少》一文查看相關知識點

.steps {
  display: flex;
  justify-content: space-between;
  padding: 0;
  margin: 0;
  counter-reset: order;  /* 定義CSS計數器 */
  list-style: none;
}
.steps > li {counter-increment: order;}
.steps > li::before {
  content: counter(order);  /* 編號 */
  display: inline-block;
  width: 1.4em;
  line-height: 1.4em;
  margin-right: .5em;
  vertical-align: middle;
  text-align: center;
  border-radius: 50%;
  border: 1px solid;
}

實現效果如下圖所示:

實現引導線

我們已經有了步驟編號和名稱,接下來需要實現步驟引導線。

引導線將各個步驟項連接為一體,使流程在視覺上具有指向性,它是個裝飾性元素,所以不應該出現在 HTML中。由於前面的 ::before 已經用於步驟編號,所以我們選擇使用 ::after 來實現引導線。

.steps > li::after {
  content: '';
  display: inline-block;
  width: 60px;
  vertical-align: middle;  /* 讓引導線和文本垂直居中 */
  border-bottom: 1px solid #ccc;
}
效果如下圖所示:

 最後一個步驟項是不需要引導線的,所以我們改用 :not 偽類選擇器把它過濾掉:

.steps > li:not(:last-child)::after {
  ...
}
現在我們面臨一個難題:怎樣確定引導線的寬度呢?使用固定寬度顯然行不通,因為這會有很大的局限性。理想的解決方案是引導線寬度能夠自動適應,占據除編號和名稱文本以外的剩餘空間。這種寬度自適應的場景,我們會很自然想到用 flex 佈局來解決:只需將每個步驟項 li 標簽的佈局屬性改為 inline-flex 盒子即可。
.steps > li {
  flex: auto;  /* 彈性寬度(根據其內容來調整) */
  display: inline-flex;  /* 內聯塊級彈性伸縮盒子 */
  align-items: center;
  counter-increment: order;
}
​
.steps > li:not(:last-child)::after {
  content: '';
  flex: 1;  /* 占滿 li 中的剩餘寬度 */
  margin: 0 1em;
  border-bottom: 1px solid #ccc;
}

現在的佈局效果已經非常接近目標了:

 如果我們看得仔細一些,就會發現在最後一個步驟項的右邊出現了一段空白,實際中我們希望它能夠和右邊對齊。

這個空白的產生和步驟項 li 標簽的 flex: auto 這個 CSS 屬性有關,該屬性會根據當前容器的可用寬度來分配父容器寬度,當分配後還有剩餘寬度時,前幾個步驟項會有 CSS 屬性為 flex: 1 的引導線來填補剩餘寬度,但最後一個步驟項沒有引導線,因此會出現空白。在瞭解根因後,我們只需要調整最後一個步驟項即可解決這個問題:
.steps > li:last-child {
  flex: none;
}

同時我們也意識到,當步驟項容器寬度不夠時,作為 flex 子元素的圓形編號可能會被擠壓變形:

 解決方案也很簡單,禁止 flex 子元素收縮:

.steps > li::before {
  ...
  flex-shrink: 0;  /* 佈局寬度不夠時禁止收縮 */
}

步驟條狀態

在調教好佈局結構之後,我們來為步驟條增加狀態。通常情況下,步驟條狀態包括“已完成”、“進行中”和“未開始”三種,對應的裝飾樣式如下表所示:

狀態步驟編號步驟名稱步驟引導線
已完成 無背景色,邊框和文本高亮色 文本高亮色 高亮色
進行中 背景和邊框高亮色,文本反色 文本高亮色 普通色
未開始 無背景色,邊框和文本普通色 文本普通色 普通色

對此我們定義普通色和高亮色這2個顏色變數,以方便代碼維護和擴展。

.steps {
  --normal-color: #666;  /* 普通色 */
  --active-color: #06e;  /* 高亮色 */
​
  ...
}

然後將所有步驟項預設以普通色呈現:

.steps > li {
  ...
  color: var(--normal-color);
}

引導線的顏色則預設自動繼承字體顏色,同時為了避免引導線喧賓奪主,我們給它加了個透明度控制下顏色深度:

.steps > li:not(:last-child)::after {
  ...
  border-bottom: 1px solid;  /* 不指定顏色,則自動繼承自身color或父級color */
  opacity: .6;
}

接下來是“已完成”和“進行中”的樣式定義,需要註意“進行中”後面的引導線不能高亮。

.steps > .done,
.steps > .active {
  color: var(--active-color);
}
.steps > .active::before {
  color: #fff;
  background: var(--active-color);
  border-color: var(--active-color);
}
.steps > .active::after {
  color: var(--normal-color);  /* “進行中”後面的引導線按普通色顯示 */
}

然後在 HTML 中調用對應的樣式鉤子:

<ol class="steps">
  <li class="done">註冊</li>
  <li class="done">域認證</li>
  <li class="done">身份校驗</li>
  <li class="active">風險等級評估</li>
  <li>開通賬號</li>
</ol>

實現效果如下圖所示:

最終方案

就顯示效果而言,現在可以收工了,但對於將優雅奉為圭臬的程式猿來說,這個步驟條還差點意思——用 done 和 active 樣式鉤子來分別標記“已完成”和“進行中”的狀態——這並不優雅。

<ol class="steps">
  <li class="done">註冊</li>  <!-- 已完成 -->
  <li class="done">域認證</li>  <!-- 已完成 -->
  <li class="done">身份校驗</li>  <!-- 已完成 -->
  <li class="active">風險等級評估</li>  <!-- 進行中 -->
  <li>開通賬號</li>
</ol>
如果回想一下我們在前端 UI 框架中使用的步驟條,就會發現它只要關心當前進展到了哪一步,而“已完成”和“未完成”都是被組件內部自行處理的。那麼,對於我們現在所做的步驟條,是否可以僅標記“進行中”,也就是只使用 active 樣式鉤子就可以了呢?就像下麵這樣:
<ol class="steps">
  <li>註冊</li>
  <li>域認證</li>
  <li>身份校驗</li>
  <li class="active">風險等級評估</li>  <!-- 進行中 -->
  <li>開通賬號</li>
</ol>

對於這樣的 HTML 結構,active 這個鉤子可繼續沿用之前的 CSS 代碼,實現當前步驟項的高亮效果,然後可以根據 active 這個類名匹配它前面的兄弟步驟項,實現與 done 這個類一樣的效果。不過我們很快就會被現實打臉:CSS 中根本沒有“前兄弟選擇器”這種東西,因此無法根據 active 向前匹配。

於是我們需要調整思路,逆向思考:既然無法匹配 active 前面的元素,那為什麼不匹配其後面的元素呢?畢竟 CSS 中是有兄弟選擇器的呀,至於 active 前面的元素,或許我們可以通過其父級來控制樣式?

現在思路清晰了許多。我們先把所有步驟項都預設設置為“已完成”狀態的高亮樣式:

.steps > li {
  ...
  color: var(--active-color);  /* 改為“已完成”,之前的值是 var(--normal-color) */
}
此時步驟條變成了這樣:

 然後加上 active 的樣式,假設當前是第4步,則效果如下:

接下來就是將 active 後面的步驟項改成“未開始”的樣式,利用兄弟選擇器輕鬆搞定:
.steps > .active ~ li {
  color: var(--normal-color);
}

最後再來測試下整體效果:

16_685afd9fd12b2449feba44a68e955dcc_943x324.gif@900-0-90-f.gif

最終完整的 CSS 代碼如下:

 

.steps {
  --normal-color: #666;
  --active-color: #06e;
​
  display: flex;
  justify-content: space-between;
  padding: 0;
  margin: 0;
  counter-reset: order;
}
​
/* 步驟項 */
.steps > li {
  flex: auto;
  display: inline-flex;
  align-items: center;
  counter-increment: order;
  color: var(--active-color);
}
.steps > li:last-child {flex: none;}
​
/* 步驟編號(帶圈數字) */
.steps > li::before {
  content: counter(order);
  flex-shrink: 0;
  width: 1.4em;
  line-height: 1.4em;
  margin-right: .5em;
  text-align: center;
  border-radius: 50%;
  border: 1px solid;
}
​
/* 步驟項引導線 */
.steps > li:not(:last-child)::after {
  content: '';
  flex: 1;
  margin: 0 1em;
  border-bottom: 1px solid;
  opacity: .6;
}
​
/* 步驟狀態 */
.steps > .active {color: var(--active-color);}
.steps > .active::before {
  color: #fff;
  background: var(--active-color);
  border-color: var(--active-color);
}
.steps > .active::after,
.steps > .active ~ li {color: var(--normal-color);}

本文附件中提供完整代碼的 demo,感興趣的小伙伴可聯繫我們獲取,可在現有基礎上定製、擴展。下麵是拋磚引玉:

知識點總結

  • flex 容器的 justify-content: space-between; 可令子元素按顯示方向均勻分佈,兩端分散對齊,實在是居家旅行之必備神器;
  • inline-flex 的盒子既能像 flex 容器那樣輕鬆拿捏其子元素的佈局,又能像行內塊元素一樣平易近人;
  • CSS 計數器洗剪吹一條龍:counter-resetcounter-incrementcounter(xxx)
  • flex: <number>對於寬度(或高度)能占盡占,該是我的就是我的,能剩一點算我輸;
  • flex: auto 從自身實際情況出發應占盡占,大家共同富裕不香嗎;
  • flex-shrink 用來設置 flex 元素的可壓榨基準,與它對應的是 flex-basis,用來設置可膨脹基準;
  • IE 都亡了,CSS 變數,放心用起來吧;
  • 強大的 CSS 偽類選擇器,可以讓代碼更精簡,還可以打出組合拳:li:not(:last-child)::after
  • 平平無奇關鍵時刻又能打能抗的兄弟選擇器:.active ~ li

本文轉載於:

https://juejin.cn/post/7226910005144043580

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # GreatSQL刪除分區慢的跟蹤 ## 背景 某業務系統,每天凌晨會刪除分區表的一個分區(按天分區),耗時較久,從最開始的30秒,慢慢變為1分鐘+,影響到交易業務的正常進行。 在測試環境進行了模擬,復現了刪除分區慢的情況,本次基於GreatSQL8.0.25-17進行測試,官方mysql版本也存 ...
  • # zookeeper ZooKeeper是一個開源的分散式應用程式協調服務 簡單來說可以理解為zookeeper = 文件系統+監聽通知機制 應用場景: 1. 集群管理、伺服器狀態感知 2. 分散式應用配置管理 3. 統一命名服務 4. 分散式鎖 > 小總結: >1. 為客戶提供寫數據功能 數據不 ...
  • # 協程的取消 本文討論協程的取消, 以及實現時可能會碰到的幾個問題. ![coroutine cancellation](https://img2023.cnblogs.com/blog/325852/202306/325852-20230607235812812-279507376.png) 本 ...
  • 1. 背景 3月份針對線上重點H5項目秒開進行治理,本文將逐步介紹如何通過H5頁面的優化手段來提高 1.5 秒開率。 2. 為什麼要優化 從用戶角度看,優化能夠讓頁面載入得更快、對用戶操作響應更及時,用戶體驗更良好,提升用戶體驗和降低用戶流失率非常重要。其中 Global Web Performan ...
  • > 不知不覺又快要到了畢業季,很多同學即將畢業找工作。找工作就免不了去面試,作為一個前端提前準備面試題還是有必要的,一方面能鞏固自己學習的內容,另一方面則是幫助我們通過面試找到一份好的工作。因此在這裡,我將開設一個前端的專欄來以文章的形式專門講解前端的面試題,由淺入深,循序漸進,希望能幫助更多的小伙 ...
  • 夏天到了,用Three.js實現一個可以搖頭和調節檔位的電風扇。主要使用到Blender處理3D模型,用Vite+Typescript搭建項目框架。 ...
  • ## 背景 > base深圳,一年半經驗,找的初級前端崗位,1-3年,投簡歷兩個月只有兩個面試,這是第一個面試 ## 一面 ### 你對html元素是怎麼分類的? 一開始我愣了一下?搞這麼簡單的問題???後面又問面試官你是指的id選擇器這些嗎,,還是display:block,inline-bloc ...
  • 本文講解了VUE項目中路由之間的傳值方式,涉及到的方法都是開發時常用的,希望對大家有多幫助。 1. 方式一:使用router-link標簽 1.1 params 傳參 首先定義好路由 const routes = [ { path : ‘/home’ , component : () => impo ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...