web必知,多终端适配
导读
移动端适配,是我们在开发中经常会遇到的,这里面可能会遇到非常多的问题:
1px问题UI图完美适配方案iPhoneX适配方案- 横屏适配
- 高清屏图片模糊问题
- ...
上面这些问题可能我们在开发中已经知道如何解决,但是问题产生的原理,以及解决方案的原理可能会模糊不清。在解决这些问题的过程中,我们往往会遇到非常多的概念:像素、分辨率、PPI、DPI、DP、DIP、DPR、视口等等,你真的能分清这些概念的意义吗?
本文将从移动端适配的基础概念出发,探究移动端适配各种问题的解决方案和实现原理。
一、英寸
一般用英寸描述屏幕的物理大小,如电脑显示器的17、22,手机显示器的4.8、5.7等使用的单位都是英寸。
需要注意,上面的尺寸都是屏幕对角线的长度:

二、分辨率
2.1 像素
像素即一个小方块,它具有特定的位置和颜色。
图片、电子屏幕(手机、电脑)就是由无数个具有特定颜色和特定位置的小方块拼接而成。
像素可以作为图片或电子屏幕的最小组成单位。
下面我们使用sketch打开一张图片,将这些图片放大即可看到这些像素点:

通常我们所说的分辨率有两种,屏幕分辨率和图像分辨率。
2.2 屏幕分辨率
屏幕分辨率指一个屏幕具体由多少个像素点组成。
iPhone XS Max 和 iPhone SE的分辨率分别为2688 x 1242和1136 x 640。这表示手机分别在垂直和水平上所具有的像素点数。
当然分辨率高不代表屏幕就清晰,屏幕的清晰程度还与尺寸有关。
2.3 图像分辨率
我们通常说的图片分辨率其实是指图片含有的像素数,比如一张图片的分辨率为800 x 400。这表示图片分别在垂直和水平上所具有的像素点数为800和400。
同一尺寸的图片,分辨率越高,图片越清晰。
2.4 PPI
PPI(Pixel Per Inch):每英寸包括的像素数。
PPI可以用于描述屏幕的清晰度以及一张图片的质量。
使用PPI描述图片时,PPI越高,图片质量越高,使用PPI描述屏幕时,PPI越高,屏幕越清晰。
在上面描述手机分辨率的图片中,我们可以看到:iPhone XS Max 和 iPhone SE的PPI分别为458和326,这足以证明前者的屏幕更清晰。
2.5 DPI
DPI(Dot Per Inch):即每英寸包括的点数。
这里的点是一个抽象的单位,它可以是屏幕像素点、图片像素点也可以是打印机的墨点。
平时你可能会看到使用DPI来描述图片和屏幕,这时的DPI应该和PPI是等价的,DPI最常用的是用于描述打印机,表示打印机每英寸可以打印的点数。
一张图片在屏幕上显示时,它的像素点数是规则排列的,每个像素点都有特定的位置和颜色。
当使用打印机进行打印时,打印机可能不会规则的将这些点打印出来,而是使用一个个打印点来呈现这张图像,这些打印点之间会有一定的空隙,这就是DPI所描述的:打印点的密度。
在上面的图像中我们可以清晰的看到,打印机是如何使用墨点来打印一张图像。
所以,打印机的DPI越高,打印图像的精细程度就越高,同时这也会消耗更多的墨点和时间。
三、设备独立像素
实际上,上面我们描述的像素都是物理像素,即设备上真实的物理单元。
下面我们来看看设备独立像素究竟是如何产生的:
智能手机发展非常之快,在几年之前,我们还用着分辨率非常低的手机,比如分辨率是320x480,我们可以在上面浏览正常的文字、图片等等。
但是,随着科技的发展,低分辨率的手机已经不能满足我们的需求了。很快,更高分辨率的屏幕诞生了,比如640x940,正好是两倍。
理论上来讲,在白色手机上相同大小的图片和文字,在黑色手机上会被缩放一倍,因为它的分辨率提高了一倍。这样,岂不是后面出现更高分辨率的手机,页面元素会变得越来越小吗?
然而,事实并不是这样的,我们现在使用的智能手机,不管分辨率多高,他们所展示的界面比例都是基本类似的。乔布斯在iPhone4的发布会上首次提出了Retina Display(视网膜屏幕)的概念,它正是解决了上面的问题,这也使它成为一款跨时代的手机。

