建立側邊導覽列元件

製作回應式投影片的側邊導覽列基礎總覽

在這篇文章中,我想與您分享我如何設計回應式網頁導覽元件的原型、支援鍵盤導覽功能、支援和不使用 JavaScript,以及跨瀏覽器運作。歡迎查看示範內容

如果您喜歡看影片,請參考這篇文章的 YouTube 版本:

總覽

建置回應式導航系統相當困難。有些使用者會使用鍵盤、有些人擁有強大的桌面,有些則使用小型行動裝置造訪。所有造訪的使用者都應該能開啟及關閉選單。

電腦版至行動裝置回應式版面配置示範
iOS 和 Android 裝置上的淺色和深色主題

網路戰術

在這個元件探索中,我可以結合幾項重要的網路平台功能,享受愉快的體驗:

  1. CSS :target
  2. CSS 格狀檢視
  3. CSS transforms
  4. 可視區域和使用者偏好設定的 CSS 媒體查詢
  5. focus 改善使用者體驗的 JS

我的解決方案只有一個側欄,且只有在「行動」可視區域在 540px 以下時才會切換。我們的中斷點會是 540px,在行動裝置互動版面配置和靜態桌面版面配置之間進行切換。

CSS :target 虛擬類別

一個 <a> 連結會將網址雜湊設為 #sidenav-open,並將另一個網址設為空白 ('')。最後,元素的 id 會比對雜湊:

<a href="#sidenav-open" id="sidenav-button" title="Open Menu" aria-label="Open Menu">

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>

<aside id="sidenav-open">
  …
</aside>

只要點選這些連結,就會改變網頁網址的雜湊狀態,然後加入虛擬類別,即可顯示或隱藏側邊導覽列:

@media (max-width: 540px) {
  #sidenav-open {
    visibility: hidden;
  }

  #sidenav-open:target {
    visibility: visible;
  }
}

CSS 格線

過去我只使用絕對或固定位置側邊導覽版面配置和元件,不過,格線的 grid-area 語法可讓我們將多個元素指派給同一列或欄。

堆疊

主要版面配置元素 #sidenav-container 是一個格狀檢視畫面,可建立 1 個資料列和 2 個資料欄,其中 1 個都命名為 stack。當空間受限時,CSS 會將所有 <main> 元素的子項指派給相同的格線名稱,將所有元素放在同一個空間中,進而形成堆疊。

#sidenav-container {
  display: grid;
  grid: [stack] 1fr / min-content [stack] 1fr;
  min-height: 100vh;
}

@media (max-width: 540px) {
  #sidenav-container > * {
    grid-area: stack;
  }
}

<aside> 是包含側邊導覽的動畫元素。其中包含 2 個子項:名為 [nav] 的導覽容器 <nav> 與名為 [escape] 的背景 <a>,前者用於關閉選單。

#sidenav-open {
  display: grid;
  grid-template-columns: [nav] 2fr [escape] 1fr;
}

調整 2fr1fr,找出您需要的選單疊加層及其負空間關閉按鈕的比例。

變更比率後的示範。

CSS 3D 變形和轉換

我們的版面配置現已堆疊在行動裝置可視區域的大小。除非我新增一些樣式 否則預設會疊加我們的文章在接下來的章節中,我將會拍攝一些使用者體驗:

  • 為開場和關閉製作動畫
  • 只有在使用者允許時,才為動畫加入動畫
  • visibility 建立動畫效果,讓鍵盤焦點不會進入螢幕外元素

開始導入動作動畫時,我想先從無障礙需求著手。

無障礙動作

並非每個人都會希望獲得滑出運動體驗。我們的解決方案會在媒體查詢中調整 --duration CSS 變數,藉此套用這項偏好設定。此媒體查詢值代表使用者的動作作業系統偏好 (如果有的話)。

#sidenav-open {
  --duration: .6s;
}

@media (prefers-reduced-motion: reduce) {
  #sidenav-open {
    --duration: 1ms;
  }
}
套用與未套用時間長度的互動示範。

