การเลื่อนที่ควบคุมอย่างดีด้วย CSS Scroll Snap

สร้างประสบการณ์การเลื่อนที่ควบคุมได้ดีด้วยการประกาศตำแหน่งการเลื่อน

Robert Flack
Robert Flack
Majid Valipour
Majid Valipour

ฟีเจอร์ CSS Scroll Snap ช่วยให้นักพัฒนาเว็บสร้างประสบการณ์การเลื่อนที่ควบคุมได้ดีด้วยการประกาศตำแหน่งการหยุด Scroll บทความแบบแบ่งหน้าและภาพสไลด์เป็นตัวอย่าง 2 ตัวอย่างที่พบได้ทั่วไป CSS Scroll Snap มี API ที่ใช้งานง่ายและสอดคล้องกันสำหรับการสร้างรูปแบบ UX ที่ได้รับความนิยมเหล่านี้

ข้อมูลเบื้องต้น

กรณีสําหรับการเลื่อนแบบ Snap

การเลื่อนเป็นวิธีที่ได้รับความนิยมและเป็นธรรมชาติในการโต้ตอบกับเนื้อหาบนเว็บ ซึ่งเป็นวิธีดั้งเดิมของแพลตฟอร์มในการให้สิทธิ์เข้าถึงข้อมูลมากกว่าที่แสดงบนหน้าจอพร้อมกัน ซึ่งจะมีประโยชน์อย่างยิ่งในแพลตฟอร์มอุปกรณ์เคลื่อนที่ที่มีพื้นที่หน้าจอจํากัด จึงไม่น่าแปลกใจที่ผู้เขียนเว็บจำนวนมากขึ้นเลือกจัดระเบียบเนื้อหาเป็นรายการแบบแบนที่เลื่อนได้แทนการจัดระเบียบแบบลําดับชั้นที่ลึก

ข้อเสียหลักของการเลื่อนคือความแม่นยำ แทบจะไม่มีกรณีที่การเลื่อนจะสิ้นสุดลงโดยที่บรรทัดนั้นอยู่ตรงกับย่อหน้าหรือประโยค ปัญหานี้เห็นได้ชัดยิ่งขึ้นสำหรับเนื้อหาแบบแบ่งหน้าหรือเนื้อหาแบบรายการที่มีขอบเขตที่มีความหมายเมื่อการเลื่อนสิ้นสุดลงตรงกลางหน้าหรือรูปภาพ ทำให้มองเห็นเนื้อหาบางส่วน กรณีการใช้งานเหล่านี้จะได้รับประโยชน์จากประสบการณ์การเลื่อนที่ควบคุมได้ดี

นักพัฒนาเว็บใช้โซลูชัน JavaScript ในการควบคุมการเลื่อนมานานแล้วเพื่อแก้ปัญหานี้ อย่างไรก็ตาม โซลูชันที่ใช้ JavaScript ไม่สามารถให้โซลูชันที่ตรงตามต้นฉบับได้เนื่องจากไม่มีองค์ประกอบพื้นฐานในการปรับแต่งการเลื่อนหรือเข้าถึงการเลื่อนแบบคอมโพสิต CSS Scroll Snap ช่วยให้คุณมีโซลูชันที่รวดเร็ว เที่ยงตรงสูง และใช้งานง่าย ซึ่งทํางานอย่างสม่ำเสมอในเบราว์เซอร์ต่างๆ

การหยุดการเลื่อน CSS ช่วยให้ผู้เขียนเว็บทำเครื่องหมายขอบเขตของคอนเทนเนอร์การเลื่อนแต่ละรายการสำหรับการดำเนินการเลื่อนที่จะสิ้นสุด จากนั้นเบราว์เซอร์จะเลือกตำแหน่งสิ้นสุดที่เหมาะสมที่สุดโดยขึ้นอยู่กับรายละเอียดของการดำเนินการเลื่อน เลย์เอาต์และระดับการมองเห็นของคอนเทนเนอร์การเลื่อน และรายละเอียดของตำแหน่งการหยุด กลับไปที่ตัวอย่างก่อนหน้านี้ เมื่อผู้ใช้เลื่อนภาพสไลด์จนจบแล้ว ภาพที่เห็นจะปรากฏขึ้น JavaScript ไม่ต้องทำการปรับเปลี่ยนการเลื่อน

