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

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

Robert Flack
Robert Flack
Majid Valipour
Majid Valipour

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

ที่มา

เคสสำหรับการสแนปการเลื่อน

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

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

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

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

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

สแนปการเลื่อน 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 ดังนี้

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