移动端设备上稀奇古怪的前端问题收集(一)
作者:京东物流 陈雨
作为一名开发者,bug 往往是我们最怕遇见的东西;而比遇到 bug 更可怕的事情,是定位不到 bug。作为一名前端开发者,与业务逻辑相关的 bug 还相对好定位、好解决一些;而一些与语法特性、平台与设备差异相关的 bug 则更令人头疼一些。这里记录下我在工作中遇到过的稀奇古怪的前端问题,作为给自己的记录和提醒。
用 vh 定义全屏显示的问题
很多页面因为设计效果的需要,要求正好铺满一整个显示界面、也不允许上下滑动。做类似的需求时,往往直觉会使用这样的代码解决问题:
{
height: 100vh;
}
这样的代码看似很优雅,但是往往会有兼容性问题——不同浏览器定义的视口高度的定义不一致,导致 100vh
并不能真正覆盖全视口高度;还有不少浏览器视口高度数值不变但实际视口大小可变,比如移动端 Chrome 浏览器的导航栏时不时隐藏但网页获取的视口高度不变,这都会导致最终显示效果不符合预期。
如果要实现全屏幕覆盖不可滑动,更为稳妥和保险的方法是使用绝对定位:
{
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
带 alpha 通道的 hex 颜色值失效的问题
在较新的 web 标准中,hex 格式的颜色代码也可以表示透明度了,只需要在常见的六位 hex 颜色代码后加两位表示透明度的 hex 值,例如 #66ccff
表示一种蓝色,而 #66ccff80
表示透明度 50% 的这种蓝色(80 是 16 进制的 128,是 256 的一半,即 50% 透明度)。虽然直接这样写代码的行为在前端开发中不普遍,但是设计师交付的视觉稿给出的参考值有不少是这种格式。如果直接把这样的颜色代码用于生产中,可能会出现以下两种问题:
◦如果你编写的项目引入了 less 或者 sass,在进行打包构建的操作时,部分预处理器无法正确识别带 alpha 通道的 hex 颜色值,因此这部分代码无法被正确转译,最终构建出的生产环境代码中这部分颜色可能丢失。
◦部分移动端浏览器并未适配带 alpha 通道的 hex 颜色值,因此即使是使用原生 css 完成的代码,也有可能出现在部分手机或部分浏览器颜色不正常的问题。
生命周期函数不执行的问题
在页面刚打开或准备关闭时,我们往往需要进行一些诸如数据初始化、登入登出、数据上报等行为,而这些往往是借助 Vue 或 React 的生命周期函数完成的。不过,生命周期函数不执行也是常被忽略的 bug,详细来说,又可以分为两类原因——
组件被 keep alive 导致未被卸载或重新加载
如果是 Vue 中使用 keep-alive
包裹的组件,或在 React 中使用类似的第三方库 keep alive 的组件,只会在第一次加载时执行生命周期初始化函数,且不会执行生命周期卸载函数。这导致的不符合预期的行为很好解决,只需要使用 onActivated
代替 onMounted
,用 onDeactivated
代替 onUnmounted
即可。
页面被直接关闭导致框架生命周期函数无法执行
不管是 Vue 还是 React,生命周期函数的正确执行都依赖于 Vue 或 React 实例的存在。而当用户直接关闭浏览器页面的时候,Vue 或 React 实例已经被销毁了,生命周期卸载函数当然就无法执行了。处理这种情况也并不麻烦,只需要在生命周期初始化函数中添加对 window 卸载事件的监听,然后把想要进行的操作放到 window 卸载事件函数里就好了。
onMonted(() => {
window.addEventListener('beforeunload', () => {
// 需要执行的代码
});
});
文本中的 emoji 上下被裁剪
UGC 内容中经常出现文本和 emoji 混排的场景,而有时可能遇到 emoji 上下边缘被裁剪的问题。这往往是由于开发页面时为了限定文本高度和间距或其他排版方面的要求,将 line-height 和 font-size 设置为同样的值,且 overflow 属性被设置为 hidden 。如果出现类似情况,建议去除 line-height 的限制,而通过 margin 等方式控制行距,从而避免 emoji 被裁减。
输入框被弹起的软键盘覆盖的问题
如果移动端页面中有输入框,那么很可能面临输入框被弹起的软键盘覆盖的问题。一般来讲,对于需要弹起软键盘的场景,较新的浏览器或者移动端 app 的 webview 会自动聚焦到输入框中并滚动到相应位置,来保证输入框的正常显示;但是,对于如下两种情况,弹起的软键盘会将输入框覆盖,影响用户输入。
浏览器未能主动聚焦到输入框
软键盘弹起时,一般会从底部将页面顶起、压缩视口;视口高度变低了,原先处于显示区域的输入框可能就被挤到输入框外了。如果用户使用的浏览器版本较早或 app 内置 webview 较为特殊,有可能在软键盘弹出后浏览器未能主动聚焦到输入框上。这时,开发者必须主动聚焦到输入框并使输入框滚动到视口内。
const inputEle = document.querySelector('#target-input');inputEle.focus();inputEle.scrollIntoView();
软键盘采用覆盖在视口上层而非压缩视口的方式弹出
如果浏览器或 webview 版本较为特殊,且输入框处于页面靠下的位置或者针对视口绝对定位于底部,那么可能会面临更加复杂的情况。刚才已经提到,正常情况下,软键盘弹起的标准做法是从底部将页面顶起、压缩视口高度;但是某些情况下,软键盘并不改变视口尺寸,而是直接盖在视口上方。这就导致页面逻辑上是展示完整的、输入框也正常显示在视口中;但软键盘遮挡了半个页面,也就真正意义上“覆盖”在输入框上。目前主流移动端浏览器较新的版本都不会出现这个问题,但是部分 app 内置 webview 会设置为“软键盘覆盖在 webview 上方”;因此要解决这个问题,必须由客户端更改 webview 的软键盘设置。如果是很旧的浏览器版本或者无法推动客户端开发解决问题,那就只能放弃治疗了。