Với touchstart, touchmove, wheel, trình duyệt không biết trước handler có gọi preventDefault() để chặn cuộn hay không. Nếu listener không khai gì, trình duyệt phải chờ handler chạy xong rồi mới quyết định cuộn — mỗi lần chạm là một lần trễ, cuộn thấy khựng.
{ passive: true } là lời cam kết "handler này sẽ không gọi preventDefault()", nên trình duyệt cuộn ngay lập tức song song với việc chạy handler.
// scroll starts immediately, handler runs in parallel
window.addEventListener('touchmove', onMove, { passive: true })
// need to block scrolling -> must stay non-passive
el.addEventListener('wheel', onWheel, { passive: false })Lưu ý:
- Trong listener passive mà vẫn gọi preventDefault() thì lệnh bị bỏ qua và console cảnh báo.
- Chrome đã mặc định passive cho touchstart/touchmove/wheel gắn ở window, document, document.body; các phần tử khác vẫn cần khai tay.
- Muốn chặn cuộn (vd khóa nền khi mở modal), cách bền hơn là dùng CSS touch-action: none / overflow: hidden thay vì preventDefault() trong handler.