JSP移动端开发实战遇到页面错位按钮点不动 教你一招搞定手机屏幕适配和触摸事件踩坑指南
做移动端网页开发的朋友,大概都经历过这种崩溃时刻——页面在电脑浏览器上跑得好好的,一到手机上就乱成一锅粥。按钮被挤到屏幕外面,文字叠在一起,最要命的是用户点了半天毫无反应,后台日志还查不出任何异常。这种”看不见的问题”比直接报错还难受,因为你知道肯定哪里出了问题,但就是抓不到。
我今天就把这些年踩过的坑一个个扒出来,重点说说页面错位和按钮点不动这两个最经典的难题,顺便把屏幕适配和触摸事件那些容易忽略的细节也捋清楚。
先搞清楚:移动端网页到底在”适配”什么
很多人以为适配就是让页面”看起来正常”,其实适配要解决的是三个层面的问题。
视觉层面,不同手机屏幕分辨率千差万别。iPhone 14是390x844的逻辑像素,三星Galaxy S23是360x780,小米13是412x915。同样的宽度在各自设备上占到的物理像素比例完全不同,这就是为什么有些页面在iPhone上完美,在安卓机上就变形。
交互层面,移动端和桌面端最大的区别就是输入方式。没有鼠标悬停,没有右键点击,全是触摸。你写的hover效果在手机上永远不会触发,这是新手最容易忽略的一点。
性能层面,移动设备的CPU、内存、网络都有限制。代码写得漂亮但跑得卡顿,用户体验照样一塌糊涂。
理解这三个层面,后面说的各种解决方案才有根基,不然就是死记硬背一堆配置项,遇到新问题还是不会。
页面错位的常见病因和药方
页面错位是最直观的问题,按钮跑到屏幕外面、两列布局挤成一列、图片尺寸撑爆容器……根本原因是你用的尺寸单位和布局方式在移动端根本站不住脚。
病因一:用px写死了所有尺寸
这是90%的错位问题的罪魁祸首。px是绝对单位,在375px宽的手机上写width: 320px,在不同宽度的设备上显示比例完全不一样。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>错误示范:px写死布局</title>
<style>
.container {
width: 320px; /* 在375px屏幕上只占85%,在360px屏幕上几乎占满,比例不固定 */
height: 200px;
background: #4CAF50;
}
.btn {
width: 120px; /* 固定宽度,无法随屏幕变化 */
padding: 10px 20px;
}
</style>
</head>
<body>
<div class="container">
<button class="btn">点我</button>
</div>
</body>
</html>
解决思路:用相对单位替代绝对单位,或者用百分比、rem、vw/vh这些弹性单位。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>正确示范:弹性布局</title>
<style>
/* 方案A:百分比布局 */
.container-percent {
width: 90%; /* 始终占父容器的90% */
margin: 0 auto; /* 居中 */
height: 200px;
background: #2196F3;
}
.btn-percent {
width: 50%; /* 按钮宽度随容器变化 */
padding: 12px;
border: none;
border-radius: 6px;
background: #fff;
color: #2196F3;
font-size: 16px;
}
/* 方案B:vw/vh视口单位 */
.container-vw {
width: 90vw; /* 占视口宽度的90% */
max-width: 400px; /* 大屏幕也有上限 */
margin: 0 auto;
height: 20vh; /* 视口高度的20% */
background: #FF5722;
display: flex;
align-items: center;
justify-content: center;
}
.btn-vw {
width: 40vw; /* 按钮也随视口变化 */
max-width: 180px; /* 防止在大屏上过大 */
padding: 10px 0;
border: none;
border-radius: 6px;
background: #fff;
color: #FF5722;
font-size: 14px;
}
</style>
</head>
<body>
<div class="container-percent">
<button class="btn-percent">百分比按钮</button>
</div>
<br>
<div class="container-vw">
<button class="btn-vw">视口单位按钮</button>
</div>
</body>
</html>
方案A适合传统布局,方案B配合max-width和min-width更灵活。我推荐日常开发用方案B的思路——主要尺寸用vw,然后用max-width在大屏上兜底,这样小屏幕不会太小,大屏幕也不会太大。
病因二:盒子模型没搞对
移动端开发中最容易踩的盒子模型坑,就是box-sizing。很多开发者习惯用padding增加按钮的点击区域,但如果浏览器默认用的是content-box,加了padding之后元素的总宽度会变成width + padding * 2,导致布局直接崩掉。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>盒子模型踩坑</title>
<style>
/* 忘记加这个全局重置,padding会撑爆容器 */
* {
box-sizing: border-box; /* 关键!padding和border算入width/height内 */
}
.wrapper {
width: 100%;
display: flex;
justify-content: space-between;
}
.box {
width: 48%; /* 两个盒子各占48% */
padding: 15px; /* 有了box-sizing: border-box,这个不会撑爆 */
background: #9C27B0;
color: white;
border-radius: 8px;
text-align: center;
}
/* 如果没有box-sizing: border-box,实际宽度是48% + 30px,两个盒子加起来超过100%,第二个盒子会换行 */
</style>
</head>
<body>
<div class="wrapper">
<div class="box">左侧按钮</div>
<div class="box">右侧按钮</div>
</div>
</body>
</html>
这个全局重置box-sizing: border-box一定要加在样式文件的最开头,这是移动端CSS开发的第一条铁律。加了这个,你后面写的任何width都不会因为padding和border而变宽,布局就稳了一大半。
病因三:fixed定位在移动端各种骚操作
移动端浏览器的地址栏和工具栏会动态显示和隐藏,这会导致position: fixed的元素位置乱跳。用户上下滑动页面时,fixed定位的按钮或者导航栏会突然跳到不同位置,用户体验极差。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>fixed定位问题</title>
<style>
.fixed-btn {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
padding: 15px;
background: #333;
color: white;
text-align: center;
/* 加上这句让某些浏览器支持底部安全区 */
padding-bottom: calc(15px + env(safe-area-inset-bottom));
}
</style>
</head>
<body>
<div style="height: 2000px; padding: 20px;">
<p>滚动页面看看底部按钮的变化...</p>
</div>
<div class="fixed-btn">固定底部按钮</div>
</body>
</html>
env(safe-area-inset-bottom)这个CSS变量专门处理iPhone X及以上机型的底部安全区域。全面屏手机底部有手势指示条,如果按钮紧贴屏幕最底部,就会被挡住或者误触。用这个变量可以让内容自动避开安全区域,比硬写padding靠谱得多。
按钮点不动:触摸事件的各种坑
按钮点不动是移动端开发最让人抓狂的问题之一。用户明明按了,页面毫无反应,查代码又看不出任何逻辑错误。这种现象背后有几种不同的成因,得分开诊断。
坑一:300ms点击延迟
这个问题在早期移动端特别经典。很多移动浏览器为了检测用户是不是在双击放大,会在点击事件之后等待300毫秒,确认没有第二次点击才触发click事件。这意味着用户按下去之后要等将近半秒按钮才有反应,体验极差,在快节奏的App交互中更是不可接受。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>解决300ms延迟</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 关键:viewport设置中加上user-scalable=no可以完全消除300ms延迟 -->
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
padding: 20px;
}
.touch-btn {
display: block;
width: 100%;
padding: 16px;
margin-bottom: 15px;
border: none;
border-radius: 10px;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
font-size: 17px;
font-weight: 500;
/* 让按钮有点击反馈 */
transition: transform 0.1s, opacity 0.1s;
}
.touch-btn:active {
transform: scale(0.97);
opacity: 0.85;
}
#log {
margin-top: 20px;
padding: 15px;
background: #f5f5f5;
border-radius: 8px;
font-size: 14px;
color: #333;
min-height: 60px;
}
</style>
</head>
<body>
<button class="touch-btn" id="normalBtn">普通click按钮(有延迟)</button>
<button class="touch-btn" id="fastBtn" style="background: linear-gradient(135deg, #11998e, #38ef7d);">
touchend优化按钮(无延迟)
</button>
<div id="log">点击按钮查看效果...</div>
<script>
const log = document.getElementById('log');
const normalBtn = document.getElementById('normalBtn');
const fastBtn = document.getElementById('fastBtn');
// 普通click,在移动端有300ms延迟
normalBtn.addEventListener('click', () => {
log.textContent = 'click事件触发!(有延迟) 时间: ' + new Date().toLocaleTimeString();
});
// 用touchend替代click,彻底消除延迟
fastBtn.addEventListener('touchend', (e) => {
e.preventDefault(); /* 阻止触发后续的click事件,避免双重触发 */
log.textContent = 'touchend事件触发!(无延迟) 时间: ' + new Date().toLocaleTimeString();
// 模拟点击动画
fastBtn.style.transform = 'scale(0.95)';
setTimeout(() => {
fastBtn.style.transform = 'scale(1)';
}, 100);
});
/* 如果坚持要用click,也可以试试FastClick库的思路:
在document上监听touchstart,然后手动触发click */
</script>
</body>
</html>
用touchend替代click是最直接的办法。但要注意e.preventDefault()这行,不加的话touchend触发完之后浏览器还会再发一个click事件,导致逻辑执行两遍。如果你用的是现代浏览器或者已经设置了viewport的user-scalable=no,其实可以不用管这个问题,300ms延迟在现在的移动浏览器上已经基本解决了。
坑二:touch事件和click事件打架
这是最容易产生玄学bug的地方。你在按钮上同时绑了touchstart和click,结果按钮要么反应两遍,要么完全不反应。原因是触摸操作会先触发touch系列事件,然后浏览器再触发click事件,两个事件都去响应同一个操作,逻辑就乱了。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>触摸事件冲突解决</title>
<style>
body { padding: 20px; font-family: sans-serif; }
.test-area {
background: #f0f0f0;
padding: 20px;
border-radius: 10px;
margin-bottom: 20px;
}
.ctrl-btn {
padding: 14px 28px;
border: none;
border-radius: 8px;
font-size: 16px;
margin: 5px;
cursor: pointer;
}
.btn-primary { background: #2196F3; color: white; }
.btn-success { background: #4CAF50; color: white; }
.btn-danger { background: #f44336; color: white; }
#status {
margin-top: 15px;
padding: 12px;
background: #fff;
border-radius: 6px;
font-size: 14px;
border: 1px solid #ddd;
}
</style>
</head>
<body>
<h3>触摸事件冲突演示</h3>
<div class="test-area">
<p><strong>错误写法</strong>:同时监听touchstart和click</p>
<button class="ctrl-btn btn-danger" id="badBtn">点我(会触发两次)</button>
<p style="margin-top:15px;"><strong>正确写法</strong>:只用touch系列事件</p>
<button class="ctrl-btn btn-success" id="goodBtn">点我(只触发一次)</button>
<p style="margin-top:15px;"><strong>通用写法</strong>:先试touch,fallback到click</p>
<button class="ctrl-btn btn-primary" id="smartBtn">点我(智能适配)</button>
</div>
<div id="status">等待操作...</div>
<script>
const status = document.getElementById('status');
let badCount = 0;
/* 错误示范:touchstart和click都绑定,会触发两次 */
const badBtn = document.getElementById('badBtn');
badBtn.addEventListener('touchstart', (e) => {
e.preventDefault();
badCount++;
status.innerHTML = `<span style="color:#f44336">错误写法被触发了 ${badCount} 次!</span>`;
});
badBtn.addEventListener('click', () => {
status.innerHTML += `<br>click也被触发了!总计:${badCount + 1} 次`;
});
/* 正确写法:只用touchend,彻底避开click */
const goodBtn = document.getElementById('goodBtn');
goodBtn.addEventListener('touchend', (e) => {
e.preventDefault();
status.textContent = '✅ 正确写法:touchend触发,click被阻止,只响应一次';
});
/* 智能写法:检测触摸能力,有触摸就用touch事件,没有就退回click */
const smartBtn = document.getElementById('smartBtn');
function isTouchDevice() {
return ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);
}
smartBtn.addEventListener(isTouchDevice() ? 'touchend' : 'click', (e) => {
if (isTouchDevice()) e.preventDefault();
status.textContent = '✅ 智能写法:检测到触摸设备,使用touchend事件';
});
</script>
</body>
</html>
这段代码里三种写法对比得很清楚。第一种是新手最容易犯的错,第二种是最干净的方案,第三种适合需要兼容鼠标的场景。实际开发中我推荐第二种——移动端页面基本不用考虑鼠标,用touch系列事件就完事了。
坑三:点击穿透问题
这个问题在弹窗或者浮层场景里特别常见。页面底部有个按钮A,上面弹了一个遮罩层B,遮罩层上有个关闭按钮C。结果用户点关闭按钮C的时候,点击事件穿透了遮罩层,把底下的按钮A也触发了。用户明明只想关弹窗,结果弹窗关了的同时还触发了一个不该触发的操作。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>点击穿透问题解决</title>
<style>
body {
font-family: sans-serif;
padding: 20px;
margin: 0;
}
.page-btn {
display: block;
width: 100%;
padding: 16px;
margin-bottom: 15px;
border: none;
border-radius: 10px;
background: #2196F3;
color: white;
font-size: 17px;
}
.overlay {
display: none;
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.5);
z-index: 1000;
}
.overlay.active { display: flex; align-items: center; justify-content: center; }
.modal {
background: white;
padding: 30px;
border-radius: 16px;
width: 80%;
max-width: 320px;
text-align: center;
}
.modal h3 { margin-top: 0; }
.close-btn {
margin-top: 20px;
padding: 12px 30px;
border: none;
border-radius: 8px;
background: #f44336;
color: white;
font-size: 16px;
}
#log {
margin-top: 20px;
padding: 15px;
background: #f9f9f9;
border-radius: 8px;
font-size: 14px;
border-left: 4px solid #2196F3;
}
</style>
</head>
<body>
<button class="page-btn" id="openBtn">打开弹窗</button>
<button class="page-btn" id="bottomBtn" style="background:#4CAF50;">页面底部按钮(不应该被穿透触发)</button>
<div class="overlay" id="overlay">
<div class="modal">
<h3>弹窗内容</h3>
<p>这是弹窗里的内容</p>
<button class="close-btn" id="closeBtn">关闭弹窗</button>
</div>
</div>
<div id="log">等待操作...</div>
<script>
const overlay = document.getElementById('overlay');
const log = document.getElementById('log');
document.getElementById('openBtn').addEventListener('click', () => {
overlay.classList.add('active');
log.textContent = '弹窗已打开';
});
document.getElementById('bottomBtn').addEventListener('click', () => {
log.innerHTML = '❌ <span style="color:#f44336">底部按钮被触发了!这可能是点击穿透导致的</span>';
});
/* 方案一:在遮罩层上拦截touch事件,阻止事件穿透 */
overlay.addEventListener('touchstart', (e) => {
/* 如果点的是modal内部,不阻止;点的是遮罩层空白区域才阻止 */
if (e.target === overlay) {
e.preventDefault();
closeOverlay();
}
});
document.getElementById('closeBtn').addEventListener('touchend', (e) => {
e.stopPropagation(); /* 阻止事件向父元素冒泡 */
e.preventDefault(); /* 阻止触发后续的click */
closeOverlay();
});
function closeOverlay() {
overlay.classList.remove('active');
log.textContent = '弹窗已关闭';
}
/* 关键点说明:
1. stopPropagation() 阻止事件冒泡,防止点击modal内的按钮时事件冒泡到overlay
2. preventDefault() 阻止浏览器默认行为(可能触发click)
3. 遮罩层的touchstart事件里判断target,只有点遮罩空白处才关闭弹窗
*/
</script>
</body>
</html>
点击穿透的核心解决思路就是两层防御:一是用stopPropagation()阻止事件冒泡,二是用preventDefault()阻止默认行为。在弹窗关闭按钮上绑定touch事件时同时调用这两个方法,基本就能解决穿透问题。另外遮罩层的空白区域点击也可以用来关闭弹窗,这时候判断e.target是不是遮罩层本身来决定是否关闭,逻辑更合理。
屏幕适配的终极方案
前面说的那些都是局部问题的解决,适配问题要从根本上解决才靠谱。移动端适配的核心就一个词:流式。元素尺寸不应该固定,而应该根据屏幕宽度按比例变化。
viewport meta标签——一切的前提
不管用哪种适配方案,这个meta标签都必须加,不加的话所有适配都白搭:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
这行代码的意思是:页面宽度等于设备宽度,初始缩放比例1.0,不允许用户手动缩放。user-scalable=no除了消除300ms延迟,还能防止用户意外放大导致布局完全乱掉。不过要注意,完全禁止缩放对视力障碍用户不友好,如果产品对无障碍有要求,可以去掉user-scalable=no。
rem适配方案——最经典的移动端适配
rem是相对于根元素字体大小的单位,只要动态设置根元素的font-size,整个页面的尺寸就能跟着屏幕宽度等比缩放。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>rem适配方案</title>
<script>
/* 根据屏幕宽度动态计算根字体大小
设计稿通常是750px宽,这里以750px为基准,1rem = 100px */
(function() {
const designWidth = 750; /* 设计稿宽度 */
const baseFontSize = 100; /* 基准fontSize,1rem = 100px */
function setRootFontSize() {
const currentWidth = document.documentElement.clientWidth;
const scale = currentWidth / designWidth;
document.documentElement.style.fontSize = (baseFontSize * scale) + 'px';
}
setRootFontSize();
window.addEventListener('resize', setRootFontSize);
})();
</script>
<style>
/* 设计稿中元素宽度150px,转换为rem就是1.5rem */
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
.header {
height: 1rem; /* 设计稿100px */
background: #2196F3;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.32rem; /* 设计稿32px */
}
.content {
padding: 0.3rem;
}
.card {
width: 7.5rem; /* 设计稿750px */
height: 4rem; /* 设计稿400px */
background: #f5f5f5;
border-radius: 0.2rem;
margin-bottom: 0.3rem;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.28rem;
color: #666;
}
.btn {
display: block;
width: 7.5rem;
height: 1.2rem;
background: #4CAF50;
color: white;
border: none;
border-radius: 0.15rem;
font-size: 0.36rem;
margin-top: 0.3rem;
}
</style>
</head>
<body>
<div class="header">适配测试头部</div>
<div class="content">
<div class="card">自适应卡片</div>
<button class="btn">自适应按钮</button>
</div>
</body>
</html>
这个方案的核心逻辑是:设计稿量出来的尺寸除以100就是rem值。比如设计稿上按钮宽750px,就写成7.5rem;字体32px,就写成0.32rem。JavaScript动态计算根字体大小,屏幕变宽rem自动变大,屏幕变窄rem自动变小,整个页面等比缩放。
flexbox——布局的神器
适配不只是尺寸要自适应,布局更要自适应。flexbox是移动端布局的最佳选择,一行代码就能让元素自适应排列,再也不用用float或者绝对定位去硬挤了。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Flexbox自适应布局</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: sans-serif; padding: 15px; }
/* 等分布局 */
.flex-row {
display: flex;
gap: 10px;
margin-bottom: 15px;
}
.flex-item {
flex: 1; /* 等分剩余空间 */
padding: 20px;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border-radius: 10px;
text-align: center;
font-size: 14px;
}
/* 自适应排列,一行放不下自动换行 */
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.tag {
padding: 6px 14px;
background: #e3f2fd;
color: #1976D2;
border-radius: 20px;
font-size: 13px;
}
/* 底部固定按钮 */
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
padding: 12px 15px;
padding-bottom: calc(12px + env(safe-area-inset-bottom));
background: white;
box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
}
.bottom-btn {
flex: 1;
padding: 12px;
border: none;
border-radius: 8px;
font-size: 15px;
font-weight: 500;
}
.btn-primary { background: #2196F3; color: white; margin-right: 10px; }
.btn-secondary { background: #f5f5f5; color: #333; }
</style>
</head>
<body>
<div class="flex-row">
<div class="flex-item">等分1</div>
<div class="flex-item">等分2</div>
<div class="flex-item">等分3</div>
</div>
<div class="tag-list">
<span class="tag">JavaScript</span>
<span class="tag">CSS</span>
<span class="tag">HTML5</span>
<span class="tag">移动端</span>
<span class="tag">适配</span>
<span class="tag">Flexbox</span>
<span class="tag">响应式</span>
</div>
<div style="height: 80px;"></div>
<div class="bottom-bar">
<button class="bottom-btn btn-secondary">取消</button>
<button class="bottom-btn btn-primary">确认提交</button>
</div>
</body>
</html>
flexbox的flex: 1让多个元素自动等分容器宽度,不管屏幕多宽都能完美适配。flex-wrap: wrap让标签类元素在宽度不够时自动换行,不需要写任何媒体查询。底部按钮栏用position: fixed加上safe-area-inset-bottom,在iPhone X以上的机型上也不会被手势指示条挡住。
实战中几个容易被忽视的细节
字体大小不要小于14px
很多设计师喜欢用小字体做精致感,但在手机上字体小于14px基本就是折磨用户。更重要的是,字体太小时点击区域也会跟着变小,用户很容易点偏或者点不到。按钮的触摸区域至少要有44x44像素(iOS的人机交互规范推荐的最小点击区域),这个一定要在样式里通过padding保证,不能只靠字体大小。
/* 一个合格的移动端按钮 */
.btn-touch {
min-height: 44px; /* 最小触摸区域高度 */
min-width: 44px; /* 最小触摸区域宽度 */
font-size: 16px; /* 字体不小于16px,阅读舒适 */
padding: 12px 24px; /* padding确保有足够点击区域 */
display: flex;
align-items: center;
justify-content: center;
}
图片处理
移动端图片处理不当会撑爆布局或者加载过慢。用max-width: 100%和height: auto让图片随容器自适应,不会超出边界。如果图片是背景图,用background-size: cover或者contain来控制缩放方式。
.responsive-img {
max-width: 100%;
height: auto;
display: block;
border-radius: 8px;
}
调试技巧
移动端开发最大的困难是调试。浏览器开发者工具在模拟器上跑没问题,真机上完全不一样。我推荐两个工具:Chrome DevTools的设备模拟器用于初步调试,Safari的”检查元素”功能(开启开发模式后连接iPhone)用于真机调试。真机调试能看到最真实的渲染效果和触摸行为,很多在模拟器上看不出来的错位和点击问题,真机上一试就知道。
总结一下
移动端开发踩的坑,归根结底是对移动端特性的理解不够深。页面错位大多是因为用了绝对尺寸,按钮点不动大多是因为事件绑定方式不对,点击穿透是因为没有处理好事件冒泡和默认行为。
记住这几个核心原则,基本能避开90%的坑:
- 布局用相对单位,px只用于边框这种确实需要固定像素的场景
- 全局加
box-sizing: border-box,这行CSS能省去无数调试时间 - 按钮用touch事件,touchend比click更适合移动端
- viewport标签必加,这是移动端开发的第一步
- flexbox是布局首选,少写媒体查询多写弹性布局
- 真机调试不能省,模拟器再准也不如实机
适配和触摸事件的问题没有一劳永逸的万能代码,但掌握了这些底层原理,遇到新问题也能快速定位和解决。开发过程中多花几分钟在真机上测试,能省回几小时的调试时间,这账怎么算都划算。
