应用Matrix3d变换后div无法滚动的技术问题咨询
解决带Matrix3D变换元素的滚动失效问题
问题场景
尝试滚动
#contentdiv时无法生效,但拖动滚动条可正常使用。经测试发现该问题与所应用的Matrix3d变换相关,移除变换后滚动功能恢复正常。由于当前页面结构由three.js的CSS3DObject生成,因此不能修改结构,且任意变换参数均会引发该问题。
复现代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .page { position: absolute; background-color: red; width: 90vw; height: 90vh; overflow-y: scroll; } #content { width: 100%; height: 200vh; background-color: green; } </style> </head> <body> <div style="width: 1440px; height: 820px; perspective: 989.827561px;"> <div style="transform-style: preserve-3d; width: 1440px; height: 820px; transform: translateZ(989.827561px) matrix3d(0.599134, 0.00687, 0.800619, 0, -0.004679, -0.999916, 0.012081, 0, -0.800635, 0.010985, 0.599052, 0, -33.888354, 168.546007, 72.503973, 1) translate(720px, 410px);"> <div class="page track0" style="transform: translate(-50%, -50%) matrix3d(0.032176, 0, -0.042115, 0, 0.000519, -0.052996, 0.000396, 0, 0.042112, 0.000653, 0.032173, 0, -94.514369, 166.635279, -114.904453, 1);"><div id="content"></div></div> </div> </div> </body> </html>
问题原因
浏览器对应用了复杂3D变换(如matrix3d)的元素会创建独立的合成层,导致鼠标滚轮事件的命中检测出现偏差——滚轮事件被外层变换元素捕获,无法正确传递到内部的滚动容器,只有拖动滚动条能直接触发容器的滚动逻辑。
解决方案
方案1:通过指针事件穿透解决
给内部滚动容器强制开启指针事件接收,同时让外层变换元素不捕获鼠标事件,确保滚轮事件直接落到滚动容器上:
.page { position: absolute; background-color: red; width: 90vw; height: 90vh; overflow-y: scroll; pointer-events: auto; /* 强制滚动容器接收指针事件 */ } /* 给所有带matrix3d变换的外层容器设置指针事件穿透 */ div[style*="matrix3d"]:not(.page) { pointer-events: none; }
注意:如果外层变换元素本身需要交互(比如点击、拖拽),这个方法会影响其功能,此时建议用方案2。
方案2:事件委托手动转发滚轮事件
在外层变换容器上监听滚轮事件,手动将事件转发给内部滚动容器,既保留外层元素的交互性,又能让滚动容器响应滚轮:
// 获取外层3D变换容器 const transformWrapper = document.querySelector('div[style*="transform-style: preserve-3d"]'); // 获取内部滚动容器 const scrollBox = document.querySelector('.page'); transformWrapper.addEventListener('wheel', (e) => { e.stopPropagation(); // 复制滚轮事件并派发给滚动容器 scrollBox.dispatchEvent(new WheelEvent('wheel', { deltaY: e.deltaY, deltaX: e.deltaX, deltaMode: e.deltaMode, bubbles: true, cancelable: true })); }, { passive: true });
这个方法不会影响外层元素的其他交互,适合页面存在多元素交互的场景。
内容的提问来源于stack exchange,提问作者Hanz Geiger
相关产品推荐
相关产品推荐

