建立媒體捲動工具元件

這項基礎總覽說明如何為電視、手機、電腦等裝置建構回應式水平捲動檢視畫面。

在這篇文章中,我想分享一些想法,說明如何為網路建立水平捲動體驗,讓使用者體驗更簡單、更有彈性、更易於存取,並且可在各瀏覽器和平台 (例如電視) 上運作。試用示範模式

示範

如果你偏好觀看影片,請參閱這篇文章的 YouTube 版本:

總覽

我們將建構水平捲動版面配置,用於代管媒體或產品的縮圖。這個元件一開始只是簡單的 <ul> 清單,但經過 CSS 轉換後,便能提供令人滿意的流暢捲動體驗,展示圖片並將圖片套用至格狀檢視畫面。我們新增了 JavaScript,以便促進 roving-index 互動,協助鍵盤使用者略過超過 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 屬性。媒體捲軸的替代文字是使用者體驗的機會,可為縮圖提供額外的背景資訊,或在圖片未載入時做為備用文字,或是為依賴螢幕閱讀器等輔助技術的使用者提供語音 UI。如要進一步瞭解,請參閱五大關鍵規則,讓替代文字符合規範

loading 屬性接受關鍵字 lazy,用於指出只有在圖片位於檢視區範圍內時,才應擷取這個圖片來源。這對於大型清單來說非常實用,因為使用者只會下載他們捲動至畫面中的項目圖片。

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

使用 color-scheme 做為 <meta> 標記,向瀏覽器傳達網頁需要淺色和深色提供的使用者代理程式樣式。這項免費功能可提供深色模式或淺色模式,具體取決於您如何查看:

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

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

如要進一步瞭解這項功能,請參閱 Thomas Steiner 的文章:https://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> 元素都會透過取得新的 inline-block 顯示類型,移除其 ::marker

不過,圖片尚未回應,而且會直接從所屬的方塊中彈出。您可以使用一些大小、適合和邊框樣式,以及背景漸層來控制這些圖片,以便在延遲載入時使用:

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 設為遠離方塊,為其提供一些不錯的空間。如果使用者沒有減少動作偏好設定,系統會轉換偏移量,為焦點事件提供細微的動作。

流動索引

在這些長長的捲動內容和選項清單中,遊戲控制器和鍵盤使用者需要特別留意。解決這個問題的常見模式稱為「流動索引」。當項目容器獲得鍵盤焦點,但一次只能允許 1 個子項保留焦點時,就會發生此錯誤。這個單一可聚焦項目一次一項的體驗設計,可讓您略過可能很長的項目清單,不必按下分頁鍵 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

顯示比例

截至本文撰寫時,aspect-ratio 的支援功能仍在 Firefox 的標記後方,但在 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 大小。使用草稿巢狀語法時,每張相片的顯示比例會根據其位於第一、第二或第三列而有所不同。巢狀語法也允許設定一些小型檢視區調整,並與其他大小邏輯搭配使用。

有了 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 個要求,100kb 的資源,耗時 131 毫秒)

ALT_TEXT_HERE

以下是加入 prefers-reduced-data CSS 後的網站成效:

ALT_TEXT_HERE

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

減少 64 個要求,也就是這個瀏覽器分頁的檢視區域內的約 60 張圖片 (在寬螢幕顯示器上進行測試)、網頁載入速度提升約 80%,以及透過網路傳輸的資料減少 10%。相當強大的 CSS。

結論

既然你知道我如何做到,你會怎麼做呢?🙂

讓我們多方嘗試,瞭解在網路上建構應用程式的所有方式。建立 Codepen 或自行發布示範內容,然後透過推文告訴我,我會將內容加入下方的社群重混部分。

資料來源

社群重混作品

尚無任何資料可提供!