Contents

神奇的選擇器 :focus-within

:focus-within 是一個非常實用的 CSS 偽類別選擇器,當一個元素本身或其任何子元素取得焦點(focus)時,就會觸發該元素的樣式。這讓我們可以不用 JavaScript 就能實現許多互動效果。

基本原理

傳統的 :focus 只會在元素本身被 focus 時觸發。:focus-within 則不同,只要子元素有任何一個被 focus,父元素就會 match,這個特性類似 DOM 事件的冒泡(bubble)機制

1
2
3
4
<div class="form-group">
  <label>姓名</label>
  <input type="text" placeholder="請輸入姓名">
</div>
1
2
3
4
5
/* 當 input 被 focus 時,父層 .form-group 也會被選中 */
.form-group:focus-within {
  border: 2px solid #007bff;
  background-color: #f0f8ff;
}

應用場景

1. 表單群組高亮

當使用者點擊某個輸入框時,整組 label + input 都一起高亮,提升使用者體驗:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
.form-group {
  padding: 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  transition: border-color 0.2s;
}

.form-group:focus-within {
  border-color: #007bff;
  box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}

.form-group:focus-within label {
  color: #007bff;
  font-weight: bold;
}

2. 下拉選單顯示

純 CSS 實現下拉選單,點擊觸發展開:

1
2
3
4
5
6
7
<nav class="dropdown">
  <button>選單</button>
  <ul class="menu">
    <li><a href="#">項目一</a></li>
    <li><a href="#">項目二</a></li>
  </ul>
</nav>
1
2
3
4
5
6
7
.menu {
  display: none;
}

.dropdown:focus-within .menu {
  display: block;
}

3. 懸浮標籤(Floating Label)

結合 :focus-within:placeholder-shown 實現無 JavaScript 的懸浮標籤效果:

1
2
3
4
<div class="input-wrap">
  <input type="text" id="username" placeholder=" " />
  <label for="username">使用者名稱</label>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
.input-wrap {
  position: relative;
}

.input-wrap label {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  transition: all 0.2s;
}

.input-wrap:focus-within label,
.input-wrap input:not(:placeholder-shown) + label {
  top: 0;
  font-size: 0.75em;
  color: #007bff;
}

:focus-within vs :focus-visible

這兩個選擇器容易混淆,差異如下:

選擇器 觸發條件
:focus 元素本身被 focus
:focus-within 元素本身或其子元素被 focus
:focus-visible 元素被 focus,且瀏覽器判斷應該顯示焦點樣式(通常是鍵盤操作時)

:focus-visible 的設計是為了解決「滑鼠點擊按鈕時也顯示藍色外框」的問題,讓焦點樣式只在鍵盤操作時顯示,兼顧無障礙設計:

1
2
3
4
/* 只有鍵盤 focus 才顯示外框,滑鼠點擊不顯示 */
button:focus-visible {
  outline: 2px solid #007bff;
}

瀏覽器支援度

:focus-within 已獲得所有現代瀏覽器支援(Chrome 60+、Firefox 52+、Safari 10.1+、Edge 79+),IE 不支援。

:focus-visible 支援度稍晚(Chrome 86+、Firefox 85+、Safari 15.4+),IE 同樣不支援。

參考資料