ตัวอย่างการใช้ CSS Scroll Snap กับภาพสไลด์
ตัวอย่างการใช้ CSS Scroll Snap กับภาพสไลด์ ฟีเจอร์นี้ช่วยให้มั่นใจได้ว่าเมื่อสิ้นสุดการเลื่อน รูปภาพจะจัดแนวกึ่งกลางในแนวนอนให้ตรงกับกึ่งกลางในแนวนอนของคอนเทนเนอร์การเลื่อน

CSS Scroll Snap

การหยุดการเลื่อนคือการปรับออฟเซ็ตการเลื่อนของคอนเทนเนอร์การเลื่อนให้อยู่ในตำแหน่งหยุดที่ต้องการเมื่อการเลื่อนเสร็จสิ้น

คุณอาจเลือกให้คอนเทนเนอร์การเลื่อนใช้การเลื่อนไปยังจุดที่พอดีโดยใช้พร็อพเพอร์ตี้ scroll-snap-type ซึ่งบอกให้เบราว์เซอร์พิจารณาจัดวางคอนเทนเนอร์การเลื่อนนี้ไปยังตำแหน่งที่แสดงผลโดยรายการที่สืบทอด scroll-snap-type กำหนดแกนที่จะเลื่อน: x, y หรือ both และระดับความเข้มงวดของการยึดตำแหน่ง: mandatory, proximity เราจะอธิบายเพิ่มเติมในภายหลัง

คุณสามารถระบุตำแหน่งการยึดได้โดยประกาศการจัดตำแหน่งที่ต้องการในองค์ประกอบ ตำแหน่งนี้คือระยะการเลื่อนที่คอนเทนเนอร์การเลื่อนของบรรพบุรุษที่อยู่ใกล้ที่สุดและองค์ประกอบนั้นจัดแนวตามที่กำหนดไว้สำหรับแกนนั้นๆ การจัดแนวต่อไปนี้เป็นไปได้ในแต่ละแกน start, end, center

การจัดแนว start หมายความว่าขอบเริ่มต้นของ Snapport ของคอนเทนเนอร์การเลื่อนควรอยู่ตรงกับขอบเริ่มต้นของพื้นที่ Snap ขององค์ประกอบ ในทํานองเดียวกัน การปรับแนว 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 ใหม่ที่สามารถใช้เพื่อปรับพื้นที่ที่มองเห็นได้จริงของคอนเทนเนอร์การเลื่อนหรือ Snapport ซึ่งจะใช้เมื่อคำนวณการจัดแนวการเลื่อน พร็อพเพอร์ตี้นี้กำหนดการฝังเมื่อเทียบกับกล่องระยะห่างจากขอบของคอนเทนเนอร์การเลื่อน ในตัวอย่างของเรา เราได้เพิ่ม15vhการฝังเพิ่มเติม15vhที่ด้านบน ซึ่งจะบอกให้เบราว์เซอร์พิจารณาตำแหน่งที่ต่ำกว่า นั่นคือ15vhใต้ขอบด้านบนของคอนเทนเนอร์การเลื่อน เพื่อเป็นขอบเริ่มต้นแนวตั้งสำหรับการเลื่อน เมื่อใช้การยึด ขอบเริ่มต้นขององค์ประกอบเป้าหมายการยึดจะชิดกับตำแหน่งใหม่นี้ จึงทำให้มีที่ว่างด้านบน

พร็อพเพอร์ตี้ scroll-margin กำหนดจำนวนการเริ่มต้นที่ใช้เพื่อปรับกล่องที่มีประสิทธิภาพของเป้าหมายการยึด ซึ่งคล้ายกับวิธีที่ scroll-padding ทำงานในคอนเทนเนอร์การเลื่อนการยึด

