一、基本概念
1. 设备像素(device pixel, dp):
设备像素又称物理像素(physical pixel),一个物理像素是显示器(手机屏幕)上最小的物理显示单元,意指显示器上一个个的点。从屏幕在工厂生产出的那天起,它上面设备像素点就固定不变了,单位 pt。在操作系统的调度下,每一个设备像素都有自己的颜色值和亮度值。
2. CSS像素:
CSS像素也被称为逻辑像素,是Web编程的概念,独立于设备的用于逻辑上衡量像素的单位,也就是说我们在做网页时用到的CSS像素单位,是抽象的,而不是实际存在的。
3. 设备独立像素(density-independent pixel,dip):
设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: css像素
,只是在android机中CSS像素就不叫“CSS像素”了而是叫”设备独立像素”),然后由相关系统转换为物理像素。所以说,物理像素和设备独立像素之间存在着一定的对应关系,这就是接下来要说的设备像素比
。
4. 设备像素比(device pixel ratio,dpr):
设备像素比 = 设备像素 / 设备独立像素 // 在某一方向上,x方向或者y方向,单位:dpi
在javascript中,可以通过window.devicePixelRatio
获取到当前设备的dpr。
在css中,可以通过-webkit-device-pixel-ratio
,-webkit-min-device-pixel-ratio
和 -webkit-max-device-pixel-ratio
进行媒体查询,对不同dpr的设备,做一些样式适配(这里只针对webkit内核的浏览器和webview)。
5. 物理像素和设备对像素的关系:
在一定的条件下两者它们两者是可以相等的,比如:在PC端浏览器默认情况下(100%,即页面没被缩放),一个物理像素 = 一个设备独立像素。而在移动端可就不一样的,为了让画质更精细,这两个值很多时候是不相等的。这里就该提到一个叫ppi的东西。
PPI 全称是(pixel per inch)翻译下就是每英寸内有多少个像素点,这个像素点指的是设备像素点(物理像素),说得接地气点PPI就是像素密度(pixel density)。PPI的值越高,画质越好,也就是越细腻,看起来更有逼格。计算公式如下:
综合上面几个基本概念,举例如下:
以iphone6
为例:
- 分辨率:
750pt×1334pt
:指屏幕上垂直有1334个物理像素,水平有750个物理像素。 - 设备宽高为
375×667
,可以理解为设备独立像素(或css像素)。 - dpr为2,根据上面的计算公式,其物理像素就是
(375×667)×2
,为750×1334
。 - 屏幕尺寸:
4.7英寸
,注意英寸是长度单位,不是面积单位。4英寸指的是屏幕对角线的长度。 - 屏幕像素密度:根据上面的公式可以计算出ppi为
326dpi
。
上图中可以看出,对于这样的css样式:
width: 2px; height: 2px;
在不同的屏幕上(普通屏幕 vs retina屏幕),css像素所呈现的大小(物理尺寸)是一致的,不同的是1个css像素所对应的物理像素个数是不一致的。
在普通屏幕下,1个css像素 对应 1个物理像素(1:1
)。 在retina 屏幕下,1个css像素对应 4个物理像素(1:4
)。
6. 视口
桌面浏览器中,浏览器的视口就是约束你的css布局视口(又称初始包含块)。它是所有CSS百分比宽度推算的根源,它的作用是给CSS布局限制了一个最大宽度,视口的宽度和浏览器窗口宽度一致。
但是在移动端,情况比较复杂。
6.1 布局视口
一个没有为移动端做优化的网页,会尽可能缩小网页让用户看到所有东西。比如说,以前的博客园:
浏览器厂商为了让用户在小屏幕下网页也能够显示地很好,所以把视口宽度设置地很大,一般在 768px ~ 1024px 之间,最常见的宽度是 980px。
所以,在手机上,视口与移动端浏览器屏幕宽度不再相关联,是完全独立的,这个浏览器厂商定的视口被称为布局视口。
布局视口我们是看不见的,只知道网页的最大宽度是 980px ,并且被缩放在了屏幕内。可以这样设置布局视口的宽度:
<meta name="viewport" content="width=640">
6.2 媒体查询与布局视口
700px指的是布局视口的宽度
@media (min-width: 700px){ ... }
document.documentElement.clientWidth/Height
返回布局视口的尺寸
6.3 视觉视口
视觉视口是用户正在看到的网页的区域,大小是屏幕中CSS像素的数量。
window.innerWidth/Height
返回视觉视口的尺寸
6.4 理想视口
布局视口明显对用户是不友好的,完全忽略了手机本身的尺寸。所以苹果引入了理想视口的概念,它是对设备来说最理想的布局视口尺寸。理想视口中的网页用户最理想的宽度,用户进入页面的时候不需要缩放。
现在讨论所谓的『最理想的宽度』到底是多少?其实,如果我们把布局视口的宽度改成屏幕的宽度不就不用缩放了么。可以这样设置告诉浏览器使用它的理想视口:
<meta name="viewport" content="width=device-width">
定义理想视口是浏览器的事情,并不能简单地认为是开发者定义的,开发者只能使用。
screen.width/height
返回理想视口的尺寸,有严重的兼容性问题—可能返回两种值:
理想视口的尺寸(下载浏览器)
屏幕的设备像素尺寸(内置浏览器)
Understanding viewportk可以测试设备的screen.width值,同一设备的不同浏览器返回的值可能是不一样的。这一情况主要发生在默认浏览器和下载浏览器(如UC、Chrome)之间。
默认浏览器是安卓系统内置的浏览器,它使用的是Webkit而不是Blink。只有在更新安卓系统的时候才能更新它。直到安卓4.3,Google不再更新。下载浏览器都返回的是理想视口尺寸。
7. 缩放
7.1 缩放与设备像素、CSS像素的关系
缩放是在放大或缩小CSS像素,比如一个宽度为 200px 的元素无论放大多少倍,还是200个CSS像素。但是因为这些像素被放大了,所以CSS像素也就跨越了更多的设备像素。缩小则相反。
7.2 缩放与视口
缩放会影响视觉视口的尺寸
页面被用户放大,视觉视口内CSS像素数量减少;被用户缩小,视觉视口内CSS像素数量增多就行了。这个道理应该是不难想的。
用户缩放不会影响布局视口
注意,这是『用户缩放』,后面会说开发者设置缩放的情况
7.3 缩放比例
我们在开发者工具中可以在这里查看缩放比例:
这里的0.3是相对于理想视口的。
在下载浏览器中,可以这么算(理想视口与视觉视口的比):
zoom level = screen.width / window.innerWidth
7.4 禁止缩放和设置缩放
<meta name="viewport" content="user-scalable=no">//禁止缩放 <meta name="viewport" content="initial-scale=2">//设置缩放
使用initial-scale有一个副作用:同时也会将布局视口的尺寸设置为缩放后的尺寸。所以initial-scale=1与width=device-width的效果是一样的。
8. 完美视口
使用initial-scale有一个副作用:同时也会将布局视口的尺寸设置为缩放后的尺寸。所以initial-scale=1与width=device-width的效果是一样的。
<meta name="viewport" content="width=device-width,initial-scale=1">
9. 再谈设备像素比
在谈到像素的时候,讲到除了缩放,屏幕是否为高密度也会影响设备像素和CSS像素的关系。
在缩放程度为100%(这个条件很重要,因为缩放也会影响他们)时,他们的比例叫做设备像素比(device pixel ratio):
dpr = 设备像素 / CSS像素
可以通过JS得到: window.devicePixelRatio
设备像素比也和视口有关:
dpr = 屏幕横向设备像素 / 理想视口的宽
二、适配方案
1. 固定高度,宽度自适应
这也是目前使用最多的方法,垂直方向用定值,水平方向用百分比、定值、flex都行。腾讯、京东、百度、天猫、亚马逊的首页都是使用的这种方法。
随着屏幕宽度变化,页面也会跟着变化,效果就和PC页面的流体布局差不多,在哪个宽度需要调整的时候使用响应式布局调调就行(比如网易新闻),这样就实现了『适配』。
原理:
这种方法使用了完美视口:
<meta name="viewport" content="width=device-width,initial-scale=1">
这样设置之后,我们就可以不用管手机屏幕的尺寸进行开发了。
2. 固定宽度,viewport缩放
设计图、页面宽度、viewport width使用一个宽度,浏览器帮我们完成缩放。单位使用px即可。
目前已知荔枝FM、网易新闻在使用这种方法。有兴趣的同学可以看看是怎么做的。
原理
这种方法需要根据屏幕宽度来动态生成viewport
,生成的 viewport 基本是这样:
<meta name="viewport" content="width=640,initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">
640 是我们根据设计图定下的,0.5 是根据屏幕宽度动态生成的。
生成的viewport告诉浏览器网页的布局视口使用 640px,然后把页面缩放成50%,这是绝对的等比例缩放。图片、文字等等所有元素都被缩放在手机屏幕中。
这个gif图说明了一切:
3. rem做宽度,viewport缩放
这也是淘宝使用的方案,根据屏幕宽度设定 rem
值,需要适配的元素都使用 rem
为单位,不需要适配的元素还是使用 px
为单位。
具体使用方法见使用Flexible实现手淘H5页面的终端适配
我这里给出less的px2rem
。因为less不支持函数,所以需要安装插件 less-plugin-functions ,然后就简单了:
.function{
.px2rem(@px,@base:72px){
return: @px / @base * 1rem;
}
}
这样使用:
div{ width: px2rem(100px); }
使用这个方法的库:
原理
实际上做了这几件事情:
- 动态生成 viewport
- 屏幕宽度设置
rem
的大小,即给<html>
设置font-size
- 根据设备像素比(window.devicePixelRatio)给
<html>
设置data-dpr
这么设置的好处是可以让不同设备的rem
或px
都显示一样的长度。
设置rem
设置rem的意义在于得到一个与屏幕宽度相关的单位,本来vw
是最合适的,但是因为兼容性的问题,只能使用rem
来做。这样,让不同设备的rem
显示一样的长度。
vw是CSS3引入的单位,1vw = 1%窗口宽度
上面的布局我们可以这样:
html{
font-size: 屏幕宽度 / 10;
}
.btn{
width:8.75rem;
height:1.25rem;
}
这样,无论屏幕宽度是多少,.btn
都是相对于屏幕的这么宽,做到了适配。
设置 viewport 缩放 和 data-dpr
这两个设置其实是干的一件事,就是适配高密度屏幕手机的px
单位。
.a{
font-size:12px;
}
[data-dpr="2"] .a{
font-size: 24px;
}
[data-dpr="3"] .a{
font-size: 36px;
}
而缩放是动态的,这样,不同设备下的px
显示一样的长度。
之前说过CSS像素和物理像素与缩放、dpr都有关系,这里说明:
在普通手机上,
.a
字体设置为12px;在dpr是2的手机上,
[data-dpr="2"] .a
字体为24px,又因为页面缩放50%,字体为还是12px
4. 总结
个人认为第三种方案是相对比较好的方案。参考以上方案,来根据我们的需求实现自己的方案。
5. 具体实现方式
5.1 动态设置viewport的scale
var scale = 1 / devicePixelRatio; document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale=' + scale + ',maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
5.2 动态设置html的font-size、data-dpr
function refreshRem() { var rem = docEl.clientWidth / 10; docEl.style.fontSize = rem + 'px'; }
5.3 布局的时候,各元素的css尺寸=设计稿标注尺寸/(设计稿横向分辨率/10)
比如:设计稿是750的,那html的font-size就是75px,如果某个元素的宽度是150px,换算成rem就是150 / 75 = 2rem。
5.4 font-size需要额外的媒介查询,并且font-size不使用rem
div { width: 1rem; height: 0.4rem; font-size: 12px; // 默认写上dpr为1的fontSize } [data-dpr="2"] div { font-size: 24px; } [data-dpr="3"] div { font-size: 36px; }
三、演示Demo和源码
适配方案会不断优化和更新,代码请移步github https://github.com/li-shuaishuai/screen_flex
最新评论
大佬
Nignx主要是后台做负载用,没想到你也这么用心
这个评论虽然不能一针见血,但是喜欢这个文章,一直喜欢这个时间管理法。很好
优秀
你对加密的定义很严谨,在平时及网络各种文章中,通常将 base64 称之为“加密”,上面及文章中提到的“加密”同样是这个意思,并非严格意义的加密。严格讲 base64 是一种编码方式。感谢你的回复。
严格意义上来说 base64 不算是加密(Encryption),而是一种编码形式(Encoding)。对于 UTF-8 这种也可以叫它为 Encoding。 加密(Encryption)是指像 R
Base64: 可逆性。 可以将图片等二进制文件转换为文本文件。 可以把非ASCII字符的数据转换成ASCII字符,避免不可见字符。 MD5: 不可逆性。 任意长度的明文字符串,加密后得到的密文字符
第一个问题BASE64的加密方式和MD5的加密方式在这里 哪种 好用?