不知不觉做前端已经两年了,从PC端,移动端,微信小程序一路走来到今天刚刚开放注册的快应用(手机厂商对抗小程序的新技能,所以在注册时用的是qq邮箱的话要去垃圾箱里才能找到注册邮件),对于前端圈日新月异的磅礴发展对于大前端发展是喜闻乐见的,这次的快应用的手机厂商们为其开放了应用入口和系统推广引流入口。这些新能力为前端开发者们带来更强的作战能力。
我们在开发PC站时经常在浏览器兼容问题上耗费巨大的时间,到了移动端,面对webkit内核的Safari与Chrome会舒心很多。but,我们要对于市面上的手机各式各样的分辨率进行适配,刚接触移动端开发的时候是不是有点猝不及防哈哈,尤其是去年年中以前老版本的微信内置浏览器用的X5内核,给网友们戏称移动端IE...
今天的主题是讲的是我对移动端多终端适配的解决方案和移动端适配的有关布局的知识总结,下面正式开始。
基本概念和原理
首先要了解的重要的基础知识点:物理像素,设备独立像素,设备像素比,css像素,布局视口,可视视口,理想视口以及css单位rem。
物理像素(设备像素)
屏幕的物理像素,又被称为设备像素。任何设备屏幕的物理像素出厂时就确定了,是固定不变的。
设备独立像素
设备独立像素也可以理解为CSS像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说CSS像素)。
设备像素比
设备像素比简称为dpr,dpr = 物理像素 / 设备独立像素。(以iphone6为例: dpr = 750 / 375 , 所以它的像素密度比为2,即 1个CSS像素 跨越了 2个物理像素),我们可以通多 window.devicePixelRatio
来获取设备的像素密度,像素密度大于1就是高清屏。
CSS像素
在CSS、JS中使用的一个长度单位,单位px。
注:在pc端1物理像素等于1px,但是移动端1物理像素不一定等于1px(高清屏)。
布局视口(layout viewport
可以看作是html元素的上一级容器即顶级容器,默认情况或者将html元素的width属性设为100%时,会占满这个顶级容器,此时用 document.documentElement.clientWidth
获取到html元素的布局宽度也就是布局视口的宽度,使用媒体查询时 max-width 和 min-width 的值指的也是布局视口的宽。
在html中一般在meta中的name为viewport字段就是控制的布局视口。布局视口一般都是浏览器厂商给的一个值。在手机互联网没有普及前,网络上绝大部分页面都是为电脑端浏览而做的,根本没有做移动端的适配。
随着移动端的发展,在手机上看电脑端的页面已成为非常普及现象。而电脑端页面宽度较大,移动端宽度有限,要想看到整个网页,会有很长的滚动条,看起来非常麻烦。于是浏览器厂商为了让用户在小屏幕下网页也能够显示地很好,所以把布局视口设置的很大,一般在768px ~ 1024px 之间,最常用的宽度就是 980。
这样用户就能看到绝大部分内容,并根据具体内容选择缩放。
故布局视口是看不见的,浏览器厂商设置的一个固定值,如980px,并将980px的内容缩放到手机屏内。一块手机屏幕,物理像素的数量是固定不变的。
视觉视口的大小是继承自布局视口的大小,视觉视口和布局视口的宽度为CSS的px数(可变的)。
理想视口
布局视口虽然解决了移动端查看pc端网页的问题,但是完全忽略了手机本身的尺寸。所以苹果引入了理想视口,它对设备来说是最理想的布局视口,用户不需要对页面进行缩放就能完美的显示整个页面。最简单的做法就是使布局视口宽度设置为手机屏幕的宽度。移动端到底怎么适配不同的屏幕呢?最简单的方法是设置如下视口:<meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
复习一下: dpr = 物理像素 / 设备独立像素。
以iphone6为例,iphone6的物理像素为750,如果没有设置布局视口时,布局视口viewport默认为980px
此时:dpr = 750 / 980 = 0.76531,等于1个CSS像素有0.76531个物理像素。接近于1像素密度所以pc端的页面在手机端看时不会太小。
当在meta中设置了如下配置时:<meta name="viewport" content="width=device-width">
相当于把布局视口设置为设备的宽度(即设备独立像素),
iphone6的设备独立像素为 375px。
此时:dpr = 750 / 375 = 2,等于1个CSS像素有2个物理像素。此时把pc端的尺寸拿来手机端看时字体和元素会特别大只。
现在移动端设计稿都是基于iphone设计的,一般为750px或640px,对应的是iphone6和iphone5的物理像素。在设计稿中,1px像素边框对应的是1物理像素。而在iphone5和iphone6中,当布局视口width=device-width时,css的1px显示出来的是2个物理像素,所以用户看到的是2px的边框。怎么解决呢?1px边框效果其实有很多hack方法,其中一种就是通过缩放viewport。<meta name="viewport" content="width=device-width,initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
viewport缩放
initial-scale是对布局视口进行缩放,initial-scale是相对于理想视口的,即initial-scale=1与width=device-width是一样的效果。initial-scale=0.5等效于width= 2倍的 device-width,所以设置initial-scale和width都可以改变布局视口的大小。
对于可视视口的缩放可以理解为,用户用双指对页面进行缩放,当用户缩小页面时,可视视口变大用户可以看到的东西越多,当用户放大页面时,可视视口
变小,用户看到的东西越少。
对于iphone6当添加如上设置后,initial-scale=0.5时。
布局视口: 375px * 2 = 750px;
所以此时布局视口为750px,此时1px等于1物理像素了。(移动端一像素有很多hack写法比如用伪类实现,svg实现等等)
看到这是不是觉得要消化的知识点有点多,不怕,休息一下消化消化,每个人都是这样过来的。猥琐发育~
多种适配方案探究
当设计师给出ui图时,面对市场上各式各样的手机它们屏幕大小不同,dpr不同,屏幕尺寸也是各种大小,那么我们应该怎么做到对ui设计图的充分还原,使得项目在各式各样的手机里运行呢?为了解决这种情况出现了许多的适配方案,各方案的实现方法不一样,还原程度也不一样,下面来总结一下常见的几种适配方案及其原理。
方案一:固定高度,使其宽度自适应
这也是我接触移动端适配第一次使用的方案。
这个方案使用了理想视口,使得布局视口等于设备宽度。<meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
在布局方面纵向使用固定px值,横向使用自适应布局(百分比,felx,小额定值)。
这种方案相对简单,ui还原度比较低。
方案二:固定布局视口宽度,使用viewport进行缩放(网易、荔枝FM)
if(/Android (\d+\.\d+)/.test(navigator.userAgent)){ var version = parseFloat(RegExp.$1); if(version>2.3){ var phoneScale = parseInt(window.screen.width)/640; if(/MZ-M571C/.test(navigator.userAgent)){ document.write('<meta name="viewport" content="width=640, minimum-scale = 0.5, maximum-scale= 0.5">'); }else if(/M571C/.test(navigator.userAgent)&&/LizhiFM/.test(navigator.userAgent)){ document.write('<meta name="viewport" content="width=640, minimum-scale = 0.5, maximum-scale= 0.5">'); }else{ document.write('<meta name="viewport" content="width=640, minimum-scale = '+ phoneScale +', maximum-scale = '+ phoneScale +', target-densitydpi=device-dpi">'); } }else{ document.write('<meta name="viewport" content="width=640, target-densitydpi=device-dpi">'); } }else{ document.write('<meta name="viewport" content="width=640, user-scalable=no, target-densitydpi=device-dpi">'); }
固定布局视口,宽度设置固定的值,总宽度为640px,根据屏幕宽度动态生成viewport。(设计稿宽度为640px)
这种布局方案页面宽度始终为640px通过设置缩放比例scale实现适配:
var scale = window.screen.width / 640;
当设计稿为640px时,我们可以直接用1:1px来写像素单位。这种布局方案中的1px不一定等于1px,当设备为iphone6时
1px(css) = window.screen.widthdpr = 640 = 375 2 / 640 = 1.171875(设备物理像素)
荔枝FM这种适配方案用到了target-densitydpi , 这是一个将被抛弃的属性,因此不推荐使用这套方案(学习一下思路也不错)
方案三:根据不同屏幕动态写入font-size,以rem作为宽度单位,固定布局视口。(网易新闻)
首先设置理想视口:<meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
接下来计算 html 元素的 font-size,将可视视口的宽度乘以一个系数:
理论上这个系数可以是任意值,假设将这个系数取 1,则 html 元素的 font-size 即1 rem等于可视视口的宽度,此时以 rem 为单位的长度 n rem 就可以理解为 n 倍可视视口的长,这个系数取 0.01 时,1 rem 等于可视视口宽的 1/100,也就等于布局视口宽的 1/100,也就等于 1vw。实际使用过程中这个系数的选择尽可能方便将设计稿长度数值换算为css中的长度数值
网易新闻手机网易网选择的系数为 100 / 750,这个系数可以如下推出:750px 是设计稿的宽度(以iphone6的物理像素数为标准),100是期望的换算比例,即设计稿中 100px 的长度对应css中 1rem,将设计稿中的长度数值除以 100 得到的就是以 rem 为单位的 css 长度的数值,设计稿的宽换算为以 rem 为单位的 css 长度应为 (750/100) rem,同时设计稿的宽对应可视视口的宽,即有 (750/100) rem = 可视视口宽,1 rem = 可视视口宽 * (100/750),(100/750)就是我们要的系数
在页面初始化时设置一下 html 元素的 font-size:在750宽的设计稿:document.documentElement.style.fontSize = window.innerWidth / 7.5 + 'px';
在640宽的设计稿:document.documentElement.style.fontSize = window.innerWidth / 7.5 + 'px';
这套方案能百分比还原设计稿。
方案四:根据不同屏幕动态写入font-size和viewport,以rem作为宽度单位.
将屏幕分为固定的块数10:
var width = document.documentElement.clientWidth; // 屏幕的布局视口宽度
var rem = width / 10; // 将布局视口分为10份
这样在任何屏幕下,总长度都为10rem。1rem对应的值也不固定,与屏幕的布局视口宽度有关。
动态缩放view:
var devicePixelRatio = window.devicePixelRatio; var isIPhone = window.navigator.appVersion.match(/iphone/gi); var dpr,scale; if (isIPhone) { if (devicePixelRatio >=3) { dpr = 3; } else if (devicePixelRatio >=2) { dpr = 2; } else { dpr = 1; } } else { dpr = 1; } scale = 1 / dpr;
淘宝只对iphone做了缩放处理,对于android所有dpr=1,scale=1即没有缩放处理。
此方案与方案三相似,增进了viewport缩放使得在iphone上1px(css) = 1px(物理像素),这套方案能百分比还原设计稿。
Flexible实现手淘H5页面的终端适配
方案五:
可以来看看我总结的 : 大漠老师最新的vw移动端适配方案
最后看到这里相信大家心里都有个底,知道选择哪一种方案更能适配自己所开发的项目
(~ ̄▽ ̄)~