移动端适配--meta标签玩的是什么

1,502 阅读9分钟

基本一直都在做移动端的开发,rem布局也写了很久,不过对于实现的原理有些模棱两可的盲点,自己总结一下留着以后回顾。 本文分以下几个层面,主打用最最通俗的语言来阐述。

  1. 布局小例子
  2. viewport作用
  3. viewport和移动端适配的关系
  4. flexible.js原理
  5. vw vh
  6. flexible.js VS vw vh

布局小例子----常见困惑

iphone6尺寸是375*667,那给div设置宽度375px后,为什么宽度不是充满屏幕呢? 代码如下:(为了方面看,我全截图吧)

然后运行结果如下:

这是为什么呢? 来看一下页面宽度是多少

哦?这个980是哪里来的呢?带着疑问引出本文的主角----viewport

viewport作用

viewport是什么?翻译过来就是视窗的意思,只不过在移动端,视窗稍微有点绕。在解释这个之前,不得不引出几个词汇,分别是物理像素(physical pixel),设备独立像素(density-indenpendent pixel),设备像素比(device pixel ratio),要怎么通俗理解这三个词呢? 容我找找网上的图。

物理像素

手机屏幕显示图像的最小单元。上图中iphone4和3gs,同样大小尺寸情况下,iphone4明显画面细腻很多,这是为什么?屏幕尺寸没变,分辨率提升,画面就细腻了,更通俗一点的就是iphone4用来显示图像的点更多了,把屏幕上的物理像素点想象成整齐排列的点阵,3gs有320 * 480个点而ip4有960 * 640个点。

设备独立像素

如果把物理像素看做是负责显示图像的硬件的话,那么设备独立像素是什么呢?我们平时写的css像素就是设备独立像素的一种了。而这1px的css像素,在不同的手机却是呈现不同的,为什么ip4画面细腻?就是人家用4个物理像素点来描绘一个css像素。

设备像素比

也就是常说的dpr , dpr = 物理像素/设备独立像素(注意,是在某一方向的,x轴或者y轴) , 理解这个很重要,iphone6的dpr是2,iphonex的dpr是3。

dpr是2的情况下css画一个点,这个点是由4个物理像素点提供支撑的。画一条线的话,那这条线其实是2排物理像素点支撑的。

同理,dpr是3的情况下css画一个点,这个点是由9个物理像素点提供支撑的。画一条线的话,那这条线其实是3排物理像素点支撑的。

viewport登场

在移动端,视窗分为三种,分别为layoutviewport、visualviewport、idealviewport。可以先记住一个,idealviewport就认为是设备宽度就好,iphone6就是375,iphone6p 就是414 ,其余两个先看我下面例子吧。

对于上面的代码做简单修改 简要说明下: js动态生成一个关于viewport的标签,meta标签可以控制viewport的缩放。

window.devicePixelRatio : 查看设备dpr

document.documentElement.clientWidth : 查看layoutviewport宽度

window.visualViewport.width : 查看visualViewport宽度

window.innerWidth : 查看文档宽度

只设置initial-scale = 1

不加meta标签

initial-scale=2, width=device-width

initial-scale= 0.5 , width=device-width

需要来个小结了:

layoutviewport

默认是980 (针对ios)

设置缩放为1 宽度为设备宽度时:就是375(设备宽度)

设置缩放为2 宽度为设备宽度时:还是375(设备宽度)

设置缩放为0.5 宽度为设备宽度时:是750(设备宽度的2倍)

layoutviewport 取设置的宽度或者visualviewport他们中的最大值

visualviewport

默认是980 (针对ios)

设置缩放为1 宽度为设备宽度时:就是375(设备宽度)

设置缩放为2 宽度为设备宽度时:是187.5(设备宽度一半)

设置缩放为0.5 宽度为设备宽度时:是750(设备宽度的2倍)

其实是有公式的,visualviewport = 设备宽度/缩放。也就是visualviewport = idealviewport / initial-scale

idealviewport

顾名思义,是理想视窗意思,就是指的设备尺寸,主要用来和initial-scale配合,计算也就是visualviewport用的。

那layoutviewport和visualviewport负责什么

其实也是可以从名字就看出来的,layoutviewport布局视窗,visualviewport视觉视窗。 这里加个图,initial-scale = 1 width=devide-width,然后box宽度设置750px,发现html宽度在375,页面出现滚动条,并且,有意思的是,是按照375宽度排列的,只有那个设置了宽度是750的box宽度变大,所以layoutviewport负责布局,visualviewport负责视觉,是不是有了点直观印象了,如下图:

layoutviewport和visualviewport不一致的情况下,页面就会出现滚动条。(截图滚动条不明显)

viewport和移动端适配关系

