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