移动端适配-方案介绍(三)

669 阅读12分钟

为了设计稿完美适配各种设备,我们就需要将设计稿展示到各个设备的理想视口中,而不是默认的布局视口(980px)中。那么如何适配,分两步:

  • 设置布局视口的宽度等于设备理想视口的宽度
  • 将设计稿按照比例展示到理想视口中

一、meta

meta 元素就是为了解决第一步

 /*
 width是设备的宽度,这里的宽度不是设备的物理像素宽度,而是设备独立像素的最佳宽度;
 设置布局视口宽度为设备理想视口宽度
 */
 <meta name="viewport" content="width=device-width, initial-scale=1.0">

meta其他属性:

  • width: 该属性被用来控制视窗的宽度,可以将 width 设置为980px这样确切的像素数,也可以设为device-width这样的关键字,表示设备的宽度,一般为了自适应布局,普遍的做法是将width设置为 device-width

  • height: 该属性被用来控制视窗的高度,可以将height设置为640px这样确切的像素数,也可以设为 device-height 这样的关键字,表示设备的实际高度,一般不会设置视窗的高度,这样内容超出的话采用滚动方式浏览。

  • initial-scale: 该属性用于指定页面的初始缩放比例,可以配置 0.0~10 的数字,initial-scale=1表示不进行缩放,布局视口刚好等于理想视口;当大于1时表示将视窗进行放大,小于1时表示缩小。这里只表示初始视口的缩放值,用户也可以自己进行缩放,例如双指拖动手势缩放或者双击手势放大。

    • 安卓设备上的initial-scale默认值: 无默认值,一定要设置,这个属性才会起作用
    • 在iphone和ipad上,无论你给viewport设的宽度是多少,如果没有指定默认的缩放值,则iphone和ipad会自动计算这个缩放值,以达到当前页面不会出现横向滚动条(或者说viewport的宽度就是屏幕的宽度)的目的
  • minimum-scale: 该属性表示用户能够手动放大的最大比例,可以配置 0.0~10 的数字

  • maximum-scale: 该属性类似maximum-scale,用来指定页面缩小的最小比例。通常情况下,不会定义该属性的值,页面太小将难以浏览

  • user-scalable: 该属性表示是否允许用户手动进行缩放,可配置 no或者yes 。当配置成no时,用户将不能通过手势操作的方式对页面进行缩放

这里需要注意的是 viewport 只对移动端浏览器有效,对PC端浏览器是无效的

二、解决方案

接下来我们解决问题的第二步:将设计稿按照比例展示到设备理想视口中;

下面以 设计稿宽度为750px,图片A 宽度为600px 为例

 将宽度为750px的设计稿放到理想视口宽度为375px的设备中,只需要将设计稿中所有的元素宽度像素除以2即可;比如:设计稿中 图片A 的宽度为600px,那我们只需要将图片宽度设置为300px,那么就能完美适配 iPhone6;
 问:设备各种各样,宽度也都不相同,那么我们如何适配所有的设备呢?
 答:给设计稿的宽度乘以某个系数,这个系数如何计算呢

通过上面描述,我们可以得到如下的等式:

可变系数\alpha=\frac{设备理想视口宽度}{设计稿宽度}=\frac{设备元素宽度}{设计稿元素宽度}

举两个例子:

  • iPhone6 的最佳设备宽度为375px,那么 可变系数\alpha=\frac{375px}{750px}=0.5
  • iPhone6 Plus 的最佳设备宽度为414px,那么 可变系数\alpha=\frac{414px}{750px}=0.552

那么我们在设置 图片A 的时候只需要如下伪代码:

 if 设备为iPhone6 时,<img src="图片A.png" width="600px * 0.5"></img>
 if 设备未iPhone6 Plus 时,<img src="图片A.png" width="600px * 0.552"></img>

2.1、@media方案(不建议使用)

media

media介绍参考:media简介

media方案实现

基于 css 的媒体查询属性 @media 分别为不同屏幕尺寸的移动设备编写不同尺寸的 css 属性,示例如下所示:

