สร้างประสบการณ์การเลื่อนที่ควบคุมได้ดีโดยการประกาศตำแหน่งการสแนปการเลื่อน
ฟีเจอร์สแนปการเลื่อน CSS ช่วยให้นักพัฒนาเว็บสร้างประสบการณ์การเลื่อนที่ควบคุมได้ดีด้วยการประกาศตำแหน่งการสแนปการเลื่อน บทความที่ใส่เลขหน้าและภาพสไลด์เป็น 2 ตัวอย่างที่นิยมใช้กันโดยทั่วไป CSS Scroll Snap มี API ที่ใช้งานง่ายและสอดคล้องกันสำหรับการสร้างรูปแบบ UX ยอดนิยมเหล่านี้
ที่มา
เคสสำหรับการสแนปการเลื่อน
การเลื่อนเป็นวิธีที่ได้รับความนิยมและเป็นธรรมชาติในการโต้ตอบกับเนื้อหาในเว็บ ซึ่งเป็นวิธีการดั้งเดิมของแพลตฟอร์มที่ให้การเข้าถึงข้อมูลมากกว่าที่แสดงบนหน้าจอในคราวเดียว ซึ่งถือเป็นสิ่งสำคัญอย่างยิ่งในแพลตฟอร์มอุปกรณ์เคลื่อนที่ที่มีพื้นที่หน้าจอจำกัด จึงไม่น่าแปลกใจที่ผู้เขียนเว็บมักจะจัดเรียงเนื้อหาให้เป็นรายการแบบเลื่อนได้แบบเรียบๆ แทนที่จะจัดเรียงเป็นลำดับชั้น
ข้อเสียหลักของการเลื่อนคือการขาดความแม่นยำ บางครั้งการเลื่อนตรงกับย่อหน้า หรือประโยคที่พบได้น้อย วิธีนี้ยิ่งเด่นชัดยิ่งขึ้นสำหรับเนื้อหาที่ใส่เลขหน้าหรือแยกส่วนโดยมีขอบเขตที่มีความหมายเมื่อการเลื่อนสิ้นสุดที่ตรงกลางหน้าหรือรูปภาพ ทำให้มองเห็นเนื้อหาได้บางส่วน กรณีการใช้งานเหล่านี้จะได้รับประโยชน์จากการเลื่อนหน้าจอที่ควบคุมได้ดี
นักพัฒนาเว็บต่างก็พึ่งพาโซลูชันแบบ JavaScript มานานแล้วในการควบคุมการเลื่อนเพื่อช่วยแก้ไขจุดบกพร่องนี้ แต่โซลูชันที่ใช้ JavaScript จะให้โซลูชันที่มีความแม่นยำเต็มรูปแบบไม่ได้เนื่องจากไม่มีการปรับแต่งการเลื่อนแบบดั้งเดิมหรือการเข้าถึงการเลื่อนแบบผสม CSS Scroll Snap ช่วยให้มั่นใจได้ถึงโซลูชันที่รวดเร็ว ความแม่นยำสูง และใช้งานง่าย ซึ่งทำงานอย่างสอดคล้องกันในเบราว์เซอร์ต่างๆ
การสแนปการเลื่อน CSS ช่วยให้ผู้เขียนเว็บทำเครื่องหมายคอนเทนเนอร์การเลื่อนแต่ละรายการที่มีขอบเขตเพื่อดำเนินการเลื่อนให้เสร็จสิ้นได้ จากนั้นเบราว์เซอร์จะเลือกตำแหน่งสิ้นสุดที่เหมาะสมที่สุดตามรายละเอียดของการดำเนินการเลื่อน การจัดวางและการมองเห็นของคอนเทนเนอร์การเลื่อน และรายละเอียดตำแหน่งการสแนป จากนั้นจึงเคลื่อนไหวไปยังตำแหน่งดังกล่าวอย่างราบรื่น กลับไปที่ตัวอย่างก่อนหน้านี้ เมื่อผู้ใช้เลื่อนภาพสไลด์เสร็จแล้ว รูปภาพที่มองเห็นได้จะสแนปเข้าที่ โดยไม่จำเป็นต้องปรับการเลื่อน โดย JavaScript
สแนปการเลื่อน CSS
การสแนปการเลื่อนคือการปรับออฟเซ็ตการเลื่อนของคอนเทนเนอร์การเลื่อนให้อยู่ในตำแหน่งการสแนปที่ต้องการหลังจากที่การเลื่อนเสร็จสิ้น
คอนเทนเนอร์การเลื่อนเลือกใช้การสแนปการเลื่อนได้โดยใช้พร็อพเพอร์ตี้ scroll-snap-type
การดำเนินการนี้จะบอกเบราว์เซอร์ว่าควรพิจารณาสแนปคอนเทนเนอร์การเลื่อนนี้ไปยังตำแหน่งสแนปที่สร้างขึ้นโดยองค์ประกอบสืบทอด scroll-snap-type
จะกำหนดแกนที่เกิดการเลื่อน เช่น x
, y
หรือ both
และความเข้มงวดของสแนป: mandatory
, proximity
ดูรายละเอียดเพิ่มเติมในภายหลัง
ตำแหน่งการสแนปเกิดขึ้นได้ด้วยการประกาศการจัดข้อความที่ต้องการบนองค์ประกอบ
ตำแหน่งนี้คือออฟเซ็ตการเลื่อนซึ่งคอนเทนเนอร์การเลื่อนระดับบนที่ใกล้ที่สุดและองค์ประกอบจะได้รับการปรับแนวตามที่ระบุสำหรับแกนที่ระบุ การปรับแนวต่อไปนี้ที่เป็นไปได้ในแต่ละแกนคือ start
, end
, center
การปรับแนว start
หมายความว่าขอบเริ่มต้นของสแนปสำหรับคอนเทนเนอร์แบบเลื่อนควรถูกล้างด้วยขอบเริ่มต้นของพื้นที่สแนปองค์ประกอบ ในทํานองเดียวกัน การปรับแนว end
และ center
หมายความว่าขอบสิ้นสุดสแนปพอร์ตของคอนเทนเนอร์ที่เลื่อนได้ควรล้างด้วยขอบสิ้นสุดหรือกึ่งกลางของพื้นที่สแนปขององค์ประกอบ
ตัวอย่างต่อไปนี้จะแสดงวิธีใช้แนวคิดเหล่านี้
เช่น แกลเลอรีแนวนอน
กรณีการใช้งานทั่วไปของการสแนปการเลื่อนคือภาพสไลด์ ตัวอย่างเช่น หากต้องการสร้างภาพสไลด์แนวนอนที่สแนปไปยังแต่ละรูปภาพขณะที่คุณเลื่อน เราระบุคอนเทนเนอร์การเลื่อนให้ต้องมี scroll-snap-type
บนแกนแนวนอน ตั้งค่าแต่ละรูปภาพเป็น scroll-snap-align: center
เพื่อให้การสแนปอยู่กึ่งกลางของรูปภาพภายในภาพสไลด์
#gallery {
scroll-snap-type: x mandatory;
overflow-x: scroll;
display: flex;
}
#gallery img {
scroll-snap-align: center;
}
<div id="gallery">
<img src="cat.jpg">
<img src="dog.jpg">
<img src="another_cute_animal.jpg">
</div>
เนื่องจากตำแหน่งการสแนปเชื่อมโยงกับองค์ประกอบ อัลกอริทึมการสแนปจึงอย่างชาญฉลาดเกี่ยวกับเวลาและวิธีสแนปตามองค์ประกอบและขนาดคอนเทนเนอร์การเลื่อน เช่น คำนึงถึงกรณีที่รูปภาพหนึ่งมีขนาดใหญ่กว่าภาพสไลด์ อัลกอริทึมการสแนปแบบไร้เดียงอาจป้องกันไม่ให้ผู้ใช้แพนกล้องไปรอบๆ เพื่อดูรูปภาพขนาดเต็ม แต่ข้อกําหนดกำหนดให้ติดตั้งใช้งานเพื่อตรวจจับเคสนี้และให้ผู้ใช้เลื่อนไปยังส่วนต่างๆ ภายในรูปภาพได้อย่างอิสระและสแนปตรงขอบเท่านั้น
ตัวอย่าง: หน้าผลิตภัณฑ์ที่ใช้เส้นทาง
กรณีทั่วไปอีกกรณีหนึ่งที่อาจได้ประโยชน์จากการสแนปการเลื่อนคือหน้าเว็บที่มีส่วนเชิงตรรกะหลายส่วนให้เลื่อนดูในแนวตั้ง เช่น หน้าผลิตภัณฑ์ทั่วไป scroll-snap-type: y proximity;
จะเหมาะกับกรณีเช่นนี้มากกว่า โหมดนี้จะไม่รบกวนเมื่อผู้ใช้เลื่อนลงไปที่กึ่งกลางของส่วนหนึ่งๆ แต่จะยังคงจับภาพและดึงความสนใจไปยังส่วนใหม่เมื่อผู้ใช้เลื่อนเข้ามาใกล้เพียงพอ
วิธีที่คุณสามารถทำได้มีดังนี้
article {
scroll-snap-type: y proximity;
/* Reserve space for header plus some extra space for sneak peeking. */
scroll-padding-top: 15vh;
overflow-y: scroll;
}
section {
/* Snap align start. */
scroll-snap-align: start;
}
header {
position: fixed;
height: 10vh;
}
<article>
<header> Header </header>
<section> Section One </section>
<section> Section Two </section>
<section> Section Three </section>
</article>
ระยะห่างจากขอบและขอบของการเลื่อน
หน้าผลิตภัณฑ์มีส่วนหัวด้านบนที่มีตำแหน่งคงที่ การออกแบบนี้ยังขอให้มองเห็นบางส่วนด้านบนอยู่เมื่อมีการสแนปคอนเทนเนอร์แบบเลื่อนเพื่อเป็นแนวทางการออกแบบแก่ผู้ใช้เกี่ยวกับเนื้อหาข้างต้น
พร็อพเพอร์ตี้ scroll-padding
เป็นพร็อพเพอร์ตี้ CSS ใหม่ที่ใช้เพื่อปรับพื้นที่ที่แสดงผลได้ที่มีประสิทธิภาพของคอนเทนเนอร์การเลื่อนหรือสแนปพอร์ต ซึ่งจะใช้เมื่อคํานวณการจัดแนวการเลื่อนของการเลื่อน พร็อพเพอร์ตี้นี้กำหนดส่วนที่ใส่ไว้ในช่องระยะห่างจากขอบของคอนเทนเนอร์การเลื่อน ในตัวอย่างของเรา เราได้เพิ่มส่วนเพิ่มเติม 15vh
เข้าไปที่ด้านบนซึ่งเป็นคำสั่งให้เบราว์เซอร์พิจารณาตำแหน่งที่ต่ำลง 15vh
ใต้ขอบด้านบนของคอนเทนเนอร์การเลื่อนเพื่อเป็นขอบเริ่มต้นในแนวตั้งสำหรับสแนปการเลื่อน เมื่อสแนป ขอบเริ่มต้นขององค์ประกอบเป้าหมายการสแนปจะกลายเป็นล้างด้วยตำแหน่งใหม่นี้ จึงทำให้ด้านบนมีพื้นที่ว่าง
พร็อพเพอร์ตี้ scroll-margin
จะกำหนดจำนวนเงินเริ่มต้นที่ใช้ในการปรับช่องประสิทธิภาพของเป้าหมายสแนปที่คล้ายกับการทำงานของ scroll-padding
ในคอนเทนเนอร์การเลื่อนสแนป
คุณอาจสังเกตเห็นว่าพร็อพเพอร์ตี้ 2 ตัวนี้ไม่มีคำว่า "snap
" อยู่ภายใน ซึ่งเป็นสิ่งที่ตั้งใจเนื่องจากผู้ใช้แก้ไขช่องสำหรับการดำเนินการเลื่อนที่เกี่ยวข้องทั้งหมด ไม่ใช่แค่การสแนปการเลื่อนเท่านั้น ตัวอย่างเช่น Chrome จะคำนึงถึงขนาดหน้าเว็บสำหรับการเลื่อนการแบ่งหน้า เช่น Page Down และ PageUp และเมื่อคำนวณจำนวนการเลื่อนสำหรับการดำเนินการ Element.scrollIntoView()
ด้วย
การโต้ตอบกับ API การเลื่อนอื่นๆ
API การเลื่อน DOM
การสแนปการเลื่อนจะเกิดขึ้นหลังการดำเนินการเลื่อนทั้งหมด รวมถึงการดำเนินการที่เริ่มต้นโดยสคริปต์ เมื่อคุณใช้ API เช่น Element.scrollTo
เบราว์เซอร์จะคำนวณตำแหน่งการเลื่อนที่ต้องการของการดำเนินการ จากนั้นใช้ตรรกะการสแนปที่เหมาะสมเพื่อหาตำแหน่งสุดท้ายของการสแนป ดังนั้น สคริปต์ผู้ใช้จึงไม่ต้องคํานวณด้วยตนเองสําหรับการสแนป
การเลื่อนอย่างราบรื่น
การเลื่อนอย่างราบรื่นจะควบคุมลักษณะการทำงานของการเลื่อนแบบเป็นโปรแกรม ขณะที่สแนปการเลื่อนจะเป็นตัวกำหนดจุดหมาย เนื่องจากอุปกรณ์ควบคุมการเลื่อนในลักษณะแนวตั้ง ทางตรง สามารถใช้ร่วมกันและส่งเสริมซึ่งกันและกัน
ลักษณะการเลื่อนเกิน
Overscroll Behavior API ควบคุมวิธีเชื่อมโยงการเลื่อนในหลายองค์ประกอบและไม่ได้รับผลกระทบจากการเลื่อนสแนป
ข้อควรระวังและแนวทางปฏิบัติแนะนำ
หลีกเลี่ยงการใช้การสแนปที่จำเป็นเมื่อองค์ประกอบเป้าหมายเว้นระยะห่างหลายระดับ ซึ่งอาจทำให้ไม่สามารถเข้าถึงเนื้อหาที่อยู่ระหว่างตำแหน่งการสแนปได้
ในหลายกรณี อาจมีการเพิ่มการเลื่อนสแนปเป็นการเพิ่มประสิทธิภาพโดยไม่ต้องตรวจหาฟีเจอร์
หากจำเป็น ให้ใช้ @supports
หรือ CSS.supports
เพื่อตรวจหาการรองรับ Snap Scroll Snap
หลีกเลี่ยงการใช้ scroll-snap-type
ซึ่งมีอยู่ในข้อกำหนดที่เลิกใช้งานแล้วด้วย
การตรวจหาฟีเจอร์ใน CSS
@supports (scroll-snap-align: start) {
article {
scroll-snap-type: y proximity;
scroll-padding-top: 15vh;
overflow-y: scroll;
}
}
การตรวจหาฟีเจอร์ใน JavaScript
if (CSS.supports('scroll-snap-align: start')) {
// use css scroll snap
} else {
// use fallback
}
อย่าคิดเองว่า API การเลื่อนแบบเป็นโปรแกรม เช่น Element.scrollTo
จะเสร็จสิ้นตามออฟเซ็ตการเลื่อนที่ขอเสมอ การสแนปการเลื่อนอาจปรับออฟเซ็ตการเลื่อนหลังจากที่การเลื่อนแบบเป็นโปรแกรมเสร็จสมบูรณ์ โปรดทราบว่านี่ไม่ใช่สมมติฐานที่ดีตั้งแต่ก่อนการสแนปการเลื่อนเนื่องจากการเลื่อนอาจถูกขัดจังหวะเนื่องจากเหตุผลอื่นๆ แต่โดยเฉพาะอย่างยิ่งในกรณีที่ใช้การสแนปการเลื่อน
งานในอนาคต
ประสบการณ์การใช้งานการเลื่อนเป็นจุดสนใจของแบบสำรวจล่าสุดของทีม Chrome
ผลการสำรวจพบว่ามีหลายส่วนที่ต้องมีการแก้ไขเพิ่มเติมเพื่อลดช่องว่างระหว่างไลบรารีปลั๊กอินกับ CSS
งานที่ใกล้จะมาถึงจะมุ่งเน้นที่ scroll-snap
ดังนี้
- ความพร้อมใช้งานและความเข้ากันได้ของ API ในเบราว์เซอร์ต่างๆ
- ใช้งาน CSS API ใหม่ เช่น
scroll-start
- จัดการเหตุการณ์ JS ใหม่ เช่น
snapChanged()