建構媒體捲動元件

基礎總覽:如何為電視、手機、桌機等裝置建構回應式水平捲軸檢視區塊。

在這篇文章中,我想分享如何為網頁建立水平捲動體驗,並盡量減少干擾、提高回應性、無障礙程度,以及跨瀏覽器和平台 (例如電視) 的適用性。試用示範模式

示範

如果比較喜歡看影片,可以觀看這篇貼文的 YouTube 版本:

總覽

我們將建構水平捲動版面配置,用於存放媒體或產品的縮圖。這個元件一開始只是簡單的 <ul> 清單,但透過 CSS 轉換後,就能提供令人滿意的流暢捲動體驗,顯示圖片並將圖片對齊格線。新增 JavaScript,方便漫遊索引互動,協助鍵盤使用者略過遍歷 100 多個項目。此外,實驗性媒體查詢 prefers-reduced-data 可將媒體捲軸轉換為輕量型標題捲軸體驗。

從無障礙標記開始

媒體捲動器僅由幾個核心元件組成,也就是含有項目的清單。最簡單的清單形式,就是可以傳遍世界各地,且所有人都看得懂。使用者進入這個頁面後,可以瀏覽清單並點按連結查看商品。這是我們無障礙的基礎。

提供含有 <ul> 元素的清單:

<ul class="horizontal-media-scroller">
  <li></li>
  <li></li>
  <li></li>
  ...
<ul>

使用 <a> 元素讓清單項目具備互動功能:

<li>
  <a href="#">
    ...
  </a>
</li>

使用 <figure> 元素以語意方式表示圖片及其說明:

<figure>
  <picture>
    <img alt="..." loading="lazy" src="https://picsum.photos/500/500?1">
  </picture>
  <figcaption>Legends</figcaption>
</figure>

請注意 <img> 上的 altloading 屬性。媒體捲軸的替代文字是提升使用者體驗的好機會,可為縮圖提供額外背景資訊、在圖片未載入時做為備用文字,或為使用螢幕閱讀器等輔助技術的使用者提供語音介面。如要瞭解詳情,請參閱五大黃金法則,確保替代文字符合規定

loading 屬性會接受 lazy 關鍵字,藉此發出信號,表示只有在圖片位於可視區域內時,才應擷取這個圖片來源。這對大型清單來說非常實用,因為使用者只會下載捲動到檢視畫面中的項目圖片。

支援使用者偏好的色彩配置

使用 color-scheme 做為 <meta> 標記,向瀏覽器發出信號,表示網頁需要淺色和深色模式的使用者代理程式樣式。這項功能可免費使用,而且無論你怎麼看,都是深色或淺色模式:

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

這個中繼標記會盡可能提供最早的信號,因此如果使用者偏好深色主題,瀏覽器就能選取深色預設畫布顏色。也就是說,在載入網站頁面時,不會出現白色畫布背景。載入時可流暢切換深色主題,讓眼睛更舒適。

如要瞭解詳情,請參閱 Thomas Steinerhttps://web.dev/color-scheme/ 的文章。

新增內容

根據上述 ul > li > a > figure > picture > img 的內容結構,下一個工作是新增圖片和標題,以便捲動瀏覽。我已在示範中加入靜態預留位置圖片和文字,但您可隨意使用偏好的資料來源。

使用 CSS 新增樣式

現在 CSS 必須取得這份一般內容清單,並將其轉換為體驗。Netflix、應用程式商店和許多其他網站和應用程式,都會使用水平捲動區域,在檢視區塊中塞滿類別和選項。

建立捲軸版面配置

請務必避免在版面配置中截斷內容,或以刪節號截斷文字。許多電視都有媒體捲軸,就像這個一樣,但往往會省略內容。這個版面配置不支援! 媒體內容也能覆寫欄大小,讓 1 個版面配置足以處理許多有趣的組合。

2
顯示捲動列。一個沒有省略符號,因此較高,每個標題都能完整顯示。另一個較短,許多標題都以省略號結尾。

容器可將預設大小做為自訂屬性提供,藉此覆寫資料欄大小。這個格線版面配置會決定欄大小,只會管理間距和方向:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2); /* parent owned value for children to be relative to*/
  margin: 0;
}

