iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 7
1
自我挑戰組

WordPress 客製化從 0 開始系列 第 7

Day 7 用 WordPress 佈景主題學 CSS 選擇器:進階篇

大家好,我是 Eric。
昨天文章的最後,丟出了幾個問題,沒有辦法透過基本的選擇器來完成,又或者說,要透過基本選擇器來完成會變得非常麻煩。以「我的表格想要偶數列跟奇數列有不同的顏色」為例,我們可以嘗試用類別的方式來指定:

<table>
    <tr class="odd">
        <td>這是第一列第一欄</td>
        <td>這是第一列第二欄</td>
    </tr>
    <tr class="even">
        <td>這是第二列第一欄</td>
        <td>這是第二列第二欄</td>        
    </tr>
</table>
tr.odd {
    background: #fff;
}
tr.even {
    background: #a0a0a0;
}

但如果是更複雜的樣式,就會需要透過其他的選擇器來完成。今天,我們就要來看看這些更進階的選擇器:虛擬元素 (pseudo element)、虛擬類別 (pseudo class) 以及同層級結合器 (sibling combinator)。

虛擬元素 (pseudo element)

虛擬元素的基本語法如下:

選擇器::虛擬元素 {
    content: "{虛擬元素內容}";
    樣式名稱: 樣式值;
}

虛擬元素,顧名思義,是「不存在於 HTML 文件中的元素」。意思是:當我們下載一份 HTML 檔案時,我們不會看到這些元素。這些元素,是透過 CSS 讓他們存在。不同於下一小節介紹的虛擬類別,有許多不同種類。虛擬元素只有兩種:::before::after

正因為他們是虛擬的,所以虛擬元素中必然會有一個 content 的屬性。

比起創造內容,虛擬元素更常用來製作一些特殊的樣式,譬如對話框。有一個名為《Bubbly》的網站,可以自動生成對話框的 CSS 樣式。

我們可以從 style.css 看到第 104 行來看看 Twenty Twenty 如何使用虛擬元素。

/* style.css Line 104 */
blockquote::before,
blockquote::after {
	content: "";
}

這段語法在清除 <blockquote> 這個元素前後可能會出現的引用標記,避免有些瀏覽器會自動轉譯出不符合預期的樣式。

而第 427 行則是透過虛擬元素的方法,讓水平線製作出 // 這樣的水平線:

/* style.css Line 427 */
hr.styled-separator::before,
hr.styled-separator::after {
	background: currentColor;
	content: "";
	display: block;
	height: 1.6rem;
	position: absolute;
	top: calc(50% - 0.8rem);
	transform: rotate(22.5deg);
	width: 0.1rem;
}

.entry-content hr::before,
hr.styled-separator::before {
	left: calc(50% - 0.5rem);
}

.entry-content hr::after,
hr.styled-separator::after {
	right: calc(50% - 0.5rem);
}

虛擬類別 (pseudo class)

如同虛擬元素,虛擬類別作為選擇器,需要配合其他選擇器,不能單獨存在。常用來表示選擇元素的狀態 (如 :hover) 及角色 (如 nth-child)。基本語法如下:

/* 注意虛擬元素有兩個冒號,而虛擬類別只有一個 */
選擇器:虛擬類別 {
    樣式名稱: 樣式值;
}

常見的虛擬類別有 :hover:focus:first-child:last-child:nth-child:not

:hover 與 :focus

這兩種虛擬類別代表著游標暫留 (hover) 於元素上,以及聚焦 (focus) 於元素上 (例如:點擊表單 <input> 欄位後,欄位中的游標會閃爍) 的狀態。

常見的搭配組合如下:

a:hover {
    opacity: 0.8;
    /* 游標暫留於連結時,不透明度會降為 0.8 */
}
input[type="text"]:focus {
    background-color: #000;
    color: #fff;
    /* 游標聚焦於單行文字表單時,變成黑底白字 */
}

在 style.css 的第 456 行,我們可以看到:

