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

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

Robert Flack
Robert Flack
Majid Valipour
Majid Valipour

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

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

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

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

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

นักพัฒนาเว็บพึ่งพาโซลูชันแบบ 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 หมายความว่าขอบเริ่มต้นของสแนปพอร์ตของคอนเทนเนอร์แบบเลื่อนควรล้างออกด้วยขอบเริ่มต้นพื้นที่สแนปองค์ประกอบ ในทำนองเดียวกัน การจัดแนว 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 จะคำนวณขนาดหน้าสำหรับการเลื่อนการแบ่งหน้า เช่น PageDown และ PageUp และขณะคำนวณปริมาณการเลื่อนสำหรับการดำเนินการ Element.scrollIntoView() ด้วย

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

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

API เลื่อน DOM

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

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

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

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

Overscroll Behavior 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. ทำงานเกี่ยวกับ CSS API ใหม่ เช่น scroll-start
  3. ทำงานบน เหตุการณ์ JS ใหม่ เช่น snapChanged()