สร้างประสบการณ์การเลื่อนที่มีการควบคุมอย่างดีด้วยการประกาศตำแหน่งการสแนปการเลื่อน
ฟีเจอร์ CSS Scroll Snap ช่วยให้นักพัฒนาเว็บสร้างประสบการณ์การเลื่อนที่ควบคุมได้ดีด้วยการประกาศตำแหน่งการสแนปการเลื่อน ตัวอย่างที่ใช้กันโดยทั่วไป 2 ตัวอย่างคือบทความที่มีการแบ่งหน้าและภาพสไลด์ CSS Scroll Snap มี API ที่ใช้งานง่ายและสอดคล้องกันสำหรับสร้างรูปแบบ UX ยอดนิยมเหล่านี้
ฉากหลัง
กรณีสำหรับการสแนปการเลื่อน
การเลื่อนเป็นวิธีที่ได้รับความนิยมและเป็นธรรมชาติในการโต้ตอบกับเนื้อหาบนเว็บ ซึ่งเป็นวิธีดั้งเดิมของแพลตฟอร์มในการให้สิทธิ์เข้าถึงข้อมูลมากกว่าที่มองเห็นได้บนหน้าจอพร้อมกัน ซึ่งมีความสำคัญอย่างยิ่งในแพลตฟอร์มบนอุปกรณ์เคลื่อนที่ที่มีพื้นที่หน้าจอจำกัด จึงไม่น่าแปลกใจที่ผู้เขียนเว็บหันมาจัดระเบียบเนื้อหาเป็นรายการแบบแบนที่เลื่อนได้มากขึ้น แทนที่จะใช้ลำดับชั้นที่ซับซ้อน
ข้อเสียหลักของการเลื่อนคือความไม่แม่นยำ การเลื่อนหน้าจอไม่ค่อยจะสิ้นสุดลงตรงกับย่อหน้าหรือประโยค ซึ่งจะเห็นได้ชัดเจนยิ่งขึ้นสำหรับเนื้อหาที่มีการแบ่งหน้าหรือแยกเป็นรายการซึ่งมีขอบเขตที่ชัดเจนเมื่อการเลื่อนสิ้นสุดที่กึ่งกลางของหน้าหรือรูปภาพ ทำให้มองเห็นได้เพียงบางส่วน กรณีการใช้งานเหล่านี้จะได้รับประโยชน์จากประสบการณ์การเลื่อนที่ควบคุมได้ดี
นักพัฒนาเว็บใช้โซลูชันที่ใช้ JavaScript ในการควบคุมการเลื่อนมาเป็นเวลานานเพื่อช่วยแก้ข้อบกพร่องนี้ อย่างไรก็ตาม โซลูชันที่ใช้ JavaScript ไม่สามารถมอบโซลูชันที่มีความแม่นยำเต็มรูปแบบได้เนื่องจากไม่มีองค์ประกอบพื้นฐานสำหรับการปรับแต่งการเลื่อนหรือการเข้าถึงการเลื่อนแบบผสม CSS Scroll Snap เป็นโซลูชันที่รวดเร็ว มีความแม่นยำสูง และใช้งานง่าย ซึ่งทำงานได้อย่างสอดคล้องกันในเบราว์เซอร์ต่างๆ
CSS Scroll Snap ช่วยให้ผู้เขียนเว็บทำเครื่องหมายคอนเทนเนอร์การเลื่อนแต่ละรายการด้วยขอบเขตสำหรับการดำเนินการเลื่อนที่ต้องการให้เสร็จสิ้นได้ จากนั้นเบราว์เซอร์จะเลือกตำแหน่งสิ้นสุดที่เหมาะสมที่สุดโดยขึ้นอยู่กับรายละเอียดของการดำเนินการเลื่อน เลย์เอาต์และความสามารถในการมองเห็นของคอนเทนเนอร์การเลื่อน และรายละเอียดของตำแหน่งสแนป จากนั้นจึงแสดงภาพเคลื่อนไหวไปยังตำแหน่งนั้นอย่างราบรื่น จากตัวอย่างก่อนหน้านี้ เมื่อผู้ใช้เลื่อนดูภาพสไลด์จนจบ รูปภาพที่มองเห็นได้จะจัดเข้าที่ JavaScript ไม่จำเป็นต้องปรับการเลื่อน
การสแนปการเลื่อน CSS
การสแนปการเลื่อนคือการปรับออฟเซ็ตการเลื่อนของคอนเทนเนอร์การเลื่อนให้อยู่ในตำแหน่งสแนปที่ต้องการเมื่อการเลื่อนเสร็จสิ้น
คุณสามารถเลือกใช้คอนเทนเนอร์การเลื่อนในการสแนปการเลื่อนได้โดยใช้พร็อพเพอร์ตี้ scroll-snap-type ซึ่งจะบอกเบราว์เซอร์ว่าควรพิจารณาจัดคอนเทนเนอร์การเลื่อนนี้ให้อยู่ในตำแหน่ง Snap ที่เกิดจากองค์ประกอบสืบทอด scroll-snap-type
กำหนดแกนที่เกิดการเลื่อน: x, y หรือ both และความเข้มงวดในการสแนป: mandatory, proximity เราจะพูดถึงเรื่องนี้เพิ่มเติมในภายหลัง
คุณสร้างตำแหน่งสแนปได้โดยประกาศการจัดแนวที่ต้องการในองค์ประกอบ
ตำแหน่งนี้คือออฟเซ็ตการเลื่อนที่คอนเทนเนอร์การเลื่อนระดับบนสุดที่ใกล้ที่สุดและองค์ประกอบอยู่ในแนวเดียวกันตามที่ระบุไว้สำหรับแกนที่กำหนด การจัดแนวต่อไปนี้เป็นไปได้ในแต่ละแกน: start, end, center
การจัดแนว start หมายความว่าขอบเริ่มต้นของ Snapport ของคอนเทนเนอร์การเลื่อนควรอยู่ชิดกับขอบเริ่มต้นของพื้นที่สแนปขององค์ประกอบ ในทำนองเดียวกัน การจัดแนว 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>
เนื่องจากตำแหน่งการสแนปเชื่อมโยงกับองค์ประกอบ อัลกอริทึมการสแนปจึงสามารถทำงานได้อย่างชาญฉลาดเกี่ยวกับเวลาและวิธีสแนปเมื่อพิจารณาจากองค์ประกอบและขนาดคอนเทนเนอร์การเลื่อน ตัวอย่างเช่น ลองพิจารณากรณีที่รูปภาพ 1 รูปมีขนาดใหญ่กว่าภาพสไลด์ อัลกอริทึมการสแนปที่เรียบง่ายอาจทำให้ผู้ใช้เลื่อนดูรูปภาพทั้งหมดไม่ได้ แต่ข้อกำหนดกำหนดให้การใช้งานต้องตรวจพบกรณีนี้และอนุญาตให้ผู้ใช้เลื่อนไปรอบๆ ภายในรูปภาพนั้นได้อย่างอิสระโดยจะสแนปที่ขอบเท่านั้น
ตัวอย่าง: หน้าสินค้าที่ผ่านการปรับปรุง
อีกกรณีหนึ่งที่พบบ่อยซึ่งอาจได้รับประโยชน์จากการสแนปการเลื่อนคือหน้าเว็บที่มีส่วนเชิงตรรกะหลายส่วนให้เลื่อนดูในแนวตั้ง เช่น หน้าสินค้าทั่วไป 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
หน้าสินค้ามีส่วนหัวด้านบนที่อยู่ในตำแหน่งคงที่ นอกจากนี้ การออกแบบยังกำหนดให้ส่วนบนบางส่วนยังคงมองเห็นได้เมื่อคอนเทนเนอร์การเลื่อนถูกจัดชิด เพื่อให้ผู้ใช้ทราบถึงเนื้อหาด้านบน
พร็อพเพอร์ตี้ scroll-padding เป็นพร็อพเพอร์ตี้ CSS ใหม่ที่ใช้ปรับขอบเขตที่มองเห็นได้จริงของคอนเทนเนอร์การเลื่อน หรือ Snapport ซึ่งใช้เมื่อคำนวณการจัดแนวการสแนปการเลื่อน พร็อพเพอร์ตี้จะกำหนดส่วนแทรกเทียบกับกล่องระยะห่างจากขอบของคอนเทนเนอร์การเลื่อน ในตัวอย่างของเรา มีการเพิ่มส่วนแทรก 15vh ไว้ที่ด้านบน ซึ่งจะสั่งให้เบราว์เซอร์พิจารณาตำแหน่งที่ต่ำลง 15vh ใต้ขอบด้านบนของคอนเทนเนอร์การเลื่อนเป็นขอบเริ่มต้นแนวตั้งสำหรับการสแนปการเลื่อน เมื่อสแนป ขอบเริ่มต้นขององค์ประกอบเป้าหมายสแนปจะถูกล้างด้วยตำแหน่งใหม่นี้ จึงทำให้มีพื้นที่ว่างด้านบน
พร็อพเพอร์ตี้ scroll-margin จะกำหนดจำนวนส่วนที่ยื่นออกมาซึ่งใช้เพื่อปรับกล่องที่มีผลของเป้าหมายการสแนป ซึ่งคล้ายกับวิธีการทำงานของ scroll-padding ในคอนเทนเนอร์การเลื่อนแบบสแนป
คุณอาจสังเกตเห็นว่าพร็อพเพอร์ตี้ทั้ง 2 รายการนี้ไม่มีคำว่า "snap" อยู่ในชื่อ ซึ่งเป็นความตั้งใจเนื่องจากพร็อพเพอร์ตี้เหล่านี้จะแก้ไขกล่องสำหรับการดำเนินการเลื่อนที่เกี่ยวข้องทั้งหมด ไม่ใช่แค่การสแนปการเลื่อน ตัวอย่างเช่น Chrome จะพิจารณาองค์ประกอบเหล่านี้เมื่อคำนวณขนาดหน้าสำหรับการเลื่อนหน้า เช่น PageDown และ PageUp รวมถึงเมื่อคำนวณจำนวนการเลื่อนสำหรับการดำเนินการ Element.scrollIntoView()
การโต้ตอบกับ API การเลื่อนอื่นๆ
DOM Scrolling API
การสแนปการเลื่อนจะเกิดขึ้นหลังจากการดำเนินการเลื่อนทั้งหมด รวมถึงการดำเนินการที่เริ่มต้นโดยสคริปต์ เมื่อคุณใช้ API เช่น Element.scrollTo เบราว์เซอร์จะคำนวณตำแหน่งการเลื่อนที่ต้องการของการดำเนินการ จากนั้นใช้ตรรกะการสแนปที่เหมาะสมเพื่อค้นหาตำแหน่งที่สแนปสุดท้าย ดังนั้นจึงไม่จำเป็นต้องใช้สคริปต์ของผู้ใช้เพื่อทำการคำนวณด้วยตนเองสำหรับการสแนป
การเลื่อนอย่างราบรื่น
การเลื่อนอย่างราบรื่นจะควบคุมลักษณะการทำงานของการเลื่อนแบบเป็นโปรแกรม ส่วนการสแนปการเลื่อนจะกำหนดปลายทางของการเลื่อน เนื่องจากทั้ง 2 วิธีควบคุมการเลื่อนในด้านที่แตกต่างกัน จึงสามารถใช้ร่วมกันและเสริมซึ่งกันและกันได้
ลักษณะการเลื่อนเกิน
Overscroll behavior API ควบคุมวิธีเชื่อมโยงการเลื่อนในองค์ประกอบหลายรายการ และไม่ได้รับผลกระทบจากการสแนปการเลื่อน
ข้อควรระวังและแนวทางปฏิบัติแนะนำ
หลีกเลี่ยงการใช้การสแนปแบบบังคับเมื่อองค์ประกอบเป้าหมายอยู่ห่างกันมาก ซึ่งอาจทำให้เข้าถึงเนื้อหาที่อยู่ระหว่างตำแหน่งสแนปไม่ได้
ในหลายกรณี คุณสามารถเพิ่มการสแนปการเลื่อนเป็นการเพิ่มประสิทธิภาพได้โดยไม่ต้องตรวจหาฟีเจอร์
หากจำเป็น ให้ใช้ @supports หรือ CSS.supports เพื่อตรวจหาการรองรับการสแนปการเลื่อน CSS
หลีกเลี่ยงการใช้ 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()