iOS端Webkit内核下SVG转Canvas PNG丢失transform3d问题求助
Webkit内核浏览器中SVG转Canvas时3D变换丢失的问题解决建议
问题概述
将SVG加载到Canvas的功能在Chrome、Firefox中正常运行,但在Webkit内核浏览器下,CSS transform3d效果会丢失,调整3D变换参数也无法解决该问题。Webkit官方已记录此Bug。
测试用例
HTML
<h1>Webkit: SVG to Canvas lost transform3d</h1> <br /> <div> <div id="imageTest"></div> <br/> </div> <button id="btn_convert">Convert SVG to canvas PNG</button> <br /> <br /> <img id="canvasTest" /> <textarea id="input_svg" style="visibility:collapse;"> <svg version= "1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200" id="chess"> <defs> <style> #chess { transform:perspective(500px) rotateX(65deg) ; } .chessPattern { fill: red; } </style> <pattern id="pattern-chess" x="0" y="0" width="40" height="40" patternUnits="userSpaceOnUse" > <rect class="chessPattern" x="0" width="20" height="20" y="0" /> <rect class="chessPattern" x="20" width="20" height="20" y="20" /> </pattern> </defs> <g id="group" > <rect width="200" height="200" fill="url(#pattern-chess)" /> </g> </svg> </textarea>
CSS
body { background: #fff; }
JavaScript
const svgString = document.querySelector("#input_svg").value; const div = document.createElement("div"); div.innerHTML = svgString; const svgs = div.querySelectorAll("svg"); const convertButton = document.querySelector("#btn_convert"); const imageTest = document.querySelector("#imageTest"); const canvasTest = document.querySelector("#canvasTest"); imageTest.innerHTML=svgString; const img = document.createElement("img"); const canvas = document.createElement("canvas"); const ctx = canvas.getContext('2d'); const URL = window.URL || window.webkitURL || window; convertButton.onclick = async () => { var imageSrc = await svgToBase64(svgs[0]); canvasTest.src=imageSrc; }; async function svgToBase64(svg) { const width = svg.getAttribute("width"); const height = svg.getAttribute("height"); canvas.width = width; canvas.height = height; const data = new XMLSerializer().serializeToString(svg); const blob = new Blob([data], { type: 'image/svg+xml' }); var url = URL.createObjectURL(blob); return new Promise((resolve) => { img.onload = () => { ctx.drawImage(img, 0, 0); URL.revokeObjectURL(url); resolve(canvas.toDataURL("image/png")); } img.src = url; }); }
临时修复方案
- 转移3D变换到SVG内部元素:将原本作用于
<svg>根元素的transform: perspective(500px) rotateX(65deg),移到内部的<g id="group">元素上。Webkit对SVG根元素的CSS 3D变换支持存在缺陷,但对内部容器元素的支持更稳定。 - 使用SVG原生3D变换:改用SVG的
transform属性配合matrix3d实现等效效果,兼容性更好。例如:<g id="group" transform="matrix3d(1,0,0,0,0,0.4226,0.9063,0,0,-0.9063,0.4226,0,0,0,0,1)"> <rect width="200" height="200" fill="url(#pattern-chess)" /> </g> - 预渲染转图片再绘制:先将带3D变换的SVG在页面中渲染,使用
html2canvas等工具将其转为图片,再将图片绘制到Canvas。此方法可绕开Webkit直接处理SVG的变换丢失问题,但需引入额外依赖。
注意事项
- 确保SVG样式内联或在
<defs>的<style>标签内,避免外部样式表,转为Blob时外部样式无法被正确加载。 - 检查SVG的
viewBox属性与Canvas宽高匹配,避免缩放导致变换异常。
内容的提问来源于stack exchange,提问作者slyi
相关产品推荐
相关产品推荐