在iPhone4使用的视网膜屏幕中,把2x2个像素当1个像素使用,这样让屏幕看起来更精致,但是元素的大小却不会改变。
如果手机使用了视网膜屏幕的技术,那么显示结果应该是下面的情况,比如列表的宽度为300个像素,那么在一条水平线上,老手机会用300个物理像素去渲染它,而新手机实际上会用600个物理像素去渲染它。
我们必须用一种单位来同时告诉不同分辨率的手机,它们在界面上显示元素的大小是多少,这个单位就是设备独立像素(Device Independent Pixels)简称DIP或DP。上面我们说,列表的宽度为300个像素,实际上我们可以说:列表的宽度为300个设备独立像素。

打开chrome的开发者工具,我们可以模拟各个手机型号的显示情况,每种型号上面会显示一个尺寸。
比如iPhone X显示的尺寸是375x812,实际iPhone X的分辨率会比这高很多,这里显示的就是设备独立像素。
3.1 设备像素比
设备像素比device pixel ratio简称dpr,即物理像素和设备独立像素的比值。
在web中,浏览器为我们提供了window.devicePixelRatio来帮助我们获取dpr。
在css中,可以使用媒体查询min-device-pixel-ratio,区分dpr:
@media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2){ }
在React Native中,我们也可以使用PixelRatio.get()来获取DPR。
当然,上面的规则也有例外,iPhone 6、7、8 Plus的实际物理像素是1080 x 1920,在开发者工具中我们可以看到:它的设备独立像素是414 x 736,设备像素比为3,设备独立像素和设备像素比的乘积并不等于1080 x 1920,而是等于1242 x 2208。
实际上,手机会自动把1242 x 2208个像素点塞进1080 * 1920个物理像素点来渲染,我们不用关心这个过程,而1242 x 2208被称为屏幕的设计像素。我们开发过程中也是以这个设计像素为准。
实际上,从苹果提出视网膜屏幕开始,才出现设备像素比这个概念,因为在这之前,移动设备都是直接使用物理像素来进行展示。
紧接着,Android同样使用了其他的技术方案来实现DPR大于1的屏幕,不过原理是类似的。由于Android屏幕尺寸非常多、分辨率高低跨度非常大,不像苹果只有它自己的几款固定设备、尺寸。所以,为了保证各种设备的显示效果,Android按照设备的像素密度将设备分成了几个区间:

Android设备不一定严格按照上面的分辨率,每个类型可能对应几种不同分辨率,所以,每个Android手机都能根据给定的区间范围,确定自己的DPR,从而拥有类似的显示。Android设备仍然不能做到在展示上完全相等。3.3 WEB端开发
在写CSS时,我们用到最多的单位是px,即CSS像素,当页面缩放比例为100%时,一个CSS像素等于一个设备独立像素。
但是CSS像素是很容易被改变的,当用户对浏览器进行了放大,CSS像素会被放大,这时一个CSS像素会跨越更多的物理像素。
页面的缩放系数 = CSS像素 / 设备独立像素。
四、视口
视口(viewport)代表当前可见的计算机图形区域。在Web浏览器术语中,通常与浏览器窗口相同,但不包括浏览器的UI, 菜单栏等——即指你正在浏览的文档的那一部分。
一般我们所说的视口共包括三种:布局视口、视觉视口和理想视口,它们在屏幕适配中起着非常重要的作用。
4.1 布局视口
4.2 视觉视口

4.3 理想视口

布局视口在移动端展示的效果并不是一个理想的效果,所以理想视口(ideal viewport)就诞生了:网站页面在移动端展示的理想大小。
如上图,我们在描述设备独立像素时曾使用过这张图,在浏览器调试移动端时页面上给定的像素大小就是理想视口大小,它的单位正是设备独立像素。
4.4 Meta viewport
<meta> 元素表示那些不能由其它HTML元相关元素之一表示的任何元数据信息,它可以告诉浏览器如何解析页面。
我们可以借助<meta>元素的viewport来帮助我们设置视口、缩放等,从而让移动端得到更好的展示效果。
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1; minimum-scale=1; user-scalable=no;">
上面是viewport的一个配置,我们来看看它们的具体含义:
Value |
可能值 | 描述 |
|---|---|---|
width |
正整数或device-width |
以pixels(像素)为单位, 定义布局视口的宽度。 |
height |
正整数或device-height |
以pixels(像素)为单位, 定义布局视口的高度。 |
initial-scale |
0.0 - 10.0 |
定义页面初始缩放比率。 |
minimum-scale |
0.0 - 10.0 |
定义缩放的最小值;必须小于或等于maximum-scale的值。 |
maximum-scale |
0.0 - 10.0 |
定义缩放的最大值;必须大于或等于minimum-scale的值。 |
user-scalable |
一个布尔值(yes或者no) |
如果设置为 no,用户将不能放大或缩小网页。默认值为 yes。 |
4.5 移动端适配
为了在移动端让页面获得更好的显示效果,我们必须让布局视口、视觉视口都尽可能等于理想视口。
device-width就等于理想视口的宽度,所以设置width=device-width就相当于让布局视口等于理想视口。
由于initial-scale = 理想视口宽度 / 视觉视口宽度,所以我们设置initial-scale=1;就相当于让视觉视口等于理想视口。
这时,1个CSS像素就等于1个设备独立像素,而且我们也是基于理想视口来进行布局的,所以呈现出来的页面布局在各种设备上都能大致相似。
4.7 获取浏览器大小
浏览器为我们提供的获取窗口大小的API有很多,下面我们再来对比一下

