建立設定元件

概略說明如何建構滑桿和核取方塊的設定元件。

在本文中,我想分享如何替回應式網頁建構設定元件,支援多種裝置輸入內容,並且能夠在各種瀏覽器中運作。試試示範

示範

如果您偏好播放影片,或是希望在 UI/使用者體驗預覽我們正在建構的內容,請參考以下的 YouTube 逐步操作說明:

總覽

我們將各項元件分為以下幾個部分:

  1. 版面配置
  2. 顏色
  3. 自訂範圍輸入內容
  4. 自訂核取方塊輸入內容
  5. 無障礙功能注意事項
  6. JavaScript

版面配置

這是第一個將所有 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-itemsalign-content 提供功能,而在處理包裝元素時,content 版面配置對齊方式則會以群組的形式將空間分配給子項。

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;
}

主要元素使用 place-content: center 對齊捷徑,因此子項在一欄和兩欄版面配置中會垂直和水平置中。

請觀看上方的影片,瞭解即使已進行包裝,「內容」會保持置中。

重複自動調整最小值

<form> 會針對每個區段使用自動調整式格線版面配置。這個版面配置會根據可用空間,從 1 欄切換為 2 欄。

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 曾在自己的網誌上充分描述額外的 min() 函式,詳情請參閱「Intrinsically 回應式 CSS Grid with minmax() 和 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 看起來很棒!

還記得先前的版面配置「只是要填空嗎?」?以下提供這類元件在元件中的完整外觀:

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-darksurface-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 是一種以人為本的語法,主要規範我們如何看待色彩,而不是使用數學 (例如 255) 測量色彩的方式。這是一項明顯的優勢,因為人類可以更輕鬆地寫字,而其他人類也能受到這些調整影響。

pod.link/csspodcast 網頁的螢幕截圖,顯示「顏色 2:Perception」劇集
歡迎透過 CSS Podcast 瞭解色調 (及更多其他功能!)

在這個示範中,我們來看一下語法 和要轉動的黑暗值我們來看看 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 目前完全無法存取這些顏色。我再重複一次:Google 並無法存取大多數現代監視器的三分之一顏色。這些顏色不單只是任何顏色,而是螢幕可以顯示最鮮明的色彩。我們的網站連線速度比 CSS 規格和瀏覽器導入作業更快,因此網站運作速度較慢。

Lea Verou

使用色彩配置自動調整表單控制項

許多瀏覽器都會提供深色主題控制項 (目前為 Safari 和 Chromium),但您必須在設計時使用的 CSS 或 HTML 中加以指定。

以上是示範在開發人員工具的「樣式」面板中的屬性效果。示範會使用 HTML 標記,我認為通常更佳的位置:

<meta name="color-scheme" content="dark light">

如要瞭解詳細資訊,請參閱 Thomas Steinercolor-scheme 文章。核取方塊輸入值外,還有許多功能等您來發掘!

CSS accent-color

表單元素上的 accent-color 最近活動屬於單一 CSS 樣式,可變更瀏覽器輸入元素中使用的色調顏色。詳情請參閱 GitHub。讓我把元件加入元件的樣式中隨著瀏覽器支援這項功能,核取方塊會聚焦於帶有粉紅色和紫色的彈出主題。

input[type="checkbox"] {
  accent-color: var(--brand);
}

來自 Chromium 的粉紅色核取方塊螢幕截圖

固定漸層和焦點內部的抽色

在使用一段時間後,顏色最為理想。我喜歡的其中一種方式是透過彩色的 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;
    }
  }
}

當此元素的某個子項聚焦在內時:

  1. 已在 .fieldset-item 背景指派較高的對比度表面顏色。
  2. 巢狀 svg 會填滿白色,提高對比度。
  3. 巢狀 <picture> clip-path 會展開為完整圓形,背景則會填滿亮的固定漸層。

自訂範圍

以下列 HTML 輸入元素為例,我會示範如何自訂外觀:

<input type="range">

我們需要自訂這個元素並分為 3 個部分:

  1. 範圍元素 / 容器
  2. 追蹤
  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 個部分:

  1. 核取方塊元素
  2. 相關標籤
  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-styleposition 樣式可用於準備我們稍後推出的虛擬元素,以便設定醒目顯示的樣式。否則大多是我意見小的風格我喜歡遊標指向指標,就像外框偏移,預設核取方塊也過小,而如果 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>

在標籤中加入 for 屬性,使其指向由 ID 勾選的核取方塊:<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 的螢幕閱讀器流程,請留意輸入焦點如何從滑桿移到下一個滑桿。這是因為我們在下一個滑桿時,隱藏了可能停下的圖示。如果沒有這個屬性,使用者就必須先停止、監聽並擺脫看不見的圖片。

可擴充向量圖形具有大量的數學能力,因此我們要新增 <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);
})

每次表單與表單互動或變更時,主控台都會將表單記錄為資料表,方便檢查後再提交至伺服器。

主控台.table() 結果的螢幕截圖,表單資料會顯示在表格中

結論

現在你知道我怎麼做,你會怎麼做?這樣可以達到一些有趣的元件架構!誰將建構第 1 版,並在最喜歡的架構中使用運算單元?🙂

讓我們帶您更多元的方法,並瞭解運用網路打造網站的所有方式。 建立示範並透過 Twitter 推文連結,我就會把連結新增至下方的「社群重混」部分!

社群重混作品

  • @tomayac 以樣式取代核取方塊標籤的懸停區域!這個版本不會有元素之間的懸停間距:示範來源