iframe内canvas模糊的根本原因是子页未独立适配DPR:必须用getBoundingClientRect获取视觉尺寸,按dpr重设canvas宽高和style.width,并调用ctx.scale(dpr,dpr),禁用transform缩放。

iframe 内部 canvas 必须独立做 DPR 适配
iframe 不会自动继承父页的 window.devicePixelRatio,也不替子页处理高分屏渲染。canvas 模糊不是 iframe “缩放”导致的,而是子页 canvas 的 width/height 属性没按物理像素重设,且没调用 ctx.scale()。
常见错误是只在父页监听 resize 或设置 rem,却让 iframe 里的 canvas 继续用固定 400x300 像素画图——结果在 DPR=2 的屏上,它被浏览器拉伸成 800×600 物理像素,但内容仍是 400×300 的位图。
- 在 iframe 子页 JS 中获取真实 DPR:
const dpr = window.devicePixelRatio || 1 - 用
canvas.parentElement.getBoundingClientRect()获取视觉宽高(别用offsetWidth) - 设
canvas.width = Math.round(visualWidth * dpr),同理设height - 立即执行
ctx.scale(dpr, dpr),否则所有绘图坐标都会错位 - 必须同步设
canvas.style.width = visualWidth + 'px',否则布局撑开
禁止对 iframe 元素使用 transform: scale()
用 transform: scale(0.5) 或 zoom: 0.5 缩放整个 iframe 标签,等于把子页所有内容当位图拉伸,Canvas、SVG、字体、border 都会模糊。这不是抗锯齿问题,是降质重采样。
真正可控的做法是让 iframe 源页自己响应缩放逻辑:
立即学习“前端免费学习笔记(深入)”;
- 父页通过
postMessage({ type: 'scale', value: 2 })通知子页 - 子页收到后动态改
document.documentElement.style.fontSize或重设 canvas 尺寸 - 若需加载不同资源,可拼接
src="?dpr=2"让服务端返回对应分辨率图片 - 避免在 CSS 中给 iframe 写
transform、zoom、image-rendering—— 这些对 iframe 内容无效
iframe 与父页 DPR 同步失败会导致定位偏移
即使 iframe 子页做了完整 DPR 适配,如果父页用了 rem 动态根字号,而子页没收到当前 DPR 值,getBoundingClientRect() 返回的坐标就和父页视觉位置对不上。横竖屏切换、窗口拖到外接显示器时尤其明显。
关键不是“监听 resize”,而是监听设备像素比变化:
- 父页应主动发消息:
window.postMessage({ type: 'dpi-sync', dpr: window.devicePixelRatio }, '*') - 子页监听
message,收到后立即更新自身font-size和 canvas 尺寸 - 不要依赖
window.matchMedia('(min-resolution: 2dppx)')—— 它不支持动态变更通知,要用matchMedia('(resolution)') - Electron 或某些 WebView 中
window.devicePixelRatio可能始终为 1,此时需 fallback 到screen.availWidth / window.innerWidth估算,但仅作兜底
background-image 和 img 在 iframe 里仍需单独处理
iframe 子页里的 <img> 和 background-image 不会因 canvas 适配了 DPR 就自动变清晰。它们仍走浏览器默认插值逻辑,尤其在缩放或容器尺寸不匹配时明显发虚。
必须分别处理:
-
<img>必须用srcset提供多倍图,例如:srcset="icon.png 1x, icon@2x.png 2x" - CSS 背景图推荐用
image-rendering: pixelated或crisp-edges抑制双线性插值(注意兼容性) - 若背景图是图标类小图,优先转为内联
<svg>,天然无损缩放 - 避免用
background-size: contain/cover拉伸小图;确保图片原始分辨率 ≥ 容器物理像素尺寸
最易被忽略的是:DPR 同步必须是双向且实时的。父页改了缩放比例,子页不重算 canvas 尺寸和字体大小,光标、选区、按钮热区就会漂移——这种问题在投屏或跨显示器拖动时才暴露,但根源早在初始化时就埋下了。



