虽然此方法能在一定程度上解决移动设备适配的问题,但我们也可以看出其存在以下问题,所以其已几乎被历史潮流淘汰。

  • 页面上所有的元素都得在不同的 @media 中定义一遍不同的尺寸,这个代价有点高
  • 如果再多一种屏幕尺寸,就得多写一个 @media 查询块
 <!DOCTYPE html>
 <html lang="en">
 ​
 <head>
     <meta charset="UTF-8">
     <!-- 设置屏幕宽度 -->
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <meta http-equiv="X-UA-Compatible" content="ie=edge">
     <title>Document</title>
     <style>
         * {
             margin: 0;
             padding: 0;
         }
 ​
         @media only screen and (min-width: 320px) {
             .logo {
                 /* width = 320px / 750px * 600px */
                 width: 256px;
             }
         }
       
         @media only screen and (min-width: 375px) {
             .logo {
                 /* width = 375px / 750px * 600px */
                 width: 300px;
             }
         }
 ​
         @media only screen and (min-width: 414px) {
             .logo {
                 /* width = 414px / 750px * 600px */
                 width: 331px;
             }
         }
     </style>
 </head>
 ​
 <body>
     <!-- 图片A宽度为600px -->
     <img class="logo" src="图片A.jpg">
 </body>
 ​
 </html>

2.2、rem方案

rem

rem(font size of the root element)是CSS3新增的一个相对单位,是指相对于根元素的字体大小的单位。如果我们设置 html 的 font-size 为 16px,则如果需要设置元素字体大小为 16px,则写为 1rem。

2.2.1、rem方案一实现

还是以上面的案例为例,设计稿页面宽度为750px,图片A 的宽度为600px,我们要将 图片A 放到iPhone6中(理想视口宽度375px)

方案:

  • 设置 html 的 font-size 为:fontSize = \frac{设备理想视口宽度}{设计稿宽度}*100px :通过在各个设备设置不同的fontSize来达到元素宽度/高度的变化
 解释一下上面的公式:
 问:我们要想把 设计稿宽度(750px)中 图片A600px) 显示到 iPhone6设备理想视口宽度(375px)中,那么设计稿中1px应该对应设备理想视口中多少像素?
 答:这个不难计算, 设备理想视口宽度/设计稿宽度 = 375px/750px = 0.5,可得出设计稿中1px等于理想视口0.5px;
 根据计算,我们把 font-size 设置为 0.5px,那么 图片A 在设计稿中的宽度是多少,就写多少rem,即在理想视口中的的宽度 就可以设置为 600rem = 600px * 0.5 = 300px; 600px则是图片A在设计稿中的宽度,300px为理想视口中的宽度;
 ​
 但是,html 中规定,font-szie最小为12px,那么我们就要将font-size扩大,扩大多少倍,就要给 图片A 的宽度缩小多少倍,为了方便计算,我们将 fontSize扩大100倍,这时 图片A在理想视口中的宽度就可以设置为 6rem = 6px * 0.5 * 100 = 300px
 此时,我们将设计稿中所有的元素宽度和高度缩小100倍即可
  • 使用 rem 单位设置图片的宽度、高度、字体大小等

代码如下:

采用js代码来设置 html 的 fontSize

 <!DOCTYPE html>
 <html lang="en">
 ​
 <head>
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>rem方案-移动端适配</title>
     <script>
         function setFontSize() {
             // 1、设置设计稿的像素: 注意不同的设计稿要进行调整
             const designSize = 750
 ​
             // 2、获取设备大小
             var deviceSize = document.documentElement.clientWidth
 ​
             // 3、假设设计稿的宽度是750px
             var fontSize = (deviceSize / designSize) * 100
            
             // 4、设置 html 的 font-size
             document.documentElement.style.fontSize = fontSize + "px"
         }
         // 首次打开页面执行函数
         setFontSize()
         // 窗口变动执行函数
         window.onresize = function() {
             setFontSize()
         }
     </script>
     <style>
         * {
             margin: 0;
             padding: 0
         }
 ​
         .logo {
             width: 6rem;
             height: 3rem;
         }
     </style>
 </head>
 ​
 <body>
     <img src="resources/图片A.png" class="logo">
 </body>
 ​
 </html>

因为html的fontSize随着设备变化而变化,因此 图片A 的宽度也会随着变化。

计算下各个设备的适配情况,如下:

设备设备最佳独立像素设计稿宽度Html-fontSize大小(100为扩大系数)图片A 宽度
iPhone6375 * 667750px375px / 750px * 100 = 50px600px / 100 * 50px = 300px = 6rem
iPhone6 Plus414 * 736750px414px / 750px * 100 = 55.2px600px * 100 * 55.2px = 331.2px = 6rem

