开发 - 移动端页面适配
移动端适配的基础知识和常见用例
viewport 视口
视口可以细分为:视觉视口(visual viewport)和布局视口(layout viewport)
视觉视口
视觉视口是页面的可视区域,相当于一个设置了overflow:hidden
属性的 div 元素,这是由硬件决定的,不受缩放的影响。
布局视口
布局视口的尺寸是内容的初始尺寸,设置 viewport meta 的 width 属性其实就是在设置布局视口的初始尺寸。
如果想在不同尺寸的视觉视口中保持同样的分辨率,那么就需要设置布局视口的宽度。
举个例子,页面中有一张原尺寸 1690px 宽的图片,此时如果设置 viewport 的宽度为 800px:
<meta name="viewport" content="width=800, initial-scale=1">
显示效果如下图,html 的宽度既不是 375px 也不是 1690px,而是在 viewport 中设置的 800px,因为图片设置了 100% 的宽度,所以图片的宽度也是 800px,视觉视口并不能完全的显示出布局视口。
如果将 viewport 的宽度设置成小于页面宽度的值,会有什么结果?
<meta name="viewport" content="width=300, initial-scale=1">
效果如下图,宽度设置没有生效,html 使用的是视觉视口的宽度
现在为移动端开发的页面,通常将 viewport 的宽度设置为device-width
(设备宽度),即让布局视口宽度与视觉视口宽度相等,这样就不会出现缩放和横向滚动条的问题
缩放属性
与缩放有关的值有 4 个:
inital-scale:初始缩放比例
maximum-scale:允许用户缩放到的最大比例
minimum-scale:允许用户缩放到的最小比例
user-scalable:用户是否可以手动缩放
meta 属性
meta 有些列属性:
viewport 视口
具体配置见上面的 viewport 视口部分,移动端常用 viewport 配置:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
charset 字符编码
常用的编码为 utf-8
<meta charset="utf-8" />
cache-control 缓存策略
cache-control 的可选值:
- no-store:不缓存数据到本地
- no-cache:在提供给本地读取之前,强制要求缓存把请求提交给原始服务器进行验证(协商缓存)
- max-age:最大可缓存时间
x-ua-compatible 浏览器版本
常用配置:加入客户端安装了 Chrome Frame,则在 IE 中使用 chrome 的渲染引擎来渲染页面,如果没有安装,则使用最高的 IE 版本模式来进行渲染
<meta http-equiv="x-ua-compatible" content="IE=Edge, chrome=1" />
seo 属性
author 作者
<meta name="author" content="something" />
keywords 关键字
<meta name="keywords" content="something" />
description 描述
<meta name="description" content="something" />
format-detection 格式检测
telephone 电话识别
safari 浏览器会将疑似电话号码的数字处理为电话链接,比如:
- 7位数字,形如:1234567
- 带括号及加号的数字,形如:(+86)123456789
- 双连接线的数字,形如:00-00-00111
- 11位数字,形如:13800138000
如果需要关闭电话识别,则需要下述配置:
<meta name="format-detection" content="telephone=no" />
email 邮箱地址识别
安卓浏览器会将疑似邮箱地址转换为邮箱链接,如果需要关闭邮箱识别,则需要下述配置:
<meta name="format-detection" content="email=no" />
高 DPR 适配
对于高分屏,例如 Retina 屏幕这样 DRP 大于 1 的屏幕,1位图像素不在对应 1 物理像素,而是使用 4 个及以上的物理像素去模拟 1 位图像素,如下图所示:
不过者也会造成一个问题:将尺寸为 80px 的图片宽度设置为 80px,那么此时 1位图像素对应 1 物理像素,DRP = 2 的高分屏中,位图像素无法在继续分解,那就只能用 4 个物理像素去模拟 1 个位图像素,模拟的方式就是就近取色,这会导致图片有一定的色差,看起来变得模糊
解决方法就是:将图片的尺寸拓展成 80px*DRP,这样每一个位图像素都会有对应的物理像素,图片就会变得清晰。
img 解决方案
通过设置 srcset 属性配置显示的图片:
<img srcset="elva-fairy-320w.png,
elva-fairy-480w.png 1.5x,
elva-fairy-640w.png 2x"
src="elva-fairy-640w.png"/>
background 解决方案
通过媒体查询页面的 DRP 来决定显示的图片:
@mixin bg-image($url,$extension:'.png'){
@media (min-device-pixel-ratio:2){
background-image:url( $url + "@2x" + $extension )
}
@media (min-device-pixel-ratio:3){
background-image:url( $url + "@3x" + $extension )
}
}
阻止移动端双击缩放
添加下述属性:
touch-action: manipulation;
视口高度去除底部栏
当使用 height: 100vh 去设置页面高度时,往往会出现如下图所示的将导航栏算入 viewport height 的情况,而我们实际需要的是右侧的结果。
这时候就需要去修改 body 的高度属性,将height:100vh
修改为height:fill-available
,移动端除了 Opera 其他浏览器基本已经兼容了该属性,具体兼容情况
Safari
避免 safari 弹性效果遮挡 fixed 定位的元素
解决方式:给 html 标签设置overflow:hidden
,给 body 标签设置overflow:auto
:
html {
overflow: hidden;
}
body {
overflow: auto;
}
border-radius 在 safari 上的失效问题
如果元素设置了 border-radius 属性且设置了 transform 属性,那么 border-radius 就会失效,解决方法是:给父元素加上 transform:translateX(0)
属性。
:active 状态失效
safari 中为按钮元素添加 :active 默认是不会生效的,只有在按钮元素绑定 touchstart 事件时才能激活 :active 状态,只需要给 touchstart 绑定一个空事件即可。
根据设备宽度计算全局字体
在引入全局css样式之前调用下述代码,通过设置 defaultFontSize 来定义 375 宽度下字体的大小,其他宽度的设备会以 defaultFontSize 和 375 宽度作为标准,动态改变全局字体大小。
(function (doc, win) {
var defaultFontSize = 20;
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function () {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
docEl.style.fontSize = defaultFontSize * (clientWidth / 375) + 'px';
};
recalc();
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
})(document, window);
判断当前浏览器/机型
navigator.userAgent 能获取到当前浏览器的 user agent 字符串
判断是否为微信浏览器
const ua = navigator.userAgent.toLowerCase();
const isWeixin = /micromessenger/i.test(ua);
判断是否为安卓
const ua = navigator.userAgent.toLowerCase();
const isAndroid = /android/i.test(ua);
判断是否为iOS
const ua = navigator.userAgent.toLowerCase();
const isIOS = /(iPhone|iPod|iPad);?/i.test(ua);
开发 - 移动端页面适配