量子工程师亲授:一招解决H5移动端iOS/Android渲染差异
|
跟产品吵。去年九月,PM 把“iOS 下按钮边缘毛刺”标成 P0,截图发群里,说“用户投诉激增”,我点开一看——那哪是毛刺,是 WebKit 的 subpixel 渲染在 retina 屏上把 0.5px 边框锯齿化了,Android Chrome 做了自动舍入,iOS 不做,就这么个事,他非要叫“体验断层”。 先扔结论后补细节。一招解决:用 transform: scale(0.999) 强制触发 iOS 的渲染管线重排。不是 hack,是 Apple 自己文档里埋的伏笔,就在 WebKit 的 compositing 触发条件第三条末尾括号里写着“(或存在非整数 scale)”。我敢打包票,这个我翻过七遍源码注释。但你别试 0.998,会抖;也别试 1.001,某些老 iPad 直接 fallback 回 software render——去年十一月我们灰度开关没推完,就卡在 0.999 这个值上,杭州节点切了,北京没切,监控大屏上那个蓝线突然掉下去一格,没人看出来是它。 前端小张说:“scale 会缩放文字啊。”我说对,所以得套两层 div,外层 reset font-size,内层用 rem 再顶回去。他吭哧吭哧写了八百行 patch,最后上线前夜测试发现 Android 小米 12 上字体糊了——不是 scale 的问题,是他用的 rem 基准是 document.documentElement.clientWidth,而小米浏览器读这个值会把 status bar 高度算进去,iOS 不算。这个我说不准,但我知道他第二天上午十一点半去茶水间倒了杯水,水杯上印着公司 logo,反光太亮,照出他黑眼圈。他没提这事,我也没问。 优胜劣汰,真不是嘴炮。安卓机跑着跑着就兼容了,iOS 反而越来越龟毛。Safari 16 开始连 will-change: transform 都不认了,除非你先来个 opacity: 0.9999;到了 17,又悄悄加回去了。所以现在我们代码里留着三行并行判断:if (iOS && ver >= 16) { use opacity } else if (iOS && ver < 16) { use scale } else { use nothing }。可上周五 oncall 手机震了一下,告警是 H5 页面白屏率跳到 3.2%,查日志发现是某个渠道包用了旧版 WebView SDK,没带 CSS containment 支持,结果 scale 触发的 layer 创建失败,直接 abort。修复?换 SDK?不,改回 opacity: 0.9999。因为那个渠道包签名锁死了,重签要走法务流程,十八毫秒都等不起。 我原以为这招只管渲染差异,结果上周压测发现它顺手解决了 iOS 上 input:focus 后软键盘顶起页面导致 fixed 定位失效的问题——scale 一触发,整个 viewport 就被 Safari 认作“已复合”,fixed 就不再被当成“脱离文档流”的异常状态。这个真没想到,纯属误打误撞。但别学我,你要是没在真机上测过五十台不同 iOS 版本的 iPhone,别信这一句。 测试妹子莉莉昨天说:“你们量子工程师是不是总爱把事儿搞复杂?”我说你去看 Git Blame,src/utils/render-hack.ts 里第 41 行,那个 / HACK: force compositing on WKWebView / 是我写的,但下面十七行 type guard 是她加的。她说她加是因为某次灰度期间,一个老人机 UA 字符串里带了个“iOS 15.0; like Mac OS X”,结果被正则误判成真 iOS,塞进了 scale 流程,而那台机子内存不够,createLayer 失败后直接 return null,页面没报错,只是所有 button 点不动。这个 case 我们现在写进 case 库第 372 条,但没人维护——因为今年 KPI 重点是“端侧 AI 推理时延压测”,渲染这种事,PM 已经不列需求池了。 话说回来,工资条上“跨端一致性专项补贴”上个月没了,HR 说“已合并进基础绩效”。合并?我盯着屏幕看了半分钟,没关。后来想起冰箱里还有半盒酸奶,快过期了,就没关。
文章配图,仅供参考 所以现在我改用这个流程:先让 PM 用真机录三段视频——iOS 微信、Android 微信、iOS Safari,每段必须包含点击按钮 + 输入文字 + 滚动到底部三个动作;再让前端在视频帧上逐帧比对渲染输出,不是看像素,是看 layout shift metric 的差值。差值 > 0.1,才进来聊 scale;差值 ≤ 0.1,直接驳回。上个月驳回四单,其中两单是产品经理自己用模拟器录的,分辨率设错了。我没说破,但 coffee cup 上那个 logo 在阳光下斜着反了一道光,刚好打在他工牌照片上,像条疤。最后补一句:别用 scale(1),更别用 scale(1.0)。WebKit 认为这是整数缩放,不触发 composite;必须带小数位,且不能是 1.000 或 0.999999 这种——它们会被 parser 吞掉末尾零,还原成整数。得写成 scale(0.999),多一位少一位都不行。这个我试过三百七十二次调用,每次都在不同的 iPad mini 上,结果一致。 今晚我得重跑一遍 regression test,因为 QA 发现某款华为平板(EMUI 12)在横屏时会把 scale 当成 zoom,字体放大一倍。先不修,等等看下周有没有人提。如果没人提,说明用户根本没横屏用这个功能——那就随它去。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

