文字模糊的根本原因是小数坐标触发亚像素渲染,需将所有坐标(canvas/svg/css)校准至物理像素网格,关键方法包括math.round()取整、dpr缩放适配、整数viewbox及语言化字体栈。

直接给元素加 text-align: center 或 display: flex 居中后字体变糊,不是居中逻辑错了,而是坐标落点没对齐物理像素——尤其在高 DPR 设备(如 iPhone、MacBook Retina 屏)上,小数坐标触发亚像素渲染,文字边缘发虚、发灰。
Canvas 文字居中模糊:别信 y = height / 2
Canvas 里用 ctx.textBaseline = "middle" + fillText(text, x, y),y 坐标若直接取容器 CSS 高度一半(比如 y = 150),在 DPR=2 的设备上实际渲染位置可能是 y = 150.333...,浏览器被迫插值,文字毛边。
- 正确做法:用
Math.round(y * window.devicePixelRatio) / window.devicePixelRatio把 y 校准到 CSS 像素网格上 - 更稳妥:直接用整数 CSS 尺寸定义 canvas,并设
canvas.width = width * dpr、canvas.height = height * dpr,再ctx.scale(dpr, dpr),此时所有坐标按 CSS 像素写即可 - 别混用:scale 后又手动把 y 乘以 dpr,等于双重缩放,偏移翻倍
- 关键补丁:对文字坐标强制
Math.round(x)和Math.round(y),哪怕只差 0.1px,也得砍掉
SVG 图形+文字模糊:viewBox 不等于安全
内联 SVG 里写了 viewBox="0 0 100 100",不代表文字就清晰——如果 <text x="50" y="50"></text> 的坐标是小数,或父容器宽高被 CSS 算出非整数(如 width: calc(100% - 1.5px)),照样糊。
- 检查真实尺寸:用
el.getBoundingClientRect().width在控制台看是否为整数;不是就用Math.round()修正 - SVG 内部坐标全用整数:
<text x="50" y="50"></text>可以,<text x="50.5" y="50"></text>不行 - 描边文字慎用
stroke-width: 1:奇数描边易跨像素,改用2或4,并加vector-effect="non-scaling-stroke" - 避免
transform: scale(0.5)拉伸 SVG:它会把所有坐标再插值一遍;高 DPR 下优先用双倍width/height+viewBox缩放
HTML/CSS 文字居中模糊:text-align 不是万能解药
text-align: center + line-height 居中按钮文字,或 Flex 居中 div,都可能糊——根本不在布局逻辑,而在字体渲染路径没对齐系统策略。
- 中日韩文字必须分语言声明字体栈:
html[lang="zh"] { font-family: "PingFang SC", "Microsoft YaHei", sans-serif; },不能共用一套 fallback - macOS 上启用
-webkit-font-smoothing: antialiased有效,但 Windows 下禁用该属性,否则干扰 ClearType - iOS WebView 必须加
-webkit-text-stroke: 0.2px transparent,否则optimizeLegibility反而让小字号更虚 - 给文字容器加
transform: translateZ(0)或will-change: transform,强制独立合成层,避免被半透明背景污染
像素对齐不是“调一次就完事”的事——它贯穿 canvas 坐标、SVG 坐标、CSS 尺寸、DPR 缩放、字体栈选择。最容易被忽略的,是把 getBoundingClientRect() 当作真理,却忘了它返回的是 CSS 像素,而真正决定清晰度的是物理像素落点。每次改完样式,真机截图放大看边缘,比任何理论都管用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











