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

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

Robert Flack
Robert Flack
Majid Valipour
Majid Valipour

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

ฉากหลัง

กรณีที่ต้องใช้การเลื่อนแบบสแนป

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

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

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

CSS Scroll Snap ช่วยให้ผู้เขียนเว็บสามารถทำเครื่องหมายคอนเทนเนอร์การเลื่อนแต่ละรายการด้วยขอบเขต สำหรับการดำเนินการเลื่อนที่จะสิ้นสุด จากนั้นเบราว์เซอร์จะเลือกตำแหน่งสิ้นสุดที่เหมาะสมที่สุดตามรายละเอียดของการดำเนินการเลื่อน เลย์เอาต์และความสามารถในการมองเห็นของคอนเทนเนอร์เลื่อน และรายละเอียดของตำแหน่งสแนป แล้วเคลื่อนไหวไปยังตำแหน่งนั้นอย่างราบรื่น กลับไปที่ตัวอย่างก่อนหน้านี้ เมื่อผู้ใช้เลื่อนภาพสไลด์จนสุด รูปภาพที่มองเห็นจะเลื่อนเข้าที่ 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 ของคอนเทนเนอร์เลื่อนควร ตรงกับขอบเริ่มต้นของพื้นที่สแนปขององค์ประกอบ ในทำนองเดียวกัน การจัดแนว end และ center หมายความว่าขอบสิ้นสุดหรือกึ่งกลางของ Snapport ของคอนเทนเนอร์เลื่อน ควรอยู่ในแนวเดียวกับขอบสิ้นสุดหรือกึ่งกลางของพื้นที่สแนปขององค์ประกอบ

ตัวอย่างการจัดแนวต่างๆ บนแกนการเลื่อนแนวนอน

ตัวอย่างต่อไปนี้จะแสดงวิธีใช้แนวคิดเหล่านี้

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

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

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

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

DOM Scrolling API

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

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

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

ลักษณะการทำงานของการเลื่อนเกิน

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

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

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

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

งานในอนาคต

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

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