这里就更不好用语言描述了,有些抽象。回顾上文,知道iphone3gs iphone6 iphonex三者屏幕尺寸大小不同,dpr的话,前两者是1 2 而 iphonex是3。那如何使得一张前端页面,在每个手机看起来都是一样大呢?以iphone6和iphonex来举例,虽然屏幕宽度都是375,但是iphonex却拥有更加密集的物理像素点阵。iphone3gs更不用说,320的宽度,dpr又是1。 倘若我们规定,只用设备的物理像素,来绘制css的像素,要求一比一的绘制,那一张320px宽度的页面,在3个手机上的展示一定大致如下:

这只是一个示意图,也许并不精准。不过大体就是这样的,ip6宽度有着750个物理像素点,iphonex宽度有1125个物理像素点,所以根据上面的假想要求,画出来的一定是这样的。那么想要iphone6画出的这个320px的页面也充满屏幕的话,要怎么做?首先假如设置initial-scale=1, width=device-width,这种情况下,宽度375的iphone6画出宽度320px的前端页面大致什么样呢?

就是这样的效果图,但是需要注意的是,此时的一条横线,3gs是用一排物理像素点描绘的,而iphone6确是用了两排物理像素点!也就引申出了经典的1px边框问题。iphone6的物理像素点再密集,用两排画一条线和只用一排画一条线,还是能看出差距的。那么这种情况是不可取的。那假如设置initial-scale=0.5, width=device-width,这种情况下呢?我也想画出看着和iphone3gs一样视觉大小的图像的话,(注意是视觉大小哦,就是拿着两手机,看着屏幕中的图一样大。)要怎么做呢?根据上面知识,对视窗进行了0.5缩放,那此时肉眼看到视觉是不是就和上面提到的这个图一致了呢?

所以,我们需要在这种情况下,写css是宽度写为640px,就能看起来和上面initial-scale=1, width=device-width一样的效果了!也解决了1px像素问题!

rem适配方案

rem是什么,这个大家应该都清楚了。就是给html设置字体大小,假如是30px,那么页面中写了2rem那就是60px。 设计给出一张设计稿,页面宽度是750px,其中一个div标注了是宽度375px。如何做到在iphone6和iphonex中,看到的这个div都是屏幕宽度的一半呢?

相信大家都已经有答案了。

对于iphone6 设置initial-scale=0.5, width=device-width,然后就直接写375px就好 对于iphonex 设置initial-scale=1/3, width=device-width,然后就直接写(375*(3/2))px就好。 缺点就是需要我们自行计算。

rem方案 : 设计稿750px,div标注375px,对于iphone6 设置initial-scale=0.5, width=device-width,如果html设置font-size为75px,那div我们就直接写5rem就行了。然后适配到iphonex中时,不需要改变div的5rem,只需改变在iphonex中html的字体以及页面缩放,设置 iphonex中 initial-scale=1/3, width=device-width,然后设置html字体为112.5px,此时的5rem为562.5px,刚好是屏幕1125的一半。

flexible.js原理

上面关于rem适配已经思路实现,现在还差几个环节,就是为什么设置iphone6是0.5缩放,iphonex是1/3缩放呢?然后又根据什么设置的html字体?

答: dpr 。那么又是怎么设置的?flexible.js就要登场了,flexible.js是手淘的前移动端适配解决方案,为什么是前方案,因为目前浏览器对于vw vh支持的更加友好,这个后面再说。看看flexible.js做了什么吧,直接截图一些代码吧。

感觉没什么好解释的,就是获取设备dpr,然后确定scale嘛

然后把meta标签塞到html中

因为已经缩放好了页面,此时iphonex的话,这个width拿到的就是1125了,rem就112.5并设置到html字体中

不过rem我们自己来计算的话就很繁琐了,如给的iphone6,宽度750的设计稿,标注的375px,我们就写375px就好,当然是写成px2rem(375)这样。

关于flexible.js的实现原理,我也就是挑重点的说了说,还是建议大家去看大漠老师写的源码,一百多行代码而已,挺好的,也很容易看懂,不过要想清楚为什么要那么做,就是我上面大篇幅写的东东啦~

vw vh

关于vw vh其实是将视口宽度 window.innerWidth 和视口高度 window.innerHeight 等分为 100 份,并且此时的视窗并不会随着 viewport 的不同设置而改变。

vw : 1vw 为视口宽度的 1%

vh : 1vh 为视口高度的 1%

上面说的设计稿为 750px,那么 1vw = 7.5px,100vw = 750px。此时给的不是750设计稿也没所谓,假如给1000px的设计稿,那我们写的1v我就是10px。其实这不就是rem做的事吗?只不过我们用rem+flexible.js绕了一圈的感觉

后面具体项目中新页面用vw试试,有什么坑 待补充

flexible.js VS vw vh

作为后面要补充的点吧,vw等我项目具体实操一波,再来补这个