a:hover,
a:focus {
	text-decoration: none;
}

這裡定義了所有的連結在滑鼠暫留,或聚焦於連結上的時候 (譬如持續按鍵盤的 tab 鍵,直到選到連結時),連結文字預設的底線就會消失。

我們再往下看到第 817 行:

button:focus,
button:hover,
.button:focus,
.button:hover,
.faux-button:focus,
.faux-button:hover,
.wp-block-button .wp-block-button__link:focus,
.wp-block-button .wp-block-button__link:hover,
.wp-block-file .wp-block-file__button:focus,
.wp-block-file .wp-block-file__button:hover,
input[type="button"]:focus,
input[type="button"]:hover,
input[type="reset"]:focus,
input[type="reset"]:hover,
input[type="submit"]:focus,
input[type="submit"]:hover {
	text-decoration: underline;
}

a.focus 的時候相反,這裡則是當滑鼠暫停於按鈕元素時,顯示文字底線。

child 系列

基本語法:

選擇器:first-child,
選擇器:last-child,
選擇器:nth-child(n) {
    樣式名稱: 樣式值;
}

Child 系列,是在告訴瀏覽器要「選擇第幾個 {{選擇器}}」。

以 style.css 第 3002 行為例:

/* style.css Line 3002 */
.wp-block-column > *:first-child {
	margin-top: 0;
}

.wp-block-column > *:last-child {
	margin-bottom: 0;
}

上述的 wp-block-column 類別,主要用於 WordPress 區塊編輯器中的 [內容欄] 區塊。個別欄位的 wp-block-column 底下第一個元素 (用 * 代表任何元素) 的上邊界會是 0,而最後一個元素的下邊界也會是 0。

舉例來說:

<div class="wp-block-columns">
    <div class="wp-block-column">
        <h2>第一個欄位的標題,上邊界是 0</h2>
        <p>第一個欄位的內容</p>
        <span>第一個欄位最底下的註腳,下邊界是 0</span>
    </div>
    <div class="wp-block-column">
        <h2>第二個欄位的標題,上邊界是 0</h2>
        <p>第二個欄位的內容</p>
        <span>第二個欄位最底下的註腳,下邊界是 0</span>
    </div>
</div>

而第 3307 行則顯示如何運用 nth-child,這個例子剛好回答了我們第一段的問題:「我的表格想要偶數列跟奇數列有不同的顏色」。

/* style.css Line 3307 */
.wp-block-table.is-style-stripes tbody tr:nth-child(odd) {
	background: #dcd7ca;
}

透過 tr:nth-child(odd) 這個選擇器,我們定義了各個奇數列的背景顏色。至於要指定偶數列的話,我們可以透過 tr:nth-child(even) 來選擇。

除了奇數偶數外,tr:nth-child(3n+1) 可以指定第 1、4、7 ... 3n+1 列。

注意事項

使用 nth-child 時,要特別注意,在計算順序時,要考慮的是「在同階層中第幾個元素」。舉例來說

div.me:nth-child(3n+1) {
    background-color: #000;
}
<div class="parent">
    <div class="me">我是第 1 個 div.me,是第 1 個子層級元素,會被選到。</div>
    <div class="me">我是第 2 個 div.me,是第 2 個子層級元素,不會被選到。</div>
    <div class="me">我是第 3 個 div.me,是第 3 個子層級元素,不會被選到。</div>
    <div>我不是 div.me,是第 4 個子層級元素,不會被選到。</div>
    <div class="me">我是第 4 個 div.me,是第 5 個子層級元素,不會被選到。</div>
    <div class="me">我是第 5 個 div.me,是第 6 個子層級元素,不會被選到。</div>
    <div class="me">我是第 6 個 div.me,是第 7 個子層級元素,會被選到。</div>
</div>

:not

基本語法:

選擇器a:not(選擇器b) {
    樣式名稱: 樣式值;
}

昨天的範例中,我們問了另一個問題:「我想要指定『不是 xx 類型』的元素」。用的就是 :not 選擇器。

