ภาพรวมพื้นฐานเกี่ยวกับวิธีสร้าง ScrollView แนวนอนที่ปรับเปลี่ยนตามอุปกรณ์สำหรับทีวี โทรศัพท์ เดสก์ท็อป ฯลฯ
ในโพสต์นี้ ผมอยากจะแชร์แนวคิดเกี่ยวกับวิธีสร้างประสบการณ์การเลื่อนแนวนอน สำหรับเว็บที่เรียบง่าย ตอบสนอง เข้าถึงได้ และทำงานได้ในเบราว์เซอร์และแพลตฟอร์มต่างๆ (เช่น ทีวี) ลองใช้เดโม
หากต้องการดูวิดีโอ โปรดดูโพสต์นี้ใน YouTube
ภาพรวม
เราจะสร้างเลย์เอาต์การเลื่อนแนวนอนซึ่งออกแบบมาเพื่อโฮสต์ภาพปกของสื่อหรือผลิตภัณฑ์
คอมโพเนนต์เริ่มต้นเป็นเพียง<ul>
รายการธรรมดา แต่
ได้รับการเปลี่ยนโฉมด้วย CSS ให้กลายเป็นประสบการณ์การเลื่อนที่ราบรื่นและน่าพึงพอใจ ซึ่งแสดง
รูปภาพและสแนปรูปภาพเหล่านั้นไปยังตารางกริด มีการเพิ่ม JavaScript เพื่ออำนวยความสะดวกในการโต้ตอบกับดัชนีการหมุนเวียน ซึ่งจะช่วยให้ผู้ใช้แป้นพิมพ์ข้ามการไปยังรายการต่างๆ กว่า 100 รายการได้
นอกจากนี้ เรายังใช้ Media Query เวอร์ชันทดลอง 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
เพื่อเป็นวิธีส่งสัญญาณว่าควรดึงข้อมูลแหล่งที่มาของรูปภาพนี้
เมื่อรูปภาพอยู่ใน Viewport เท่านั้น ซึ่งจะเป็นประโยชน์อย่างยิ่งสำหรับรายการขนาดใหญ่ เนื่องจากผู้ใช้จะดาวน์โหลดรูปภาพเฉพาะรายการที่เลื่อนมาจนเห็นเท่านั้น
รองรับค่ากำหนดรูปแบบสีของผู้ใช้
ใช้ color-scheme
เป็นแท็ก <meta>
เพื่อส่งสัญญาณไปยังเบราว์เซอร์ว่าหน้าเว็บต้องการทั้งรูปแบบ User-Agent ที่มีให้สำหรับธีมสว่างและธีมมืด โดยเป็นโหมดมืดหรือโหมดสว่างฟรี
ขึ้นอยู่กับว่าคุณมองในมุมใด
<meta name="color-scheme" content="dark light">
แท็ก Meta จะให้สัญญาณที่เร็วที่สุดเท่าที่จะเป็นไปได้ เพื่อให้เบราว์เซอร์ เลือกสี Canvas เริ่มต้นเป็นสีเข้มได้หากผู้ใช้ต้องการธีมมืด ซึ่งหมายความว่าการไปยังหน้าต่างๆ ของเว็บไซต์จะไม่แสดงพื้นหลังสีขาว ระหว่างการโหลด ธีมมืดที่ราบรื่นระหว่างการโหลด ทำให้สบายตามากขึ้น
ดูข้อมูลเพิ่มเติมได้จาก 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);
}
}
เพิ่มสไตล์อีกเพียงเล็กน้อยเพื่อสร้างโครงร่างของแถบเลื่อนสื่อให้เสร็จสมบูรณ์
.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
แต่รูปภาพยังไม่ตอบสนองตามอุปกรณ์และจะแสดงทันทีเมื่อคุณเปิดกล่อง ที่รูปภาพอยู่ ปรับแต่งด้วยขนาด ความพอดี และรูปแบบเส้นขอบ รวมถึง การไล่ระดับสีพื้นหลังเมื่อใช้การโหลดแบบ 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);
}
}
การใช้พร็อพเพอร์ตี้เชิงตรรกะช่วยให้เครื่องมือเลื่อนสื่อทำงานได้ในโหมดการเขียน และทิศทางของเอกสาร
การสแนปการเลื่อน
คอนเทนเนอร์ที่เลื่อนได้ซึ่งมีเนื้อหาล้นสามารถกลายเป็น Viewport ที่สแนปได้ด้วย CSS บรรทัดเดียว จากนั้นบุตรหลานจะระบุวิธีที่ต้องการจัดแนวกับ Viewport นั้น
.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
ให้ห่างจากกล่องเพื่อให้มีพื้นที่ว่างที่ดูดี
หากผู้ใช้ไม่มีค่ากำหนดการเคลื่อนไหวเกี่ยวกับการลดการเคลื่อนไหว ระบบจะเปลี่ยน
ออฟเซ็ตเพื่อให้การเคลื่อนไหวเล็กน้อยกับเหตุการณ์โฟกัส
ดัชนีเคลื่อนที่
ผู้ใช้เกมแพดและแป้นพิมพ์ต้องให้ความสนใจเป็นพิเศษในรายการเนื้อหาและตัวเลือกที่ยาวเหยียดเหล่านี้ รูปแบบทั่วไปในการแก้ปัญหานี้เรียกว่าดัชนีแบบเคลื่อนที่ เมื่อคอนเทนเนอร์ของรายการโฟกัสด้วยแป้นพิมพ์ แต่ระบบอนุญาตให้มีองค์ประกอบย่อยเพียง 1 รายการที่ถือโฟกัสได้ในแต่ละครั้ง ประสบการณ์การใช้งานที่เน้นรายการที่โฟกัสได้รายการเดียวในแต่ละครั้งนี้ออกแบบมาเพื่อให้ข้ามรายการที่อาจยาวได้ แทนที่จะกด Tab 50 ครั้งขึ้นไป เพื่อไปที่ท้ายรายการ
โดยมีไอเทม 300 รายการในแถบเลื่อนแรกของเดโม เราสามารถทำได้ดีกว่าการให้ผู้ใช้ เลื่อนผ่านทุกรายการเพื่อไปยังส่วนถัดไป
หากต้องการสร้างประสบการณ์การใช้งานนี้ JavaScript ต้องสังเกตเหตุการณ์แป้นพิมพ์และเหตุการณ์โฟกัส ฉันได้สร้างคลังโอเพนซอร์สขนาดเล็กใน npm เพื่อช่วยให้การสร้างประสบการณ์ของผู้ใช้ นี้เป็นเรื่องง่าย วิธีใช้สำหรับ 3 Scroller มีดังนี้
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 ไวยากรณ์ของ Nest ยังช่วยให้คุณปรับวิวพอร์ตเล็กๆ น้อยๆ ได้ด้วย โดยจะอยู่ร่วมกับตรรกะการกำหนดขนาดอื่นๆ
เมื่อใช้ CSS ดังกล่าวและฟีเจอร์นี้พร้อมใช้งานในเครื่องมือเบราว์เซอร์มากขึ้น เลย์เอาต์ที่จัดการได้ง่ายแต่ดึงดูดสายตามากขึ้นก็จะแสดงผล
ต้องการลดการใช้อินเทอร์เน็ต
แม้ว่าเทคนิคถัดไปนี้จะใช้ได้หลัง Flag ใน Canary เท่านั้น
แต่ฉันก็อยากจะแชร์วิธีที่ฉันใช้เพื่อประหยัดเวลาในการโหลดหน้าเว็บและปริมาณการใช้อินเทอร์เน็ตได้อย่างมากด้วย CSS เพียงไม่กี่บรรทัด prefers-reduced-data
Media Query จาก
ระดับ 5 ช่วยให้คุณถามได้ว่าอุปกรณ์อยู่ใน
สถานะลดการใช้ข้อมูลใดๆ หรือไม่ เช่น โหมดประหยัดอินเทอร์เน็ต หากเป็นเช่นนั้น เราจะแก้ไข
เอกสาร และในกรณีนี้คือซ่อนรูปภาพ
figure {
@media (prefers-reduced-data: reduce) {
& {
min-inline-size: var(--size);
& > picture {
display: none;
}
}
}
}
เนื้อหายังคงนำทางได้ แต่จะไม่มีค่าใช้จ่ายในการดาวน์โหลดรูปภาพขนาดใหญ่
นี่คือเว็บไซต์ก่อนเพิ่ม prefers-reduced-data
CSS
(คำขอ 7 รายการ ทรัพยากร 100 KB ใน 131 มิลลิวินาที)
ประสิทธิภาพของเว็บไซต์หลังจากเพิ่ม prefers-reduced-data
CSS มีดังนี้
(คำขอ 71 รายการ ทรัพยากร 1.2 MB ใน 1.07 วินาที)
คำขอน้อยลง 64 รายการ ซึ่งก็คือรูปภาพประมาณ 60 รูปภายใน Viewport (การทดสอบบนจอแสดงผลแบบจอกว้าง) ของแท็บเบราว์เซอร์นี้ การเพิ่มประสิทธิภาพการโหลดหน้าเว็บประมาณ 80% และข้อมูล 10% ผ่านสาย CSS ที่มีประสิทธิภาพมาก
บทสรุป
ตอนนี้คุณรู้วิธีที่ฉันทำแล้ว คุณจะทำอย่างไร 🙂
มาลองใช้แนวทางที่หลากหลายและเรียนรู้วิธีต่างๆ ในการสร้างสรรค์บนเว็บกัน สร้าง Codepen หรือโฮสต์เดโมของคุณเอง แล้วทวีตมาหาฉันพร้อมกับเดโมนั้น จากนั้นฉันจะเพิ่มเดโมลงในส่วน รีมิกซ์ของชุมชนด้านล่าง
แหล่งที่มา
รีมิกซ์ของชุมชน
ยังไม่มีอะไรให้ดูที่นี่