คุณอาจสังเกตเห็นว่าพร็อพเพอร์ตี้ทั้ง 2 รายการนี้ไม่มีคําว่า "snap" การดำเนินการนี้เกิดขึ้นโดยเจตนา เนื่องจากมีการแก้ไขกล่องสําหรับการดำเนินการเลื่อนที่เกี่ยวข้องทั้งหมด ไม่ใช่แค่การเลื่อนไปยังส่วนที่ต้องการ เช่น Chrome จะพิจารณาค่าเหล่านี้เมื่อคำนวณขนาดหน้าเว็บสําหรับการเลื่อนหน้า เช่น PageDown และ PageUp รวมถึงเมื่อคํานวณจํานวนการเลื่อนสําหรับการดําเนินการElement.scrollIntoView()

ดูการสาธิต | แหล่งที่มา

การโต้ตอบกับ API เลื่อนอื่นๆ

DOM Scrolling API

การเลื่อนแบบกระโดดจะเกิดขึ้นหลังจากการดำเนินการเลื่อนทั้งหมด รวมถึงการดำเนินการที่เริ่มต้นโดยสคริปต์ เมื่อคุณใช้ API เช่น Element.scrollTo เบราว์เซอร์จะคำนวณตำแหน่งการเลื่อนที่ต้องการของการดำเนินการ จากนั้นจะใช้ตรรกะการยึดที่เหมาะสมเพื่อค้นหาตำแหน่งสุดท้ายที่ยึด ดังนั้น สคริปต์ของผู้ใช้จึงไม่จำเป็นต้องทำการคำนวณใดๆ สำหรับการจับคู่

การเลื่อนอย่างราบรื่น

การเลื่อนอย่างราบรื่นจะควบคุมลักษณะการทํางานของการเลื่อนแบบเป็นโปรแกรม ขณะที่การเลื่อนไปยังส่วนที่ต้องการจะกําหนดปลายทาง เนื่องจากตัวควบคุมเหล่านี้ควบคุมการเลื่อนในแนวตั้งและแนวนอน จึงใช้ร่วมกันและเสริมกันได้

ลักษณะการเลื่อนเกิน

Overscroll behavior API จะควบคุมวิธีเชื่อมโยงการเลื่อนในองค์ประกอบหลายรายการ และจะไม่ได้รับผลกระทบจากการเลื่อนแบบ Snap

ข้อควรระวังและแนวทางปฏิบัติแนะนำ

หลีกเลี่ยงการใช้การจับคู่แบบบังคับเมื่อองค์ประกอบเป้าหมายอยู่ห่างกันมาก ซึ่งอาจทำให้เข้าถึงเนื้อหาที่อยู่ตรงกลางตำแหน่งการจับคู่ไม่ได้

ในหลายกรณี คุณสามารถเพิ่มการเลื่อนไปยังส่วนถัดไปเพื่อเพิ่มประสิทธิภาพได้โดยไม่ต้องตรวจหาองค์ประกอบ หากจำเป็น ให้ใช้ @supports หรือ CSS.supports เพื่อตรวจหาการรองรับ CSS 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 จะสิ้นสุดที่ออฟเซตการเลื่อนที่ขอเสมอ การเลื่อนแบบกระโดดอาจปรับค่าออฟเซตการเลื่อนหลังจากการเลื่อนแบบเป็นโปรแกรมเสร็จสมบูรณ์ โปรดทราบว่านี่ไม่ใช่สมมติฐานที่ดีแม้แต่ก่อนที่จะมีการเลื่อนแบบ Snap เนื่องจากการเลื่อนอาจถูกขัดจังหวะด้วยเหตุผลอื่นๆ แต่กรณีนี้จะเกิดขึ้นกับการเลื่อนแบบ Snap โดยเฉพาะ

งานในอนาคต

ประสบการณ์การเลื่อนเป็นประเด็นหลักในแบบสํารวจล่าสุดของทีม Chrome ผลการสำรวจระบุถึงหลายด้านที่ต้องดำเนินการเพิ่มเติมเพื่อลดช่องว่างระหว่างไลบรารีปลั๊กอินกับ CSS งานที่กําลังจะมีขึ้นจะมุ่งเน้นที่ scroll-snap ซึ่งรวมถึง

  1. ความพร้อมใช้งานและความเข้ากันได้ของ API ในเบราว์เซอร์ต่างๆ
  2. พัฒนาCSS API ใหม่ เช่น scroll-start
  3. ทํางานกับเหตุการณ์ JS ใหม่ เช่น snapChanged()