接著,<picture> 元素會使用自訂屬性建立基本長寬比:方塊:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

只要再加入幾個次要樣式,即可完成媒體捲軸的基礎架構:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  & > li {
    display: inline-block; /* removes the list-item bullet */
  }

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

設定 overflow 會設定 <ul>,允許透過清單捲動和使用鍵盤導覽,然後每個直接子項 <li> 元素都會移除 ::marker,並取得新的顯示類型 inline-block

不過,圖片還不是回應式,而且會從所在方塊中爆開。使用一些大小、合身度和邊框樣式,以及延遲載入時的背景漸層,即可控制這些圖片:

img {
  /* smash into whatever box it's in */
  inline-size: 100%;
  block-size: 100%;

  /* don't squish but do cover the space */
  object-fit: cover;

  /* soften the edges */
  border-radius: 1ex;
  overflow: hidden;

  /* if empty, show a gradient placeholder */
  background-image:
    linear-gradient(
      to bottom,
      hsl(0 0% 40%),
      hsl(0 0% 20%)
    );
}

捲動邊框間距

與網頁內容對齊,加上無邊框捲動表面積,是打造和諧且極簡元件的關鍵。

如要完成與排版和版面配置線對齊的無邊框捲動版面配置,請使用與 scroll-padding 相符的 padding

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block: calc(var(--gap) / 2); /* make space for scrollbar and focus outline */
}

修正水平捲動邊框間距錯誤 上文說明瞭設定捲動容器邊框間距的簡單程度,但這項功能仍有相容性問題 (已在 Chromium 91 以上版本修正!)。如要瞭解這段歷史,請參閱這裡,但簡而言之,捲動檢視區塊並非一律會將邊框間距納入考量。

最後一個清單項目的內嵌結尾側會醒目顯示一個方塊,表示邊框間距和元素寬度相同,可建立所需的對齊方式。

為了讓瀏覽器在捲動器結尾加入邊框間距,我會以每個清單中的最後一個圖案為目標,並附加所需邊框間距量的虛擬元素。

.horizontal-media-scroller > li:last-of-type figure {
  position: relative;

  &::after {
    content: "";
    position: absolute;

    inline-size: var(--gap);
    block-size: 100%;

    inset-block-start: 0;
    inset-inline-end: calc(var(--gap) * -1);
  }
}

使用邏輯屬性可讓媒體捲軸在任何書寫模式和文件方向中運作。

捲動貼齊

只要一行 CSS,溢位捲動容器就能變成對齊檢視區塊,然後由子項指定要如何與該檢視區塊對齊。

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block-end: calc(var(--gap) / 2);

  scroll-snap-type: inline mandatory;

  & figure {
    scroll-snap-align: start;
  }
}

專注

這個元件的靈感來自於電視、應用程式商店等平台上的超高人氣。許多電玩遊戲平台都使用與此非常相似的媒體捲軸,做為主要主畫面版面配置。這項功能不僅是小幅增強,更是重大的使用者體驗時刻。假設您在沙發上使用遙控器操作這個媒體捲軸,可以透過以下方式稍微提升互動體驗:

.horizontal-media-scroller a {
  outline-offset: 12px;

  &:focus {
    outline-offset: 7px;
  }

  @media (prefers-reduced-motion: no-preference) {
    & {
      transition: outline-offset .25s ease;
    }
  }
}

這會將焦點外框樣式 7px 移出方塊,讓方塊有適當的空間。如果使用者沒有減少動態效果的動作偏好設定,系統就會轉換位移,為焦點事件提供細微的動態效果。

Roving index

在這些長長的捲動內容和選項清單中,使用遊戲手把和鍵盤的使用者需要特別注意。解決這個問題的常見模式稱為「漫遊索引」。當項目容器成為鍵盤焦點,但一次只能有 1 個子項保留焦點時,這項設計一次只會聚焦於一個可聚焦的項目,讓使用者不必按 Tab 鍵 50 次以上,就能略過可能很長的項目清單,直接到達結尾。

