增强 vw/rem 移动端适配,适配宽屏、桌面端、三折屏

增强 vw/rem 移动端适配,适配宽屏、桌面端、三折屏

vw 和 rem 是两个神奇的 CSS 长度单位,认识它们之前,我一度认为招聘广告上的"像素级还原"是一种超能力,我想具备这种能力的人,一定专业过硬、有一双高分辨率的深邃大眼睛。

时间一晃,入坑两年,我敏捷地移动有点僵硬不算过硬的小手,将一些固定的 px 尺寸复制到代码,等待编译阶段的 vw/rem 转换,刷新浏览器的功夫,完美还原的界面映入眼前,我推了推眼镜,会心一笑。多亏了 vw 和 rem。

TLDR:极简配置 postcss-mobile-forever 增强 vw 的宽屏可访问性,限制视图最大宽度。

用 vw 和 rem 适配移动端视图的结果是一致的,都会得到一个随屏幕宽度变化的等比例伸缩视图 。一般使用 postcss-px-to-viewport 做 vw 适配,使用 postcss-px2rem 配合 amfe-flexible 做 rem 适配。由于 rem 适配的原理是模仿 vw,所以后面关于适配的增强,一律使用 vw 适配做对比。

vw 适配有一些优点(同样 rem):

  • 加速开发效率;
  • 像素级还原设计稿;
  • 也许更容易被自动生成。

但是 vw 适配也不完美,它引出了下面的问题:

  1. 开发过程机械化,所有元素是固定的宽高,不考虑响应式设计,例如不使用 flexgrid 布局;
  2. 助长不规范化,不关注细节,只关注页面还原度和开发速度,例如在非按钮元素的 <div> 上添加点击事件;
  3. 桌面端难以访问,包容性降低。

前两个问题,也许要抛弃 vw、回归响应式布局才能解决,在日常开发时,我们要约束自己以开发桌面端的标准来开发移动端页面,改善这两个问题。

马克·吐温在掌握通过密西西比河的方法之后,发现这条河已经失去了它的美丽------总会丢掉一些东西,但是在艺术中比较不受重视的东西同时也被创造出来了。让我们不要再注意丢掉了什么,而是注意获得了什么。 ------《禅与摩托车的维修艺术》

后面,我们将关注第三点,介绍如何在保持现状(vw 适配)的情况下,尽可能提高不同屏幕的包容性,至少让我们在三折屏的时代能得到从前 1 倍的体验,而不是 1/3。

移动端 桌面端

上面是一个页面分别在手机和电脑上展示的截图,可以看到左图移动端的右上角没有隐藏分享按钮,所以用户是允许(也应该允许)被分享到桌面端访问的,可惜,当用户准备享受大屏震撼的时候,真的被震撼了:他不知道这个页面的技术细节是神奇的 vw,也不知道他只能用鼠标小心地拖动浏览器窗口边缘,直到窗口窄得和手机一样,最崩溃的是,当他得意地按下了浏览器的缩小按钮,页面像冰冷的机器纹丝不动,浇灭了他的最后一点自信。

限制最大宽度

由于 vw 是视口单位,因此当屏幕变宽,vw 元素也会变大,无限变宽,无限变大。

现在假设在一张宽度 600 像素的设计图上,有一个宽度 60px 的元素,最终通过工具,它会被转为 10vw。这个 10vw 元素是任意伸缩的,但是现在我希望,当屏幕宽度扩大到 700px 后,停止元素的放大。

出现了一堆枯燥的数字,不用担心,后面还有一波,请保持耐心。

首先计算 10vw 在宽 700 像素的屏幕上,应该是多少像素:60 * 700 / 600 = 70。通过最大宽度(700px)和标准宽度(600px)的比例,乘以元素在标准宽度时的尺寸(60px),得到了元素的最大尺寸 70px

接着结合 CSS 函数:min(10vw, 70px),这样元素的宽度将被限制在 70px 以内,小于这个宽度时会以 10vw 等比伸缩。

除了上面的作为正数的尺寸,可能还会有用于方位的负数,负数的情况则使用 CSS 函数 max(),下面的代码块是一个具体实现:

js 复制代码
/**
 * 限制大小的 vw 转换
 * @param {number} n
 * @param {number} idealWidth 标准/设计稿/理想宽度,设计稿的宽度
 * @param {number} maxWidth 表示伸缩视图的最大宽度
 */
function maxVw(n, idealWidth = 600, maxWidth = 700) {
  if (n === 0) return n;

  const vwN = Math.round(n * 100 / idealWidth);
  const maxN = Math.round(n * maxWidth / idealWidth);
  const cssF = n > 0 ? "min" : "max";
  return `${cssF}(${vwN}vw, ${maxN}px)`;
}

矫正视图外的元素位置

上一节提供的方法,包容了限制最大宽度尺寸的大部分情况,但是如果不忘像素级还原的❤️初心,就会找到一些漏洞。

