การสร้างคอมโพเนนต์แถบเลื่อนสื่อ

ภาพรวมพื้นฐานเกี่ยวกับวิธีสร้างมุมมองการเลื่อนแนวนอนที่ปรับเปลี่ยนตามอุปกรณ์สำหรับทีวี โทรศัพท์ เดสก์ท็อป ฯลฯ

ในโพสต์นี้ เราต้องการแชร์แนวคิดเกี่ยวกับวิธีสร้างประสบการณ์การเลื่อนในแนวนอนสำหรับเว็บที่เรียบง่าย ตอบสนอง เข้าถึงได้ และใช้งานได้ในเบราว์เซอร์และแพลตฟอร์มต่างๆ (เช่น ทีวี) ลองใช้เดโม

สาธิต

หากต้องการดูวิดีโอ คุณสามารถใช้โพสต์นี้ในเวอร์ชัน YouTube:

ภาพรวม

เราจะสร้างเลย์เอาต์แบบเลื่อนแนวนอนสำหรับแสดงภาพขนาดย่อของสื่อหรือผลิตภัณฑ์ คอมโพเนนต์เริ่มต้นจากรายการ <ul> ธรรมดาๆ แต่ได้รับการเปลี่ยนรูปแบบด้วย CSS ให้กลายเป็นประสบการณ์การเลื่อนที่ราบรื่นและน่าพึงพอใจ ซึ่งแสดงภาพและจัดวางภาพเหล่านั้นเป็นตารางกริด ระบบจะเพิ่ม JavaScript เพื่ออำนวยความสะดวกในการโต้ตอบกับดัชนีการค้นหา ซึ่งช่วยให้ผู้ใช้แป้นพิมพ์ข้ามการไปยังรายการต่างๆ กว่า 100 รายการได้ นอกจากนี้ ระบบจะใช้คำค้นหาสื่อเวอร์ชันทดลอง prefers-reduced-data เพื่อเปลี่ยนแถบเลื่อนสื่อให้กลายเป็นแถบเลื่อนชื่อที่เบา

เริ่มต้นด้วยมาร์กอัปที่เข้าถึงได้

แถบเลื่อนสื่อประกอบด้วยคอมโพเนนต์หลักเพียง 2 อย่าง ได้แก่ รายการที่มีรายการ รายการเพลงในรูปแบบที่ง่ายที่สุดสามารถเดินทางไปทั่วโลกและทุกคนสามารถรับชมได้อย่างชัดเจน ผู้ใช้ที่มาถึงหน้านี้จะเรียกดูรายการและคลิกลิงก์เพื่อดูรายการได้ นี่คือฐานที่เข้าถึงได้

ส่งรายการที่มีองค์ประกอบ <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>

โปรดสังเกตแอตทริบิวต์ alt และ loading ใน <img> ข้อความแสดงแทนของแถบเลื่อนสื่อเป็นโอกาสด้าน UX ในการช่วยเพิ่มบริบทของภาพขนาดย่อ หรือใช้เป็นข้อความสำรองในกรณีที่รูปภาพไม่โหลด หรือแสดง UI ที่พูดสำหรับผู้ใช้ที่พึ่งพาเทคโนโลยีความช่วยเหลือพิเศษ เช่น โปรแกรมอ่านหน้าจอ ดูข้อมูลเพิ่มเติมได้จากกฎ 5 ข้อสําหรับข้อความแสดงแทนที่เป็นไปตามข้อกําหนด

แอตทริบิวต์ loading ยอมรับคีย์เวิร์ด lazy เป็นวิธีส่งสัญญาณว่าควรดึงข้อมูลแหล่งที่มาของรูปภาพนี้เมื่อรูปภาพอยู่ในวิวพอร์ตเท่านั้น ซึ่งจะมีประโยชน์อย่างยิ่งสำหรับรายการขนาดใหญ่ เนื่องจากผู้ใช้จะดาวน์โหลดเฉพาะรูปภาพของรายการที่เลื่อนเข้ามาในมุมมองเท่านั้น

รองรับค่ากำหนดรูปแบบสีของผู้ใช้

ใช้ color-scheme เป็นแท็ก <meta> เพื่อส่งสัญญาณให้เบราว์เซอร์ทราบว่าหน้าเว็บของคุณต้องการทั้งสไตล์ User Agent แบบสว่างและแบบมืด ซึ่งก็คือโหมดมืดหรือโหมดสว่าง (แล้วแต่ว่าคุณจะมองอย่างไร)

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

เมตาแท็กจะให้สัญญาณที่เร็วที่สุดเท่าที่จะเป็นไปได้ เพื่อให้เบราว์เซอร์เลือกสีแคนวาสเริ่มต้นเป็นสีเข้มได้หากผู้ใช้ต้องการธีมมืด ซึ่งหมายความว่าการไปยังส่วนต่างๆ ระหว่างหน้าต่างๆ ของเว็บไซต์จะไม่แสดงพื้นหลังผ้าใบสีขาวระหว่างการโหลด ธีมมืดที่เปลี่ยนระหว่างการโหลดโดยอัตโนมัติ สบายตากว่ามาก

