前言
這是前端面試系列的第3篇,前面的章節,你可以在這裡找到:
面試前端候選人的時候,我經常會問這樣一個有關CSS的問題:
你知道偽類與偽元素麼,它們的分別是什麼? 這時,能回答上來的很少。
換一種問法,你知道 :hover, :active, :focus, :visited麼? 這時,基本都能回答上來,這不就是 a 標籤的四種狀態麼。
嗯,ok。然後繼續問,那麼 ::before 和 ::after,聽說過麼? 這時,能聽到的回答是,嗯,我看到過,偶爾會用。
偽類與偽元素,都有一個“偽”字,那它們有什麼區別麼? 這時,迴應我的,是一片沉默。。。
從回答上來分析,雖然偽類和偽元素平時都有接觸,但在概念上,都比較模糊。今天,我們就來說說偽類與偽元素的區別,以及使用場景。偽類,不是隻有 a 標籤的四種狀態。偽元素,也不是隻有 ::before 與 ::after。更多的偽類與偽元素,詳見文末附錄。
概念上的區別
從概念上來區分,大致有以下幾點:
偽類,更多的定義的是狀態。常見的偽類有 :hover,:active,:focus,:visited,:link,:not,:first-child,:last-child等等。
偽元素,不存在於DOM樹中的虛擬元素,它們可以像正常的html元素一樣定義css,但無法使用JavaScript獲取。常見偽元素有 ::before,::after,::first-letter,::first-line等等。
CSS3明確規定了,偽類用一個冒號(:)來表示,而偽元素則用兩個冒號(::)來表示。但目前因為相容性的問題,它們的寫法可以是一致的,都用一個冒號(:)就可以了,所以非常容易混淆。
實戰場景——偽類
表單校驗
表單的校驗中,常會用到 :required
、:valid
和 :invalid
這三個偽類。先來看看它們所代表的含義。
- :required,指定具有 required屬性 的表單元素
- :valid,指定一個 匹配指定要求 的表單元素
- :invalid,指定一個 不匹配指定要求 的表單元素
看下面這個例子:
<p>input中型別為email的校驗</p>
<p>符合email校驗規則</p>
<input type="email" required placeholder="請輸入" value="24238477@qq.com" />
<br><br>
<p>不符合email校驗規則</p>
<input type="email" required placeholder="請輸入" value="lalala" />
<br><br>
<p>有required標識,但未填寫</p>
<input type="email" required placeholder="請輸入" value="" />
複製程式碼
input {
&:valid {
border-color: green;
box-shadow: inset 5px 0 0 green;
}
&:invalid {
border-color: red;
box-shadow: inset 5px 0 0 red;
}
&:required {
border-color: red;
box-shadow: inset 5px 0 0 red;
}
}
複製程式碼
效果如下:
摺疊皮膚
過去,要實現摺疊皮膚的顯示或隱藏,只能用JavaScript來搞定。但是現在,可以用偽類 :target
來實現。 :target 是文件的內部連結,即 URL 後面跟有錨名稱 #,指向文件內某個具體的元素。
看下面這個例子:
<div class="t-collapse">
<!-- 在url最後新增 #modal1,使得target生效 —>
<a class="collapse-target" href="#modal1">target 1</a>
<div class="collapse-body" id="modal1">
<!-- 將url的#modal1 變為 #,使得target失效 —>
<a class="collapse-close" href="#">target 1</a>
<p>...</p>
</div>
</div>
複製程式碼
.t-collapse {
>.collapse-body {
display: none;
&:target {
display: block;
}
}
}
複製程式碼
元素的index
當我們要指定一系列標籤中的某個元素時,並不需要用JavaScript獲取。可以用 :nth-child(n)
與 :nth-of-type(n)
來找到,並指定樣式。但它們有一些小區別,需要注意。
首先,它們的n可以是大於零的數字,或者類似2n+1的表示式,再或者是 even / odd。
另外,還有2個區別:
- :nth-of-type(n) 除了關注n之外,還需要關注最前面的
型別
,也就是標籤。 - :nth-child(n) 它關注的是:其父元素下的第n個孩子,與型別無關。
看下面這個例子,注意兩者的差異:
<h1>這是標題</h1>
<p>第一個段落。</p>
<p>第二個段落。</p>
<p>第三個段落。</p>
<p>第四個段落。</p>
<p>第五個段落。</p>
複製程式碼
實戰場景——偽元素
antd的彩蛋事件
還記得2018年聖誕節的“彩蛋事件”,在整個前端圈,轟動一時。因為按鈕上的一朵雲,導致不少前端er提前回家過年了。當時,彩蛋事件出現的第一時間,就嚇得我趕快開啟工程看了一眼,果然也中招了。為了保住飯碗,得趕緊把雲朵去掉。
檢視了生成的html,發現原來是 button 下藏了一個 ::before
。所以,趕緊把樣式覆蓋掉,相容程式碼如下:
.ant-btn {
&::before {
display: none !important;
}
}
複製程式碼
美化選中的文字
在網頁中,預設的劃詞效果是,原字色保持不變,劃過時的背景變為藍底色。其實,這是可以用 ::selection
來進行美化的。看下面這個例子:
<p>Custom text selection color</p>
複製程式碼
::selection {
color: red;
background-color: yellow;
}
複製程式碼
效果如下:
劃過的部分美化為:紅色的字型,並且底色變為了黃色。
總結
CSS也可以實現動態的互動,並非只有JavaScript才能實現。
書寫的時候,要尊重規範。寫偽類的時候用 :
,而寫偽元素的時候用 ::
。
相容性的問題,交給postcss去做。本文並未涉及相容性的寫法,包括字首問題,可以交給autoprefixer去做。
附錄
CSS3中的偽類
:root 選擇文件的根元素,等同於 html 元素
:empty 選擇沒有子元素的元素
:target 選取當前活動的目標元素
:not(selector) 選擇除 selector 元素意外的元素
:enabled 選擇可用的表單元素
:disabled 選擇禁用的表單元素
:checked 選擇被選中的表單元素
:nth-child(n) 匹配父元素下指定子元素,在所有子元素中排序第n
:nth-last-child(n) 匹配父元素下指定子元素,在所有子元素中排序第n,從後向前數
:nth-child(odd) 、 :nth-child(even) 、 :nth-child(3n+1) :first-child 、 :last-child 、 :only-child
:nth-of-type(n) 匹配父元素下指定子元素,在同類子元素中排序第n
:nth-last-of-type(n) 匹配父元素下指定子元素,在同類子元素中排序第n,從後向前數
:nth-of-type(odd) 、 :nth-of-type(even) 、 :nth-of-type(3n+1) :first-of-type 、 :last-of-type 、 :only-of-type
CSS3中的偽元素
::after 已選中元素的最後一個子元素
::before 已選中元素的第一個子元素
::first-letter 選中某個款級元素的第一行的第一個字母
::first-line 匹配某個塊級元素的第一行
::selection 匹配使用者劃詞時的高亮部分
PS:歡迎關注我的公眾號 “超哥前端小棧”,交流更多的想法與技術。