移动端开发中的相关概念讲解
1、移动端自适配方案
移动端如何根据不同手机尺寸进行页面的适配
rem 自适应和 vw 自适应
rem 自适配
定义:相对单位,相对于根元素 html 的 font-size 大小
rem 是相对于 html 标签的 font-size 所设定的相对大小的一个相对单位,比如 html 的 font-size 为 750px,则 1rem 在设备上表现为 750px
通用方案:阿里巴巴的 Flexible 方案,html 的 font-size 大小等于页面宽度 10%,相当于把页面等于 10 个 rem
简单方案:头部嵌入一段 script,根据页面宽度改变根元素 html 的 font-size 大小,页面元素的单位用 rem,相当于元素是相对于根元素的 font-size 大小进行自适应变化
;(function(doc, win) {
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function() {
// viewport的宽度
var clientWidth = docEl.clientWidth
if (!clientWidth) return
if (clientWidth >= 750) {
docEl.style.fontSize = '75px'
} else {
docEl.style.fontSize = 75 * (clientWidth / 750) + 'px'
}
}
if (!doc.addEventListener) return
win.addEventListener(resizeEvt, recalc, false)
doc.addEventListener('DOMContentLoaded', recalc, false)
})(document, window)
如何将设计师的设计稿单位 px 转成 rem
例如,设计稿宽度是 750px,当设备宽度为 750px 时,1 个 rem 就是 75px,一个页面的宽度也就是 10 个 rem,px 转 rem 公式为:宽度(px)/rem 基准值(75)
,若用 sass 语法,可以写个 function 进行 rem 转换,也可直接用 postcss 插件:px2rem
来转换
vw 自适配
定义:相对于 viewport 窗口的宽度的大小的 1/100
1vw 就代表 1%宽度的 viewport 的宽度,100vw 代表 1 个 viewport 的宽度
使用 vw 做 css 单位,可以不用动态计算 html 元素的 font-size 大小,页面能根据不同宽度手机做自适应
如何将设计师的设计稿单位 px 转成 vw
例如,设计稿宽度是 750px,当设备宽度为 750px 时,1 个 vw 就是 7.5px,一个页面宽度就是 100vw
同理,计算公式:宽度(px)/ vw基准值(7.5)
也可以用 postcss 插件(postcss-px-to-viewport)进行计算
vw 对于浏览器兼容性不是很好
vw 兼容方案:https://www.w3cplus.com/css/vw-for-layout.html
类似的相对单位
em:相对于父元素 font-size 的大小
vh: 相对于 viewport 视口的高度的大小的 1/100
vmin: 相对于 viewport 视口宽度或高度较小值的 1/100
vmax:相对于 viewport 视口宽度或高度较大值的 1/100
vmin 和 vmax 单位是相对于 viewport 视口宽度或高度较大或者较小值的 1/100,也就是说不论横屏或者视频,这两个单位的相对值始终不会变化
用处:当我们不希望横屏或竖屏改变元素的宽高时,可以用着两个单位
2、浏览器内核
webview 上不同系统的渲染引擎有什么区别?
主流:ios 使用的 webkit,安卓使用的 blink
大概在 05 年左右苹果开发了 webkit 浏览器内核,浏览器主流内核就是 webkit,后面安卓也采用 webkit 浏览器内核。由于 webkit 初始架构比较简单,apple 基于原本的 webkit 开发了 webkit2,google 则根据 webkit 内核移植出新的浏览器内核 blink(chrome 版本 28 及往后使用该内核),Opera 后期也追随 google 用上了 blink 渲染引擎
为什么会有浏览器前缀
由于不同的浏览器会使用不同的内核,最初不同的内核对 css3 样式的兼容性不一样,所以存在不同浏览器前缀
- -moz- :Firefox,GEcko 引擎
- -webkit-: Safari 和 Chrome,Webkit 引擎
- -o- :Opera(早期),Presto 引擎,后改为 Webkit 引擎
- -ms- :Internet Explorer,Trident 引擎
为兼容不同浏览器,使用autoprefixer
插件,可自动添加浏览器前缀(ios8 出现 flex 布局不支持)
"browserslist": [
"> 1%",
"last 2 versions",
"Android >= 3.2",
"Firefox >= 20",
"iOS 7"
]
webkit 内核大致结构:
- 操作系统:是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行。WebKit 也是在操作系统上工作的。
- 第三方库,为了 WebKit 提供支持,如图形库、网络库、视频库等。
- WebCore 是各个浏览器使用的共享部分,包括 HTML 解析器、CSS 解析器、DOM 和 SVG 等。JavaScriptCore 是 WebKit 的默认引擎,在谷歌系列产品中被替换为 V8 引擎。
- WebKit Ports 是 WebKit 中的非共享部分,由于平台差异、第三方库和需求的不同等原因,不同的移植导致了 WebKit 不同版本行为不一致,它是不同浏览器性能和功能差异的关键部分。
- WebKit 嵌入式编程接口,供浏览器调用,与移植密切相关,不同的移植有不同的接口规范。
相关链接:
v8 引擎介绍:https://blog.csdn.net/swimming_in_it_/article/details/78869549
webkit 内核介绍:https://blog.csdn.net/offbye/article/details/40039289
3、viewport 的概念
viewport: 手机端浏览器的可视窗口大小,用来控制根元素容器的宽高,也就是整个浏览器的宽高,不能够被 css 修改,相当于 html 的一个父元素
相关概念:移动设备有三个 viewport,布局窗口、视觉窗口、理想窗口
布局窗口:可供页面布局的大小
视觉窗口:在手机端上展示的大小
理想窗口:就等于设备屏幕的大小,也就是视觉窗口的大小
移动端开发常用 meta 标签来初始化 viewport 的缩放比,让布局窗口和视觉窗口保持一致
<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
相关链接:http://www.w3cplus.com/css/viewports.html
4、iphone 的 retina 屏上 1px 问题
物理像素:设备的像素,代表显示器的最小物理显示单元
设备独立像素:可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如:css 像素)
dpr(device independent pixels): 物理像素/设备独立像素,可通过
window.devicePixelRatio
获取对应设备的 dpr比如 iphone6 的 dpr 是 2,它的设备宽度一般是 375px,但是实际物理像素是 750px,这个时候,如果一个 1px 的 border,显示在 iphone6 上其实是两个物理像素,所以会出现 1px 在 iPhone 上感觉会比较粗
解决方法:
直接针对 dpr 来设置,1/dpr 个像素,比如 dpr 为 2 则设置为 0.5px,或新增一个 1px 宽度的伪类,使用 transform 属性缩小到 0.5 倍宽度
直接将 meta 头标签,设置初始宽度为 1/dpr 倍物理像素,比如 dpr 为 2,则设置为:
<meta name="viewport" content="initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5, user-scalable=no">
此时页面相当于缩放到了原来 0.5 倍,但是 rem 是相对单位,所有页面布局和样式会整体自适应,同时此刻 1px 也对应 1 个物理像素
关于背景图或者相关的 icon,设计师一般也会提供 2 倍图甚至是 3 倍图,也是这个原因,可根据媒体查询到对应 dpr 是选择几倍图
相关文章:https://www.cnblogs.com/surfaces/p/5158582.html
5、媒体查询
目的:据页面的特定宽度来定义特殊的 CSS 规则(这里的宽度也是视口宽度(viewport))
/*
标示:@media
关键字: not only
设备类型:all、print、screen、speech
打印机:print
电脑或手机显示器:screen
阅读器: speech
且: and
或: ,
*/
/* 页面最大宽度为400px */
@media all and (max-width: 400px) {
div {
width: 300px;
}
}
/* 指定显示器类型,页面最大宽度为400px且最小宽度为200px */
@media only screen and (max-width: 400px) and (min-width: 200px) {
div {
width: 300px;
}
}
/* 排除显示器类型,页面最大宽度为400px且最小宽度为200px,或者dpr为2 */
@media not screen and (max-width: 400px) and (min-width: 200px),
(-webkit-device-pixel-ratio: 2) {
div {
width: 300px;
}
}
6、通过 js 获取相关的宽高属性
-
屏幕尺寸:
screen.width/height
它们是显示器的宽高,不会随着浏览器宽高的变化而变化,通常除了数据统计,对我们没有任何意义
-
页面尺寸:
window.innerWidth/innterHeight
浏览器的内部尺寸。它定义了当前用户有多大区域,可供你的 CSS 布局占用。你可以通过window.innerWidth
和window.innerHeight
来获取,通常浏览器宽度方法或者缩小,会对应跟着方法或者缩小。
-
viewport
的尺寸:document.documentElement.clientWidth/clientHeight
一般情况下,document.documentElement
是代表的 html 元素,但是 viewport 是比 html 更高级的元素,并且 html 的尺寸变化不会影响到document.documentElement. clientWidth/clientHeight
的变化,所以实际上document.documentElement.clientWidth/clientHeight
代表的是 viewport 的尺寸
-
document.documentElement.clientWidth/clientHeight
和window.innerWidth/innerHeight
的差别
严格来说,两者基本一致,但是window.innerWidth/innerHeight
实际上会包含滚动条的宽度,但是document.documentElement.clientWidth/clientHeight
则不会
- html 元素的尺寸:
document.documentElement.offsetWidth/Height
如果clientWidth/Height
一直用以标示 viewport 的尺寸,我们该如何去获取<html>元素的尺寸呢?—document.documentElement.offsetWidth/Height
,一般获取元素的大小也使用offsetWidth/offsetHeight
,会包含 border,padding
- 获取元素相对于 viewport 的位置:
getBoundingClientRect
用法:var rect = element.getBoundingClientRect()
返回值类型:TextRectangle
对象,每个矩形具有四个整数性质( 上, 右 , 下,和左 )表示的坐标的矩形,以像素为单位
7、iphonx 适配
设备安全区域
由于 iPhone X 的顶部和底部状态栏,以及全面屏的普及,会导致全屏的页面,四个圆角以及底部、顶部被遮住,因此需要根据 iPhone X 做一些适配
iOS 11
为屏幕适配引入了一个十分重要的概念:Safe Area
。
适配方案:
1、将 viewport-fit
通过 meta
标签设置为 cover
,表示页面内容填充屏幕
<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
2、使用 css 的 constant()
函数做适配
如果页面只是简单的流式布局
ios11 之前使用的是 constant
做适配,ios11 之后使用标准的 env
做适配
body {
padding-top: constant(safe-area-inset-top); //为导航栏+状态栏的高度 88px
padding-left: constant(safe-area-inset-left); //如果未竖屏时为0
padding-right: constant(safe-area-inset-right); //如果未竖屏时为0
padding-bottom: constant(safe-area-inset-bottom); //为底下圆弧的高度 34px
padding-top: env(safe-area-inset-top); //为导航栏+状态栏的高度 88px
padding-left: env(safe-area-inset-left); //如果未竖屏时为0
padding-right: env(safe-area-inset-right); //如果未竖屏时为0
padding-bottom: env(safe-area-inset-bottom); //为底下圆弧的高度 34px
}
3、针对特殊情况单独处理
/*iPhoneX 的适配*/
@media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) {
.iphonex-padding-bottom {
padding-bottom: constant(safe-area-inset-bottom) !important;
padding-bottom: env(safe-area-inset-bottom) !important;
}
}
参考文档:https://www.cnblogs.com/lolDragon/p/7795174.html
8、使用 vue 的 异步组件处理加载状态
为减少手机端的首屏渲染时间,一般使用 vue-router
懒加载方案,但页面跳转首次访问会有卡顿现象
可在页面跳转中间加一层 loading 组件,此时可以使用 vue 的异步组件方案来处理
// route.js
import loadable from 'loadable.js'
const routes = [
{
path: '/loan-home',
name: 'LoanHome',
component: loadable(() => import('@/pages/xxx'))
}
]
// loadable
export default asyncComponent => {
const component = () => ({
component: asyncComponent(),
loading: LoadingComponent,
delay: 0
})
return {
render(h) {
return h(component, {})
}
}
}
参考文档
- viewport 介绍:http://www.w3cplus.com/css/viewports.html
- Flexible 实现:https://www.w3cplus.com/mobile/lib-flexible-for-html5-layout.html
- vw 进行页面适配:https://www.w3cplus.com/css/vw-for-layout.html
- 媒体查询相关介绍:http://www.cnblogs.com/august-8/p/4537685.html
- 一像素解决方案:https://www.cnblogs.com/surfaces/p/5158582.html