ดูข้อมูลเพิ่มเติมได้จาก Thomas Steiner ที่ https://web.dev/color-scheme/

เพิ่มเนื้อหา

จากโครงสร้างเนื้อหาข้างต้นของ ul > li > a > figure > picture > img งานถัดไปคือการเพิ่มรูปภาพและชื่อเพื่อเลื่อนดู ผมได้เตรียมเดโมพร้อมด้วย รูปภาพตัวยึดตำแหน่งและข้อความแบบคงที่มา แต่คุณสามารถเพิ่มประสิทธิภาพได้จากแหล่งข้อมูลโปรด

เพิ่มสไตล์ด้วย CSS

ตอนนี้ CSS จะนำรายการเนื้อหาทั่วไปนี้ไปเปลี่ยนให้เป็นประสบการณ์การใช้งาน Netflix, App Store และเว็บไซต์และแอปอื่นๆ อีกมากมายใช้พื้นที่การเลื่อนแนวนอนเพื่อบรรจุหมวดหมู่และตัวเลือกไว้ในวิวพอร์ต

การสร้างเลย์เอาต์แถบเลื่อน

สิ่งสำคัญคือหลีกเลี่ยงการตัดเนื้อหาในเลย์เอาต์หรือใช้การตัดข้อความด้วยเครื่องหมายจุดไข่ปลา ทีวีหลายชุดมีเครื่องเลื่อนสื่อเหมือน เครื่องนี้ แต่มักจะหันมาใช้เนื้อหาแบบวงรี แต่เลย์เอาต์นี้ไม่มี นอกจากนี้ ยังช่วยให้เนื้อหาสื่อลบล้างขนาดคอลัมน์ได้ ทําให้เลย์เอาต์ 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);
  }
}

เพิ่มสไตล์รองอีก 2-3 สไตล์เพื่อทำให้แถบเลื่อนสื่อสมบูรณ์

.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> ให้อนุญาตการเลื่อนและไปยังส่วนต่างๆ ด้วยแป้นพิมพ์ผ่านรายการ จากนั้นระบบจะนำ ::marker ออกจากองค์ประกอบ <li> ย่อยโดยตรงแต่ละรายการโดยรับ 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%)
    );
}

ระยะห่างจากขอบของการเลื่อน

การจัดวางเนื้อหาของหน้าเว็บ รวมถึงพื้นที่การเลื่อนจากขอบถึงขอบเป็นองค์ประกอบที่สําคัญอย่างยิ่งต่อความสอดคล้องและคอมโพเนนต์แบบมินิมอล

หากต้องการสร้างเลย์เอาต์การเลื่อนแบบเต็มหน้าจอที่สอดคล้องกับการจัดวางแบบอักษรและบรรทัดเลย์เอาต์ ให้ใช้ padding ที่ตรงกับ scroll-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 เพียง 1 บรรทัด จากนั้นองค์ประกอบย่อยจะต้องระบุวิธีที่ต้องการจัดแนวกับวิวพอร์ตนั้น

.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;
  }
}

โฟกัส

แรงบันดาลใจในการสร้างคอมโพเนนต์นี้มาจากความนิยมอย่างมากในทีวี ใน App Store และอื่นๆ แพลตฟอร์มวิดีโอเกมหลายแพลตฟอร์มใช้ตัวเลื่อนสื่อ คล้ายกับเลย์เอาต์นี้เป็นเลย์เอาต์หน้าจอหลัก โฟกัสเป็นองค์ประกอบ UX ที่สำคัญมาก ไม่ใช่แค่การเพิ่มเล็กๆ น้อยๆ ลองนึกภาพการใช้ตัวเลื่อนสื่อนี้จากโซฟาด้วยรีโมต คุณสามารถปรับปรุงการโต้ตอบเล็กๆ น้อยๆ ดังนี้

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

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

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

ซึ่งจะตั้งค่าสไตล์เส้นขอบโฟกัส 7px ให้อยู่ห่างจากกล่องเพื่อให้มีระยะห่างที่เหมาะสม หากผู้ใช้ไม่มีค่ากําหนดการเคลื่อนไหวเกี่ยวกับการลดการเคลื่อนไหว ระบบจะเปลี่ยนระยะห่างให้เหตุการณ์โฟกัสเคลื่อนไหวเล็กน้อย

ดัชนีการเดินทาง

ผู้ใช้เกมแพดและแป้นพิมพ์ต้องได้รับการพิจารณาเป็นพิเศษในรายการเนื้อหาและตัวเลือกแบบเลื่อนยาวเหล่านี้ รูปแบบทั่วไปในการแก้ปัญหานี้เรียกว่าดัชนีแบบเลื่อน เกิดขึ้นเมื่อคอนเทนเนอร์ของรายการมีโฟกัสแป้นพิมพ์ แต่อนุญาตให้มีโฟกัสที่รายการย่อยได้เพียงรายการเดียวในแต่ละครั้ง ประสบการณ์การโฟกัสรายการทีละรายการนี้ออกแบบมาเพื่ออนุญาตให้ข้ามรายการที่อาจยาวมาก แทนที่จะต้องกด 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

