基本總覽,說明如何建構滑桿和核取方塊的設定元件。
在本文中,我想分享如何為網頁建構回應式、支援多種裝置輸入,且可在不同瀏覽器上運作的設定元件。試用示範。
如果您偏好觀看影片,或想預覽我們建構的 UI/UX,請觀看這部 YouTube 簡短逐步操作影片:
總覽
我將這個元件的各個面向分成以下幾個部分:
版面配置
這是第一個完全使用 CSS Grid 的 GUI 挑戰示範!以下是使用 Chrome 開發人員工具醒目顯示的各個格線:

僅用於間隔
最常見的版面配置:
foo {
display: grid;
gap: var(--something);
}
我將這個版面配置稱為「僅限間隔」,因為它只使用格線在區塊之間新增間隔。
有五種版面配置採用這項策略,以下是所有版面配置:

fieldset 元素包含每個輸入群組 (.fieldset-item),並使用 gap: 1px 在元素之間建立細線框線。不必費心處理邊界問題!
.grid { display: grid; gap: 1px; background: var(--bg-surface-1); & > .fieldset-item { background: var(--bg-surface-2); } }
.grid { display: grid; & > .fieldset-item { background: var(--bg-surface-2); &:not(:last-child) { border-bottom: 1px solid var(--bg-surface-1); } } }
自然格狀換行
最複雜的版面配置是巨集版面配置,也就是 <main> 和 <form> 之間的邏輯版面配置系統。
置中納入內容
Flexbox 和格線都提供 align-items 或 align-content 的功能,在處理包裝元素時,content 版面配置對齊方式會將空間分配給子項。
main {
display: grid;
gap: var(--space-xl);
place-content: center;
}
主要元素使用 place-content: center 對齊簡寫,因此子項在單欄和雙欄版面配置中,都會垂直和水平置中。
請觀看上方影片,瞭解「內容」如何保持置中,即使發生換行也一樣。
重複自動調整 minmax
<form> 會為每個部分使用自動調整格線版面配置。這個版面配置會根據可用空間,從一欄切換為兩欄。
form {
display: grid;
gap: var(--space-xl) var(--space-xxl);
grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
align-items: flex-start;
max-width: 89vw;
}
這個格線的 row-gap (--space-xl) 值與 column-gap (--space-xxl) 不同,可為回應式版面配置增添自訂風格。當資料欄堆疊時,我們希望有較大的間距,但不要像在寬螢幕上那麼大。
grid-template-columns 屬性會使用 3 個 CSS 函式:repeat()、minmax() 和 min()。Una Kravets 撰寫了一篇很棒的版面配置網誌文章,並將其稱為 RAM。
與 Una 的版面配置相比,我們的版面配置有 3 項特別之處:
- 我們傳遞額外的
min()函式。 - 我們指定
align-items: flex-start。 - 採取
max-width: 89vw風格。
Evan Minto 在網誌文章「Intrinsically Responsive CSS Grid with minmax() and min()」中,詳細說明瞭額外的 min() 函式。建議您閱讀這篇文章。flex-start 對齊校正功能會移除預設的拉伸效果,因此這個版面配置的子項不需要等高,可以有自然、固有的高度。YouTube 影片快速介紹了這項新增的對齊功能。
max-width: 89vw 值得在這篇文章中稍作分析。
以下是套用和未套用樣式的版面配置:
為什麼會這樣?指定 max-width 時,系統會提供 auto-fit 版面配置演算法的背景資訊、明確大小或確定大小,以便瞭解空間可容納的重複次數。雖然空間顯然是「全寬」,但根據 CSS 格線規格,必須提供明確的大小或大小上限。我已提供最大大小。
那麼,為什麼要使用 89vw?因為這對我的版面配置「有效」。我和其他幾位 Chrome 團隊成員正在調查為何更合理的值 (例如 100vw) 不足,以及這是否確實是錯誤。
間距
這個版面配置之所以和諧,主要是因為間距的調色盤有限,準確來說是 7 個。
:root {
--space-xxs: .25rem;
--space-xs: .5rem;
--space-sm: 1rem;
--space-md: 1.5rem;
--space-lg: 2rem;
--space-xl: 3rem;
--space-xxl: 6rem;
}
這些流程與格線、CSS @nest 和 @media 的第 5 級語法搭配使用,效果非常好。以下是完全 <main> 版面配置樣式組合的範例。
main {
display: grid;
gap: var(--space-xl);
place-content: center;
padding: var(--space-sm);
@media (width >= 540px) {
& {
padding: var(--space-lg);
}
}
@media (width >= 800px) {
& {
padding: var(--space-xl);
}
}
}
內容置中的格線,預設會適度留白 (例如在行動裝置上)。但隨著可用的可視區域空間增加,它會透過增加邊框間距來展開。2021 年的 CSS 相當出色!
還記得先前的版面配置「just for gap」嗎?以下是這個元件中更完整的版本:
header {
display: grid;
gap: var(--space-xxs);
}
section {
display: grid;
gap: var(--space-md);
}
顏色
這項設計巧妙運用色彩,既能展現豐富情感,又保有簡約風格。我的做法如下:
:root {
--surface1: lch(10 0 0);
--surface2: lch(15 0 0);
--surface3: lch(20 0 0);
--surface4: lch(25 0 0);
--text1: lch(95 0 0);
--text2: lch(75 0 0);
}
我會用數字命名介面和文字顏色,而不是 surface-dark 和 surface-darker 等名稱,因為在媒體查詢中,我會翻轉這些顏色,而淺色和深色不會有意義。
我會在偏好媒體查詢中翻轉這些值,如下所示:
:root {
...
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--surface2: lch(100 0 0);
--surface3: lch(98 0 0);
--surface4: lch(85 0 0);
--text1: lch(20 0 0);
--text2: lch(40 0 0);
}
}
}
在深入探討顏色語法細節之前,請先快速瀏覽整體架構和策略。不過,我好像講得太快了,讓我稍微倒退一下。
LCH?
在不深入探討色彩理論的情況下,LCH 是以人為導向的語法,可滿足我們感知色彩的方式,而非我們用數學測量色彩的方式 (例如 255)。這項做法具有明顯優勢,因為人類可以更輕鬆地編寫提示,而其他人類也會配合這些調整。
在今天的示範中,我們將著重於語法和切換的值,以建立淺色和深色模式。我們來看看 1 種表面和 1 種文字顏色:
:root {
--surface1: lch(10 0 0);
--text1: lch(95 0 0);
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--text1: lch(40 0 0);
}
}
}
--surface1: lch(10 0 0) 轉換為 10% 亮度、0 色度和 0 色相:非常深、無彩色的灰色。接著,在淺色模式的媒體查詢中,使用 --surface1: lch(90 0 0); 將亮度翻轉為 90%。這就是策略的要點。首先,請變更 2 個主題之間的亮度,維持設計所需的對比度,或維持無障礙功能。
lch() 的好處在於,明度是以人為導向,我們可以對 % 的變化感到滿意,因為它在感知上和一致性上都會有 % 的差異。例如,hsl()較不可靠。
如想進一步瞭解色域和 lch(),請參閱這篇文章。即將推出!
CSS 目前完全無法存取這些顏色。 讓我再說一次:我們無法存取大多數現代螢幕中三分之一的顏色。而且這些顏色不只是任何顏色,而是螢幕可顯示的最鮮豔顏色。我們的網站之所以看起來褪色,是因為螢幕硬體的發展速度比 CSS 規格和瀏覽器實作更快。
Lea Verou
使用 color-scheme 建立自動調整表單控制項
許多瀏覽器都提供深色主題控制項 (目前有 Safari 和 Chromium),但您必須在 CSS 或 HTML 中指定設計使用這些控制項。
上圖示範了 DevTools「樣式」面板中屬性的效果。示範中使用了 HTML 標記,我認為這通常是較好的位置:
<meta name="color-scheme" content="dark light">
如要瞭解詳情,請參閱 Thomas Steiner 撰寫的這篇color-scheme文章。除了深色核取方塊輸入外,還有更多好處!
CSS accent-color
最近,表單元素上的 accent-color 相關活動頻繁,這是一種單一 CSS 樣式,可變更瀏覽器輸入元素中使用的色調顏色。詳情請參閱 GitHub。我已將其納入這個元件的樣式中。由於瀏覽器支援,我的核取方塊會更符合主題,並帶有粉紅色和紫色。
input[type="checkbox"] {
accent-color: var(--brand);
}

