นักเล่นอินเทอร์เน็ตมืออาชีพ • ผู้ที่ชื่นชอบเกม • ผู้สร้างเทคโนโลยี
นักเล่นอินเทอร์เน็ตมืออาชีพ • ผู้ที่ชื่นชอบเกม • ผู้สร้างเทคโนโลยี

หกอย่างที่ฉันได้เรียนรู้เกี่ยวกับการเลื่อนแบบยางของ iOS Safari

เพื่อแก้ปัญหาการเลื่อนใน Safari บน iOS ฉันจำเป็นต้องสร้างหน้าเว็บทดสอบแบบง่ายๆ ของตัวเอง!
หน้านี้ได้รับการแปลจากภาษาอังกฤษโดยนักศึกษาฝึกงานด้าน AI ที่มีแรงบันดาลใจสูงของฉัน เพื่อความสะดวกของคุณ พวกเขายังคงเรียนรู้อยู่ ดังนั้นอาจมีข้อผิดพลาดหลงเหลืออยู่บ้าง สำหรับข้อมูลที่ถูกต้องที่สุด โปรดดูเวอร์ชันภาษาอังกฤษ
บ้าน บล็อก หกอย่างที่ฉันได้เรียนรู้เกี่ยวกับการเลื่อนแบบยางของ iOS Safari

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

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

ด้านล่างนี้คือภาพรวมสั้นๆ ของสิ่งที่ฉันค้นพบระหว่างกระบวนการนี้

หน้าทดสอบของฉัน

หน้าทดสอบของฉันค่อนข้างเรียบง่าย มันประกอบด้วยข้อมูลจำลองที่วางไว้ใน div แบบคงที่เพื่อแทนที่ 'หน้า' พร้อมกับ div คงที่ที่ลอยอยู่เหนือหน้าเพื่อแทนที่ 'เมนู' ดังนี้.

ภาพหน้าจอของเมนูด้านข้าง HTML ที่เปิดอยู่บน iOS Safari

รหัสต้นฉบับทั้งหมดสำหรับหน้านี้สามารถพบได้ที่ด้านล่างของบทความบล็อกนี้.

ทำความเข้าใจการทำงานตามค่าเริ่มต้น

สิ่งแรกที่ฉันทำคือพยายามทำความเข้าใจพฤติกรรมเริ่มต้นของ Safari บน iOS สิ่งที่สังเกตได้เด่นชัดที่สุดคือเมื่อคุณเลื่อนถึงด้านล่างสุดของเมนู เนื้อหาของหน้าจะปรากฏให้เห็น "เอฟเฟกต์ยางยืด" ซึ่งเป็นฟีเจอร์ที่ฝังไว้ใน Safari

ภาพหน้าจอแบบเคลื่อนไหวของเอฟเฟกต์ Rubber Band ที่เกิดปัญหาใน iOS Safari ที่ด้านล่างของหน้า

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

ภาพหน้าจอเคลื่อนไหวของเอฟเฟ็กต์ยางยืดที่เป็นปัญหาใน iOS Safari ที่ด้านบนสุดของหน้า

อย่างไรก็ตาม ปัญหาแรกที่ผมสังเกตเห็นคือถ้าคุณเลื่อนไปถึงด้านบนสุดหรือด้านล่างสุดอย่างต่อเนื่อง Safari จะเริ่มมีการแสดงผลเพี้ยนทั้งบนหน้าพื้นหลังและเมนู

ฉันไม่แน่ใจว่าเกิดจากอะไร แต่ฉันสงสัยว่ามันเกี่ยวข้องกับฟีเจอร์ rubber-band

ภาพสกรีนช็อตแบบเคลื่อนไหวของปัญหากระตุกใน Safari บน iOS ที่อยู่ด้านล่างของหน้า

เข้าใจว่าสิ่งที่กฎ CSS "-webkit-overflow-scrolling" ทำงานอย่างไร

สิ่งถัดไปที่ฉันทำคือการนำกฎ CSS -webkit-overflow-scrolling ไปใช้กับเมนู ซึ่งช่วยให้การเลื่อนแบบโมเมนตัมเกิดขึ้น เปิดใช้งานการเลื่อนแบบโมเมนตัม.

ดังที่เห็นในภาพด้านล่าง การเลื่อนยังคงดำเนินต่อไป แม้ฉันจะปัดด้วยนิ้วก็ตาม.

แสดงปัญหาการเลื่อนแบบโมเมนตัมบน iOS Safari

แต่ยังมีเอฟเฟกต์ยางยืดเมื่อเลื่อนไปถึงด้านบนสุดหรือด้านล่างสุด ตามที่แสดงด้านล่าง

แสดงปัญหาการเลื่อนด้วยโมเมนตัมบน iOS Safari พร้อมเอฟเฟกต์ Rubber Band

ผู้ใช้จำเป็นต้องรอจนกว่าเอฟเฟกต์การดีดจะเสร็จสิ้น

ระหว่างการทดสอบ ผมสังเกตเห็นว่าในขณะที่เอฟเฟกต์ rubber-band กำลังทำงาน ผู้ใช้ไม่สามารถย้ายโฟกัสไปยังองค์ประกอบอื่นได้จนกว่าการเคลื่อนไหวจะเสร็จสมบูรณ์

ในตัวอย่างด้านล่าง ผมเลื่อนหน้าพื้นหลังก่อน แล้วพยายามเลื่อนเมนูอย่างรวดเร็ว แต่สุดท้ายกลับเลื่อนไปยังหน้าพื้นหลังอยู่ดี

แสดงให้เห็นว่า หน้าเบื้องหลังถูกเลื่อนบน iOS Safari

