เลื่อนเด้งบนเว็บไซต์ของคุณ

เผยแพร่แล้ว: 2022-03-10
สรุปโดยย่อ ↬ บทความนี้อธิบายผลกระทบของการเลื่อนการเด้งกลับและวิธีทำงานบนเว็บเบราว์เซอร์ต่างๆ ประกอบด้วยบทวิจารณ์เกี่ยวกับโซลูชันต่างๆ ที่แนะนำบนเว็บซึ่งสามารถใช้เพื่อป้องกันการเลื่อนการเลื่อนไปมาได้ คุณสมบัติ CSS, overscroll-behavior ซึ่งใช้งานใน Chrome ในเดือนธันวาคม 2017 และใน Firefox ในเดือนมีนาคม 2018 ได้อธิบายไว้ในบทความนี้ด้วย ความเข้าใจที่ดีเกี่ยวกับผลกระทบนี้จะเป็นประโยชน์อย่างมากสำหรับการสร้างหรือออกแบบเว็บไซต์ที่มีองค์ประกอบคงที่

การเด้งเลื่อน (บางครั้งเรียกว่า 'แถบยาง' หรือ 'การเลื่อนแบบยืดหยุ่น') มักใช้เพื่ออ้างถึงเอฟเฟกต์ที่คุณเห็นเมื่อคุณเลื่อนไปที่ด้านบนสุดของหน้าหรือองค์ประกอบ HTML หรือด้านล่างของ หน้าหรือองค์ประกอบบนอุปกรณ์ที่ใช้หน้าจอสัมผัสหรือแทร็คแพด และสามารถมองเห็นพื้นที่ว่างได้ครู่หนึ่งก่อนที่องค์ประกอบหรือหน้าจะเด้งกลับมาและจัดตำแหน่งตัวเองกลับไปที่ด้านบน/ด้านล่าง (เมื่อคุณปล่อยนิ้วหรือสัมผัส) คุณสามารถเห็นผลที่คล้ายคลึงกันเกิดขึ้นใน CSS scroll-snapping ระหว่างองค์ประกอบต่างๆ

อย่างไรก็ตาม บทความนี้เน้นที่การเลื่อนการเลื่อนเมื่อคุณเลื่อนไปที่ด้านบนสุดหรือด้านล่างสุดของหน้าเว็บ กล่าวอีกนัยหนึ่ง เมื่อสโครลพอร์ตถึงขอบเขตการเลื่อน

การรวบรวมข้อมูล วิธีที่มีประสิทธิภาพ

คุณรู้หรือไม่ว่า CSS สามารถใช้ในการรวบรวมสถิติได้? แท้จริงแล้ว มีแม้กระทั่งแนวทางเฉพาะ CSS สำหรับการติดตามการโต้ตอบ UI โดยใช้ Google Analytics อ่านบทความที่เกี่ยวข้อง →

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

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

เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

การเผชิญหน้าครั้งแรกของฉันกับเอฟเฟกต์

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

เลื่อนการเด้งใน Firefox บน macOS
เลื่อนการตีกลับใน Firefox บน macOS (ตัวอย่างขนาดใหญ่)

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

เลื่อนการเด้งใน Chrome บน macOS
เลื่อนการตีกลับใน Chrome บน macOS (ตัวอย่างขนาดใหญ่)

ไม่นะ! นี่ไม่ใช่สิ่งที่ควรจะเกิดขึ้น! ฉันได้ตั้งค่าตำแหน่งของส่วนท้ายให้อยู่ที่ด้านล่างของหน้าโดยการตั้งค่าคุณสมบัติ position CSS ให้มีค่า fixed นี่เป็นเวลาที่ดีที่จะทบทวน position: fixed; เป็น. ตามข้อกำหนด CSS 2.1 เมื่อมีการแก้ไข "กล่อง" (ในกรณีนี้คือส่วนท้ายสีน้ำเงินเข้ม) จะ "ได้รับการแก้ไขในส่วนที่เกี่ยวกับวิวพอร์ตและไม่เคลื่อนที่เมื่อเลื่อน" สิ่งนี้หมายความว่าส่วนท้ายไม่ควรขยับเมื่อคุณเลื่อนหน้าขึ้นและลง นี่คือสิ่งที่ทำให้ฉันกังวลเมื่อเห็นว่าเกิดอะไรขึ้นใน Chrome

