# 1 移动端适配
为什么要做适配
- 为了适应各种移动端设备,完美呈现应有的布局效果
- 各个移动端设备,分辨率大小不一致,网页想铺满整个屏幕,并在各种分辨下等比缩放
# 适配方案
- 固定高度,宽度百分比适配-布局非常均匀,适合百分比布局
- 固定宽度,改变缩放比例适配-什么情况都可以
- Rem适配
- 像素比适配
单位
em
根据元素自身的字体大小计算,元素自身16px 1em=16px
Rem R -> root
根节点( html ) 根据html的字体大小计算其他元素尺寸
百分比适配
固定高度,宽度百分比适配
- 根据设置的大小去设置高度,单位可以用
px
百分比auto
- 常用
Flex
布局 - 百分比宽度
以
640
设计稿为例,在外层容器上设置最大以及最小的宽
#wrapper { max-width: 640px; /*设置设计稿的宽度*/ min-width: 300px; margin: 0 auto; }
@程序员poetry: 代码已经复制到剪贴板
后面的区块布局都用百分比,具体元素大小用
px
计算
Rem适配(常用)
- 根据屏幕的分辨率动态设置
html
的文字大小,达到等比缩放的功能 - 保证
html
最终算出来的字体大小,不能小于12px
- 在不同的移动端显示不同的元素比例效果
- 如果
html
的font-size:20px
的时候,那么此时的1rem = 20px
- 把设计图的宽度分成多少分之一,根据实际情况
rem
做盒子的宽度,viewport
缩放
head
加入常见的meta
属性
<meta name="format-detection" content="telephone=no"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <!--这个是关键--> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,minimum-scale=1.0">
@程序员poetry: 代码已经复制到剪贴板
把这段代码加入
head
中的script
预先加载
// rem适配用这段代码动态计算html的font-size大小 (function(win) { var docEl = win.document.documentElement; var timer = ''; function changeRem() { var width = docEl.getBoundingClientRect().width; if (width > 750) { // 750是设计稿大小 width = 750; } var fontS = width / 10; // 把设备宽度十等分 1rem<=75px docEl.style.fontSize = fontS + "px"; } win.addEventListener("resize", function() { clearTimeout(timer); timer = setTimeout(changeRem, 30); }, false); win.addEventListener("pageshow", function(e) { if (e.persisted) { //清除缓存 clearTimeout(timer); timer = setTimeout(changeRem, 30); } }, false); changeRem(); })(window)
@程序员poetry: 代码已经复制到剪贴板
像素比适配
window.devicePixelRatio
- 物理像素是手机屏幕分辨率
- 独立像素 指
css
像素 屏幕宽度 - 像素比 = 物理像素 /
css
宽度 - 获取设备的像素比
window.devicePixelRatio
# 2 移动端300ms延迟
由来:300毫秒延迟解决的是双击缩放。双击缩放,手指在屏幕快速点击两次。safari浏览器就会将网页缩放值原始比例。由于用户可以双击缩放或者是滚动的操作,
当用户点击屏幕一次之后,浏览器并不会判断用户确实要打开至这个链接,还是想要进行双击操作 因此,safair浏览器就会等待300ms,用来判断用户是否在次点击了屏幕
解决方案:
- 禁用缩放,设置meta标签
user-scalable=no
fastclick.js
原理:FastClick的实现原理是在检查到touchend事件的时候,会通过dom自定义事件立即发出click事件,并把浏览器在
300ms
之后真正的click事件阻止掉。fastclick.js还可以解决穿透问题
- fastclick可以解决在手机上点击事件的
300ms
延迟 - zepto的touch模块,tap事件也是为了解决在click的延迟问题
触摸事件的响应顺序
ontouchstart
ontouchmove
ontouchend
onclick
# 3 如何解决移动端 Retina 屏 1px 像素问题
伪元素 + transform scaleY(.5)
border-image
background-image
box-shadow
一般来说,在PC端浏览器中,设备像素比(dpr)等于1,1个css像素就代表1个物理像素;但是在
retina
屏幕中,dpr普遍是2或3,1个css像素不再等于1个物理像素,因此比实际设计稿看起来粗不少
- 伪元素+scale
<style> .box{ width: 100%; height: 1px; margin: 20px 0; position: relative; } .box::after{ content: ''; position: absolute; bottom: 0; width: 100%; height: 1px; transform: scaleY(0.5); transform-origin: 0 0; background: red; } </style> <div class="box"></div>
@程序员poetry: 代码已经复制到剪贴板
- border-image
div{ border-width: 1px 0px; border-image: url(border.png) 2 0 stretch; }
@程序员poetry: 代码已经复制到剪贴板
# 4 如何解决移动端击穿(穿透)问题
在移动端开发的时候,我们有时候会遇到这样一个bug:点击关闭遮罩层的时候,遮罩层下面的带有点击的元素也会被触发,给人一种击穿了页面的感觉,这是为什么呢?
- 点击“打开弹框”按钮,显示遮罩层
- 点击“关闭弹框”按钮,遮罩层消失,底下的连接被触发
var show = document.getElementById('show') // 打开按钮 var mask = document.getElementById('mask') // 遮罩层 var btn = document.getElementById('btn') // 关闭按钮 show.onclick = function () { mask.style.display = 'block' } btn.addEventListener('touchstart', function () { mask.style.display = 'none' }, false)
@程序员poetry: 代码已经复制到剪贴板
- 这样问题的形成原因是什么呢?
- 我们先来看一段代码:(以下代码需在移动端上运行)
<div id="btn">我是一个按钮</div> var btn = document.getElementById('btn') btn.addEventListener('touchstart', function () { console.log('start') }, false) btn.addEventListener('touchmove', function () { console.log('move') }, false) btn.addEventListener('touchend', function () { console.log('touchend') }, false) btn.addEventListener('click', function () { console.log('click') }, false)
@程序员poetry: 代码已经复制到剪贴板
以上代码会出现2种运行情况
start ===> move ===> end start ===> end ===> click
@程序员poetry: 代码已经复制到剪贴板
看到这里相信大家都明白了,由于「关闭弹框」按钮绑定的事件是
touch
,a标签是click
事件,在touch
事件触发后,我们弹出框的遮罩层就消失了,这时候的click
事件就被a标签给捕获到了,形成了击穿的效果
方法一、阻止默认事件
btn.addEventListener('touchend', function (e) { mask.style.display = 'none' e.preventDefault() }, false)
@程序员poetry: 代码已经复制到剪贴板
在执行 touchstart 和 touchend 事件时,隐藏执行完隐藏命令后,立即阻止后续事件(推荐在touchend时,阻止后续的默认事件)
方法二、统一使用click事件
btn.addEventListener('click', function () { mask.style.display = 'none' }, false)
@程序员poetry: 代码已经复制到剪贴板
这个方法简单,就是交互的效率没有
click
事件高,另外,用户在touch
的时候,有可能微微滑动了一下,就会无法触发点击事件。影响用户体验。
方法三、延迟执行
btn.addEventListener('touchend', function () { setTimeout(function
@程序员poetry: 代码已经复制到剪贴板