使用固定漸層和 focus-within 的抽色效果
色彩在少量使用時最能突顯效果,而我喜歡透過色彩繽紛的 UI 互動來達到這個效果。
上述影片中有多層 UI 回饋和互動,可透過以下方式為互動賦予個性:
- 醒目顯示背景資訊。
- 提供「值在範圍內有多滿」的使用者介面意見回饋。
- 提供使用者介面意見回饋,指出欄位接受輸入內容。
如要在使用者與元素互動時提供意見回饋,CSS 會使用 :focus-within 虛擬類別來變更各種元素的外觀,讓我們來拆解 .fieldset-item,這非常有趣:
.fieldset-item {
...
&:focus-within {
background: var(--surface2);
& svg {
fill: white;
}
& picture {
clip-path: circle(50%);
background: var(--brand-bg-gradient) fixed;
}
}
}
當這個元素的其中一個子項具有 focus-within 時:
.fieldset-item背景會指派對比度較高的表面顏色。- 巢狀
svg則填滿白色,提高對比度。 - 巢狀
<picture>clip-path會展開為完整圓形,背景則填滿明亮的固定漸層。
自訂範圍
以下 HTML 輸入元素範例說明如何自訂外觀:
<input type="range">
這個元素有 3 個部分需要自訂:
範圍元素樣式
input[type="range"] {
/* style setting variables */
--track-height: .5ex;
--track-fill: 0%;
--thumb-size: 3ex;
--thumb-offset: -1.25ex;
--thumb-highlight-size: 0px;
appearance: none; /* clear styles, make way for mine */
display: block;
inline-size: 100%; /* fill container */
margin: 1ex 0; /* ensure thumb isn't colliding with sibling content */
background: transparent; /* bg is in the track */
outline-offset: 5px; /* focus styles have space */
}
CSS 的前幾行是樣式的自訂部分,希望清楚標示這些部分能有所幫助。其餘樣式大多是重設樣式,可提供一致的基礎,用於建構元件的複雜部分。
追蹤樣式
input[type="range"]::-webkit-slider-runnable-track {
appearance: none; /* clear styles, make way for mine */
block-size: var(--track-height);
border-radius: 5ex;
background:
/* hard stop gradient:
- half transparent (where colorful fill we be)
- half dark track fill
- 1st background image is on top
*/
linear-gradient(
to right,
transparent var(--track-fill),
var(--surface1) 0%
),
/* colorful fill effect, behind track surface fill */
var(--brand-bg-gradient) fixed;
}
訣竅在於「顯示」鮮豔的填滿顏色。方法是在頂端加上硬停漸層。漸層在填滿百分比之前是透明的,之後則使用未填滿的軌道表面顏色。未填滿的表面後方是全寬顏色,等待透明度將其顯現。
軌跡填滿樣式
我的設計需要 JavaScript 才能維持填滿樣式。雖然有僅限 CSS 的策略,但需要將捲軸元素的高度設為與軌道相同,而我無法在這些限制內找到和諧。
/* grab sliders on page */
const sliders = document.querySelectorAll('input[type="range"]')
/* take a slider element, return a percentage string for use in CSS */
const rangeToPercent = slider => {
const max = slider.getAttribute('max') || 10;
const percent = slider.value / max * 100;
return `${parseInt(percent)}%`;
};
/* on page load, set the fill amount */
sliders.forEach(slider => {
slider.style.setProperty('--track-fill', rangeToPercent(slider));
/* when a slider changes, update the fill prop */
slider.addEventListener('input', e => {
e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
})
})
我認為這能讓視覺效果更上一層樓。即使沒有 JavaScript,滑桿也能正常運作,--track-fill 屬性並非必要,如果沒有,就不會有填滿樣式。如果可以使用 JavaScript,請填入自訂屬性,同時觀察使用者是否有任何變更,並將自訂屬性與值同步。
Ana Tudor 在 CSS-Tricks 上發表了一篇精彩文章,示範如何使用 CSS 解決方案填滿軌道。我也覺得 range 元素非常實用。
縮圖樣式
input[type="range"]::-webkit-slider-thumb {
appearance: none; /* clear styles, make way for mine */
cursor: ew-resize; /* cursor style to support drag direction */
border: 3px solid var(--surface3);
block-size: var(--thumb-size);
inline-size: var(--thumb-size);
margin-top: var(--thumb-offset);
border-radius: 50%;
background: var(--brand-bg-gradient) fixed;
}
這些樣式大多是為了製作出漂亮的圓形。您會再次看到固定的背景漸層,統一了滑桿、軌道和相關 SVG 元素的動態顏色。我將互動樣式分開,以便隔離用於懸停醒目顯示的 box-shadow 技術:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
::-webkit-slider-thumb {
…
/* shadow spread is initally 0 */
box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);
/* if motion is OK, transition the box-shadow change */
@media (--motionOK) {
& {
transition: box-shadow .1s ease;
}
}
/* on hover/active state of parent, increase size prop */
@nest input[type="range"]:is(:hover,:active) & {
--thumb-highlight-size: 10px;
}
}
目標是打造易於管理且生動的視覺效果,突顯使用者意見回饋。使用方塊陰影,可以避免效果觸發版面配置。做法是建立不模糊的陰影,並與圓形滑桿元素相符。然後在懸停時變更並轉換其展開大小。
如果核取方塊的醒目顯示效果也這麼簡單就好了…
跨瀏覽器選取器
我發現需要使用 -webkit- 和 -moz- 選取器,才能確保跨瀏覽器的一致性:
input[type="range"] {
&::-webkit-slider-runnable-track {}
&::-moz-range-track {}
&::-webkit-slider-thumb {}
&::-moz-range-thumb {}
}
自訂核取方塊
以下 HTML 輸入元素範例說明如何自訂外觀:
<input type="checkbox">
這個元素有 3 個部分需要自訂:
核取方塊元素
input[type="checkbox"] {
inline-size: var(--space-sm); /* increase width */
block-size: var(--space-sm); /* increase height */
outline-offset: 5px; /* focus style enhancement */
accent-color: var(--brand); /* tint the input */
position: relative; /* prepare for an absolute pseudo element */
transform-style: preserve-3d; /* create a 3d z-space stacking context */
margin: 0;
cursor: pointer;
}
transform-style 和 position 樣式會為我們稍後介紹的虛擬元素做好準備,以便設定醒目顯示的樣式。否則,這大多是我個人的主觀風格。我喜歡將游標設為指標、喜歡外框偏移、預設核取方塊太小,如果支援 accent-color,請將這些核取方塊納入品牌色彩配置。
核取方塊標籤
為核取方塊提供標籤有 2 個重要原因。第一個是代表核取方塊值的用途,回答「開啟或關閉什麼?」第二個是使用者體驗,網頁使用者已習慣透過相關聯的標籤與核取方塊互動。
<input type="checkbox" id="text-notifications" name="text-notifications" >
<label for="text-notifications"> <h3>Text Messages</h3> <small>Get notified about all text messages sent to your device</small> </label>
在標籤上,加入指向核取方塊 ID 的 for 屬性:<label for="text-notifications">。在核取方塊上,請同時使用名稱和 ID,確保各種工具和技術 (例如滑鼠或螢幕閱讀器) 都能找到核取方塊:<input type="checkbox" id="text-notifications" name="text-notifications">。:hover、:active 等功能可免費與表單連結,增加表單的互動方式。
核取方塊醒目顯示
我想讓介面保持一致,而滑桿元素有不錯的縮圖醒目顯示,我想與核取方塊搭配使用。縮圖可以使用 box-shadow 及其 spread 屬性,放大或縮小陰影。不過,這個效果在這裡不適用,因為我們的核取方塊是正方形,也應該是正方形。
我可以使用虛擬元素和大量棘手的 CSS 達到相同的視覺效果:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
input[type="checkbox"]::before {
--thumb-scale: .01; /* initial scale of highlight */
--thumb-highlight-size: var(--space-xl);
content: "";
inline-size: var(--thumb-highlight-size);
block-size: var(--thumb-highlight-size);
clip-path: circle(50%); /* circle shape */
position: absolute; /* this is why position relative on parent */
top: 50%; /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
left: 50%;
background: var(--thumb-highlight-color);
transform-origin: center center; /* goal is a centered scaling circle */
transform: /* order here matters!! */
translateX(-50%) /* counter balances left: 50% */
translateY(-50%) /* counter balances top: 50% */
translateZ(-1px) /* PUTS IT BEHIND THE CHECKBOX */
scale(var(--thumb-scale)) /* value we toggle for animation */
;
will-change: transform;
@media (--motionOK) { /* transition only if motion is OK */
& {
transition: transform .2s ease;
}
}
}
/* on hover, set scale custom property to "in" state */
input[type="checkbox"]:hover::before {
--thumb-scale: 1;
}
建立圓形虛擬元素很簡單,但將其放在附加的元素後面則較為困難。以下是修正前後的對比:
這絕對是微互動,但對我來說,保持視覺一致性很重要。動畫縮放技術與我們在其他地方使用的技術相同。我們將自訂屬性設為新值,並讓 CSS 根據動作偏好設定進行轉換。這裡的主要功能是 translateZ(-1px)。父項建立了 3D 空間,而這個虛擬元素子項則透過將自身稍微向後放置在 Z 空間中,來利用這個空間。
無障礙設定
YouTube 影片清楚示範了這個設定元件的滑鼠、鍵盤和螢幕閱讀器互動。我會在這裡說明一些細節。
HTML 元素選項
<form>
<header>
<fieldset>
<picture>
<label>
<input>
每個標頭都包含使用者瀏覽工具的提示和訣竅。有些元素會提供互動提示、有些會連結互動功能,有些則有助於建構螢幕閱讀器瀏覽的無障礙樹狀結構。
HTML 屬性
我們可以隱藏螢幕閱讀器不需要的元素,在本例中,就是滑桿旁的圖示:
<picture aria-hidden="true">
上方影片示範 Mac OS 的螢幕閱讀器流程。請注意,輸入焦點會直接從一個滑桿移到下一個滑桿。這是因為我們隱藏了可能在前往下一個滑桿時停留的圖示。如果沒有這個屬性,使用者就必須停下來、聆聽,然後略過可能看不到的圖片。
SVG 包含許多數學運算,我們來新增 <title> 元素,以便在滑鼠游標懸停時顯示標題,以及人類可讀的註解,說明數學運算建立的內容:
<svg viewBox="0 0 24 24">
<title>A note icon</title>
<path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>
除此之外,我們也使用了足夠且標示清楚的 HTML,因此表單在滑鼠、鍵盤、電玩遊戲控制器和螢幕閱讀器上的測試效果都很好。
JavaScript
我們已說明如何透過 JavaScript 管理軌道填滿顏色,現在來看看與 <form> 相關的 JavaScript:
const form = document.querySelector('form');
form.addEventListener('input', event => {
const formData = Object.fromEntries(new FormData(form));
console.table(formData);
})
每次與表單互動並變更表單時,控制台都會將表單記錄為資料表中的物件,方便您在提交至伺服器前查看。

結論
現在你知道我是怎麼做的了,你會怎麼做呢?這會產生一些有趣的元件架構!誰會用自己最愛的架構,製作第一個有版位的版本?🙂
讓我們嘗試各種方法,瞭解所有建構網頁的方式。建立示範、推文給我連結,我會將其新增至下方的社群混音部分!