目录
- 为什么需要做适配
- 基本概念
- 视口
- 适配方案
- 调研
为什么需要做适配
- 各个移动端设备,屏幕尺寸、分辨率大小不一致
- 让拥有不同屏幕大小的终端设备拥有一致的 UI 界面
高清屏幕带来的问题
- 1px问题
- 高清屏图片显示模糊
基本概念
- 屏幕尺寸
- 屏幕密度
- 物理像素
- 分辨率
- 设备独立像素
- 物理分辨率逻辑分辨率
- CSS 像素
- 设备像素比
屏幕尺寸
- 屏幕对角线的长度,单位英寸
- 1英寸 = 2.54厘米
物理像素(设备像素)
- 设备屏幕上真实存在的像素点
- 是屏幕呈像的最小单位
- 每个物理像素由3个颜色像素构成
- 每个物理像素可以表示2^24种颜色
屏幕密度(PPI)
- 屏幕密度是指一个设备表面上存在的像素数量,它通常以每英寸有多少像素来计算。
- PPI = √(X^2+Y^2)/ Z
iphone 6 屏幕 PPI: √(750^2+ 1334^2)/ 4.7 = 325.61
物理分辨率
- 物理分辨率是指纵横向上的物理像素点数
- iphone6 屏幕分辨率: 750 * 1334
现在设备的物理分辨率在变得越来越大,这样就暴露出来一个问题
设备独立像素(逻辑像素)
- 计算机坐标系统中的一个点
- 可以由程序使用的虚拟像素
逻辑分辨率
- 逻辑分辨率是指纵横方向上的设备独立像素点数
CSS 像素
- 虚拟像素
- CSS 像素单位是 px 是一个相对的单位,主要使用在浏览器上,用来精确度量 Web 页面上的内容。
一般情况之下
,CSS 像素称可以等同于设备独立像素。
<meta name="viewport" content="width=device-width, initial-scale=1" />
设备像素比(dpr)
- 设备像素比简称为 dpr,其定义了物理像素和设备独立像素的对应关系。
它的值可以按下面的公式计算得到:
设备像素比 = 物理像素 / 设备独立像素
通过 JS 来获取 window.devicePixelRatio
视口
开发网页时,head中总有这么一个标签:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
什么是viewport
视口 (viewport) 代表当前可见的计算机图形区域。在 Web 浏览器术语中,通常与浏览器窗口相同,但不包括浏览器的 UI, 菜单栏等——即指你正在浏览的文档的那一部分。
- 在尺寸较大的设备中,在这些设备上,应用显示区域不一定是全屏的,viewport 是浏览器窗口的大小。
- 在大多数移动设备中,浏览器是全屏的,viewport 是整个屏幕的大小。
- 视口在CSS标准文档中称为初始包含块
可以使用 document.documentElement.clientWidth 获取视口宽度
窄屏设备的问题
早期移动设备物理像素点数宽度多数在 320、480 以及 640px
- 需要不断的滚动来保证阅读的连续性,体验糟糕
放大 viewport
- 页面缩小,需要通过放大和滑动来浏览细节。
- 滚动条条问题依然存在
- 限制了依据视口宽度做媒体查询机制的有效性
根据设备宽度而变化的视口
- 可以使用媒体查询来做移动端适配,我们可以设置 viewport 宽度为 device-width,以保证媒体查询技术的有效性
- 可以结合各种相对长度单位(%/rem/vw 等),设置合适的 viewport,以实现布局伸缩和内容大小固定的完美统一。
分类
- 视觉视口
- 布局视口
- 理想视口
布局视口
<meta name="viewport" width="device-width">
手机上,为了容纳为桌面浏览器设计的网站,默认的布局视口的宽度远大于屏幕的宽度,布局视口的出现,在极大程度上帮助了桌面网站到移动设备上的转移。可以通过document.documentElement.clientWidth 来获取。<br /> 在 pc 端,单独一个 width 为 20%的元素最终拿到的值要根据初始包含块的 width 来决定,因为我们横向的布局都是按初始包含块开始填的,在移动端一样,不过我们这个时候应该叫它布局视口。
用户在缩放是视口的大小是如何变化的?
视觉视口
视觉视口语设备屏幕一样宽,并且它的css像素的数量会随用户的缩放而改变visual viewport的宽度可以通过window.innerWidth 来获取,但在Android 2, Oprea mini 和 UC 8中无法正确获取。
理想视口
视觉视口语设备屏幕一样宽,并且它的css像素的数量会随用户的缩放而改变visual viewport的宽度可以通过window.innerWidth 来获取,但在Android 2, Oprea mini 和 UC 8中无法正确获取。
以 iphone6 手机为例
- 屏幕物理分辨率:750*1334
- 屏幕逻辑分辨率:375*667 (screen.width/height)
- 设备像素比(dpr):2 (window.devicePixelRatio)
- 浏览器默认视口宽度:980 (document.documentElement.clientWidth)
视口meta标签
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
属性名 | 取值 | 描述 |
---|---|---|
width | device-width | 或正整数 定义视口的宽度,单位为像素,一般为 device-width:表示宽度为设备屏幕的宽度 |
initial-scale | [0.0-10.0] | 定义初始缩放值,一般设置为 1.0 |
minimum-scale | [0.0-10.0] | 定义缩小最小比例,它必须小于或等于 maximum-scale 设置 |
maximum-scale | [0.0-10.0] | 定义放大最大比例,它必须大于或等于 minimum-scale 设置 |
user-scalable | yes / no | 定义是否允许用户手动缩放页面,默认值 yes |
PPK的三大视口理论
在这里介绍《移动 web 手册》这本书中介绍了 3 大视口理论,分别为布局视口、视觉视口、理想视口
- 在桌面浏览器上,浏览器的窗口是约束我们 CSS 布局的视口(又称为初始包含块)
- 在手机上,桌面视口被拆分为俩个:布局视口和视觉视口,布局视口限制我们的 CSS 布局,视觉视口决定用户看的到什么
- 视觉视口宽度:window.innerWidth
- 布局视口宽度:document.documentElement.clientWidth
- 理想视口,它是对设备来说最理想的布局视口尺寸。理想视口中的网页用户最理想的宽度,用户进入页面的时候不需要缩放。
我只需要加入, 然而,这段代码其实也并不完美,在 IE 浏览器中,由于横屏竖屏的切换会对布局视口造成影响,为了解决这个兼容性的问题,最后再加上一句,就有了现在的:
适配方案
- 响应式设计
- 自适应设计
响应式设计方案
响应式设计方案,常见于 PC、移动等多端共用一套代码的场景,比如 bootstrap 站点
自适应设计
为了在特定的设备上显示最好的视觉效果,大部分移动端产品都有了区分于 PC 的专门的 m 站。
其技术实现通常为:服务器根据浏览器请求的 user-agent 判断设备类型,然后返回(或重定向)对应的站点内容。
自适应设计主要有 2 类: 布局伸缩式、等比缩放式
布局伸缩式
常见于排版比较简单的信息流展示类业务。其布局特点一般为横向伸缩,竖向高度固定或由内容填充决定;文字图标等网页内容一般会固定大小,且在宽屏窄屏上的视觉大小保持一致。
技术方案
- 设置 viewport 宽度为 device-width,保证 px 为单位取值的一些文字图标等网页内容视觉上在宽窄屏大小一致。
- 布局方案:灵活使用相对单位%或弹性布局,以保证布局的横向伸缩和容器内各元素的大小间距符合预期;
等比缩放式
等比缩放顾名思义整个页面根据屏幕宽度的不同进行等比缩放,常见于产品类、运营类等业务场景,
等比缩放式
Flexible 方案
由于在 2014 年之前,视口单位(vw、vh)还没得到个浏览器厂商的支持, 淘宝的前端团队借助 js 控制 viewport 的能力, 使用 rem 单位,去模拟出 vw 的特性来实现整个页面内容的等比例缩放,在项目中引入flexible后,我们在页面上统一使用rem单位来布局页面。
1. 使用 rem 模拟 vw 特性适配多种屏幕尺寸
- rem是以根元素的字体大小为基准。例:html的font-size: 16px,则1rem = 16px
- Flexible将整个页面的宽度切成了10份,然后将计算出来的页面宽度的1/10设置为html节点的fontSize,也就意味着,之后我们在当前页面的html节点的子节点上应用rem为单位时都是按照页面比例来计算的。
var docEl = document.documentElement;
function setRemUnit() {
var rem = docEl.clientWidth / 10;
docEl.style.fontSize = rem + 'px';
}
setRemUnit();
2. 控制 viewport 的 width 和 scale 值适配高倍屏显示
- 设置viewport的width为device-width,改变浏览器viewport的默认宽度为理想的视口宽度,从而使得用户可以看到完整的布局的内容。
- 等比设置viewport的initial-scale、maximum-scale、minimum-scale的值,从而实现1物理像素=1css像素,以适配高倍屏的显示效果(就是在这个地方规避了的“1px问题”)
var metaEL = doc.querySelector('meta[name="viewport"]');
var dpr = window.devicePixelRatio;
var scale = 1 / dpr;
metaEl.setAttribute(
'content',
'width=device-width, initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no',
);
使用视口单位
- vw(Viewport’s width):1vw 等于视口宽度的 1%
- vh(Viewport’s height) :1vh 等于视口高度的 1%
- vmin : vw 和 vh 中的较小值
- vmax : 选取 vw 和 vh 中的最大值
高清屏图片模糊问题
解决方法
在 dpr=2 的屏幕上展示两倍图(@2x),在 dpr=3 的屏幕上展示三倍图(@3x)
image-set
.avatar {
background-image: url('conardLi_1x.png');
background-image: -webkit-image-set('conardLi_2x.png' 2x, 'conardLi_3x.png' 3x);
}
使用 img 标签的 srcset 属性,浏览器会自动根据像素密度匹配最佳显示图片
<img src="avatar_1x.png" srcset="avatar_2x.png 2x, avatar_3x.png 3x" />
svg
svg的全称是可缩放矢量图(Scalable Vector Graphics)。不同于位图的基于像素,SVG 则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。
调研
小红书
- 使用 rem 适配
- 最大基准值为 60px
- 字体和页面都进行缩放
- 配合 媒体查询,限制 body 的最大宽度
@media screen and (min-width: 768px) body {
width: 450px !important;
}
拍拍贷
- vm 适配
- 不限制页面宽度
饿了么
- rem + vw 适配
- 对 viewport 进行了缩放
- html 元素的 font-size 依然由 px 指定
- 具体元素的布局上使用 vw + rem 的形式
- 没有限制布局宽度
携程
- px+flex+百分比
- 固定 1 倍 vieport
- 设置 body 的最大宽度为 max-width: 540px;
总结
- 新闻,社区等可阅读内容较多的场景:px+flex+百分比
- 对视觉组件种类较多,视觉设计对元素位置的相对关系依赖较强的移动端页面:vw + rem
谢谢观看