关于移动端适配,你必须要知道的
关注“前端学苑” ,坚持每天进步一点点
「~移动端适配最佳实践~」
一般情况下设计稿的设计师按照375的尺寸设计,然而,在现在移动终端(就是手机)快速更新的时代,每个品牌的手机都有着不同的物理分辨率,这样就会导致,每台设备的逻辑分辨率也不尽相同,此时357的设计稿,如果想要还原那基本是不可能了,因为如果一个左右布局,左边如果写死,右边自适应的话,每个设备的右边所展示的内容大小就不尽相同,移动端适配就显得尤其重要。
一、基础知识
屏幕尺寸
屏幕尺寸是以屏幕对角线的长度来计量,计量单位为英寸。如图所示两个对角线的长度就是这个屏幕的尺寸。
设备物理分辨率(设备像素)
相信我们所有前端开发者,都是见证了手机这个移动设备发展的过程。从蓝屏手机,到彩屏手机,到诺基亚研发出来触屏手机,再到智能手机一步步发展下来,我们的我们的手越来越清晰,越来越大,所以我们的屏幕发展也越来越迅速。
图像分辨率
我们通常说的图片分辨率其实是指图片含有的像素数,比如一张图片的分辨率为800 x 400。这表示图片分别在垂直和水平上所具有的像素点数为800和400。
同一尺寸的图片,分辨率越高,图片越清晰。
二、移动端常用适配方案
设备宽度+ 根节点(html)font-size字体大小
updataHtml();
function updataHtml(){
var w = document.documentElement.clientWidth;
document.documentElement.style.fontSize=w/16+'px';
}
window.onresize=function(){
updataHtml();
}
html{font-size: 20px; }
flexible+rem方案
通用原理:
flexible方案是阿里早期开源的一个移动端适配解决方案,rem 是相对于html节点的font-size来做计算的。我们通过设置document.documentElement.style.fontSize就可以统一整个页面的布局标准。
核心代码
// 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都是按照页面比例来计算的。
以iPhone6为例:布局视口为375px,则1rem = 37.5px,这时UI给定一个元素的宽为75px(设备独立像素),我们只需要将它设置为75 / 37.5 = 2rem。
思路:
该方案的核心原理是通过window.navigator.appVersion判断是否是iphone,只解决苹果设备上的dpr为2和3的情况,其他的比如ipad、Android直接设置dpr为1,然后通过 1/ dpr 得到缩放值,做的事情也很简单,就是动态设置meta标签的内容,没有设置为width=device-width,而是通过设置initial-scale来缩放布局视口,dpr为1,缩放为1;dpr为2,缩放0.5;dpr为3,缩放0.3333;通过这种方法使得布局视口在视觉上还是屏幕大小但CSS像素数量却增加了4倍/9倍。
设置dpr的核心代码
if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
}
else if
(devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
使用方法:
1、直接引入flexible.js
第一种方法是将文件下载到你的项目中,然后通过相对路径添加:
<script src="build/flexible_css.debug.js"></script>
<script src="build/flexible.debug.js"></script>
或者直接加载阿里CDN的文件:
<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>
2、设置media
3、直接通过口算将px值转换为rem
特点:
1、根据dpr的值来修改html的font-size,从而使用rem实现等比缩放
2、根据dpr的值来修改viewport实现1px的线
3、不能与响应式布局兼容
4、对Android没有做处理,导致1px和backgroudImage还要额外做处理
5、计算麻烦,如果设计图是750px,则换算比例就是1rem=75px
常见应用场景:
1、对设计图还原度高的页面
2、非工程类项目,可以直接引入使用
如何快速计算
1、cssrem插件
编译器VScode 它里面有个插件叫cssrem,用它就可以在我们输入px值后自动转换rem。
2、vue中的适配:px2rem
1)下载并引入lib-flexible
cnpm install --save lib-flexible
在main.js中 :import ‘lib-flexible/flexible’
2、引入px2rem-loader
cnpm install --save px2rem-loader
3、将px2rem-loader添加到cssLoaders
在build/util.js中添加如下代码
const px2remLoader = {
loader: 'px2rem-loader',
options: {
remUnit: 75//这个是重点,设计稿是750px
}
}
const loaders = [cssLoader,px2remLoader]
说明:可以直接用px做单位按照750的设计稿撸代码了
腾讯阀值控制
根据设计稿同比缩放,加上阀值控制
初始化的rem是100,对应的fontsize也是100,基准的屏幕宽度按照320的设计稿,根据当前屏幕的宽高像素比,算出来当前的rem,100比较好算,设置成其他的也无妨,因为你算的是相对比例。
具体详细:
1、css设置了font-size:100px;
2、引入刚才那个js。
3、比如一个按钮设计稿件是30pxX30px 它是除以100的。最后咱们设置是0.3remX0.3rem。
它在js里面设置了三个区间:
1)var innerWidth = Math.max(Math.min(clientWidth, 480), 320);
2)innerWidth > 362 && innerWidth <= 375
3)innerWidth > 375
document.documentElement.clientWidth ==> 可见区域宽度
window.innerWidth 获取窗口宽度
项目地址:info.3g.qq.com
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" name="viewport" />
<script>
(function() {
var baseFontSize = 100;
var baseWidth = 320;
var clientWidth = document.documentElement.clientWidth || window.innerWidth;
var innerWidth = Math.max(Math.min(clientWidth, 480), 320);
var rem = 100;
if (innerWidth > 362 && innerWidth <= 375) {
rem = Math.floor(innerWidth / baseWidth * baseFontSize * 0.9);
}
if (innerWidth > 375) {
rem = Math.floor(innerWidth / baseWidth * baseFontSize * 0.84);
}
document.querySelector('html').style.fontSize = rem + 'px';
}());
</script>
三、移动端常见问题
移动端文字居中问题 垂直方向
在开发过程中,发现在andriod机子上出现上下居中问题,文字偏上。
已经试过的方法:
1、line-height
2、padding
3、flex
这三种方法试过都没有效果。
lang=en时按钮文字偏上,而lang=zh时按钮文字偏下
.box{
display: table-cell;
text-align: center;
vertical-align: middle;
}
click 在ios上有300ms延迟,原因及如何解决?
原因:双击缩放(double tap to zoom),会产生 300 毫秒延迟的主要原因。
解决方法:
1) 禁止双击缩放
<meta name="viewport" content="width=device-width,user-scalable=no">
完全禁止缩放了,例如,想放大查看某张图片也是不被允许的
适用场景: 无需用户放大查看的元素页面、游戏页面等(注:ios10以前,上面是有效的)
2) 指针事件 (Pointer Events)
html {
touch-action: manipulation; // 值为none时,禁用元素(及其不可滚动的后代)上的所有手势
}
触摸动作也经常用于完全解决由支持双击缩放手势引起的点击事件的延迟。
3) 利用fastClick
其原理是:检测到touchend 事件后,会通过DOM自定义事件立刻出发模拟click事件,并且把浏览器300毫秒之后真正发的事件给阻断掉。
FastClick 使用方法: 在 window load 事件之后,在 <body> 上调用 FastClick.attach()
window.addEventListener( "load", function() {
FastClick.attach( document.body );
}, false );
h5底部输入框被键盘遮挡问题 (ios)
var oHeight = $(document).height(); //浏览器当前的高度
$(window).resize(function(){
if($(document).height() < oHeight){
$("#footer").css("position","static");
}else{
$("#footer").css("position","absolute");
}
});
h5动画效果(脱离文档流) 用定位(重要) (输入框无法输入问题)
微信头部高度:iphone 4s ,5 高度64px (核心区域)
软键盘与输入框配合问题(注:软键盘弹出时,用户无法在输入框输入内容)(常用)
1)css:#wrap{width:100%;height:100%;position:relative;overflow:hidden;} 找到父元素
注:建议不要用fixed定位,用absolute定位。
2)js:$("body").height($("body").height()); //设置页面动态高度
1px变粗的原因
viewport的设置和屏幕物理分辨率是按比例而不是相同的.
移动端window对象有个devicePixelRatio属性, 它表示设备物理像素和css像素的比例, 在retina屏的iphone手机上, 这个值为2或3, css里写的1px长度映射到物理像素上就有2px或3px那么长。
transform: scale(0.5) 方案 - 推荐: 很灵活
div::after{
content: '';
position:absolute;
height:1px;
width: 100%;
background:#000;
transform: scaleY(0.5);
}
拍照取相册 accept="image/*(重要)
<input type="file" accept="image/*" capture="camera">
<input type="file" accept="video/*" capture="camcorder">
<input type="file" accept="audio/*" capture="microphone">
capture表示,可以捕获到系统默认的设备,比如:camera--照相机;camcorder--摄像机;microphone--录音。
项目开发结果:
<input type="file" accept="image/*" >
测试环境:
苹果手机 (IOS):钉钉测试、微信测试、Safari测试
测试手机:
1、苹果手机 (IOS):
iphone6s plus(拍照、照片图库、iCloud)
iphone XR(拍照、照片图库、浏览)
2、安卓手机 (Android):
小米 MUI 10.9.6.20开发版
微信测试:出现弹出框(截图、文件)选择文件可以打开相册。
vivo Y66L、华为 Honor V10、华为 mate9、三星 S10、oppo A57
微信测试:出现弹出框(相机、文档)选择文档进行打开相册。
MEIZU M1046
微信测试:出现弹出框(相机、图库、文档)选择图库可以打开相册。
相同点:
钉钉测试:出现弹出框(照片和视频、手机文件)可以打开相册。
qq浏览器测试:出现弹出框(相机、拍照)选择相机可以打开相册。
觉得本文对你有帮助?请分享给更多人
关注「前端学苑」加星标,提升前端技能