อย่างไรก็ตาม หากรอสักครู่เพื่อให้เอฟเฟกต์เสร็จสมบูรณ์ ฉันก็จะเริ่มเลื่อนเมนูได้.

แสดงให้เห็นถึงการรอจนกว่าเอฟเฟกต์ยางยืดบน iOS Safari จะเสร็จสมบูรณ์

วิธีป้องกันไม่ให้หน้าพื้นหลังเลื่อน

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

อ้างอิงจากคำตอบนี้ใน Stack Overflow, คุณสามารถมั่นใจได้ว่าองค์ประกอบที่มี disable-scrolling จะไม่ทำการเลื่อนตามค่าเริ่มต้นเมื่อเหตุการณ์ touchmove ถูกเรียกใช้งาน.

document.ontouchmove = function(event) { var isTouchMoveAllowed = true, target = event.target; while (target !== null) { if (target.classList && target.classList.contains('disable-scrolling')) { isTouchMoveAllowed = false; break; } target = target.parentNode; } if (!isTouchMoveAllowed) { event.preventDefault(); } };

จากนั้นนำคลาส disable-scrolling ไปใช้กับ div ของหน้า:

<div class="page disable-scrolling">

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

แสดงให้เห็นว่าพื้นหลังยังคงถูกเลื่อนอยู่

วิธีป้องกันไม่ให้หน้าเว็บด้านหลังเลื่อน

โดยการใช้งาน fix นี้ จะทำให้สามารถป้องกันการเลื่อนเกินขอบได้ (overscrolling) ซึ่งหมายความว่าเมื่อองค์ประกอบถูกเลื่อนไปถึงจุดบนสุดหรือล่างสุดของมัน การเลื่อนจะไม่ดำเนินต่อไปยังส่วนของ body ของหน้าเว็บ

ด้วยเหตุนี้ หน้าเว็บจึงไม่สามารถเลื่อนขึ้น-ลงได้ และยังช่วยยับยั้งไม่ให้เกิดเอฟเฟ็กต์ยางเด้งเมื่อเลื่อน

function removeIOSRubberEffect(element) { element.addEventListener("touchstart", function() { var top = element.scrollTop, totalScroll = element.scrollHeight, currentScroll = top + element.offsetHeight; if (top === 0) { element.scrollTop = 1; } else if (currentScroll === totalScroll) { element.scrollTop = top - 1; } }); } removeIOSRubberEffect(document.querySelector(".scrollable"));

สคริปต์ JavaScript นี้ทำให้องค์ประกอบไม่ไปถึงด้านบนสุดหรือด้านล่างสุด โดยเว้นระยะห่างไว้ที่เพียง 1 พิกเซลเท่านั้น

หากตำแหน่งการเลื่อนยังไม่ถึงจุดบนสุดหรือล่างสุด การเลื่อนเกินขอบเขตจะไม่เกิดขึ้น.

ตัวอย่างการป้องกันการเลื่อนเกินขอบเขต โดยไม่ไปถึงจุดบนสุดหรือจุดล่างสุด

วิธีป้องกันไม่ให้เลื่อนไปยังหน้าพื้นหลัง

ถ้าคุณต้องการลบเอฟเฟ็กต์ดีดออกจากเมนู ทั้งเพื่อเหตุผลด้านความงาม หรือเพราะในกรณีของฉัน มันทำให้เกิดปัญหาการเรนเดอร์เพิ่มเติม เพียงลบกฎ CSS -webkit-overflow-scrolling ออกเท่านั้น

อย่างไรก็ตาม ตามที่คุณเห็นด้านล่าง คุณยังสูญเสียความลื่นไหลในการเลื่อน

ตัวอย่างเต็มสำหรับการป้องกันการดีดกลับบน iOS Safari

รหัสต้นฉบับทั้งหน้า

นี่คือโค้ดต้นฉบับทั้งหมดของหน้านี้

<!-- License MIT, Author Special Agent Squeaky (specialagentsqueaky.com) --> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="minimum-scale=1.0, width=device-width, maximum-scale=1.0, user-scalable=no, initial-scale=1"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style> .page{ font-size: 24px; overflow: scroll; } .menu{ position: fixed; top: 0; bottom: 0; left: 0; width: 80%; background: gray; z-index: 1; font-size: 10px; overflow: scroll; /* uncomment to get smooth momentum scroll, but also a rubber band effect */ /*-webkit-overflow-scrolling: touch;*/ } .menu-item{ padding: 10px; background: darkgray; font-size: 24px; } </style> </head> <body> <div class="menu scrollable"> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> <div class="menu-item">hello world</div> </div> <div class="page disable-scrolling"> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. </div> <script> document.ontouchmove = function(event) { var isTouchMoveAllowed = true, target = event.target; while (target !== null) { if (target.classList && target.classList.contains('disable-scrolling')) { isTouchMoveAllowed = false; break; } target = target.parentNode; } if (!isTouchMoveAllowed) { event.preventDefault(); } }; function removeIOSRubberEffect(element) { element.addEventListener("touchstart", function() { var top = element.scrollTop, totalScroll = element.scrollHeight, currentScroll = top + element.offsetHeight; if (top === 0) { element.scrollTop = 1; } else if (currentScroll === totalScroll) { element.scrollTop = top - 1; } }); } removeIOSRubberEffect(document.querySelector(".scrollable")); </script> </body> </html>

เขียนโดย Special Agent Squeaky เผยแพร่ครั้งแรก 2015-06-10 อัปเดตล่าสุด 2015-06-10

📺 ดูวิดีโอล่าสุดของ Squeaky!

วิธีเพิ่มคำบรรยายเรียลไทม์แบบง่ายๆ สำหรับสตรีมสดของคุณ