增强 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 倍的用户体验吧。

相关推荐
GISer_Jing5 分钟前
前端常问的宏观“大”问题详解(二)
linux·前端·ubuntu
Moment6 分钟前
前端性能指标 —— CLS
前端·javascript·面试
掘金安东尼39 分钟前
上周前端发生哪些新鲜事儿? #407
前端·面试·github
小谭鸡米花1 小时前
ECharts各类炫酷图表/3D柱形图
前端·javascript·echarts·大屏端
郝晨妤1 小时前
【鸿蒙5.0】向用户申请麦克风授权
linux·服务器·前端·华为·harmonyos·鸿蒙
神秘代码行者1 小时前
使用 contenteditable 属性实现网页内容可编辑化
前端·html5
小鱼人爱编程1 小时前
Look My Eyes 最新IDEA快速搭建Java Web工程的两种方式
java·前端·后端
郝晨妤1 小时前
【鸿蒙5.0】鸿蒙登录界面 web嵌入(隐私页面加载)
前端·华为·harmonyos
小鱼人爱编程1 小时前
当上小组长的第3天,我裁掉了2年老员工
前端·后端·面试
晓得迷路了1 小时前
栗子前端技术周刊第 74 期 - 2025 Vue.js 现状报告、Element Plus X、Material UI v7...
前端·javascript·vue.js