window.innerHeight:获取浏览器视觉视口高度(包括垂直滚动条)。window.outerHeight:获取浏览器窗口外部的高度。表示整个浏览器窗口的高度,包括侧边栏、窗口镶边和调正窗口大小的边框。window.screen.Height:获取获屏幕取理想视口高度,这个数值是固定的,设备的分辨率/设备像素比window.screen.availHeight:浏览器窗口可用的高度。document.documentElement.clientHeight:获取浏览器布局视口高度,包括内边距,但不包括垂直滚动条、边框和外边距。document.documentElement.offsetHeight:包括内边距、滚动条、边框和外边距。document.documentElement.scrollHeight:在不使用滚动条的情况下适合视口中的所有内容所需的最小宽度。测量方式与clientHeight相同:它包含元素的内边距,但不包括边框,外边距或垂直滚动条。
六、移动端适配方案
尽管我们可以使用设备独立像素来保证各个设备在不同手机上显示的效果类似,但这并不能保证它们显示完全一致,我们需要一种方案来让设计稿得到更完美的适配。
6.1 flexible方案
lib-flexible这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport来替代此方案。
下面我们来看看现在最流行的vh、vw方案。
6.2 vh、vw方案
vh、vw方案即将视觉视口宽度 window.innerWidth和视觉视口高度 window.innerHeight 等分为 100 份。
上面的flexible方案就是模仿这种方案,因为早些时候vw还没有得到很好的兼容。
vw(Viewport's width):1vw等于视觉视口的1%vh(Viewport's height):1vh为视觉视口高度的1%vmin:vw和vh中的较小值vmax: 选取vw和vh中的较大值

