Safari中Canvas绘制图片尺寸偏大与Chrome显示不一致问题
Safari下Canvas绘制图片尺寸偏大问题解决方案
不需要将图片上传至imgur,更换图片存储位置完全无法解决该兼容问题。该问题的核心原因是你没有处理高分屏的设备像素比适配,加上Safari对图片原始尺寸的读取逻辑和Chrome存在差异,和图片存本地还是存图床没有关联。
问题根源
- 现有Canvas初始化逻辑只设置了Canvas标签的像素宽高,没有区分CSS显示尺寸和实际渲染像素尺寸,在Retina等高分辨率屏幕下,Safari的默认像素比缩放逻辑和Chrome不一致,会导致绘制出来的元素尺寸出现偏差
- 代码中读取图片尺寸用的是
image.width,部分版本Safari在图片未完全完成解码时,该属性返回值和实际原始尺寸存在偏差,应该使用naturalWidth/naturalHeight读取图片的真实原始像素尺寸
修复步骤
1. 替换Canvas初始化及窗口resize逻辑
新增设备像素比适配,保证两个浏览器下Canvas的渲染基准一致:
var c = document.getElementById("canvas"); var ctx = c.getContext("2d"); function resizeCanvas() { const dpr = window.devicePixelRatio || 1; // 设置Canvas的CSS显示尺寸为窗口大小 c.style.width = `${window.innerWidth}px`; c.style.height = `${window.innerHeight}px`; // 按设备像素比设置Canvas实际渲染像素尺寸,避免高分屏模糊/尺寸偏差 c.width = window.innerWidth * dpr; c.height = window.innerHeight * dpr; // 缩放上下文,后续绘制逻辑不需要额外调整坐标计算规则 ctx.scale(dpr, dpr); } // 初始化执行 resizeCanvas(); window.addEventListener("resize", resizeCanvas);
2. 调整城堡类的图片尺寸读取逻辑
将图片尺寸读取属性替换为naturalWidth/naturalHeight,保证所有浏览器下拿到的图片原始尺寸一致:
class castle { constructor() { const castle = new Image() castle.src = './Img/castle.png' castle.onload = () => { this.scale = 0.5 this.image = castle // 读取图片原始自然尺寸,兼容全浏览器 this.width = this.image.naturalWidth * this.scale this.height = this.image.naturalHeight * this.scale this.position = { x: window.innerWidth / 2 - this.width / 2, y: window.innerHeight / 2 - this.height / 2 } this.center = { x: window.innerWidth / 2, y: window.innerHeight / 2 } } } draw() { ctx.drawImage( this.image, this.position.x, this.position.y, this.width, this.height ) } }
注意事项
- 所有绘制逻辑中的坐标、尺寸计算,统一以
window.innerWidth/innerHeight作为视口基准,不要直接读取c.width/c.height做计算——适配设备像素比后,c的实际像素宽高是乘以dpr后的值,直接使用会导致尺寸计算错误 - 调整代码后先清空浏览器缓存再测试,避免旧的图片资源、脚本缓存导致异常复现
- 如果项目中有多个Canvas绘制元素,所有图片资源的尺寸读取都建议替换为
naturalWidth/naturalHeight,避免同类问题出现
内容的提问来源于stack exchange,提问作者TomFan
相关产品推荐
相关产品推荐