下面是一个图例,移动端页面提供了 Top 按钮用于帮助用户返回顶部,按照上一节的方法,Top 按钮会出现在中央移动端视图之外、右边的空白区域中,而不是矫正回中央移动端视图的右下角。

假设 Top 按钮的样式是这样的:

css 复制代码
.top {
  position: fixed;
  right: 30px;
  bottom: 30px;
  /* ... */
}

按照标准宽度 600、最大宽度 700,上面的 30px 都被转换成了 min(5vw, 35px)bottom 没错,但 right 需要矫正。

对照上面右图矫正过的状态,right 的值 = 右半边的空白长度 + Top 按钮到居中视图右边框的长度 = 桌面端视图的一半 - 视图中线到 Top 按钮的右边框长度。

沿着第二个等号后面的思路,fixed 定位时桌面端视图一半的尺寸即为 50%,中线到 Top 按钮右边框的长度,分两种情况:

  • 在屏幕宽度大于最大宽度 700 时,为 700 / 2 - 30 * 700 / 600,即为 315px(其中 700 / 2 是中线到移动端右边框长度,30 * 700 / 600 是屏宽 600 时的 30px 在屏宽 700 时的尺寸);
  • 在屏幕宽度小于最大宽度 700 时,为 (600 / 2 - 30) / 600,即为 45%

结合 calc()min() 和上面得到的 50%315px45%,参考第二个等式,可以得到 right 的新值为 calc(50% - min(315px, 45%))。当尺寸大于移动端视图的一半时,会出现负数的情况,这时使用 max() 替换 min()

上面的计算方法是一种符合预期的稳定的方法,另一种方法是强制设置移动端视图的根元素成为包含块,设置之后,right: min(5vw, 35px) 将不再基于浏览器边框,而是基于移动端视图的边框。

postcss-mobile-forever

上面介绍了增强 vw 以包容移动端视图在宽屏展示的两个方面,除了介绍的这些,还有一点点边角情况,例如:

  • 逻辑属性的判断和转换;
  • 矫正 fixed 定位时和包含块宽度有关的 vw% 尺寸;
  • 矫正 fixed 定位时leftrightvw% 尺寸;
  • 为移动端视图添加居中样式;
  • 各种情况的判断和转换方法选择。

postcss-mobile-forever 是一个 PostCSS 插件,利用 mobile-forever 这些工作可以在编译阶段完成,上面举了那么多例子,汇总成一份 mobile-forever 配置就是:

json 复制代码
{
  "viewportWidth": 700,
  "appSelector": "#app",
  "maxDisplayWidth": 600
}

上面是 mobile-forever 用户使用最多的模式,max-vw-mode,此外还提供:

  • mq-mode ,media-query 媒体查询模式,生成可访问性更高的样式,同样限制最大宽度,但是避免了 vw 带来的无法通过桌面端浏览器缩放按钮缩放页面的问题,也提供了更高的浏览器兼容性;
  • vw-mode,朴素地将固定尺寸转为 vw 伸缩页面,不限制最大宽度。

postcss-mobile-forever 相比 postcss-px-to-viewport 提供了更多的模式,包容了宽屏展示,相比 postcss-px2rem,无需加载 JavaScript,不为项目引入复杂度,即使用户禁用了 js,也能正常展示页面。

scale-view 提供运行时的转换方法。

优秀的模版

postcss-mobile-forever 的推广离不开开源模版的支持、尝试与反馈,下面是这些优秀的模版,它们为开发者提供了更多元的选项,为用户提供了更包容的产品:

  • vue3-vant-mobile,一个基于 Vue 3 生态系统的移动 web 应用模板,帮助你快速完成业务开发。【查看在线演示
  • vue3-vant4-mobile,基于Vue3.4、Vite5、Vant4、Pinia、Typescript、UnoCSS等主流技术开发,集成 Dark Mode(暗黑)模式和系统主题色,且持久化保存,集成 Mock 数据,包括登录/注册/找回/keep-alive/Axios/useEcharts/IconSvg 等其他扩展。你可以在此之上直接开发你的业务代码!【查看在线演示
  • fantastic-mobile,一款自成一派的移动端 H5 框架,支持多款 UI 组件库,基于 Vue3。【查看在线演示

增强后的 vw/rem 看起来已经完成了适配宽屏的任务,不过回想最初的另外两个问题,机械化的开发过程与不规范化的开发细节,没有解决。作为一名专业的前端开发工程师,请考虑使用响应式设计开发你的下一个项目,为三折屏带来 3 倍的用户体验吧。

相关推荐
活宝小娜1 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点1 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow1 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o1 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
开心工作室_kaic2 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā2 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
沉默璇年4 小时前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder4 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
2401_882727574 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
SoaringHeart4 小时前
Flutter进阶:基于 MLKit 的 OCR 文字识别
前端·flutter