轉自神奇的選擇器 :focus-within
CSS 的偽類選擇器和偽元素選擇器,讓 CSS 有了更為強大的功能。
偽類大家聽的多了,偽元素可能聽到的不是那麼頻繁,其實 CSS 對這兩個是有區分的。
有個錯誤有必要每次講到偽類都提一下,有時你會發現偽類元素使用了兩個冒號 (::) 而不是一個冒號 (:),這是 CSS3 規範中的一部分要求,目的是為了區分偽類和偽元素,大多數瀏覽器都支援下面這兩種表示方式。
通常而言,
#id:after{ ... } 複製程式碼
#id::after{ ... } 複製程式碼複製程式碼
符合標準而言,單冒號(:)用於 CSS3 偽類,雙冒號(::)用於 CSS3 偽元素。
當然,也有例外,對於 CSS2 中已經有的偽元素,例如 :before,單冒號和雙冒號的寫法 ::before 作用是一樣的。
所以,如果你的網站只需要相容 webkit、firefox、opera 等瀏覽器或者是移動端頁面,建議對於偽元素採用雙冒號的寫法,如果不得不相容低版本 IE 瀏覽器,還是用 CSS2 的單冒號寫法比較安全。
偽類選擇器 :focus-within
言歸正傳,今天要說的就是:focus-within
偽類選擇器。
它表示一個元素獲得焦點,或,該元素的後代元素獲得焦點。劃重點,它或它的後代獲得焦點。
這也就意味著,它或它的後代獲得焦點,都可以觸發 :focus-within
。
:focus-within
的冒泡性
這個屬性有點類似 Javascript 的事件冒泡,從可獲焦元素開始一直冒泡到根元素 html
,都可以接收觸發 :focus-within
事件,類似下面這個簡單的例子這樣:
<div class="g-father">
<div class="g-children">
<input type="button" value="Button">
</div>
</div>
複製程式碼複製程式碼
html, body, .g-father, .g-children { padding: 30px; border:1px solid #999; }
input { ... &:focus { background: #00bcd4; } }
複製程式碼
html:focus-within { background: #e91e63; } body:focus-within { background: #ff5722; } .g-father:focus-within { background: #ffeb3b; } .g-children:focus-within { background: #4caf50; } 複製程式碼複製程式碼
就是這樣:
CodePen Demo -- :focus-within 冒泡觸發
這個選擇器的存在,讓 CSS 有了進一步的讓元素持久停留在一種新狀態的的能力。
下面幾個例子,看看 :focus-within
可以提供什麼能力,做些什麼事情。
感應使用者聚焦區域
它或它的後代獲得焦點,這一點使得讓感知獲焦區域變得更大,所以,最常規的用法就是使用 :focus-within
感應使用者操作聚焦區域,高亮提醒。
下面的效果沒有任何 JS 程式碼:
這裡是什麼意思呢?:focus-within
做了什麼呢?
- 我們無須去給獲焦的元素設定
:focus
偽類,而是可以給需要的父元素設定,這樣當元素獲焦時,我可以一併控制它的父元素的樣式
核心思想用 CSS 程式碼表達出來大概是這樣:
<div class="g-container">
<div class="g-username">
<input type="text" placeholder="user name" class="g_input" >
</div>
<div class="g-username">
<input type="text" placeholder="code" class="g_input" >
</div>
</div>
複製程式碼複製程式碼
.g-container:focus-within { ...
複製程式碼input { .... } 複製程式碼
} 複製程式碼複製程式碼
DEMO -- CSS focus-within INPUT
運用上面思想,我們可以把效果做的更炫一點點,在某些場景製作一些增強使用者體驗的效果:
DEMO -- PURE CSS FOCUS By :focus-within
TAB導航切換
在之前的一篇文章裡,介紹了兩種純 CSS 實現的 TAB 導航欄切換方法:
現在又多了一種方式,利用了 :focus-within
可以在父節點獲取元素獲得焦點的特性,實現的TAB導航切換:
DEMO -- focus-within switch tab
主要的思路就是通過獲焦態來控制其他選擇器,以及最重要的是利用了父級的 :not(:focus-within)
來設定預設樣式:
.nav-box:not(:focus-within) { // 預設樣式 }
.nav-A:focus-within ~ .content-box .content-A { display: block; }
複製程式碼
.nav-B:focus-within ~ .content-box .content-B { display: block; } 複製程式碼複製程式碼
配合 :placeholder-shown
偽類實現表單效果
:focus-within
一個人能力有限,通常也會配合其他偽類實現一些不錯的效果。這裡要再簡單介紹的是另外一個有意思的偽類 :placeholder-shown
。
:placeholder-shown
:The :placeholder-shown CSS pseudo-class represents any<input>
or<textarea>
element that is currently displaying placeholder text.
另外,劃重點,這個偽類是仍處於實驗室的方案。也就是未納入標準,當然我們的目的是探尋有意思的 CSS 。
意思大概就是,當 input
型別標籤使用了 placeholder 屬性有了預設佔位的文字,會觸發此偽類樣式。配合:not()
偽類,可以再改變當預設文字消失後的樣式,再配合本文的主角,我們可以實現表單的一系列效果。
CSS 程式碼大概呈現成這樣:
.g-container { width: 500px; height: 60px;
複製程式碼input { height: 100%; width: 100%; &:not(:placeholder-shown) { ... } &:placeholder-shown { ... } } &:focus-within { ... } 複製程式碼
} 複製程式碼複製程式碼
實際效果如下:
可以看到,上面的效果沒有用到任何 JS,可以實現:
- 整個 input(包括父元素所在區域)獲焦與非獲焦樣式控制
- placeholder 屬性設定的文字出現與消失後樣式控制
CodePen Demo -- :placeholder-shown && :focus-within
實現離屏導航
這個是其他很多文章都有提到過的一個功能,利用 focus-within
便捷的實現離屏導航,可以說將這個屬性的功能發揮的淋漓盡致,這裡我直接貼一個 codepen 上 Dannie Vinther 對這個效果的實現方案:
CodePen Demo -- Off-screen nav with :focus-within [PURE CSS]
實現掘金登入動效切換
juejin.im是我很喜歡的一個部落格網站,它的登入有一個小彩蛋,最上面的熊貓在你輸入帳號密碼的時候會有不同的狀態,效果如下:
利用本文所講的 focus-within
,可以不借助任何 Javascript,實現這個動效:
感興趣的可以戳這裡看看完整的Demo程式碼:
相容性
好了,例子舉例的也差不多了,下面到了殺人誅心的相容性時刻,按照慣例,這種屬性大概率是一片紅色,看看 CANIUSE,截圖日期(2018/08/02),其實也還不算特別慘淡。
最後
感謝耐心讀完。本文只是拋磚引玉,期待發掘 focus-within
更多有意義的用法。
更多精彩 CSS 技術文章彙總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。
好了,本文到此結束,希望對你有幫助 :)
如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。