可以看到,在不同的设备下,图片A的宽度一直是6rem,html的fontSize随着设备的不同值不同,这样图片A就可以动态适配

效果展示:视频展示不了

​​

2.2.2、rem方案二实现(推荐)

优化:

方案一的js写的不是特别完美,没有考虑到横屏之类的,可以采用下面js,代码实现如下:

phone.js

 (function (doc, win) {
     // 设计稿宽度
     const designSize = 750
     // 获取当前页面元素
     var docEle = doc.documentElement,
         // 判断横屏或者屏幕大小事件
         resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
         recalc = function () {
             // js获取当前设备的宽度 :document.documentElement.clientWidth; 
             var clientWidth = docEle.clientWidth;
             if (!clientWidth) return;
             //宽度大于750px 平板或者桌面
             if (clientWidth >= designSize) {
                 // 设置fontSize为100px,即最大为100px
                 docEle.style.fontSize = '100px';
             } else {//移动端的适配
                 // 设置 html 的 font-size
                 var fontSize = (clientWidth / designSize) * 100
                 docEle.style.fontSize = fontSize + 'px';
             }
         };
     if (!doc.addEventListener) return;
     // 增加窗口大小变化监听器
     win.addEventListener(resizeEvt, recalc, false);
     // 增加内容刷新监听器
     doc.addEventListener('DOMContentLoaded', recalc, false);
 })(document, window);

引入phone.js,进行页面变化的监控:

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>rem优化版方案-移动端适配</title>
    
     <style>
         * {
             margin: 0;
             padding: 0
         }
 ​
         .logo {
             width: 6rem;
             height: 3rem;
         }
     </style>
      <script src="js/phone.js"></script>
 </head>
 <body>
     <img src="resources/图片A.png" class="logo">
 </body>
 </html>

2.2.3、flexible方案:与方案二的原理一样

参考:github.com/amfe/lib-fl…

2.2.4、postcss-pxtorem(后续学习)

目前在前端工程化开发中,我们可以借助webpack的工具来完成自动的转化

2.2.5、VS Code插件

px to rem的插件,在编写时自动转化,不过在插件中要设置设计稿的大小

2.3、vw方案

vw

vw、vh 方案即将视觉视口宽度 window.innerWidth 和视觉视口高度 window.innerHeight 等分为 100 份。