如果视觉视口为375px,那么1vw = 3.75px,这时UI给定一个元素的宽为75px(设备独立像素),我们只需要将它设置为75 / 3.75 = 20vw。
这里的比例关系我们也不用自己换算,我们可以使用PostCSS的 postcss-px-to-viewport 插件帮我们完成这个过程。写代码时,我们只需要根据UI给的设计图写px单位即可。
当然,没有一种方案是十全十美的,vw同样有一定的缺陷:
px转换成vw不一定能完全整除,因此有一定的像素差。- 比如当容器使用
vw,margin采用px时,很容易造成整体宽度超过100vw,从而影响布局效果。当然我们也是可以避免的,例如使用padding代替margin,结合calc()函数使用等等...
web必知,多终端适配的更多相关文章
- 【web必知必会】——图解HTTP(上)
本篇总结关于http的相关知识,主要内容参考如下导图: 主要讲解的内容有: 1 URL与URI的区别. 2 请求报文与相应报文的内容. 3 GET与POST的区别. 4 http的cookie.持久化 ...
- 【web必知必会】—— 图解HTTP(转)good
本篇总结关于http的相关知识,主要内容参考如下导图: 主要讲解的内容有: 1 URL与URI的区别. 2 请求报文与相应报文的内容. 3 GET与POST的区别. 4 http的cookie.持久化 ...
- 【web必知必会】—— 使用DOM完成属性填充
本文介绍了使用DOM的简单方法实现动态加载图片的功能. 前文介绍了: 1 DOM四个常用的方法 首先看一下效果,初始时是一个相册,可以点击导航,切换图片,并切换下方显示内容: 点击house,可以动态 ...
- 【web必知必会】—— DOM:四个常用的方法
终于开始复习DOM的知识了,这一阵忙乎论文,基本都没好好看技术的书. 记得去年实习的时候,才开始真正的接触前端,发现原来JS可以使用的如此灵活. 说起DOM就不得不提起javascript的组成了,j ...
- 【web必知必会】—— 图解HTTP(下)
上一篇<图解HTTP 上>总结了HTTP的报文格式,发送方式,以及HTTP的一些使用. 本文再总结以下内容: 1 http状态码 2 http报文首部中的各字段 3 http中的身份验证 ...
- Visual Studio (VS IDE) 你必须知道的功能和技巧 - 【.Net必知系列】
前言 本文主要阐述一些Visual Studio开发下需要知道的少部分且比较实用的功能,也是很多人忽略的部分.一些不常用而且冷门的功能不在本文范围,当然本文的尾巴[.Net必知系列]纯属意淫,如有雷同 ...
- c++程序员必知的几个库
c++程序员必知的几个库 1.C++各大有名库的介绍——C++标准库 2.C++各大有名库的介绍——准标准库Boost 3.C++各大有名库的介绍——GUI 4.C++各大有名库的介绍——网络通信 5 ...
- 移动端H5页面的最佳终端适配之Flexible
lib-flexible是什么? lib-flexible是一个制作H5适配的开源库,可以点击这里下载相关文件,获取需要的JavaScript和CSS文件. 当然你可以直接使用阿里CDN: <s ...
- 2015 前端[JS]工程师必知必会
2015 前端[JS]工程师必知必会 本文摘自:http://zhuanlan.zhihu.com/FrontendMagazine/20002850 ,因为好东东西暂时没看懂,所以暂时保留下来,供以 ...
随机推荐
- PWN二进制漏洞学习指南
目录 PWN二进制漏洞学习指南 前言 前置技能 PWN概念 概述 发音 术语 PWN环境搭建 PWN知识学习途径 常见漏洞 安全机制 PWN技巧 PWN相关资源博客 Pwn菜鸡小分队 PWN二进制漏洞 ...
- html5的Message信息提示框
1.定义dialog <dialog id="showDialog"> <div>您没有权限访问本页面!</div> </dialog&g ...
- python3 调用 centos 常用系统命令
一.创建目录 1 import os 2 3 base_path = '/data/sw_backup' 4 addr= 'FT' 5 ip='192.168.1.1' 6 path = base_p ...
- linux 安装rabbitmq
1.安装rabbitmq会依赖erlang.socat.unixodbc 下载 unixODBC-2.3.7.tar.gz ,创建路径/usr/local/unixODBC-2.3.7,解压到该路径下 ...
- # Host xx.xxx.x.xxx found: line 1 /root/.ssh/known_hosts updated. Original contents retained as /root/.ssh/known_hosts.old
一直可以ssh登录远程服务器,突然不行了. 原因:远程服务器最近打过安全补丁,安全标识已经更新. 清理本机的安全密匙即可 解决办法: #ssh-keygen -R "需要远程服务器ip地址& ...
- 直播预告|App 首页如何动态化更新?来看蚂蚁技术专家详解「支付宝」全新卡片技术栈
立即前往直播间预约观看 从icon到card,一场内容前置化的变革 从 Windows 时代开始,应用程序图标就成为了用户(流量)的主入口,一直持续到移动端时代. 图标即入口的方式,虽然足够方便但却不 ...
- 修改记事本PE结构弹计算器Shellcode
目录 修改记事本PE结构弹计算器Shellcode 0x00 前言 0x01 添加新节 修改节数量 节表位置 添加新节表信息 0x02 添加弹计算器Shellcode 修改代码 0x03 修改入口点 ...
- Django开发 X-Frame-Options to deny 报错处理
本博客已停更,请转自新博客查看 https://www.whbwiki.com/318.html 错误提示 Refused to display 'http://127.0.0.1:8000/inde ...
- Python使用cx_Oracle模块操作Oracle数据库--通过sql语句和存储操作
https://www.jb51.net/article/125160.htm?utm_medium=referral Python使用cx_Oracle调用Oracle存储过程的方法示例 http ...
- 记一次 .NET 某电商无货源后端服务 死锁分析
一:背景 1. 讲故事 这个月初,星球里的一位朋友找到我,说他的程序出现了死锁,怀疑是自己的某些写法导致mongodb出现了如此尴尬的情况,截图如下: 说实话,看过这么多dump,还是第一次遇到真实的 ...