示範的第一個捲動器中有 300 個項目。我們可以做得更好,不必讓使用者逐一瀏覽所有項目,才能前往下一個區段。

如要建立這類體驗,JavaScript 必須監控鍵盤事件和焦點事件。我在 npm 上建立小型開放原始碼程式庫,協助輕鬆達成這項使用者體驗。以下說明如何將這項功能用於 3 個捲動器:

import {rovingIndex} from 'roving-ux';

rovingIndex({
  element: someElement
});

這個範例會查詢文件的捲軸,並針對每個捲軸呼叫 rovingIndex() 函式。傳遞 rovingIndex() 元素,即可取得漫遊體驗 (例如清單容器),以及目標查詢選擇器 (如果焦點目標不是直接子項)。

document.querySelectorAll('.horizontal-media-scroller')
  .forEach(scroller =>
    rovingIndex({
      element: scroller,
      target: 'a',
}))

如要進一步瞭解這項效果,請參閱開放原始碼程式庫 roving-ux

顯示比例

撰寫本文時,Firefox 支援 aspect-ratio 的功能仍處於標記狀態,但 Chromium 瀏覽器或機上盒已可使用。由於媒體捲動器格線版面配置只會指定方向和間距,因此大小可以在媒體查詢中變更,而媒體查詢會檢查長寬比支援。逐步強化,加入更多動態媒體捲軸。

在 16:9 和 4:3 的其他設計比例旁,顯示長寬比為 4:4 的方塊

@supports (aspect-ratio: 1) {
  .horizontal-media-scroller figure > picture {
    inline-size: auto; /* for a block-size driven ratio */
    aspect-ratio: 1; /* boxes by default */

    @nest section:nth-child(2) & {
      aspect-ratio: 16/9;
    }

    @nest section:nth-child(3) & {
      /* double the size of the others */
      block-size: calc(var(--size) * 2);
      aspect-ratio: 4/3;

      /* adjust size to fit more items into the viewport */
      @media (width <= 480px) {
        block-size: calc(var(--size) * 1.5);
      }
    }
  }
}

如果瀏覽器支援 aspect-ratio 語法,媒體捲軸圖片就會升級為 aspect-ratio 大小。使用草稿巢狀語法,每個圖片會根據是第一、第二或第三列,變更顯示比例。巢狀語法也允許設定一些小型的 viewport 調整項目,與其他大小調整邏輯位於同一位置。

有了這項 CSS,當更多瀏覽器引擎支援這項功能時,系統就會算繪出易於管理但更具視覺吸引力的版面配置。

偏好減少數據用量

雖然這項技術目前僅在 Canary透過標記啟用,但我想分享我如何透過幾行 CSS 程式碼,大幅節省網頁載入時間和資料用量。第 5 級prefers-reduced-data 媒體查詢可讓您詢問裝置是否處於任何資料用量減少的狀態,例如省電模式。如果是,我就可以修改文件,並隱藏圖片。

ALT_TEXT_HERE

figure {
  @media (prefers-reduced-data: reduce) {
    & {
      min-inline-size: var(--size);

      & > picture {
        display: none;
      }
    }
  }
}

使用者仍可瀏覽內容,但不會下載耗用大量資源的圖片。以下是加入 prefers-reduced-data CSS 前的網站:

(7 項要求,131 毫秒內有 100 KB 的資源)

ALT_TEXT_HERE

加入 prefers-reduced-data CSS 後的網站效能如下:

ALT_TEXT_HERE

(71 個要求,1.2 MB 的資源,耗時 1.07 秒)

減少 64 個要求,也就是這個瀏覽器分頁視埠中的約 60 張圖片 (測試是在寬螢幕上進行),網頁載入速度提升約 80%,且透過網路傳輸的資料量減少 10%。功能強大的 CSS。

結論

現在您已瞭解我的做法,您會怎麼做呢?🙂

讓我們多元化方法,學習在網路上建構內容的所有方式。 建立 Codepen 或代管自己的試用版,然後在推文中提及我,我會將其新增至下方的「社群混音」部分。

資料來源

社群重混作品

目前沒有任何資料可提供!