我們來看看 style.css 中的第 422 行,是怎麼運用 :not

/* style.css Line 422 */
.entry-content hr:not(.has-background),
hr.styled-separator {
	color: #6d6d6d;
}

這個例子中,Twenty Twenty 選擇在類型 entry-content 底下「不具有 has-background 類型」的水平線 <hr>,並將這些水平線的顏色變成灰色 (#6d6d6d)。

同層級結合器 (sibling combinator)

除了昨天提到的選擇子層級外,我們有時候也會需要套用同層級的選擇器。譬如說「緊鄰頁首主視覺的第一個 <h1> 元素」,這時候,我們就會需要使用同層級結合器。

跟子層級結合器一樣,同層級結合器也可以區分為精確比對 (adjacent sibling combinator,更精確的說是「相鄰比對」),與廣泛比對 (general sibling combinator)。

相鄰比對

基本語法:

選擇器 a + 選擇器 b {
    樣式名稱: 樣式值;
}

我們可以在 style.css 的第 681 行看到相關案例:

/* style.css Line 681 */
label.inline,
input[type="checkbox"] + label {
	display: inline;
	font-weight: 400;
	margin-left: 0.5rem;
}

這段語法中,我們可以看到,具有 inline 類型的 <label> 標籤,以及與核取方塊 <input type="checkbox"> 相鄰的標籤 (通常指的是在核取方塊右邊的敘述標籤),它們的字重會是 400,而左邊界的寬度則是 0.5rem。

<form>
    <input type="text" name="name" id="name"/>
    <label class="inline" for="name">姓名 (會套用樣式)</label>
    <input type="checkbox" name="check1" id="check1">
    <label for="check1">我會套用樣式</label>
    <input type="checkbox" name="check2" id="check2">
    <label for="check2">我也會套用樣式</label>
    <input type="checkbox" name="check3" id="check3">
    <span>我來阻止你們結合</span>
    <label for="check3">我不會套用樣式</label>
</form>

廣泛比對

基本語法:

選擇器 a ~ 選擇器 b {
    樣式名稱: 樣式值;
}

由於在 Twenty Twenty 的 style.css 中找不到實際案例,以下我們一樣將前面的選擇器稍加調整:

/* style.css Line 681 */
label.inline,
input[type="checkbox"] ~ label {
	display: inline;
	font-weight: 400;
	margin-left: 0.5rem;
}
<form>
    <input type="text" name="name" id="name"/>
    <label class="inline" for="name">姓名 (會套用樣式)</label>
    <input type="checkbox" name="check1" id="check1">
    <label for="check1">我會套用樣式</label>
    <input type="checkbox" name="check2" id="check2">
    <label for="check2">我也會套用樣式</label>
    <input type="checkbox" name="check3" id="check3">
    <span>我來阻止你們結合</span>
    <label for="check3">我照樣會套用樣式</label>
</form>

必須注意的是,同層級結合器只會選擇「選擇器 a 之後」的同層級選擇器。換句話說,下面的情況無法透過相鄰、或是廣泛同層級結合器來選擇:

<form>
    <input type="text" name="name" id="name"/>
    <label class="inline" for="name">姓名 (會套用樣式)</label>
    <label for="check1">選不到我</label>
    <input type="checkbox" name="check1" id="check1">
    <input type="checkbox" name="check2" id="check2">
    <label for="check2">我也會套用樣式</label>
    <input type="checkbox" name="check3" id="check3">
    <span>我來阻止你們結合</span>
    <label for="check3">我照樣會套用樣式</label>
</form>

由於同層級結合器在講解上稍微抽象,所以可以參考我在 Codepen 上時做的示範


上一篇
Day 6 用 WordPress 佈景主題學 CSS 選擇器:基本篇
下一篇
Day 8 從 WordPress 看 CSS 樣式:版面配置 (flex)
系列文
WordPress 客製化從 0 開始30

尚未有邦友留言

立即登入留言