現在,當側邊導覽列要保持開啟及關閉時,如果使用者偏好減少動作,我會立即將元素移到檢視畫面中,而不顯示任何動作。

轉換、轉換、翻譯

退出側邊導覽列 (預設)

如要將行動裝置側邊導覽列的預設狀態設為螢幕外狀態,可以使用 transform: translateX(-110vw) 定位元素。

請注意,我們已在 -100vw 的一般螢幕外程式碼中新增另一個 10vw,確保側邊導覽列的 box-shadow 在隱藏時不會透視至主要可視區域。

@media (max-width: 540px) {
  #sidenav-open {
    visibility: hidden;
    transform: translateX(-110vw);
    will-change: transform;
    transition:
      transform var(--duration) var(--easeOutExpo),
      visibility 0s linear var(--duration);
  }
}
以下位置的側邊導覽列:

#sidenav 元素符合為 :target 時,請將 translateX() 位置設為 homebase 0,然後觀察當網址雜湊變更後,CSS 會將元素從自身的 -110vw 滑出至 0 的「內」位置。var(--duration)

@media (max-width: 540px) {
  #sidenav-open:target {
    visibility: visible;
    transform: translateX(0);
    transition:
      transform var(--duration) var(--easeOutExpo);
  }
}

轉場效果顯示設定

現在,目標是在螢幕閱讀器關閉時隱藏選單,以免系統將焦點放在螢幕外的選單中。方法是在 :target 變更時設定瀏覽權限轉場。

  • 進入畫面時,請勿轉換顯示設定,而是立即顯示,這樣我可以立即看到元素滑入畫面並接受焦點。
  • 離開時,系統會延遲顯示轉換的顯示狀態,但延遲顯示,所以在轉場結束時,就會轉換為 hidden

改善無障礙使用者體驗

這項解決方案需要變更網址,才能管理狀態。當然,<a> 元素應在此使用,以便免費獲得一些實用的無障礙功能。現在交織互動元素,使用標籤清楚表達意圖。

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>

<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
  <svg>...</svg>
</a>
示範旁白和鍵盤互動的使用者體驗。

現在,我們的主要互動按鈕都能清楚指出他們使用滑鼠和鍵盤的意圖。

:is(:hover, :focus)

這個實用的 CSS 功能虛擬選取器可讓您分享懸停樣式,快速地與懸停樣式搭配使用。

.hamburger:is(:hover, :focus) svg > line {
  stroke: hsl(var(--brandHSL));
}

JavaScript 上的 Sprinkle

按下 escape 鍵即可關閉

鍵盤上的Escape鍵應該向右關閉選單?我們來接線吧。

const sidenav = document.querySelector('#sidenav-open');

sidenav.addEventListener('keyup', event => {
  if (event.code === 'Escape') document.location.hash = '';
});
瀏覽器歷史記錄

為避免開啟和關閉互動無法堆疊多個項目至瀏覽器記錄,請將下列 JavaScript 內嵌到關閉按鈕中:

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu" onchange="history.go(-1)"></a>

這會在關閉時移除網址歷史記錄項目,使其看似從未開啟過選單。

以使用者體驗為重

下一段程式碼片段能幫助我們將焦點放在開啟或關閉按鈕的開啟和關閉按鈕上。我想輕鬆換機。

sidenav.addEventListener('transitionend', e => {
  const isOpen = document.location.hash === '#sidenav-open';

  isOpen
      ? document.querySelector('#sidenav-close').focus()
      : document.querySelector('#sidenav-button').focus();
})

開啟側邊導覽列時,將焦點移至關閉按鈕。側邊導覽列關閉時,請聚焦開啟的按鈕。只要在 JavaScript 中呼叫元素上的 focus() 即可。

結論

現在你知道該怎麼做了,你會怎麼做?!這可以提供一些有趣的元件架構!誰打算使用第 1 版使用運算單元?🙂

現在就來制定多樣化做法, 並瞭解在網路上建立應用程式的所有方式。建立 Glitch透過推文發布您的版本,然後我將其加入下方的社群重混部分。

社群重混作品