สัดส่วนภาพ

ขณะเขียนโพสต์นี้ การรองรับ aspect-ratio อยู่ในการตั้งค่าใน Firefox แต่ใช้ได้ในเบราว์เซอร์ Chromium หรือกล่องรับสัญญาณ เนื่องจากเลย์เอาต์ตารางกริดของเครื่องมือเลื่อนสื่อระบุเฉพาะทิศทางและระยะห่างเท่านั้น ขนาดจึงอาจเปลี่ยนแปลงภายใน Media Query ซึ่งฟีเจอร์จะตรวจสอบการรองรับสัดส่วนการแสดงผล การเพิ่มประสิทธิภาพแบบเป็นขั้นเป็นตอนในโปรแกรมเลื่อนสื่อแบบไดนามิกมากขึ้น

กล่องที่มีสัดส่วนภาพ 4:4 จะแสดงอยู่ข้างสัดส่วนการออกแบบอื่นๆ ที่ใช้คือ 16:9 และ 4:3

@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 เมื่อใช้ไวยากรณ์การฝังฉบับร่าง รูปภาพแต่ละรูปจะเปลี่ยนสัดส่วนภาพโดยขึ้นอยู่กับว่ารูปภาพนั้นอยู่ในแถวที่ 1, 2 หรือ 3 ไวยากรณ์ที่ฝังยังช่วยให้คุณตั้งค่าการปรับวิวพอร์ตเล็กๆ น้อยๆ ควบคู่ไปกับตรรกะการปรับขนาดอื่นๆ ได้ด้วย

เมื่อใช้ CSS ดังกล่าว การแสดงผลเลย์เอาต์ที่จัดการได้ง่ายแต่ดูน่าสนใจยิ่งขึ้นจะแสดงผลได้ เนื่องจากฟีเจอร์นี้พร้อมใช้งานในเครื่องมือเบราว์เซอร์จํานวนมากขึ้น

ต้องการใช้อินเทอร์เน็ตน้อยลง

แม้ว่าเทคนิคถัดไปนี้จะใช้ได้หลังเปิดใช้ Flag ใน Canary เท่านั้น แต่เราอยากแชร์วิธีประหยัดเวลาในการโหลดหน้าเว็บและการใช้อินเทอร์เน็ตได้อย่างมากด้วย CSS เพียงไม่กี่บรรทัด prefers-reduced-data การค้นหาสื่อจากระดับ 5 ช่วยให้สามารถสอบถามได้ว่าอุปกรณ์อยู่ในสถานะการลดปริมาณข้อมูลหรือไม่ เช่น โหมดประหยัดอินเทอร์เน็ต หากใช่ เราจะแก้ไขเอกสารได้ และในกรณีนี้ เราจะซ่อนรูปภาพ

ALT_TEXT_HERE

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

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

เนื้อหายังคงไปยังส่วนต่างๆ ได้ แต่ดาวน์โหลดรูปภาพขนาดใหญ่ได้โดยไม่ต้องเสียค่าใช้จ่าย นี่คือเว็บไซต์ก่อนที่จะเพิ่ม CSS ของ prefers-reduced-data

(คําขอ 7 รายการ ทรัพยากร 100 KB ใน 131 มิลลิวินาที)

ALT_TEXT_HERE

ประสิทธิภาพของเว็บไซต์หลังจากเพิ่ม prefers-reduced-data CSS

ALT_TEXT_HERE

(คำขอ 71 รายการ, ทรัพยากร 1.2 MB ใน 1.07 วินาที)

คำขอน้อยลง 64 รายการ ซึ่งก็คือรูปภาพประมาณ 60 ภาพภายในวิวพอร์ต (การทดสอบที่ถ่ายในจอแสดงผลแบบหน้าจอกว้าง) ของแท็บเบราว์เซอร์นี้ การโหลดหน้าเว็บที่เพิ่มขึ้นประมาณ 80% และ 10% ของข้อมูลที่ส่งผ่านสาย CSS ที่มีประสิทธิภาพมาก

บทสรุป

ตอนนี้คุณก็รู้วิธีที่เราทําแล้ว คุณจะทําอย่างไร 🙂

มาลองใช้แนวทางที่หลากหลายและดูวิธีทั้งหมดในการสร้างบนเว็บกัน สร้าง Codepen ขึ้นมาหรือโฮสต์เดโมของคุณเอง ทวีตข้อความให้ผมด้วย แล้วเราจะเพิ่มวิดีโอนั้นลงในส่วน รีมิกซ์ของชุมชนด้านล่าง

แหล่งที่มา

รีมิกซ์ของชุมชน

ยังไม่มีข้อมูลให้ดู