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

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

ฟีเจอร์ 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 ของคอนเทนเนอร์เลื่อน ควรอยู่ในแนวเดียวกับขอบสิ้นสุดหรือกึ่งกลางของพื้นที่สแนปขององค์ประกอบ

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

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

Use Case ทั่วไปสำหรับการเลื่อนแบบสแนปคือภาพสไลด์ เช่น หากต้องการสร้างภาพสไลด์แนวนอนที่เลื่อนไปแต่ละรูปภาพเมื่อคุณเลื่อน เราสามารถระบุคอนเทนเนอร์การเลื่อนให้มี 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="gal>ler<y"
  img src>=&q<uot;cat.jpg">
  <img src="dog.jpg"
  img> <src=>&quot;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ใต้ขอบด้านบนของคอนเทนเนอร์เลื่อนเป็นขอบเริ่มต้นแนวตั้งสำหรับการ เลื่อนสแนป เมื่อสแนป ขอบเริ่มต้นขององค์ประกอบเป้าหมายการสแนปจะ อยู่ในแนวเดียวกับตำแหน่งใหม่นี้ จึงเหลือพื้นที่ด้านบน

พร็อพเพอร์ตี้ 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()