เพื่อให้บทความนี้สมบูรณ์ยิ่งขึ้น ฉันจะแสดงให้คุณเห็นว่าหน้าเว็บเลื่อนไปมาอย่างไรบน Mobile Edge, Mobile Safari และ Desktop Safari ด้านล่าง ซึ่งต่างจากสิ่งที่เกิดขึ้นในการเลื่อนบน Firefox และ Chrome ฉันหวังว่าสิ่งนี้จะช่วยให้คุณเข้าใจดีขึ้นว่าโค้ดเดียวกันนี้ทำงานอย่างไรในรูปแบบต่างๆ ในปัจจุบัน การพัฒนาการเลื่อนที่ทำงานในลักษณะเดียวกันในเว็บเบราว์เซอร์ต่างๆ ถือเป็นเรื่องท้าทาย

เลื่อนการเด้งใน Safari บน macOS สามารถเห็นเอฟเฟกต์ที่คล้ายกันสำหรับ Edge และ Safari บน iOS
เลื่อนการเด้งใน Safari บน macOS สามารถเห็นเอฟเฟกต์ที่คล้ายกันสำหรับ Edge และ Safari บน iOS (ตัวอย่างขนาดใหญ่)

กำลังค้นหาวิธีแก้ปัญหา

หนึ่งในความคิดแรกของฉันคือจะมีวิธีที่ง่ายและรวดเร็วในการแก้ไขปัญหานี้ในทุกเบราว์เซอร์ สิ่งนี้หมายความว่า ฉันคิดว่าฉันสามารถหาวิธีแก้ปัญหาที่ต้องใช้โค้ด CSS สองสามบรรทัดและไม่ต้องใช้ JavaScript ดังนั้น สิ่งแรกที่ฉันทำคือพยายามทำสิ่งนี้ให้สำเร็จ เบราว์เซอร์ที่ฉันใช้ในการทดสอบ ได้แก่ Chrome, Firefox และ Safari บน macOS และ Windows 10 และ Edge และ Safari บน iOS เวอร์ชันของเบราว์เซอร์เหล่านี้เป็นเวอร์ชันล่าสุดในขณะที่เขียนบทความนี้ (2018)

โซลูชัน HTML และ CSS เท่านั้น

ตำแหน่งสัมบูรณ์และสัมพัทธ์

สิ่งแรกที่ฉันพยายามคือ การใช้ตำแหน่งสัมบูรณ์และสัมพัทธ์เพื่อวางตำแหน่งส่วนท้าย เพราะฉันเคยชินกับการสร้างส่วนท้ายแบบนี้ แนวคิดคือตั้งค่าหน้าเว็บของฉันให้มีความสูง 100% เพื่อให้ส่วนท้ายอยู่ด้านล่างสุดของหน้าด้วยความสูงคงที่เสมอ ในขณะที่เนื้อหาใช้ความสูง 100% ลบความสูงของส่วนท้าย และคุณสามารถเลื่อนดูได้ อีกวิธีหนึ่ง คุณสามารถตั้งค่า padding-bottom แทนการใช้ calc และตั้งค่าความสูง body-container เป็น 100% เพื่อให้เนื้อหาของแอปพลิเคชันไม่ทับซ้อนกับส่วนท้าย โค้ด CSS มีลักษณะดังนี้:

 html { width: 100%; height: 100%; overflow: hidden; position: relative; } body { width: 100%; margin: 0; font-family: sans-serif; height: 100%; overflow: hidden; } .body-container { height: calc(100% - 100px); overflow: auto; } .color-picker-main-container { width: 100%; font-size: 22px; padding-bottom: 10px; } footer { position: absolute; bottom: 0; height: 100px; width: 100%; }

โซลูชันนี้ทำงานในลักษณะเดียวกับโซลูชันดั้งเดิม (ซึ่งเป็นเพียง position: fixed; ) ข้อดีอย่างหนึ่งของโซลูชันนี้เมื่อเปรียบเทียบกับการเลื่อนนั้นไม่ได้มีไว้สำหรับทั้งหน้า แต่สำหรับเนื้อหาของหน้าที่ไม่มีส่วนท้ายเท่านั้น ปัญหาที่ใหญ่ที่สุดของวิธีนี้คือใน Mobile Safari ทั้งส่วนท้ายและเนื้อหาของแอปพลิเคชันจะย้ายพร้อมกัน ทำให้วิธีนี้มีปัญหามากเมื่อเลื่อนอย่างรวดเร็ว:

