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

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

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

การสาธิต

หากชอบวิดีโอ นี่คือโพสต์นี้เวอร์ชัน YouTube

ภาพรวม

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

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

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

ส่งรายการที่มีองค์ประกอบ <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> จะใช้คุณสมบัติที่กำหนดเองเพื่อสร้างสัดส่วนภาพฐานคือ 1 กล่อง:

.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

แต่รูปภาพจะยังไม่ปรับเปลี่ยนตามอุปกรณ์ และจะแสดงออกมาจากกล่องที่อยู่ด้านในเลย ลองยึดเอาขนาด ความพอดี และลักษณะเส้นขอบบางส่วน และการไล่ระดับสีของพื้นหลังสำหรับการโหลดแบบ Lazy Loading ดังนี้

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

ดัชนี Roving

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

อัตราส่วน

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

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

ด้วย 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

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

ALT_TEXT_HERE

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

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

บทสรุป

ตอนนี้คุณก็รู้แล้วว่าผมทำยังไงแล้วคุณล่ะ คุณจะต้องทำอย่างไร 🙂

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

แหล่งที่มา

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

ยังไม่มีอะไรให้ดูที่นี่