仅Safari中Canvas绘图导致包裹div无法调整大小问题求助
我用div包裹canvas元素,给外层div设置了resize: both和overflow: auto样式,该功能在Chrome中正常工作,但在Safari 14.0.3里,只要对canvas执行绘图操作(比如clearRect、设置fillStyle),div就无法调整大小,鼠标悬停右下角调整区域时光标也不会变化。注释掉绘图相关的useEffect代码后,Safari中的div又能正常调整大小。我的应用需要支持在canvas上绘图,canvas还监听了mousemove、mousedown、mouseup事件。
代码示例:
function Base() { React.useEffect(() => { const canvas = document.getElementById("covering-canvas-11"); const context = canvas.getContext("2d"); console.log("context for convercaning canvas 11 is ", context); if (context) { context.clearRect(0, 0, 40, 40); context.fillStyle = "white"; } }); return ( <div> <div style={{ resize: "both", overflow: "auto", background: "#ccc", width: "40px", height: "40px", }} > <canvas id={`covering-canvas-11`} width="40px" height="40px"></canvas> </div> </div> ); } ReactDOM.render( <Base />, document.getElementById('root') );
解决方案
这是Safari的已知渲染Bug:当canvas内容被修改后,浏览器会错误地提升canvas元素的层级,遮挡住父div的resize控制点。可通过以下方式修复:
调整层级关系:给父div添加
position: relative和z-index: 1,同时给canvas设置position: relative和更低的z-index: 0,强制让父div的层级高于canvas,确保resize控制点能被鼠标捕获。修改后的代码片段:<div style={{ resize: "both", overflow: "auto", background: "#ccc", width: "40px", height: "40px", position: "relative", zIndex: 1 }} > <canvas id={`covering-canvas-11`} width="40px" height="40px" style={{position: "relative", zIndex: 0}} ></canvas> </div>添加透明伪元素遮罩:给父div添加一个透明的伪元素覆盖层,不影响canvas交互但能确保resize控制点正常工作。先定义CSS类:
.resize-container::after { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; pointer-events: none; }再给父div添加该类,并设置
position: relative。优化useEffect执行逻辑:原代码的useEffect无依赖数组,会在每次组件渲染时重复执行绘图操作,加重Safari的渲染异常。添加空依赖数组让它只执行一次:
React.useEffect(() => { // 绘图代码 }, []);减少不必要的canvas重绘,降低触发Bug的概率。
内容的提问来源于stack exchange,提问作者Mark

