canvas全屏自适应的核心是同步更新canvas.width/height属性并缩放坐标系。需区分css尺寸与内部分辨率,结合devicepixelratio适配高清屏,按contain或cover模式保持宽高比,并用resizeobserver+节流监听尺寸变化。

Canvas 全屏自适应,核心不是“让它看起来填满”,而是“让逻辑像素匹配显示需求,同时不模糊、不变形”。关键在两步:同步更新 canvas.width/canvas.height 属性(决定绘图分辨率),并合理缩放坐标系(适配设备像素比和宽高比)。
必须区分 CSS 尺寸和 canvas 内部尺寸
仅用 CSS 设置 width: 100%; height: 100% 只改变显示大小,画布实际分辨率仍是默认 300×150 或初始值——结果就是图像被拉伸、变糊。真正起作用的是 JS 动态设置的 canvas.width 和 canvas.height 属性,它们定义了绘图上下文的逻辑像素网格。
- 先获取目标尺寸:比如全屏时用
document.documentElement.clientWidth和clientHeight - 再赋值给 canvas 元素:
canvas.width = width; canvas.height = height; - 最后重设 CSS 尺寸保持视觉一致:
canvas.style.width = width + 'px'; canvas.style.height = height + 'px';
适配高清屏:引入 devicePixelRatio
在 Retina 或高 DPR 设备上,若直接按 CSS 像素设 canvas 尺寸,绘图会模糊。正确做法是把内部尺寸放大 DPR 倍,再用 CSS 缩回视觉大小,并用 ctx.scale(dpr, dpr) 对齐坐标系。
- 计算目标逻辑尺寸:
const dpr = window.devicePixelRatio || 1; - 设 canvas 属性:
canvas.width = width * dpr; canvas.height = height * dpr; - 设 CSS 显示尺寸:
canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; - 缩放绘图上下文:
ctx.scale(dpr, dpr);(此后所有坐标仍按 CSS 像素写,无需乘 DPR)
保持宽高比:contain 模式 vs cover 模式
全屏不等于强行拉满——很多场景需要内容完整可见(contain)或铺满无留白(cover)。这取决于你的设计目标:
- contain(等比缩放,全部可见):取父容器宽高比与目标比例的较小缩放因子,计算出实际绘制区域宽高,再居中绘制
-
cover(等比缩放,填满裁切):取较大缩放因子,超出部分用
ctx.translate()或 CSSobject-fit: cover配合裁剪 - 示例逻辑:
const ratio = imageWidth / imageHeight;,对比containerWidth / containerHeight,决定以宽还是高为基准缩放
监听尺寸变化:别只靠 window.resize
窗口 resize 事件能捕获浏览器缩放或手动拖拽,但无法感知父容器因 Flex/Grid/JS 动态变化引起的尺寸调整。更健壮的方式是:
- 对全屏 Canvas,仍用
window.addEventListener('resize', handleResize),并首次执行一次 - 对嵌套在弹性布局中的 Canvas,优先使用
ResizeObserver监听父容器变化(兼容性已覆盖主流浏览器) - 避免高频触发:用节流(throttle)包裹重绘逻辑,尤其涉及清空、重绘、文字渲染时











