移动端布局适配

始终保持视觉稿比例的移动端布局

布局要求:

由于手机的屏幕宽度大小不一,于是在布局复杂的移动端页面开发中我们就存在这样一个需求:

自适应不同宽度的设备,最大程度还原视觉稿比例。

演变过程 :

假如一个类似淘宝手机端首页的页面布局需要你去实现,你需要适配不同尺寸的手机终端

解决方案1:百分比布局

可能你首先想到的会是百分比布局

问题:百分比参照的容器的宽度是不同的,需要一个统一的参照,布局比较复杂的情况不太适用,这种方法也不利于后续布局变更的维护。

解决方案2:rem + 媒体查询

也是我最早接触移动端开发的时候使用的方法,使用rem单位。

html{
  font-size:50px;
}
.div1{
  width:.5rem;
}
.div2{
  width:1rem;
}复制代码

以上只是实现了参照的统一,并没有达到不同终端适配的效果,于是我们加上了这样子的一些媒体查询。

...
@media screen and (min-width: 361px) and (max-width: 375px) {
  html {
    font-size: 50px;
  }
}
@media screen and (min-width: 376px) and (max-width: 393px) {
  html {
    font-size: 52.4px;
  }
}
@media screen and (min-width: 394px) and (max-width: 412px) {
  html {
    font-size: 54.93px;
  }
}
...

.div1{
  width:.5rem;
}

.div2{
  width:1rem;
}复制代码

仍然,我们的实现效果是 trace1 所示

但是理想的情况是 trace 0

解决方案3:手淘 2015 年出的方案 flexible.js

作者在2019年1月更新了这样一段话,说明现在已经不推荐大家来采用这个方案了,并提供一篇文章说明现在推荐采用的新方案,这个我们后续会讲到。

这个方案的原理是通过 js 来动态计算根节点的 font-size,然后结合 rem 来实现。这里附上 GitHub 仓库的地址

除此之外,flexible.js 中另外一个比较重要的想法是实现了页面中物理像素和 css 像素的数量一致,它根据设备的 dpr (设备像素比)对 viewport 进行了缩放(当然仅限于安卓设备)。解决了 Retina 屏幕下1px border的问题,更准确的说是 dpr 为 2 的设备中如何实现0.5px border的问题,因为设备能展示的最小单元是一个物理像素,所以dpr 为 2 的设备能展现的最小单位是0.5px。有相关的文章说它也解决了 Retina 屏幕下图片模糊的问题,物理像素值与css像素值相等,导致屏幕不会因为 css 像素值 < 物理像素值而从周围的点取色值。

更详细的对该方案的介绍和相关物理像素css像素dpr 的背景知识的介绍,可以阅读这两篇文章:

理解flexible.js所需的viewport知识

关于移动端适配,你必须要知道的

值得注意的是,由于缩放了viewport,会导致我们在 css 中如果使用 px 单位,在不同 dpr 设备中所展现的效果是不一样的,需要根据 dpr 值做一些额外的处理。例如:

@mixin font-dpr($font-size){
    font-size: $font-size;​
    [data-dpr="2"] & {
        font-size: $font-size * 2;
    }
​    [data-dpr="3"] & {
        font-size: $font-size * 3;
    }
}
@include font-dpr(16px);复制代码

如果你想要使用媒体查询,在这个方案中也是不太友好的。

解决方案4:视口单位的使用

在 CSS 规范中,有4种类型的可用视口单位:

  • vw --- 1vw 等于视口宽度的 1%

  • vh --- 1vh 等于视口高度的 1%

  • vmin --- vw 和 vh 中的较小值

  • vmax --- vw 和 vh 中的较大值

视口,即浏览器屏幕大小,1vw 等于浏览器宽度的 1%,100vw 即整个浏览器的宽度。


目前浏览器对视口单位的兼容性覆盖率已经90% +,我们可以使用 vw 来实现适配。 viewport 单位的浏览器兼容性

其余3个单位常用的场景如下:

vh : vh 比较常用的情况是100 vh , 使得高度撑满整个屏幕。

vmin,vmax: 解决移动端中横屏显示的问题

应用场景1: 实现固顶的导航栏

应用场景2: 固定宽度或高度的div


