移动端Wap页面适配解决方案

2,268 阅读8分钟

web前端开发人员如何才能开发出适配每个终端的wap页面呢?如果还有点迷茫不知所措,下面的文章希望可能给你帮助,同时也可以加深自己的记忆,有欠缺错误的地方,欢迎评论指出,相互学习。

备注:(不讨论百分比布局方式)
      如果有点心急的话可以直接跳到第5步,欲知其原理还得慢慢来

首先,在解决问题之前,我们先了解一下熟悉一些有趣的概念,帮助我们更深的理解解决办法哦!

1、像素

什么是像素?

像素是web页面布局的基础,估计我们每个前端开发人员都离不开,那么到底什么才是一个像素呢?可能大家会和我一样有点质疑,是的平时每天都在写,但是到底是指什么呢?
像素:就是计算机屏幕所能显示一种特定颜色的最小区域。
在web前端开发领域,像素有以下两种含义:
 1、设备像素(物理像素):设备屏幕的物理像素,对于任何设备来讲物理像素的数量是固定不变的。
 2、设备独立像素(也称密度无关像素,虚拟像素):可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说CSS像素),然后由相关系统转换为物理像素。
    CSS像素(虚拟像素):这是一个抽象的像素概念,它是为web开发者创造的。
设备 年份 尺寸 像素 点数
iPhone4S 2011年 3.5 640*960 320*480
iPhone5S 2013年 4.0 640*1136 320*568
iPhone6 2014年 4.7 750*1334 375*667
iPhone6S Plus 2015年 5.5 1242*2208 414*736

备注:此表所列举的像素即为设备像素(物理像素)

2、屏幕密度

指一个设备表面上存在的像素数量,它通常以每英寸有多少像素来计算(PPI)。

3、设备像素比

简称为dpr,其定义了物理像素和设备独立像素的对应关系。它的值可以按下面的公式计算得到:
设备像素比(DPR) = 设备像素个数 / 理想视口CSS像素个数(device-width)
在JavaScript中,可以通过 window.devicePixelRatio 获取到当前设备的dpr

举例:iPhone6的设备宽度和高度为375pt * 667pt,可以理解为设备的独立像素;而其dpr为2(window.devicePixelRatio ),根据上面公式,我们可以很轻松得知其物理像素(设备像素)为750pt * 1334pt。

4、视口(viewport)

布局视口:移动端CSS布局的依据视口,即CSS布局会根据布局视口来计算

可以通过以下JavaScript代码获取布局视口的宽度和高度:

document.documentElement.clientWidth; 
document.documentElement.clientHeight;

可视视口:用户正在看到网站的区域

理想视口:定义了理想视口的宽度,比如对于iphone6来讲,理想视口是375*667。
但是最终作用的还是布局视口,因为我们的css是依据布局视口计算的,
所以你可以这样理解理想视口:理想的布局视口。
下面这段代码可以告诉手机浏览器要把布局视口设为理想视口:

<meta name="viewport" content="width=device-width" />


打起精神咯,讲了这么多开始进入正题咯...此时可以来一条华丽的风格线

5、基本定义了解之后开始写代码了,边写代码边打开调试模式,对照看可能理解更深刻。以iPhone6设备为例子(如果下面出现的术语有疑问可以返回来继续浏览)

马上开始解决问题喽!

前情概要:iPhone6的设备宽度和高度为375pt * 667pt,可以理解为设备的独立像素;
而其dpr为2,根据上面公式,我们可以很轻松得知其物理像素(设备像素)为750pt * 1334pt。

a、创建HTML页面,

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>适配移动终端</title>
<style>
  /* 初始化样式 */
  *{padding: 0;margin: 0}
  .box{width: 375px;height: 375px;background: blanchedalmond}
</style>
</head>
<body>
  <div class="box"></div>
<script>
  window.onload = function () {
        const screenWidth = document.body.clientWidth;
        console.log("window.devicePixelRatio "+window.devicePixelRatio);
        console.log("document.body.clientWidth的值为 " + screenWidth);
  }
</script>
</body>
</html>

打开调试器,查看设备像素比=2;布局视口的宽度=980px

2.png

查看body的宽度:980px,为布局视口的宽度

3.png

查看box元素的宽度:375px

4.png

此时,为了让box元素的宽度占满屏幕,我们需要将box的宽度设置为多少呢?自己可以动手操作一下 . . . . ...

最后.box{width:980px;height:980px},如下图所示

6.png

原因:
980px是布局视口,通过document.documentElement.clientWidth获得,
而我们平时写的css样式则是相对于布局视口操作的,
所以,但是当布局视口发生变化的时候我们需要手动改页面中元素的尺寸,

那么有没有简单的办法呢或者可优化的地方呢?

