猫猫:移动端详情弹窗 - Unicode 性别符号跨环境渲染异常
移动端详情弹窗中的 ♂ 在本地与远端方向不同;根因是 Unicode 字形、字体环境和 CSS 旋转共同决定视觉结果,最终改用内联 SVG 固定几何形状。
2026-10-08
猫猫手册移动端详情页的性别标记,在本地开发时看起来正常,部署到域名后却出现方向变成水平的问题。最终将字体依赖的 Unicode 性别字符改成内联 SVG,消除了跨环境差异。
① 现象
- 本地开发环境的详情弹窗中,公猫性别标记按预期显示;
- 通过域名访问的远端页面中,同一个标记出现水平放置的视觉差异;
- 问题集中在移动端详情弹窗的性别区域,其他弹窗布局没有同步异常。
② 原始实现
渲染函数根据数据中的 gender 字段直接输出 Unicode 字符:
const symbol = gender === '公' ? '♂' : gender === '母' ? '♀' : '·';
return `<span class="drawer-gender-badge gender-${gender}"><b>${symbol}</b></span>`;
其中:
♂是 UnicodeU+2642;♀是 UnicodeU+2640;- 字符编码只负责选择一个字符,不包含“向右上旋转 45°”这类几何信息。
原来的视觉方向由两部分叠加决定:
- 浏览器使用当前系统字体绘制
♂/♀字形; - CSS 再对公猫字符应用
transform: rotate(45deg)。
因此,源码中看到 ♂ 并不能证明最终像素一定相同;字体字形、CSS 是否命中、计算样式以及浏览器输出都需要分别确认。
③ 排查与证据
按“数据 → DOM → CSS → 构建产物 → 线上产物”的顺序检查:
- 数据字段为
公时,客户端渲染函数确实生成了gender-公和♂; - 本地 DOM 中性别标记是
<span>包裹<b>,不是图片或 SVG; - CSS 只对
.drawer-gender-badge.gender-公 b设置rotate(45deg),Unicode 字符本身不提供旋转; - 远端构建产物中曾经可以找到同一条旋转规则,因此不能简单归因于“远端漏发了 CSS”;
- 线上差异更可能来自字体字形与 CSS 变换组合的环境差异,或者旧缓存、选择器命中和计算样式的差异。
这类问题要区分四件事:
- Unicode 字符是否正确传输;
- 浏览器使用什么字体和字形绘制它;
- CSS 规则是否匹配并进入计算样式;
- 最终像素是否符合设计预期。
④ 修复
将三个状态都改成真正的内联 SVG:
- 公猫:圆形加右上箭头;
- 母猫:圆形加下方十字;
- 未知性别:实心圆点。
SVG 路径直接描述几何形状,不再依赖:
- 系统是否安装某个字体;
- 不同字体对
♂的字形设计; - Unicode 字形自身的比例和方向;
- 对文本节点额外使用
transform: rotate(45deg)。
同时保留外层的 aria-label="性别:...",并给 SVG 设置 aria-hidden="true",避免装饰性路径重复被读屏器读取。
⑤ 验证
- 本地详情弹窗 DOM 已确认输出
<svg>,不再输出<b>、♂或♀; - SVG 的
transform为none,方向由路径本身固定; - 本地
npm run build通过; - 线上 JS 已确认包含 SVG 路径,且不包含
♂/♀; - 线上 CSS 已确认包含 SVG 样式,且不包含
rotate(45deg); - GitHub Pages 与 Vercel 部署均成功。
⑥ 可复用经验
凡是需要固定方向、比例和结构的图标,尤其是性别符号、箭头、状态标志等,不要把 Unicode 文本字符当成稳定的插画资源。Unicode 适合表达语义文本;需要稳定视觉结果时,优先使用内联 SVG 或其他明确的矢量路径。
排查“本地正常、远端变形”的文字图标时,优先检查:
- 实际 DOM 是文本、字体图标、SVG 还是图片;
- 字符的 Unicode code point 与字体 fallback 链;
- DevTools 中元素的
font-family、transform和最终 computed style; - 线上 HTML、CSS、JS 是否确实是新构建产物;
- 必要时用 SVG 替换字体依赖,再比较线上实际产物。