问题有哪些
- 1px边框
- click事件300ms延迟
- Touch事件点击穿透
- 移动端图片
1px边框
1.高清屏下,1px 边框“变粗”的原因
- 并不是真的变粗了,而是设计想要的 1像素,不是程序员眼中的 1CSS像素,而是 1物理像素
- 如果 dpr=2,设计实际想要的就是 1px/2=0.5px
- 如果 dpr=3,设计实际想要的就是 1px/3=0.3333px
2.解决方案
- 和设计商量,如果不在意这个问题,不用去管
- 直接设置“细”边框
- 存在兼容性问题,不同的浏览器会有不同的表现
- 对于 iOS8 以后的 iOS 系统推荐使用这种方法
- 伪类 + transform(推荐)
- 其他方案可参考:www.cnblogs.com/zzsdream/ar…
具体实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>1px 边框</title>
<style>
body {
background-color: #f5f5f5;
}
.list {
padding: 0;
margin: 0;
font-size: 30px;
}
.item {
list-style: none;
line-height: 60px;
border-bottom: 1px solid #ccc;
}
/* 直接设置“细”边框 */
.item1 {
border-width: 0.5px;
}
//高清屏幕下 1px 对应更多的物理像素,所以 1 像素边框看起来比较粗,使用媒查询:
@media screen and (-webkit-min-device-pixel-ratio:2){
#demo{
border: 0.5px solid black;
}
}
/* 伪类 + transform */
@media (-webkit-min-device-pixel-ratio: 2) {
.border-1px {
position: relative;
border: none;
}
/* 往后添加一个伪类去设置边框 */
.border-1px::after {
box-sizing: border-box;
content: '';
position: absolute;
top: 0;
left: 0;
/* 将来会用scale缩小一半 */
width: 200%;
height: 200%;
/* 设置相应边框 */
border-bottom: 1px solid #ccc;
/* border: 1px solid #ccc; */
/* 设置圆角 */
/* border-radius: 20px; */
transform-origin: 0 0;
transform: scale(0.5);
/* background-color: rgba(255, 0, 0, 0.5); */
}
}
@media (-webkit-min-device-pixel-ratio: 3) {
.border-1px::after {
width: 300%;
height: 300%;
transform: scale(0.3333);
}
}
</style>
</head>
<body>
<ul class="list">
<li class="item">“变粗”的 1px 边框</li>
<!-- <li class="item">变粗的原因</li>
<li class="item">解决方案</li> -->
<li class="item item1">直接设置“细”边框</li>
<li class="item border-1px">伪类 + transform</li>
</ul>
</body>
</html>
click事件300ms延迟
移动端
click
屏幕产生 200-300 ms 的延迟响应,往往会造成按钮点击延迟甚至是点击失效。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>click 事件 300ms 延迟</title>
<style>
.btn {
width: 100%;
height: 300px;
font-size: 100px;
/* touch-action: manipulation; */
}
</style>
</head>
<body>
<button id="btn" class="btn">提交</button>
<script src="https://cdn.bootcdn.net/ajax/libs/fastclick/1.0.6/fastclick.min.js"></script>
<script>
const $btn = document.getElementById('btn');
$btn.addEventListener(
'touchstart',
() => {
console.time('click');
},
false
);
$btn.addEventListener(
'click',
() => {
console.timeEnd('click');
console.log('提交表单');
},
false
);
</script>
</body>
</html>
移动端 click 事件 300ms 延迟的原因
- 原因:double-tap to zoom 双击缩放 (等待检测你的操作是不是双击缩放)
解决方案
解决方法一
- 不使用 click 事件,把 click 事件中要处理的放到 touchstart 或 touchend 中去处理
$btn.addEventListener(
'touchend',
() => {
console.timeEnd('click');
console.log('提交表单');
},
false
);
解决方案二
- 禁止双击缩放(浏览器厂商的努力)
- patrickhlauke.github.io/touch/tests…
- viewport 中禁止缩放
- touch-action: manipulation;(只允许滚动和持续缩放)
解决方案三
- 使用 Fastclick 库
- github.com/ftlabs/fast…
- 主要针对老版本浏览器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1,maximum-scale=1, user-scalable=no"
/>
<title>click 事件 300ms 延迟</title>
<style>
.btn {
width: 100%;
height: 300px;
font-size: 100px;
/* touch-action: manipulation; */
}
</style>
</head>
<body>
<button id="btn" class="btn">提交</button>
<!-- 引入Fastclick 库 -->
<script src="https://cdn.bootcdn.net/ajax/libs/fastclick/1.0.6/fastclick.min.js"></script>
<script>
// 使用 Fastclick 库
if ('addEventListener' in document) {
document.addEventListener(
'DOMContentLoaded',
function () {
FastClick.attach(document.body);
},
false
);
}
const $btn = document.getElementById('btn');
$btn.addEventListener(
'touchstart',
() => {
console.time('click');
},
false
);
// $btn.addEventListener(
// 'touchend',
// () => {
// console.timeEnd('click');
// console.log('提交表单');
// },
// false
// );
$btn.addEventListener(
'click',
() => {
console.timeEnd('click');
console.log('提交表单');
},
false
);
</script>
</body>
</html>
Touch事件点击穿透
在发生触摸动作约300ms之后,移动端会模拟产生click动作,如果touch事件隐藏了原来元素 则click总作用到它底下的具有点击特性的元素,触发新元素的click事件和跳转,此现象被称为点击穿透
Touch 事件点击穿透的原因
事件触发的先后顺序是:touchstart -> touchend -> click。正是由于这种 click 事件的滞后性设计为事件穿透(点击穿透)埋下了伏笔。
- touch事件结束后会默认触发该元素的click事件
- 移动端 Touch 事件会立即触发,而 click 事件会延迟一段时间触发
常见的事件穿透场景:
- 上层元素监听了触摸事件,触摸之后该层元素消失
- 下层元素具有点击特性(监听了click事件或默认的特性(a标签、input、button标签))
- 比如标元素触发触摸事件时隐藏或移除自身,对应位置元素触发 click 事件或 a 链接跳转。
- 目标元素使用触摸事件跳转至新页面,新页面中对应位置元素触发 click 事件或 a 链接跳转。
注意:a 标签的链接跳转事件属于 click 事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1,maximum-scale=1, user-scalable=no"
/>
<title>Touch 事件点击穿透</title>
<style>
.btn {
width: 100%;
height: 300px;
font-size: 100px;
}
.mask {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
opacity: 1;
transition: opacity 0.5s;
}
</style>
</head>
<body>
<button id="btn" class="btn">提交</button>
<div id="mask" class="mask"></div>
<script>
const $btn = document.getElementById('btn');
const $mask = document.getElementById('mask');
// touchend和 touchstart都会造成点击穿透 点击遮罩层消失会触发下面的click事件
// 由于 mask 元素触发 touchstart 触摸事件并立即隐藏掉自身,之后应该按先后顺 序触发 mask 元素的 touchend 和 click 事件。
// 然而,当要触发 click 事件的时候由于 mask 元素已经隐藏掉了,于是触发了 div 的 click 事件。
$mask.addEventListener(
'touchend',
() => {
$mask.style.display = 'none';
},
false
);
$mask.addEventListener(
'touchstart',
() => {
console.time('click');
},
false
);
$btn.addEventListener(
'click',
() => {
console.timeEnd('click');
console.log('提交表单');
},
false
);
</script>
</body>
</html>
解决方案
解决方法一
解决事件穿透的方法有很多,大致可以分为两类:第一种是禁止混用 click 和 touch 两种事件;另一种是延迟元素的隐藏或移除。
- 让原本隐藏的元素延迟隐藏
$mask.addEventListener(
'touchend',
() => {
// $mask.style.display = 'none';
// 延时消失
setTimeout(() => {
$mask.style.display = 'none';
}, 200);
// 2.2.消失过程中添加动画效果 css添加transition和初始opacity = 1
$mask.style.opacity = 0;
},
false
);
// 过渡结束将元素隐藏
$mask.addEventListener(
'transitionend',
() => {
$mask.style.display = 'none';
},
false
);
解决方法二
阻止默认行为
//阻止该默认click行为的触发
$mask.addEventListener('touchstart', function(e){
e.preventDefault();
console.log('hello')
$mask.style.display = 'none';
})
解决方法三
使背后元素不具备click特性,用touchXxxx代替click
banner_img.addEventListener('touchstart',()=>{
location.href = 'http://www.baidu.com'
})
解决方案四
让背后的元素暂时失去click事件,300毫秒左右再复原
#anode{
pointer-events: none;
}
btn.addEventListener('touchstart',(event)=>{
shade.style.display = 'none';
setTimeout(()=>{
anode.style.pointerEvents = 'auto'
},500)
})
移动端图片
- img图片
- 背景图片
img 图片
- 一般使用百分比,并且只设置宽度或高度中的一个,不同时设置,让宽高能够等比例缩放,图片不失真
- 当图片实际宽度小于父容器宽度时,图片不会随着父容器宽度的变大而进一步拉伸
- 这个可以解决图片宽度拉伸问题 但是一旦超过图片原本宽度就会留白
/* 图片留白使其居中显示 */
.img-container {
display: flex;
justify-content: center;
}
背景图片
<style>
.bg-container {
width: 100%;
/* 如果高度固定 */
height: 200px;
background: url(./bg.png) no-repeat;
/* 缩放背景图片以完全覆盖背景区,可能背景图片部分看不见 */
background-size: cover;
}
</style>
<div class="bg-container"></div>
<style>
.bg-container {
width: 100%;
/* 如果高度不固定 */
/* 563px 224px 224 / 563 */
/* padding相对于宽度的百分比 */
padding-top: 39.7869%;
background: url(./bg.png) no-repeat;
/* 缩放背景图片以完全覆盖背景区,可能背景图片部分看不见 */
background-size: cover;
}
</style>
<div class="bg-container"></div>
还可以使用媒体查询
/* 小屏幕使用小图片 */
background: url(./bg.png) no-repeat;
/* 结合媒询一起使用 */
/* 大屏幕使用大图片 */
@media (min-width: 560px) {
.bg-container {
background-image: url(./bg_lg.png);
}
}