继续:

b、在该HTML页面中加入

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">

这行代码大家一定很熟悉,移动端开发一般都要加,加入这行代码的意思是什么呢?可以让布局视口的宽度等于理想视口的宽度,页面的初始缩放比例以及最大缩放比例都为1,且不允许用户对页面进行缩放操作

7.png

这样布局视口和设备的宽度一样了,都是375px;但是页面元素box上一步设置的大小是980px所以已经超出了当前屏幕出现了滚动条,要让该元素全屏显示需要修改box样式将宽度改成375px; 但是还是一样的问题,当设备变成了一下设备甚至更多,如下:

设备 设备宽度
iPhone5S 320*568
iPhone6 375*667
iPhone6S Plus 414*736
... ...

还有很多的安卓手机

宽度还是会改变,应该继续做些什么呢?

叮咚!接着就要给大家推荐一个牛一般的存在移动端适配flexible方案

8.png

下载链接中的js,同时引入到我们的HTML页面中。 看看是不是解决问题了,不管在iPhone5、iPhone6、iPhone6S Plus...各种设备下.box{width:10rem}都能让该元素宽度显示全屏幕,那这个JS到底做了些什么操作呢?

在这里先要插播一个单位rem,相信大家都很熟悉, rem 是相对于根元素<html>的font-size来做计算。
而在这个方案中使用rem单位,是能轻易的根据<html>的font-size计算出元素的盒模型大小。

那么应该怎样换算成rem呢?

上图中:根元素HTML字体大小为37.5px

那么在该实例中 1rem = 37.5px

同理:

如果根元素HTML字体大小为75px

那么在该实例中 1rem = 75px

那么如果一个页面根元素(html)字体大小设置为41.4px,那么该页面中有一个元素宽度是270px,转化成rem是多少呢?

1rem = 41.4px

270px / 41.4px = 6.52rem(约等于)

移动端适配flexible方案主要做了些什么呢?

目的:适配移动终端 当我们将页面的字体设置为 布局视口/10的时候,想要让一个元素全屏显示宽度,就都是设置10rem

下面我们来自己算一下:

设置 布局视口 根目录字体 大小 页面中某元素宽度100%
iphone5 320px 32px 1rem = 32px 320px/32px = 10rem
iphone6 375px 37.5px 1rem = 37.5px 375px/37.5px = 10rem
iphone6Ps 414px 41.4px 1rem = 41.4px 414px/41.4px = 10rem
... ... ... ...
解析:布局视口 (375px)/ 根元素字体大小(37.5px) = 10rem

附上flexible.js(细细品味)

 (function flexible (window, document) {
      var docEl = document.documentElement
      var dpr = window.devicePixelRatio || 1

     // adjust body font size
    function setBodyFontSize () {
           if (document.body) {
               document.body.style.fontSize = (12 * dpr) + 'px'
               }
          else {
              document.addEventListener('DOMContentLoaded', 
              setBodyFontSize)
             }
             }
            setBodyFontSize();

           // set 1rem = viewWidth / 10
          function setRemUnit () {
           var rem = docEl.clientWidth / 10
           docEl.style.fontSize = rem + 'px'
           }

           setRemUnit()

           // reset rem unit on page resize
          window.addEventListener('resize', setRemUnit)
          window.addEventListener('pageshow', function (e) {
                  if (e.persisted) {
                        setRemUnit()
                      }
                    })

                    // detect 0.5px supports
          if (dpr >= 2) {
              var fakeBody = document.createElement('body')
              var testElement = document.createElement('div')
              testElement.style.border = '.5px solid transparent'
              fakeBody.appendChild(testElement)
              docEl.appendChild(fakeBody)
          if (testElement.offsetHeight === 1) {
             docEl.classList.add('hairlines')
               }
             docEl.removeChild(fakeBody)
               }
            }(window, document))

希望你可以自己做一个实例,毕竟书上得来终觉浅,绝知此事要躬行(对某个元素疑问的可以返回去自己看或者搜索更多的内容,帮助理解)。

你可以找个现有的PSD设计图开始练习,尺寸为750px*1300px(其实和PSD的大小是没有关系的)

将PSD的尺寸当成布局视口就可以了,当然根元素字体就是布局视口尺寸/10

怎么样了?加油,你是最棒的,其实解决这个不只是这种办法,大家可以在理解都基础上开始各种尝试,比如根据dpr的值改变布局视口的大小等等...

总结:其实下载移动端适配flexible方案的js,引入js就可以解决适配问题,前面啰啰嗦嗦的只是为了清楚为什么这样做可以解决问题,希望能有所帮助。自己理解可能也有些误差,不足之处望指正。

(参考链接:github.com/amfe/articl…