是不是还傻傻理不清移动端适配?

291 阅读6分钟

物理像素、设备分辨率、css像素、设备独立像素、设备像素比dpr、像素密度ppi之间的区别

物理像素、设备分辨率

  • 物理像素也叫设备像素,物理像素点是屏幕的最小颗粒,是显示器上的真实像素,每个像素的大小是屏幕固有的属性,屏幕出厂以后就不会再改变。一个彩灯(物理像素)由红、蓝、绿小灯组成,三盏小灯不同的亮度混合出各种色彩

image.png

  • 设备分辨率是指宽和高分别是多少个物理像素,例如常见的显示器的分辨率为 1920 * 1080。

设备独立像素、逻辑分辨率

为什么会出现设备独立像素?

iPhone 3GS 和 iPhone 4/4s 的尺寸都是 3.5 寸,但 iPhone 3GS 的分辨率是 320x480,iPhone 4/4s 的分辨率是 640x960

这意味着,iPhone 3GS 有 320 个物理像素,iPhone 4/4s 有 640 个物理像素

如果我们按照真实的物理像素进行布局,比如说我们按照 320 物理像素进行布局,到了 640 物理像素的手机上就会有一半的空白,为了避免这种问题,就产生了虚拟像素单位

我们统一 iPhone 3GS 和 iPhone 4/4s 都是 320 个虚拟像素,只是在 iPhone 3GS 上,最终 1 个虚拟像素换算成 1 个物理像素,在 iphone 4s 中,1 个虚拟像素最终换算成 2 个物理像素

定义

设备独立像素(device independent pixels)是操作系统定义的一种虚拟像素单位,应用程序将设备独立像素告诉操作系统,操作系统再将设备独立像素转化为设备像素,从而控制屏幕上真正的物理像素点。

什么是逻辑分辨率?

例如屏幕的设备分辨率是1920 * 1200(单位:设备像素),我们可以在当前的分辨率下设置逻辑分辨率是1280 * 800(单位:设备独立像素)。那么横、纵方向的设备像素数量恰好是设备独立像素的1.5倍。这也意味着,设备独立像素的边长是设备像素边长的1.5倍。

逻辑分辨率用屏幕的 宽 * 高 来表示(单位:设备独立像素),我们通过操作系统的分辨率设置来改变设备独立像素的大小。

通俗来讲逻辑分辨率就是以设备独立像素为单位的来表示屏幕的“宽、高”。

CSS像素、dpr、ppi

在CSS使用的px就是指css像素。在css中我们通常使用px作为单位,在PC浏览器中css的1个像素都是对应着电脑屏幕的1个物理像素。

dpr(device pixel ratio),设备像素比,代表设备独立像素到设备像素的转换关系,在JavaScript中可以通过 window.devicePixelRatio 获取

计算公式如下:

当设备像素比为1:1时,使用1(1×1)个设备像素显示1个CSS像素

当设备像素比为2:1时,使用4(2×2)个设备像素显示1个CSS像素

当设备像素比为3:1时,使用9(3×3)个设备像素显示1个CSS像素

在缩放比例为 100% 的情况下,1 个 css 像素大小等于 (1 * 1) 个设备独立像素

在缩放比例为 200% 的情况下,1 个 css 像素大小等于 (2 * 2) 个设备独立像素

在缩放比例为 300% 的情况下,1 个 css 像素大小等于 (3 * 3) 个设备独立像素

ppi (pixel per inch),每英寸像素,表示每英寸所包含的像素点数目,更确切的说法应该是像素密度。数值越高,说明屏幕能以更高密度显示图像

计算公式如下:

layout viewport、visual viewport 以及 ideal viewport

layout viewport

layout viewport为布局视口,是 html 元素的父容器。

visual viewport

visual viewport 为视觉视口,是用户看到的网页部分。

ideal viewport

Ideal Viewport 为理想视口,即网页在设备上的最佳展示大小,不同的设备有自己不同的 ideal viewport,ideal viewport 的宽度等于移动设备的屏幕宽度,所以其是最适合移动设备的 viewport。

meta 标签对 viewport 进行控制

该 meta 标签的作用是让当前 viewport 的宽度等于设备的宽度,同时不允许用户手动缩放。如果你不这样的设定的话,那就会使用那个比屏幕宽的默认 viewport(layout viewport),也就是说会出现横向滚动条
相关的属性意义如下所示

width设置 layout viewport 的宽度,为一个正整数,或字符串 "width-device"
height设置页面的初始缩放值,为一个数字,可以带小数
initial-scale允许用户的最小缩放值,为一个数字,可以带小数
minimum-scale允许用户的最大缩放值,为一个数字,可以带小数
maximum-scale设置 layout viewport 的高度,这个属性对我们并不重要,很少使用
user-scalable是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes 代表允许

适配方案选择

使用 css 媒体查询

基于 css 的媒体查询属性 @media 分别为不同屏幕尺寸的移动设备编写不同尺寸的 css 属性,示例如下所示。虽然此方法能在一定程度上解决移动设备适配的问题,但我们也可以看出其存在以下问题,所以其已几乎被历史潮流淘汰

  • 页面上所有的元素都得在不同的 @media 中定义一遍不同的尺寸,这个代价有点高;
  • 如果再多一种屏幕尺寸,就得多写一个 @media 查询块;
@media only screen and (min-width: 375px) {
  .logo {
    width : 62.5px;
  }
}

@media only screen and (min-width: 360px) {
  .logo {
    width : 60px;
  }
}

@media only screen and (min-width: 320px) {
  .logo {
    width : 53.3333px;
  }
}

使用 rem 单位

rem(font size of the root element)是指相对于根元素的字体大小的单位,如果我们设置 html 的 font-size 为 16px,则如果需要设置元素字体大小为 16px,则写为 1rem。但是其还是必须得借助 @media 属性来为不同大小的设备设置不同的 font-size,相对上一种方案,可以减少重复编写相同属性的代价,简单示例如下所示。
我们也能看到该方案存在以下问题:

  • 不同的尺寸需要写多个 @media;
  • 所有涉及到使用 rem 的地方,全部都需要调用方法 calc() ,这个也挺麻烦的;

@media only screen and (min-width: 375px) {
  html {
    font-size : 375px;
  }
}

@media only screen and (min-width: 360px) {
  html {
    font-size : 360px;
  }
}

@media only screen and (min-width: 320px) {
  html {
    font-size : 320px;
  }
}

//定义方法:calc
@function calc($val){
    @return $val / 1080;
}

.logo{
	width : calc(180rem);
}

flexible 适配方案

使用 rem 模拟 vw 特性适配多种屏幕尺寸

它的核心代码如下所示

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

上面的代码中,将 html 节点的 font-size 设置为页面 clientWidth(布局视口)的 1/10,即1rem就等于页面布局视口的1/10,这就意味着我们后面使用的rem都是按照页面比例来计算的。