เราทราบดีว่าการตอบสนองของการเลื่อนมีความสำคัญต่อการมีส่วนร่วมของผู้ใช้กับเว็บไซต์ในอุปกรณ์เคลื่อนที่ แต่ Listener เหตุการณ์แบบสัมผัสมักจะทำให้เกิดปัญหาที่ส่งผลต่อประสิทธิภาพการเลื่อนที่ร้ายแรง Chrome ได้แก้ไขปัญหานี้โดยอนุญาตให้ Listener เหตุการณ์การแตะเป็นแบบ
แพสซีฟ
(ส่งตัวเลือก {passive: true}
ไปยัง addEventListener()
) และจัดส่ง
เหตุการณ์ตัวชี้ API
ฟีเจอร์เหล่านี้เป็นฟีเจอร์ที่ยอดเยี่ยมในการกระตุ้นเนื้อหาใหม่ให้เป็นโมเดลที่ไม่บล็อกการเลื่อน แต่ในบางครั้งนักพัฒนาซอฟต์แวร์พบว่าเนื้อหาเหล่านี้เข้าใจยากและนำไปใช้ได้ยาก
เราเชื่อว่าเว็บควรจะเร็วโดยค่าเริ่มต้นโดยที่นักพัฒนาซอฟต์แวร์ไม่จำเป็นต้องเข้าใจรายละเอียดเล็กๆ น้อยๆ ของลักษณะการทำงานของเบราว์เซอร์ ใน Chrome 56 เราจะกำหนดค่าเริ่มต้นให้ แตะผู้ฟังให้เป็นแบบพาสซีฟโดยค่าเริ่มต้นในกรณีที่บ่อยที่สุดตรงกับความตั้งใจของนักพัฒนาซอฟต์แวร์ เราเชื่อว่าการดำเนินการนี้จะช่วยปรับปรุงประสบการณ์ของผู้ใช้ได้อย่างมากขณะที่ส่งผลกระทบในเชิงลบต่อเว็บไซต์น้อยที่สุด
ในบางกรณีที่เกิดขึ้นไม่บ่อยนัก การเปลี่ยนแปลงนี้อาจส่งผลให้การเลื่อนโดยไม่ตั้งใจ ปัญหานี้มักจะแก้ได้ง่ายๆ โดยใช้รูปแบบ touch-action: none กับองค์ประกอบที่ไม่ควรเลื่อน อ่านต่อเพื่อดูรายละเอียด วิธีดูว่าคุณได้รับผลกระทบหรือไม่ และทำอะไรได้บ้าง
ข้อมูลภูมิหลัง: กิจกรรมที่ยกเลิกได้จะทำให้หน้าเว็บช้าลง
หากเรียกใช้ preventDefault() ในเหตุการณ์ touchstart
หรือ touchmove
รายการแรก จะทำให้ไม่สามารถเลื่อนได้
ปัญหาคือผู้ฟังส่วนใหญ่จะไม่เรียกใช้ preventDefault()
แต่เบราว์เซอร์จะต้องรอให้เหตุการณ์เสร็จสิ้นก่อนจึงจะตรวจสอบได้
"Listener เหตุการณ์แบบแพสซีฟ" ที่นักพัฒนาแอปกำหนดช่วยแก้ปัญหานี้ได้ เมื่อคุณเพิ่มเหตุการณ์การแตะที่มีออบเจ็กต์ {passive: true}
เป็นพารามิเตอร์ที่ 3 ในแฮนเดิลเหตุการณ์ หมายความว่าคุณกำลังบอกเบราว์เซอร์ว่า Listener touchstart
จะไม่เรียกใช้ preventDefault()
และเบราว์เซอร์จะเลื่อนได้อย่างปลอดภัยโดยไม่บล็อก Listener เช่น
window.addEventListener("touchstart", func, {passive: true} );
การฝึกฝน
แรงจูงใจหลักของเราคือการลดเวลาที่ใช้ในการอัปเดตจอแสดงผลหลังจากผู้ใช้แตะหน้าจอ เพื่อทำความเข้าใจการใช้งาน Touchstart และ Touchmove เราได้เพิ่มเมตริกเพื่อระบุความถี่ของการบล็อกการเลื่อนที่เกิดขึ้น
เราดูเปอร์เซ็นต์ของกิจกรรมการแตะที่ยกเลิกได้ซึ่งส่งไปยังเป้าหมายรูท (หน้าต่าง เอกสาร หรือเนื้อหา) และพิจารณาแล้วว่า 80% ของผู้ฟังเหล่านี้มีแนวคิดเป็นแบบแพสซีฟ แต่ไม่ได้ลงทะเบียนไว้ จากจำนวนปัญหานี้ เราสังเกตเห็นโอกาสอันยอดเยี่ยมในการปรับปรุงการเลื่อน โดยที่นักพัฒนาซอฟต์แวร์ไม่ต้องดำเนินการใดๆ ด้วยการทำให้เหตุการณ์เหล่านี้เป็นแบบ "แพสซีฟ" โดยอัตโนมัติ
จึงได้กําหนดวิธีการแทรกแซงของเราว่า หากเป้าหมายของ Listener แบบทัชอัปหรือย้ายคือ window
, document
หรือ body
เราจะตั้งค่าเริ่มต้น passive
เป็น true
ซึ่งหมายความว่าโค้ดอย่างเช่น
window.addEventListener("touchstart", func);
จะเทียบเท่ากับ
window.addEventListener("touchstart", func, {passive: true} );
ขณะนี้ระบบจะไม่สนใจการโทรไปยัง preventDefault()
ภายใน Listener
กราฟด้านล่างแสดงเวลาที่ใช้โดยการเลื่อนบนสุด 1% แรกนับตั้งแต่เวลาที่ผู้ใช้แตะหน้าจอเพื่อเลื่อนจนถึงเวลาที่มีการอัปเดตจอแสดงผล ข้อมูลนี้มีไว้สำหรับ
เว็บไซต์ทั้งหมดใน Chrome สำหรับ Android ก่อนที่จะมีการเปิดการแทรกแซง
การเลื่อน 1% ใช้เวลามากกว่า 400 มิลลิวินาที ซึ่งตอนนี้มีการลดเหลือเพียง 250 มิลลิวินาที
ใน Chrome 56 เบต้า ซึ่งลดลงประมาณ 38% ในอนาคต เราหวังว่าจะทำให้การไม่ใช้งานจริงแบบแพสซีฟเป็นค่าเริ่มต้นสำหรับ Listener ทั้งหมด touchstart
และ touchmove
โดยลดค่านี้ให้ต่ำกว่า 50 มิลลิวินาที
ความเสียหายและคำแนะนำ
ในกรณีส่วนใหญ่ การเกิดความเสียหายจะไม่เกิดขึ้น แต่เมื่อเกิดความเสียหายขึ้น อาการที่พบบ่อยที่สุดคือการเลื่อนจะเกิดขึ้นเมื่อคุณไม่ต้องการ ในบางกรณีที่เกิดขึ้นไม่บ่อยนัก นักพัฒนาซอฟต์แวร์อาจสังเกตเห็นเหตุการณ์คลิกที่ไม่คาดคิด
(เมื่อ preventDefault()
หายไปจาก Listener touchend
)
ใน Chrome 56 ขึ้นไป เครื่องมือสำหรับนักพัฒนาเว็บจะบันทึกคำเตือนเมื่อคุณเรียกใช้ preventDefault()
ในกรณีที่การฝึกฝนทำงานอยู่
touch-passive.html:19 Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080
แอปพลิเคชันของคุณระบุได้ว่าปัญหานี้พบได้ในเบื้องต้นหรือไม่ โดยตรวจสอบว่าการเรียกใช้ preventDefault
มีผลใดๆ ผ่านพร็อพเพอร์ตี้ defaultPrevented
หรือไม่
เราพบว่าหน้าเว็บส่วนใหญ่ที่ได้รับผลกระทบนั้นแก้ไขได้ค่อนข้างง่าย โดยการใช้พร็อพเพอร์ตี้ CSS touch-action ทุกครั้งที่ทำได้ หากต้องการป้องกันไม่ให้เบราว์เซอร์เลื่อนและซูมในองค์ประกอบหนึ่งๆ ให้ใช้ touch-action: none
กับองค์ประกอบนั้น หากคุณมีภาพสไลด์แนวนอน ให้ใช้ touch-action: pan-y pinch-zoom
กับภาพสไลด์ดังกล่าว เพื่อให้ผู้ใช้ยังคงเลื่อนในแนวตั้งและซูมได้ตามปกติ การใช้การแตะอย่างถูกต้องเป็นสิ่งจำเป็นอยู่แล้วในเบราว์เซอร์ เช่น Edge ของเดสก์ท็อปที่รองรับเหตุการณ์ของตัวชี้ ไม่ใช่ "กิจกรรมการแตะ" สำหรับ Safari บนอุปกรณ์เคลื่อนที่และเบราว์เซอร์ในอุปกรณ์เคลื่อนที่รุ่นเก่าที่ไม่รองรับการแตะ Listener จะต้องเรียกใช้ preventDefault
ต่อไปแม้ว่า Chrome จะไม่สนใจการทำงานดังกล่าวก็ตาม
ในกรณีที่มีความซับซ้อน อาจจำเป็นต้องใช้การดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้ด้วย
- หาก Listener ของ
touchstart
เรียกใช้preventDefault()
ให้ตรวจสอบว่ามีการเรียกpreventDefault() จาก Listener ปลายทางที่เกี่ยวข้องด้วยเพื่อระงับการสร้างเหตุการณ์การคลิกและลักษณะการแตะที่เป็นค่าเริ่มต้นอื่นๆ ต่อไป - สุดท้าย (และไม่แนะนำให้ใช้) ให้ส่งผ่าน
{passive: false}
ไปยัง addEventListener() เพื่อลบล้างลักษณะการทำงานเริ่มต้น โปรดทราบว่าคุณจะต้องใช้ฟีเจอร์เพื่อตรวจจับว่า User Agent รองรับ EventListenerOptions หรือไม่
บทสรุป
ใน Chrome 56 การเลื่อนเริ่มทํางานได้เร็วขึ้นมากในหลายเว็บไซต์ นี่เป็นผลกระทบเดียวที่นักพัฒนาแอปส่วนใหญ่จะเห็นจากการเปลี่ยนแปลงนี้ ในบางกรณี นักพัฒนาซอฟต์แวร์อาจสังเกตเห็นการเลื่อนโดยไม่ตั้งใจ
แม้ว่าการดำเนินการดังกล่าวจะยังจำเป็นต่อการใช้งานสำหรับ Safari บนอุปกรณ์เคลื่อนที่ แต่เว็บไซต์ไม่ควรอาศัยการเรียกใช้ preventDefault()
ภายในผู้ฟัง touchstart
และผู้ฟัง touchmove
เนื่องจากเราไม่รับประกันว่าจะยึดตามฟังก์ชันดังกล่าวใน Chrome อีกต่อไป นักพัฒนาซอฟต์แวร์ควรใช้พร็อพเพอร์ตี้ CSS touch-action
กับองค์ประกอบที่ควรปิดใช้การเลื่อนและการซูมเพื่อแจ้งเตือนเบราว์เซอร์ก่อนที่จะเกิดเหตุการณ์การแตะขึ้น
หากต้องการระงับลักษณะการทำงานเริ่มต้นของการแตะ (เช่น การสร้างเหตุการณ์การคลิก) ให้เรียกใช้ preventDefault()
ใน Listener touchend