ตำแหน่งสัมบูรณ์และสัมพัทธ์
ตำแหน่งสัมบูรณ์และสัมพัทธ์

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

ความพยายามอื่น ๆ

หนึ่งในวิธีแก้ไขปัญหาที่แนะนำบนเว็บและฉันพยายามใช้กับโค้ดของฉัน ได้แสดงไว้ด้านล่างเป็นตัวอย่าง

 html { width: 100%; position: fixed; overflow: hidden; } body { width: 100%; margin: 0; font-family: sans-serif; position: fixed; overflow: hidden; } .body-container { width: 100vw; height: calc(100vh - 100px); overflow-y: auto; -webkit-overflow-scrolling: touch; } .color-picker-main-container { width: 100%; font-size: 22px; padding-bottom: 10px; } footer { position: fixed; bottom: 0; height: 100px; width: 100%; }

รหัสนี้ทำงานบน Chrome และ Firefox บน macOS ในลักษณะเดียวกับโซลูชันก่อนหน้า ข้อดีของวิธีนี้คือเลื่อนไม่ได้จำกัดความสูง 100% ดังนั้นการเลื่อนตามโมเมนตัมจึงทำงานได้อย่างถูกต้อง อย่างไรก็ตาม บน Safari ส่วนท้ายจะหายไป:

ไม่มีส่วนท้ายใน macOS Safari
ไม่มีส่วนท้ายใน macOS Safari (ตัวอย่างขนาดใหญ่)

บน iOS Safari ส่วนท้ายจะสั้นลง และมีช่องว่าง (หรือสีขาว) โปร่งใสเป็นพิเศษที่ด้านล่าง นอกจากนี้ ความสามารถในการเลื่อนดูหน้าจะหายไปหลังจากที่คุณเลื่อนไปที่ด้านล่างสุด คุณสามารถเห็นช่องว่างสีขาวด้านล่างส่วนท้ายได้ที่นี่:

ส่วนท้ายที่สั้นกว่าบน iOS Safari
ส่วนท้ายที่สั้นกว่าบน iOS Safari

โค้ดหนึ่งบรรทัดที่น่าสนใจที่คุณอาจเห็นเป็นจำนวนมากคือ: -webkit-overflow-scrolling: touch; . แนวคิดเบื้องหลังนี้คืออนุญาตให้เลื่อนตามโมเมนตัมสำหรับองค์ประกอบที่กำหนด คุณสมบัตินี้อธิบายว่า "ไม่ได้มาตรฐาน" และ "ไม่ได้อยู่ในแทร็กมาตรฐาน" ในเอกสารประกอบ MDN ซึ่งแสดงเป็น “ค่าคุณสมบัติไม่ถูกต้อง” ภายใต้การตรวจสอบใน Firefox และ Chrome และจะไม่ปรากฏเป็นคุณสมบัติบนเดสก์ท็อป Safari ฉันไม่ได้ใช้คุณสมบัติ CSS นี้ในท้ายที่สุด

เพื่อแสดงตัวอย่างโซลูชันอื่นที่คุณอาจพบและผลลัพธ์อื่นที่ฉันพบ ฉันได้ลองใช้โค้ดด้านล่าง:

 html { position: fixed; height: 100%; overflow: hidden; } body { font-family: sans-serif; margin: 0; width: 100vw; height: 100vh; overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; } .color-picker-main-container { width: 100%; font-size: 22px; padding-bottom: 110px; } footer { position: fixed; }

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

โซลูชั่นด้วย JavaScript

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

สัมผัสเหตุการณ์

แนวทางหนึ่งในการแก้ปัญหาการเด้งเลื่อนคือการป้องกันเหตุการณ์ touchmove หรือ touchstart บน window หรือ document แนวคิดเบื้องหลังนี้คือการป้องกันเหตุการณ์การสัมผัสในหน้าต่างโดยรวม ในขณะที่กิจกรรมการสัมผัสในเนื้อหาที่คุณต้องการเลื่อนดูได้รับอนุญาต ตัวอย่างของรหัสเช่นนี้แสดงอยู่ด้านล่าง:

 // Prevents window from moving on touch on older browsers. window.addEventListener('touchmove', function (event) { event.preventDefault() }, false) // Allows content to move on touch. document.querySelector('.body-container').addEventListener('touchmove', function (event) { event.stopPropagation() }, false)