上面的 flexible 方案就是模仿这种方案,因为早些时候 vw 还没有得到很好的兼容。

  • vw(viewport's width):1vw等于视觉视口宽度的1%
  • vh(viewport's height) : 1vh 等于视觉视口高度的1%
  • vmin : vw 和 vh 中的较小值
  • vmax : 选取 vw 和 vh 中的较大值

12-vw+vh.jpg

如果按视觉视口为 375px,那么 1vw = 3.75px,这时 UI 给定一个元素的宽为 75px (设备独立像素),我们只需要将它设置为 75 / 3.75 = 20vw;每个设备的视觉视口都是不同的,因此也需要动态计算 1vw等于多少px

2.3.1、vw方案一实现

通过meta元素将布局视口的宽度设置为理想视口的宽度(即最佳设备独立像素),可得出 100vw = 设备的宽度

以 iPhone6 为例,即 100vw = 375px,得 1vw = 3.75px,10vw = 37.5px

在设计稿宽度为750px的布局中,图片A 像素为 600*300;

当设置html的fontSize为10vw时,在 iPhone6 中,图片A的宽度为:300px / 37.5px = 8rem

如下代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0px;
            margin: 0px;
        }

        html{
            font-size: 10vw;
        }

        .logo {
            width: 8rem;
            height: 4rem;
        }
    </style>

</head>
<body>
    <img src="resources/图片A.png" class="logo">
</body>
</html>

以上就可以了,不用再添加 js 代码计算html的fontSize,因为html的fontSize为10vw,会随着设备的width不断的变化;

计算下各个设备的适配情况,如下:

设备设备最佳独立像素设计稿宽度Html-fontSize大小:10vw图片A 宽度
iPhone6375 * 667750px10vw = 375px / 100 * 10 = 37.5px600px * (375px / 750px) = 300px = (300px / 37.5px) rem = 8rem
iPhone6 Plus414 * 736750px10vw = 414px / 100 * 10 = 41.4px600px * (414px / 750px) = 331.2px = (331.2px / 41.4px) rem = 8rem

可以看到,在不同的设备下,图片A的宽度一直是8rem,html的fontSize是10vw,随着设备的不同,10vw的值不同,这样 图片A 就可以动态适配

当然我们可以通过上面的计算,发现 vw 的一个问题:

  • 计算元素的像素非常的不方便,主要是以下三步

    • 先根据 设计稿宽度与设备宽度 计算出缩放比
    • 设计稿元素像素 乘以 缩放比计算出 元素在理想视口像素
    • 元素理想视口像素 换算成 rem 单位的值

2.3.2、VS Code插件

px to rem的插件,在编写时自动转化,不过在插件中要设置设计稿的大小,可自行搜索;主要是为了解决方案一计算困难的问题,让插件帮助我们自动计算

2.3.3、vw方案三实现(推荐)

该方案也是为了解决方案一计算困难的问题,个人理解比较方便;思路与 rem方案二 是一样的,只不过是html的FontSize换了个单位表达而已;

算法中心思想:计算设计稿中1px在设备视觉窗口中的vw

以设计稿宽度为750px, iPhone6 为例,由于100vw是设备的宽度,那么以下转换公式是等价的:

\frac{100vw}{750px} <=> \frac{375px}{750px}

可以得出:

设计稿中1px=100vw/750=0.1333333vw(设备视觉视口中),那么,元素在设计稿中的像素是多少,就可以写多少rem;但是html的fontSize最小值为12px,因此,我们将html的fontSize设置扩大100倍为 13.33333 = 0.133333vw * 100,这样设计稿中的像素缩小100倍就可以得到在视觉窗口中的像素。 例如:图片A 在视觉稿中的宽度为600px,那么只需要将图片A的宽度设置为6rem即可;

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0px;
            margin: 0px;
        }
        
        html{
            font-size: 13.33333vw;
        }

        .logo {
            width: 6rem;
            height: 3rem;
        }
    </style>

</head>
<body>
    <img src="resources/图片A.png" class="logo">
</body>
</html>

以上就可以了,不用再添加 js 代码计算html的fontSize,因为html的fontSize为13.33333vw,会随着设备的width不断的变化;

计算下各个设备的适配情况,如下:

设备设备最佳独立像素设计稿宽度Html-fontSize大小:10vw图片A 宽度
iPhone6375 * 667750px13.33333vw = 375px / 100 * 13.33333 = 49.99998px600px = (600/100)rem = 6rem = 6 * 49.99998 = 299.99988px
iPhone6 Plus414 * 736750px13.33333vw = 414px / 100 * 13.33333 = 55.199998px600px = (600/100)rem = 6rem = 6 * 55.199998 = 331.199988px

可以看到

  • 在不同的设备下,图片A的宽度一直是6rem,html的fontSize是13.33333vw,随着设备的不同,13.33333vw的值不同,这样 图片A 就可以动态适配
  • 与 vw方案一 中 图片A 最终在设备上的宽度几乎是一样的

相比vw方案一优势在于,计算元素的rem值非常方便,只需要将对应的设计稿中的元素除以100即可;

总结

移动端适配方案就学习到这里,后续有更好的方案再进行更新;

推荐使用:2.3.3、vw方案三实现(推荐)或者 2.2.2、rem方案二实现(推荐)

另外需要特别注意:重要的事情说三遍!!!

当设计稿不是750px的时候,需要将上面的计算公式中的750px换成对应的设计稿宽度的像素

当设计稿不是750px的时候,需要将上面的计算公式中的750px换成对应的设计稿宽度的像素

当设计稿不是750px的时候,需要将上面的计算公式中的750px换成对应的设计稿宽度的像素

参考文档:

2022 年移动端适配方案指南 — 全网最新最全 - 掘金 (juejin.cn)

关于移动端适配,你必须要知道的 - 掘金 (juejin.cn)

超详细讲解H5移动端适配 - 掘金 (juejin.cn)

前端移动端适配总结 - 掘金 (juejin.cn)

01 (理解)移动端适配的理解和开发模式哔哩哔哩_bilibili

01 移动端-介绍哔哩哔哩bilibili

HTML5+CSS3移动端适配