天天看點

談談一些有趣的CSS題目(八)-- 純CSS的導航欄Tab切換方案

開本系列,談談一些有趣的 <code>CSS</code> 題目,題目類型天馬行空,想到什麼說什麼,不僅為了拓寬一下解決問題的思路,更涉及一些容易忽視的 CSS 細節。

解題不考慮相容性,題目天馬行空,想到什麼說什麼,如果解題中有你感覺到生僻的 CSS 屬性,趕緊去補習一下吧。

不斷更新,不斷更新,不斷更新,重要的事情說三遍。

談談一些有趣的CSS題目(一)-- 左邊豎條的實作方法

談談一些有趣的CSS題目(二)-- 從條紋邊框的實作談盒子模型

談談一些有趣的CSS題目(三)-- 層疊順序與堆棧上下文知多少

談談一些有趣的CSS題目(四)-- 從倒影說起,談談 CSS 繼承 inherit

談談一些有趣的CSS題目(五)-- 單行居中,兩行居左,超過兩行省略

談談一些有趣的CSS題目(六)-- 全相容的多列均勻布局問題

談談一些有趣的CSS題目(七)-- 消失的邊界線問題

所有題目彙總在我的 Github 。

不用 <code>Javascript</code>,使用純 <code>CSS</code> 方案,實作類似下圖的導航欄切換:

談談一些有趣的CSS題目(八)-- 純CSS的導航欄Tab切換方案

CSS 的強大之處有的時候超乎我們的想象,Tab 切換,正常而言确實需要用到一定的腳本才能實作。下面看看如何使用 CSS 完成同樣的事情。

實作 Tab 切換的難點在于如何使用 CSS 接收到使用者的點選事情并對相關的節點進行操作。即是:

如何接收點選事件

如何操作相關DOM

下面看看如何使用兩種不同的方法實作需求:

首先,我們要解決的問題是<code>如何接收點選事件</code>,這裡第一種方法我們采用 <code>:target</code> 僞類接收。

<code>:target</code> 是 CSS3 新增的一個僞類,可用于選取目前活動的目标元素。當 URL 末尾帶有錨名稱 #,就可以指向文檔内某個具體的元素。這個被連結的元素就是目标元素(target element)。它需要一個 id 去比對文檔中的 target 。

解釋很難了解,看看實際的使用情況,假設我們的 <code>HTML</code> 代碼如下:

由于要使用 <code>:target</code>,需要 HTML 錨點,以及錨點對應的 HTML 片段。是以上面的結構要變成:

這樣,上面 <code>&lt;a href="#content1"&gt;</code> 中的錨點 <code>#content1</code> 就對應了清單1 <code>&lt;div id="content1"&gt;</code> 。錨點2與之相同對應清單2。

接下來,我們就可以使用 <code>:target</code> 接受到點選事件,并操作對應的 DOM 了:

上面的 CSS 代碼,一開始頁面中的 <code>#content1</code> 與 <code>#content2</code> 都是隐藏的,當點選清單1觸發<code>href="#content1"</code> 時,頁面的 URL 會發生變化:

由 <code>www.example.com</code> 變成 <code>www.example.com#content1</code>

接下來會觸發 <code>#content1:target{ }</code> 這條 CSS 規則,<code>#content1</code> 元素由 <code>display:none</code> 變成<code>display:block</code> ,點選清單2亦是如此。

如此即達到了 Tab 切換。當然除了 <code>content1 content2</code> 的切換,我們的 <code>li</code> 元素樣式也要不斷變化,這個時候,就需要我們在 DOM 結構布局的時候多留心,在 <code>#content1:target</code> 觸發的時候可以同時去修改 <code>li</code> 的樣式。

在上面 <code>HTML</code> 的基礎上,再修改一下,變成如下結構:

仔細對比一下與上面結構的異同,這裡我隻是将 <code>ul</code> 從兩個 <code>content</code> 上面挪到了下面,為什麼要這樣做呢?

因為這裡需要使用兄弟選擇符 ~ 。

E~F{ cssRules } ,CSS3 兄弟選擇符(E~F) ,選擇 E 元素後面的所有兄弟元素 F。 注意這裡,最重要的一句話是 E~F 隻能選擇 E 元素 之後 的 F 元素,是以順序就顯得很重要了。

在這樣調換位置之後,通過兄弟選擇符 ~ 可以操作整個 <code>.nav</code> 的樣式。

上面的 CSS 規則中,我們使用 ~ 選擇符,在 <code>#content1:target</code> 和 <code>#content2:target</code> 觸發的時候分别去控制兩個導航 <code>li</code> 元素的樣式。

至此兩個問題,<code>1. 如何接收點選事件</code> 與 <code>2. 如何操作相關DOM</code> 都已經解決,剩下的是一些小樣式的修補工作。

Demo戳我:純CSS導航切換(:target僞類實作)

上面的方法通過添加 <code>&lt;a&gt;</code> 标簽添加頁面錨點的方式接收點選事件。

這裡還有一種方式能夠接收到點選事件,就是擁有 <code>checked</code> 屬性的表單元素, <code>&lt;input type="radio"&gt;</code> 或者<code>&lt;input type="checkbox"&gt;</code> 。

假設有這樣的結構:

對于上面的結構,當我們點選 <code>&lt;input class="nav1" type="radio"&gt;</code> 單選框表單元素的時候,使用 <code>:checked</code>是可以捕獲到點選事件的。

同樣用到了兄弟選擇符 ~

這樣,當接收到表單元素的點選事件時,可以通過兄弟選擇符 ~ 操作它的兄弟元素的樣式。

可以試着點選下面 codepen 中的單選框。

但是,這裡有個問題 我們的 Tab 切換,要點選的是<code>&lt;li&gt;</code>元素,而不是表單元素,是以這裡很重要的一點是,使用 <code>&lt;label for=""&gt;</code> 綁定表單元素。看看如下結構:

上面的 <code>&lt;li&gt;</code> 中,有一層 <code>&lt;label for="li"&gt;</code> ,裡面的 <code>for="li1"</code> 意思是綁定 id 為li1 的表單元素。

label 标簽中的 for 定義:for 屬性規定 label 與哪個表單元素綁定。

這樣改造之後,當我們點選 <code>&lt;li&gt;</code> 元素的時候,相當于點選了 <code>&lt;input class="nav1" id="li1" type="radio"&gt;</code>這個單選框表單元素,而這個表單元素被點選選中的時候,又可以被 <code>:checked</code> 僞類捕獲到。

這個時候,我們就可以将頁面上的表單元素隐藏,做到點選 <code>&lt;li&gt;</code> 相當于點選表單:

這樣,應用到本題目,我們應該建立如下 DOM 結構:

使用兩個單選框,分别對應兩個導航選項,運用上面介紹的 label 綁定表單,<code>:checked</code> 接收點選事件,可以得到第二解法。

看看最後的結果:

Demo戳我:純CSS導航切換(label 綁定 input:radio &amp;&amp; ~)

所有題目彙總在我的 Github ,發到部落格希望得到更多的交流。

到此本文結束,如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。