使用 vw 推荐采用的解决方案

1.网易新闻的解决办法

地址:3g.163.com/touch/news/

首先我们需要将我们的视口变为理想视口

<meta name="viewport" content="width=device-width,initial-scale=1">复制代码

PC 端中默认视口的宽度就等于设备的宽度,但是在移动端的浏览器中不是。为了让未适配手机视图的PC端网页在移动端中也能比较完整的展示,手机端的浏览器做了相应的处理,默认的 viewport 宽度会大于真实设备的宽度(在 IOS 中默认的 html 的宽度是 980px)。

width=device-width 的作用其实就是让我们在css 代码里面写的 px 对应真实设备上的 px 值。

现在我们的视口宽度就等于设备的宽度了,在设备宽度为375 px 的 IPhone6 中

html{  width: 13.33333333vw}复制代码

就等同于设置了 font-size: 50px。网易新闻采用的方案如下:

结合了媒体查询来处理 vw 的兼容性问题,如果不支持 vw 单位,可以降级为使用固定的 px。

···
@media screen and (min-width: 361px) and (max-width: 375px) {
  html {
    font-size: 50px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 376px) and (max-width: 393px) {
  html {
    font-size: 52.4px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 394px) and (max-width: 412px) {
  html {
    font-size: 54.93px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
···复制代码

然后在实际的布局中使用 rem

可以使用 vscode 插件 px2rem 来进行转化,也可全局转化。


2.flexible.js 作者新提出的解决方案

不推荐使用flexible.js之后,作者大漠在如何在Vue项目中使用vw实现移动端适配中有提到使用 Postcss 插件结合 vw 解决方案。作者在文章最末尾给出了实现的 demo 与下载的链接。

"dependencies": {
    "cssnano": "^3.10.0",  // 压缩与优化css
    "postcss-aspect-ratio-mini": "0.0.2", // 处理元素容器宽高比
    "postcss-cssnext": "^3.1.0",  // css的polyfill
    "postcss-px-to-viewport": "0.0.3", // 编译时将px转化为视口单位
    "postcss-viewport-units": "^0.1.3", // 处理视口单位的兼容性问题
    "postcss-write-svg": "^3.0.1" // 用来解决1px的border的问题
}复制代码

cssnanopostcss-cssnext 的补充知识了解。

cssnano: github.com/iuap-design…

postcss-cssnextgithub.com/jiayisheji/…

然后在.postcssrc.js文件对新安装的PostCSS插件进行配置。

module.exports = {
    "plugins": {
        "postcss-import": {},
        "postcss-url": {},
        "postcss-aspect-ratio-mini": {},
        "postcss-write-svg": {
            utf8: false
        },
        "postcss-cssnext": {},
        "postcss-px-to-viewport": {
            viewportWidth: 750,     // (Number) The width of the viewport. 
            viewportHeight: 1334,    // (Number) The height of the viewport.
            unitPrecision: 3,       // (Number) The decimal numbers to allow the REM units to grow to.
            viewportUnit: 'vw',     // (String) Expected units.
            selectorBlackList: ['.ignore', '.hairlines'],  // (Array) The selectors to ignore and leave as px.
            minPixelValue: 1,       // (Number) Set the minimum pixel value to replace.
            mediaQuery: false       // (Boolean) Allow px to be converted in media queries.
        },
        "postcss-viewport-units":{},
        "cssnano": {
            preset: "advanced",
            autoprefixer: false,
            "postcss-zindex": false 
       }
    }
}复制代码

文中还提及了对视口单位兼容性问题的解决方案:

采用 postcss-viewport-unitsviewport-units-buggyfill 结合的方法

postcss-viewport-units 在编译时给视口单位增加 content 属性,例如:

然后viewport-units-buggyfill通过这个content属性来做兼容性处理。

最后附上作者 demo 的 Github地址


多种终端适配的方案

前面讨论的都是纯移动端中的问题,接下来我们把讨论的范围扩大一下,如果我们需要实现一个多终端适配的网站,应该要如何实现?

我选择了一些比较典型的网页,在浏览器中将窗口大小缩放,观察效果。

方案1:出现横向滚动条, 忽略IPad视图

最小的PC端屏幕宽度是1280px,许多网站会将主体内容的宽度定在1200px,设置一个min-width:1200px,当窗口大小小于这个置时,出现横向的滚动条。

示例网站1

百度FEX

小于 1200px 时,横向出现滚动条,在 IPAD 下是出现横向滚动条的,小于 640px 时,变到了手机端的视图。

示例网站2

海康威视AI开放平台,和示例网站1很相似,手机视图变化的断点定在了 768px。

方案2:全适配

示例网站1

腾讯ISUX

页面内容比较简单,布局多采用块状,能比较方便的采用百分比, flex 或者是 grid 布局结合媒体查询来实现全适配。

示例网站2

css-tricks.com/

相比起网站1,页面内容就比较复杂了,需要做多个媒体查询的处理来实现效果。

网站的全局适配有很多种解决方法,不同视图变化的断点也不是固定的,你可以根据你网站的内容来自己定义如何来变化。

当然,这些单凭前端来完成是不足够的,设计师在出视觉稿的时候也需要考虑网页在PC端,移动端,IPAD尺寸下视图应当如何展现,并定义好各个视图转变的断点值是多少,这样才能保证我们的页面在不同屏幕尺寸下有良好的展现。


字体大小的适配

如果你选取了采用方案1,那某种程度上是可以避免掉字体大小适配的问题的,只需要保持在PC端一个字体规范,移动端一个字体规范,界面最终的显示并不会有问题。

如果采用了方案2,那你可能还需要考虑字体大小需要随着屏幕大小而变化的问题。具体内容可参考掘金翻译计划中的这篇文章:Web 流式文字排版的现状

文章大致的内容是作者发现,

视口单位被引入更多是作为绝对单位网页布局的一种扩展

1.抛出了一个问题:为什么很少有网站把它应用到字体大小当中?

2.总结出了一个 rem 和 vw 结合来控制字体大小的最佳实践。( 带 CSS 锁的流式文字排版 )。

作者推导出这个公式

body {
  font-size: calc([minimum size] + ([maximum size] - [minimum size]) * ((100vw - [minimum viewport width]) / ([maximum viewport width] - [minimum viewport width])));
}复制代码

我们用一个张鑫旭的博客中提到的实际的例子来帮助理解一下

假设我们希望浏览器宽度在 600px ~ 1000px 变化的时候,根元素的 font-size 大小是18px~22px之间对应变化的,默认根结点的字体大小是16px,那我们可以这样子做

html { font-size: calc(112.5% + 4 * (100vw - 600px) / 400); }复制代码

3.最后作者又回过头来推翻了自己的论点,考虑到使用vw来实现字体的大小变化会引起无障碍访问功能的问题,所以他并不提倡在实际的网站中采用这种做法。

比如使用 vw 来实现 div 的宽度,那么在网页缩放的时候所占当前页面的比例还是一致的,同理如果用 vw 来实现font-size,缩放页面大小也是不会改变的,对于一些需要使用无障碍功能将页面字体放大来方便查看的人来说,这个显示是不太合适的。


总结

未来视口单位的兼容性肯定会越来越好,在移动端的适配中,对于元素的布局可以直接采用 vw,使用Postcss插件来让我们的开发更加方便与自动化。

多终端的适配有多种不同的解决方案,需要根据你当前网页所要展现的内容确定最适合自己的解决方案,当然需要与视觉实现沟通设计好不同屏幕尺寸下的展示效果。

对于字体的适配,在有需要的情况下如果不考虑无障碍访问功能的话,可以使用这个带 CSS 锁的字体大小适配方案配合 rem 单位一起使用。如果要考虑无障碍访问功能,那就优雅的降级采用 media query + rem 来实现。


参考文章

基于视口单位的网页排版

浅说移动前端中 Viewport 和 Viewport units

使用Flexible实现手淘H5页面的终端适配

lib-flexible仓库地址

理解flexible.js所需的viewport知识

关于移动端适配,你必须要知道的

基于vw等viewport视区单位配合rem响应式排版和布局

如何在Vue项目中使用vw实现移动端适配

Web 流式文字排版的现状


转载于:https://juejin.im/post/5d4574aff265da03e61af359

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值