ภาพรวมพื้นฐานเกี่ยวกับวิธีสร้างมุมมองการเลื่อนแนวนอนที่ปรับเปลี่ยนตามอุปกรณ์สำหรับทีวี โทรศัพท์ เดสก์ท็อป ฯลฯ
ในโพสต์นี้ เราต้องการแชร์แนวคิดเกี่ยวกับวิธีสร้างประสบการณ์การเลื่อนในแนวนอนสำหรับเว็บที่เรียบง่าย ตอบสนอง เข้าถึงได้ และใช้งานได้ในเบราว์เซอร์และแพลตฟอร์มต่างๆ (เช่น ทีวี) ลองใช้เดโม
หากต้องการดูวิดีโอ คุณสามารถใช้โพสต์นี้ในเวอร์ชัน 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 รายการมีความยืดหยุ่นพอที่จะรองรับการผสมผสานที่น่าสนใจได้หลายแบบ
คอนเทนเนอร์อนุญาตให้ลบล้างขนาดคอลัมน์โดยระบุขนาดเริ่มต้นเป็นพร็อพเพอร์ตี้ที่กำหนดเอง เลย์เอาต์ตารางกริดนี้ไม่ได้กำหนดขนาดคอลัมน์ แต่จะจัดการระยะห่างและทิศทางเท่านั้น
.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 ซึ่งฟีเจอร์จะตรวจสอบการรองรับสัดส่วนการแสดงผล
การเพิ่มประสิทธิภาพแบบเป็นขั้นเป็นตอนในโปรแกรมเลื่อนสื่อแบบไดนามิกมากขึ้น
@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 ช่วยให้สามารถสอบถามได้ว่าอุปกรณ์อยู่ในสถานะการลดปริมาณข้อมูลหรือไม่ เช่น โหมดประหยัดอินเทอร์เน็ต หากใช่ เราจะแก้ไขเอกสารได้ และในกรณีนี้ เราจะซ่อนรูปภาพ
figure {
@media (prefers-reduced-data: reduce) {
& {
min-inline-size: var(--size);
& > picture {
display: none;
}
}
}
}
เนื้อหายังคงไปยังส่วนต่างๆ ได้ แต่ดาวน์โหลดรูปภาพขนาดใหญ่ได้โดยไม่ต้องเสียค่าใช้จ่าย นี่คือเว็บไซต์ก่อนที่จะเพิ่ม CSS ของ prefers-reduced-data
(คําขอ 7 รายการ ทรัพยากร 100 KB ใน 131 มิลลิวินาที)
ประสิทธิภาพของเว็บไซต์หลังจากเพิ่ม prefers-reduced-data
CSS
(คำขอ 71 รายการ, ทรัพยากร 1.2 MB ใน 1.07 วินาที)
คำขอน้อยลง 64 รายการ ซึ่งก็คือรูปภาพประมาณ 60 ภาพภายในวิวพอร์ต (การทดสอบที่ถ่ายในจอแสดงผลแบบหน้าจอกว้าง) ของแท็บเบราว์เซอร์นี้ การโหลดหน้าเว็บที่เพิ่มขึ้นประมาณ 80% และ 10% ของข้อมูลที่ส่งผ่านสาย CSS ที่มีประสิทธิภาพมาก
บทสรุป
ตอนนี้คุณก็รู้วิธีที่เราทําแล้ว คุณจะทําอย่างไร 🙂
มาลองใช้แนวทางที่หลากหลายและดูวิธีทั้งหมดในการสร้างบนเว็บกัน สร้าง Codepen ขึ้นมาหรือโฮสต์เดโมของคุณเอง ทวีตข้อความให้ผมด้วย แล้วเราจะเพิ่มวิดีโอนั้นลงในส่วน รีมิกซ์ของชุมชนด้านล่าง
แหล่งที่มา
รีมิกซ์ของชุมชน
ยังไม่มีข้อมูลให้ดู