「前端面試題系列3」偽類與偽元素的區別及實戰

Micherwa發表於2019-01-15

前言

這是前端面試系列的第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;
    }
}
複製程式碼

效果如下:

「前端面試題系列3」偽類與偽元素的區別及實戰

摺疊皮膚

過去,要實現摺疊皮膚的顯示或隱藏,只能用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>
複製程式碼

「前端面試題系列3」偽類與偽元素的區別及實戰

實戰場景——偽元素

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;
}
複製程式碼

效果如下:

「前端面試題系列3」偽類與偽元素的區別及實戰

劃過的部分美化為:紅色的字型,並且底色變為了黃色。

總結

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:歡迎關注我的公眾號 “超哥前端小棧”,交流更多的想法與技術。

「前端面試題系列3」偽類與偽元素的區別及實戰

相關文章