ฉันลองใช้รหัสนี้หลายรูปแบบเพื่อให้การเลื่อนทำงานอย่างถูกต้อง การป้องกัน touchmove บน window ไม่ได้ทำให้เกิดความแตกต่าง การใช้ document ไม่ได้ทำให้เกิดความแตกต่าง ฉันยังพยายามใช้ทั้ง touchstart และ touchmove เพื่อควบคุมการเลื่อน แต่ทั้งสองวิธีนี้ก็ไม่ต่างกัน ฉันได้เรียนรู้ว่าคุณไม่สามารถเรียก event.preventDefault() ด้วยวิธีนี้ได้อีกต่อไปเนื่องจากเหตุผลด้านประสิทธิภาพ คุณต้องตั้งค่าตัวเลือก passive false ในตัวฟังเหตุการณ์:

 // Prevents window from moving on touch on newer browsers. window.addEventListener('touchmove', function (event) { event.preventDefault() }, {passive: false})

ห้องสมุด

คุณอาจเจอห้องสมุดที่เรียกว่า “iNoBounce” ซึ่งสร้างขึ้นเพื่อ “หยุดเว็บแอป iOS ของคุณไม่ให้เด้งไปมาเมื่อเลื่อน” สิ่งหนึ่งที่ควรทราบเมื่อใช้ไลบรารีนี้ในขณะนี้เพื่อแก้ปัญหาที่ฉันได้อธิบายไว้ในบทความนี้คือคุณต้องใช้ -webkit-overflow-scrolling สิ่งที่ควรทราบอีกประการหนึ่งคือวิธีแก้ปัญหาที่กระชับกว่าที่ฉันลงเอยด้วย (ซึ่งจะอธิบายในภายหลัง) ทำสิ่งที่คล้ายกับใน iOS คุณสามารถทดสอบได้ด้วยตัวเองโดยดูตัวอย่างใน GitHub Repository และเปรียบเทียบกับโซลูชันที่ฉันลงเอยด้วย

Overscroll พฤติกรรม

หลังจากลองใช้วิธีแก้ปัญหาเหล่านี้ทั้งหมดแล้ว ฉันพบข้อมูลเกี่ยวกับคุณสมบัติ CSS overscroll-behavior คุณสมบัติ CSS overscroll-behavior โครลถูกนำไปใช้ใน Chrome 63 ในเดือนธันวาคม 2017 และใน Firefox 59 ในเดือนมีนาคม 2018 คุณสมบัตินี้ ตามที่อธิบายไว้ในเอกสารประกอบ MDN “ช่วยให้คุณควบคุมพฤติกรรมการเลื่อนโอเวอร์โฟลว์ของเบราว์เซอร์ — จะเกิดอะไรขึ้นเมื่อขอบเขตของ ถึงพื้นที่เลื่อนแล้ว” นี่เป็นวิธีแก้ปัญหาที่ฉันใช้

ทั้งหมดที่ฉันต้องทำคือตั้งค่า overscroll-behavior เป็น none ใน body ของเว็บไซต์ของฉัน และฉันสามารถปล่อยให้ position ของส่วนท้าย fixed แม้ว่าการเลื่อนตามโมเมนตัมจะใช้กับทั้งหน้า แทนที่จะใช้เนื้อหาที่ไม่มีส่วนท้าย โซลูชันนี้ดีเพียงพอสำหรับฉันและปฏิบัติตามข้อกำหนดทั้งหมดของฉัน ณ เวลานั้น และส่วนท้ายของฉันไม่เด้งบน Chrome โดยไม่คาดคิดอีกต่อไป อาจเป็นประโยชน์ที่จะทราบว่า Edge มีคุณสมบัตินี้ถูกตั้งค่าสถานะว่าอยู่ในระหว่างการพัฒนาในขณะนี้ overscroll-behavior อาจถูกมองว่าเป็นการเพิ่มประสิทธิภาพหากเบราว์เซอร์ยังไม่รองรับ

บทสรุป

ถ้าคุณไม่ต้องการให้ส่วนหัวหรือส่วนท้ายคงที่ของคุณเด้งไปมาบนหน้าเว็บของคุณ คุณสามารถใช้คุณสมบัติ CSS overscroll-behavior ได้แล้ว

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