转自:https://segmentfault.com/a/1190000011586301css
做者:Devinnnhtml
作过移动端适配的小伙伴必定有遇到过这行代码:前端
<meta name = "viewport" content ="width=device-width, initial-scale=1.0">
可是,不少小伙伴只是感性的认识:噢,我加了这行代码,而后页面的宽度就会跟个人设备宽度一致。然而,这种理解是很片面的。那么,这句话的本质究竟是什么呢?html5
不急,咱们先往下面看,这里先留个悬念。web
这里,咱们先来辨析一下在适配的时候常常会遇到的一些名词、数值单位。算法
首先,先来看一下物理像素。segmentfault
以iphone6为例,可知道:浏览器
分辨率:1334pt x 750ptsass
指的是屏幕上垂直有1136个物理像素,水平有750个物理像素。前端工程师
屏幕尺寸:4.7in
注意英寸是长度单位,不是面积单位。4.7英寸指的是屏幕对角线的长度,1英寸等于2.54cm。
屏幕像素密度:326ppi
指的是每英寸屏幕所拥有的像素数,在显示器中,dpi=ppi。dpi强调的是每英寸多少点。同时,屏幕像素密度=分辨率/屏幕尺寸
接着,咱们来看一下其余的单位。
设备独立像素:设备独立像素,不一样于设备像素(物理像素),它是虚拟化的。好比说css像素,咱们常说的10px其实指的就是它。须要注意的是,物理像素开发者是没法获取的,它是天然存在的一种东西,该是多少就是多少。
设备像素比:缩写简称dpr,也就是咱们常常在谷歌控制台移动端调试顶端会看到的一个值。设备像素比 = 设备像素 / css像素(垂直方向或水平方向)。能够经过JS来获取: window.devicePixelRatio
注:如下涉及的像素均为CSS像素。而且默认不考虑缩放。
布局视口
写过css的小伙伴应该知道,咱们在 html
、 body
设置 width:100%;height:100%;
的时候,它并非无效的。咱们都知道 100%
这种百分数应该是继承父元素而来的。那在这里是继承哪里的呢?
在PC浏览器中,有一个用来约束CSS布局视口的东西,又叫作初始包含块。这也就是全部宽高继承的由来。除去 margin
、 padding
,布局视口和浏览器可视窗口宽度是一致的,同时也和浏览器自己的宽度一致。
可是在移动端,就大不同了。
如下的例子是在不加 meta
标签的前提下进行演示的。
假如咱们如今作一个二八分的左右布局,那么若是在PC端上面的话,显示的效果很是完美,这没什么好说的。
那若是是在手机端呢,这里以iphone6为例子来说解:
图例以下:
代码以下:
* { margin: 0; padding: 0; } html, body { height: 100%; width: 100%; } .left { float: left; width: 20%; height: 100%; background: red; } .right { float: right; width: 80%; height: 100%; background: green; } <body> <divclass="left"> </div> <div class="right"> </div> </body >
这里咱们会看到,为何 body
的高度是 980px
,而浏览器的宽度只有 375px
,那么这个 980px
究竟是从哪里来的呢?
其实,这里的 980px
就是移动端所谓的布局视口了。
在移动端,默认的状况下,布局视口的宽度是要远远大于浏览器的宽度的。这两个视口不一样于PC端,是相互独立存在的。为何呢?试想一下,若是一个网页不对移动端进行适配,用户进行阅读的时候,若是默认状况下布局视口的宽度等于浏览器宽度,那是否是展现起来更加的不友好。也就是说,若是一个 div
的宽度为20%,那么它在布局视口宽度为 980px
的时候,展现给用户的像素还有196px,而若是宽度只有 375px
的状况下,宽度只有 75px
,展现的大小相差特别大。
因此,浏览器厂商为了让用户在小屏幕下网页也可以显示地很好,因此把布局视口宽度设置地很大,通常在 768px~1024px
之间,最多见的宽度是 980px
。这个宽度能够经过 document.documentElement.clientWidth
获得。
视觉视口
对于视觉视口来讲,这个东西是呈现给用户的,它是用户看到网页区域内CSS像素的数量。因为用户能够自行进行缩放控制,因此这个视口并非开发者须要重点关注的。
值得注意的是,在移动端缩放不会改变布局视口的宽度,当缩小的时候,屏幕覆盖的css像素变多,视觉视口变大,反之亦然。
而在PC端,缩放对应布局宽度和视觉窗口宽度都是联动的。而浏览器宽度自己是固定的,不管怎么缩放都不受影响。
若是对上面的宽度仍是很乱,那么这里有一个表格能够帮助你理清思路。
如下表格横向都以浏览器窗口的宽度做为基准:
对于PC端来讲:
对于移动端来讲:
理想视口
以上,布局视口很明显对用户十分的不友好,彻底忽略了手机原本的尺寸。
因此苹果引入了理想视口的概念,它是对设备来讲最理想的布局视口尺寸。理想视口中的网页用户最理想的宽度,用户进入页面的时候不须要缩放。
那么很明显,所谓的理想宽度就是浏览器(屏幕)的宽度了。
因此就有了下面的这段代码:
<meta name ="viewport" content="width=device-width">
然而,这段代码其实也并不完美,在IE浏览器中,因为横屏竖屏的切换会对其形成影响,为了解决这个兼容性的问题,最后再加上一句,就有了如今的:
<meta name="viewport" content="width=device-idth,initial-scale=1">
initial-scale=1 的意思是初始缩放的比例是1,使用它的时候,同时也会将布局视口的尺寸设置为缩放后的尺寸。而缩放的尺寸就是基于屏幕的宽度来的,也就起到了和
width=device-width```一样的效果。
另外,值得一提的是,咱们在进行媒体查询的时候,查询的宽度值其实也是布局视口的宽度值。
有时候咱们会发现,当咱们在适某一机型的时候,显示上没什么问题。可是一旦我换到另一部手机,发现出现了模糊的状况,尤为以图片更为显著。
其实这个问题,就是涉及到了上面讲到的一个属性:设备像素比,即咱们常常说的dpr。下面先来看dpr的表现:
假设如今有一台iphone6,那么它的设备独立像素是375x667,dpr为2,尺寸是4.7in,那么物理像素就是750x1334。
一样的咱们也有一台不知名的设备,它的设备独立像素恰好也是375x667,尺寸也是4.7in,可是dpr为1,此时的物理像素就是375x667。
因而,它们的屏幕表现以下:
在不一样的屏幕上,不管是普通屏幕仍是retina屏幕,css像素所呈现的大小是一致的。(若是不理解这句话,能够写一个2px的正方形使用谷歌控制台移动设备调试,在不一样的设备之间来回切换,你会发现大小实际上是同样的。一开始我总觉得这个css像素的实际宽高由于受到dpr的影响而在不一样设备上的长宽是不一致的。)
不一样的是,1个css像素对应(覆盖)的物理像素个数。
因此,若是咱们想要在这两个屏幕显示这么一个css样式:
width: 2px;
heigth: 2px;
在普通屏幕下,也就是dpr为1的屏幕中,1个css像素对应(覆盖)的是一个物理像素。在retina屏幕下,1个css像素对应(覆盖)的是4个物理像素。换句话说,就是dpr为2的设备。看下面这张图:
浅显的理解就是能够看做是2cmx2cm的正方形被切割成四块,而后遇到dpr为2的时候,被切割的四块又被分别切割成四块,可是总面积不变。
知道了1个css像素覆盖的物理像素可能不一样,就好理解为何会出现模糊的状况了。
这里又讲到一个名词:位图像素。
位图像素是栅格图像(如:png,jpg,gif等)最小的数据单元。每个位图像素都包含着一些自身的显示信息。(如:显示位置,颜色值,透明度等)
理论上来讲,1个位图像素对应1个物理像素,图片才能等到完美清晰的展现。
可是上面说过,在retina屏幕上,会出现1个位图像素对应多个物理像素。
仍是以iphone6为例,1个位图像素对应4个物理像素。因为单个位图像素已是最小的数据单位了,它不能再被进行切割。因而为了可以显示出来,就只能就近取色,从而致使所谓的图片模糊问题。以下:
很明显,因为位图像素不够分而产生模糊的状况,解决的办法十分简单,就是使用跟dpr同个倍数大小的图片。好比iphone6,一个200x300的 img
标签,原图就要提供400x600的大小。
那么当加载到 img
标签中,浏览器会自动对每1px的css像素减半,能够理解为此时仍是维持着1:1的css像素:物理像素,不产生模糊。
这个作法其实就是手淘团队在作retina适配的一个重要的原理之一,后面会讲到,这里先放着不说。
反向思考一下,若是普通屏幕,也就是dpr为1的屏幕,也使用了两倍的图片,会发生什么样的状况呢?
很明显,在普通屏幕下,200×300的 img
标签,所对应的物理像素个数就是200×300个,而两倍图片的位图像素个数则是200x300x4,因而就出现一个物理像素点对应4个位图像素点,因此它的取色也只能经过必定的算法进行缩减,显示结果就是一张只有原图像素总数四分之一,肉眼看上去虽然图片不会模糊,可是会以为有点色差。(其实就是模糊的逆向过程)
用图片来表示就是:
这里摘取了网上一篇博文的demo来阐述上面所说的问题。
以上是一张100x100的图片,分别放在了100x100,50x50,25x25的容器中,在retina屏幕下面的显示效果。
经过取色器放大镜能够看出边界像素点的差异:
在图一中,边界像素点就近取色,色值介于红白之间,偏淡,图片看上去会模糊(能够理解为图片拉伸)。
在图二中,图片正常,很清晰。
在图三中,边界像素点就近取色,色值介于红白之间,偏浓,图片看上去有色差。
现今,适配手机端的传统rem布局已经逐步被手淘团队的一套flexible布局代替。
具体的实现方式以及细节这里也不铺开来讲,具体参考w3cplus的一篇文章,很容易读懂和理解。
这里我更想分析一下flexible.js作法的意义和缘由。
读过文章以后,相信你们应该对整个开发适配的流程比较熟悉了。
假设如今要适配一个iphone6的设备。上面已经说过了iphone6的各个参数,这里再也不赘述,须要的自行上移查看。
因而:
设计师给了一个750px宽度的设计稿(注意这里是750px而不是375px)
前端工程师用750px的这个比例开始还原
把宽高是px的转换成rem
字体使用px而不使用rem
flexible.js会自动判断dpr进行整个布局视口的放缩
从flexible.js中可见,在宽高中使用的是rem,这是为了保证在不一样宽度尺寸的设备中可以保证布局的等比例缩放。
而为何字体不使用rem而是采用px呢?
首先,用过rem单位的小伙伴都会发现,使用rem后因为不一样的尺寸,换算以后出现各类奇奇怪怪的数值,最为明显的就是更多的小数位,好比 13.755px
之类的数值。在浏览器中,各浏览器中对小数点的计算存在误差,并且有些带小数的 font-size
值在特定的浏览器显示并不够清晰。
其次,咱们并不但愿在小屏幕下面显示跟大屏幕同等量的字体。而且若是使用rem的话,那么因为等比例的存在,在小屏幕下就会存在小屏幕字体更小的状况,不利于咱们更好的去阅读,违背了适配的初衷。因此,对于字体的适配,更好的作法就是使用px和媒体查询来进行适配。
因此,也就不难解释为何要对 font-size
进行放大的处理了,以下的sass代码:
@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; } }
因为retina屏幕下dpr的不一样,咱们又想显示的字体同样大,因而就给字体再增大dpr的倍数,这样当缩小dpr倍的时候,那么字体也就和设计稿所示的大小同样大了,在不一样的手机中显示的大小也是一致的。
从flexible.js的代码中能够知道,flexible布局仅仅只是针对iPhone进行适配,而默认全部的安卓设备都强制性设置dpr为1。
因而,由于这个缘故,不少小伙伴可能就会产生这样的问题:为何安卓不用retina屏幕,安卓下面是否是就不会有模糊的问题?
其实否则,模糊的本质是由于dpr,而安卓手机不一样的设备的dpr也是不尽相同的。也就是说,安卓手机下也存在模糊的状况。只不过它的屏幕不叫retina屏幕,没有这个叫法,因此不少小伙伴都误认为安卓手机没有这个毛病。
那么问题又来了?既然也有模糊的毛病,那么为何安卓手机不进行适配呢?
问题就在这里了,有兴趣的小伙伴能够去看一下大中华的安卓手机,dpr参数五花八门,从1到4,连1.7五、2.75这种奇葩的数字也有,因此我的以为权衡之下,直接简单“粗暴”把安卓手机所有设置为1,是效率和收益更高的作法。
固然,也有人进行了flexible.js的改进,就是对dpr比较正常的安卓手机进行适配,也就是说只适配dpr为整数的安卓设备。对于那些奇葩的dpr为1.75的设备直接忽略。实现这个并不难,有兴趣的小伙伴们能够试下。
最后,对于响应式和自适应的区别,网上有各类各样的解释。
我的认为,其实不必把它讲得那么复杂,知乎上有个小伙伴讲我以为就很白话文:
响应式针对的是不一样分辨率设备而进行的适配式设计,以利用@media规则为主要手段,而自适应则忽略@media以比例布局为主,目的是适应不一样的浏览器窗口大小。
因而咱们会发现,现今大型网站,例如说淘宝网,已经没有作响应式了。什么意思呢?
咱们会发现,淘宝网手机端和网页端使用的是两个域名,也就是说,不一样的客户端已经再也不共用一套dom结构了。而是区分开来作自适应。而后每次用户访问的时候它就根据客户端的类型重定向。
为何呢?
试想一下淘宝这种大型网站,一个分页下的商品条目特别多,而且每一个商品条目的dom结构又十分复杂,并且pc端每每显示的信息是要比手机端更多的。若是不分开作两套,而是直接用响应式的话,那么pc端上显示的不少dom就要在手机端上隐藏,结果这些dom都没有被用到,可是却加载了。在这个流量和速度至上的时代,代码冗余先不说,多加载的这些无用的代码而消耗的流量,从某种意义上来讲就已经损失了不少的效益。
以上,就是本文的所有啦。
文章有借鉴,借鉴的连接都会在这里放出来。
前辈们的经验和知识很宝贵,咱们须要作的,是站在巨人的肩膀上,去提炼这些东西,有本身更好的理解、思考和开拓新知识面。
相关连接:
移动端适配方案(主要讲解的是移动端视口方面的知识):
https://segmentfault.com/a/1190000004336869
https://segmentfault.com/a/1190000004358316
Retina屏幕下模糊的由来:
http://mobile.51cto.com/web-484304.htm
手淘flexible.js布局:http://www.w3cplus.com/mobile/lib-flexible-for-html5-layout.html