前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Canvas devicePixelRatio 模糊 高清屏
浏览浏览器文件与多媒体

Canvas 在高 DPR 屏幕上模糊时,应该怎样按 devicePixelRatio 设置尺寸与变换?

Canvas 在高 DPR 屏幕发虚,根源是位图分辨率与 CSS 尺寸不一致。解决思路:用 devicePixelRatio 放大画布实际像素,再对绘图上下文做整体缩放,同时用 CSS 固定显示尺寸。

前端进阶之旅 · 一题精讲更新于 2026.09.05
浏览器#文件与多媒体#动画
先看核心答案
理解线索

双尺寸与坐标变换

  1. CSS 尺寸控制元素的布局显示大小
  2. backing store实际位图像素缓冲区
  3. setTransform重置矩阵避免叠加缩放

不处理 CSS 缩放,只关注 canvas 自身尺寸与变换关系。

核心回答

先记住这个答案

先把 canvas 的 width/height 设为 CSS 显示尺寸乘以 devicePixelRatio,再调用 ctx.scale(dpr, dpr) 让后续绘制使用 CSS 像素坐标,最后把 style.width/height 设回原 CSS 尺寸。若期间调整过变换,需先 ctx.setTransform(1,0,0,1,0,0) 复位,避免缩放叠加。这样 backing store 与显示像素一一对应,文字和矢量线条不再模糊。

  • canvas 尺寸属性与 CSS 尺寸分离
  • 必须按 dpr 放大 backing store
  • ctx.scale 后用 CSS 像素绘制
  • 变换需 setTransform 复位

模糊的根因:像素倒挂

Canvas 的 width 和 height 属性定义的是位图缓冲区的像素数,即 backing store;而 CSS 的 style.width 和 style.height 决定元素占据的屏幕区域。当两者数值相同时,在 DPR=2 的屏幕上,一块 200×100 的位图被拉伸到 400×200 的 CSS 面积,每个位图像素对应用 2×2 个物理像素,浏览器只能做插值补点,导致边缘和文字发虚。

正确的做法是让 backing store 的像素数等于 CSS 尺寸乘以 devicePixelRatio。绘制时如果不调整变换,后续所有坐标都必须换算成物理像素,很繁琐。所以常见方案是调用 ctx.scale(dpr, dpr) 将默认用户单位放大,之后继续使用 CSS 像素坐标,浏览器自动映射到高密度位图。

1200×800 画板适配 2x 屏

设计一个图表库的 resize 流程,画布逻辑尺寸固定 600×400,目标设备 DPR=2。代码先读取 window.devicePixelRatio(设为 2),然后设置 canvas.width = 600 * 2,canvas.height = 400 * 2,再执行 ctx.setTransform(2,0,0,2,0,0),最后把 canvas.style.width 和 canvas.style.height 设为 '600px' 和 '400px'。注意不能省略 setTransform,因为可能存在上一次残余变换。

这样处理后的后果:之后所有 fillRect、arc、drawImage 都接受 CSS 像素坐标,内部自动映射到物理像素,线条宽度无需乘 DPR。若改成 ctx.scale(dpr, dpr),当后续代码已有变换时容易累积,建议统一用 setTransform 一次性覆盖,避免状态混乱。

失效场景与补偿手段

一种常见误区是只增大 canvas.width 而不改 style.width,这样画布位图变大了但显示区域不变,可能导致内容被截断或显示缩小。必须同时修改 CSS 属性保持布局不变。处理动画时若每帧调用 clearRect,注意坐标系统已缩放,清空区域要覆盖 0,0 到实际逻辑宽高,可调用 ctx.clearRect(0,0,width,height) 其中 width/height 是逻辑值。

另一个边界是浏览器窗口缩放或系统缩放变化导致 devicePixelRatio 变化。需要监听 resize 事件重新读取 DPR 并执行整个重置。重置时先 ctx.setTransform(1,0,0,1,0,0) 复位,再更新尺寸,防止残留变换。代价是重设尺寸会清空画布,必须重绘所有内容,因此高频 resize 时应做防抖或使用 requestAnimationFrame 合并。

回答前,多想一步

容易答错的地方

只调 canvas.width 不调 CSS
有人误以为放大 width 即可,但 CSS 尺寸不变,画布仍按原大小绘制,只是内部坐标系变大,实际显示会缩小,不会变清晰。必须同步设置 style 尺寸。
用 scale 而非 setTransform
直接 ctx.scale(dpr,dpr) 在已有变换时会叠加,若之前有旋转或缩放,整体矩阵错误。正确做法是先用 setTransform(1,0,0,1,0,0) 复位再 setTransform(dpr,0,0,dpr,0,0),保证基底干净。
试着用自己的话回答

面试官还会怎么问?

若 canvas 需要显示在多个不同 DPR 的窗口,如何监听变化?

通过 ResizeObserver 观察元素尺寸,结合 window.devicePixelRatio 监听屏幕缩放事件(matchMedia('resolution'))。变化时重建 canvas 尺寸并重绘。注意性能,使用 rAF 合并。

ctx.scale 后如何避免 clearRect 清不净?

clearRect 使用当前变换,若已放大到 dpr,则传 0,0,逻辑宽,逻辑高 即可。如果变换有偏移,需考虑平移;最简单方法是 setTransform(dpr,0,0,dpr,0,0) 后 clearRect。

用 CSS 的 transform: scale(2) 替代可避免模糊吗?

不能,CSS 缩放仅影响显示尺寸,canvas 的 backing store 未变化,仍会插值模糊。只有提升 canvas.width 才增加物理像素密度。

从一道题,走向一组知识

把知识连起来

文件与多媒体

导出画布时 HTMLCanvasElement.toBlob 与 toDataURL 的差异和选型依据是什么?

同属「文件与多媒体」专题,接着看 Canvas toBlob toDataURL 导出 差异 在具体场景中的处理方式。

文件与多媒体

Blob.type 为空时能不能根据内容嗅探类型,浏览器给出什么保证?

同属「文件与多媒体」专题,接着看 Blob type MIME 嗅探 浏览器 在具体场景中的处理方式。

参考资料

  • Optimizing canvas

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 模糊的根因:像素倒挂
  3. 1200×800 画板适配 2x 屏
  4. 失效场景与补偿手段
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