aurora blog
  • JS

    • 基本汇总
    • Date时间
    • Array方法
    • String 方法
    • Object方法
    • RegExp正则
    • Es6 新特性等
    • Event-Loop
    • Http and Https
    • for in和for of区别
    • Web Worker
    • Promise && async
    • 堆内存 & 栈内存
    • JS设计模式探索
    • npm & yarn
    • Fetch和Axios的区别
    • 学习及面试问题整理
    • URL 输入到页面加载过程
    • 跨域&nginx本地项目代理
  • FE框架

    • react

      • 基本用法
      • react生命周期
      • hooks 16.8版本后
      • Route原理
      • Redux源码解析
      • React16 Fiber
      • React-VirtualDOM
      • React事件委托机制
      • React性能优化
      • 状态管理方案对比
      • React 18新特性
    • vue

      • vue 基本用法
      • vue 生命周期
      • VirtualDOM
      • vue 事件委托
      • vue 架构
      • vue 状态管理
      • 问题等
    • React-Native

      • React-Native 基本用法
    • 微前端

      • 遇到的问题
    • 鸿蒙 harmony

      • harmony 基础
  • 构建工具

    • webpack

      • Webpack配置详解
      • Webpack的使用
      • Babel-polyfill
      • webpack面试题
    • vite

      • vite配置详解
      • vite面试题
    • rollup

      • Rollup配置详解
      • rollup面试题
    • 构建工具对比
  • 性能优化

    • 性能优化策略
    • 缓存策略
    • 性能优化面试题
  • 浏览器

    • 浏览器渲染原理
    • 浏览器缓存机制
    • 浏览器面试题
  • 工程化

    • 代码规范
    • 工程化面试题
  • 前端安全

    • XSS 攻击与防护
    • CSRF 攻击与防护
    • 前端安全面试题
  • 移动端开发

    • 移动端适配
    • 移动端开发面试题
  • 前端监控

    • 错误监控
    • 性能监控
    • 前端监控面试题
  • Typescript

    • Typescript详解
  • Servers

    • Nodejs
    • Nginx
  • Git命令

    • git常用规范
  • 数据库

    • mongodb
    • mongodb
  • Other

    • Jenkins自动化部署

移动端适配

  • 移动端适配概述
  • 视口设置
    • viewport 配置
    • 动态设置
  • 适配方案
    • 1. rem 适配
    • 2. vw/vh 适配
    • 3. flexible.js(已废弃)
    • 4. 媒体查询
  • 1px 问题
    • 问题原因
    • 解决方案
  • 移动端特殊处理
    • 1. 禁止点击高亮
    • 2. 禁止长按菜单
    • 3. 禁止双击缩放
    • 4. 禁止滚动穿透
    • 5. 安全区域适配(iPhone X+)
  • 触摸事件
    • 事件类型
    • 手势识别
  • 性能优化
    • 1. 减少重排重绘
    • 2. 使用 will-change
    • 3. 图片优化
    • 4. 减少 DOM 操作
  • 调试技巧
    • 1. Chrome DevTools
    • 2. 真机调试
    • 3. vConsole
  • 最佳实践
    • 1. 选择合适的适配方案
    • 2. 处理 1px 问题
    • 3. 优化触摸体验
    • 4. 性能优化

移动端适配概述

移动端适配是确保网页在不同设备上正常显示的关键,主要包括:

  • 视口设置:viewport 配置
  • 单位选择:rem、vw/vh、px
  • 媒体查询:响应式设计
  • 1px 问题:高分辨率屏幕处理

视口设置

viewport 配置

标准配置:

<meta name="viewport" 
      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

参数说明:

  • width=device-width:视口宽度等于设备宽度
  • initial-scale=1.0:初始缩放比例
  • maximum-scale=1.0:最大缩放比例
  • user-scalable=no:禁止用户缩放

动态设置

function setViewport() {
  const width = window.innerWidth || document.documentElement.clientWidth;
  const scale = width / 375; // 设计稿宽度
  const viewport = document.querySelector('meta[name="viewport"]');
  viewport.setAttribute('content', 
    `width=375, initial-scale=${scale}, maximum-scale=${scale}, user-scalable=no`);
}

适配方案

1. rem 适配

原理:

  • 根据屏幕宽度动态设置根元素字体大小
  • 使用 rem 单位

实现:

(function() {
  function setRem() {
    const width = document.documentElement.clientWidth || document.body.clientWidth;
    const rem = width / 10; // 375px 设计稿,1rem = 37.5px
    document.documentElement.style.fontSize = rem + 'px';
  }
  
  setRem();
  window.addEventListener('resize', setRem);
})();

使用:

/* 设计稿 375px,元素宽度 100px */
.element {
  width: 2.67rem; /* 100 / 37.5 */
}

工具:

  • postcss-pxtorem:自动转换 px 到 rem

2. vw/vh 适配

原理:

  • 使用视口单位
  • 1vw = 视口宽度的 1%
  • 1vh = 视口高度的 1%

实现:

/* 设计稿 375px,元素宽度 100px */
.element {
  width: 26.67vw; /* 100 / 375 * 100 */
}

工具:

  • postcss-px-to-viewport:自动转换 px 到 vw

3. flexible.js(已废弃)

原理:

  • 动态设置根元素字体大小
  • 使用 rem 单位
  • 处理 1px 问题

注意: 已不推荐使用,推荐使用 rem 或 vw/vh

4. 媒体查询

断点设置:

/* 移动端 */
@media screen and (max-width: 767px) {
  .container {
    width: 100%;
  }
}

/* 平板 */
@media screen and (min-width: 768px) and (max-width: 1023px) {
  .container {
    width: 750px;
  }
}

/* PC */
@media screen and (min-width: 1024px) {
  .container {
    width: 1200px;
  }
}

1px 问题

问题原因

高分辨率屏幕:

  • 设备像素比(DPR)> 1
  • 1px CSS = 多个物理像素
  • 导致边框变粗

解决方案

1. transform scale:

.border {
  position: relative;
}

.border::after {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 1px;
  background: #000;
  transform: scaleY(0.5);
  transform-origin: 0 0;
}

2. viewport 缩放:

const dpr = window.devicePixelRatio;
const scale = 1 / dpr;
const viewport = document.querySelector('meta[name="viewport"]');
viewport.setAttribute('content', 
  `width=device-width, initial-scale=${scale}, maximum-scale=${scale}`);

3. border-image:

.border {
  border: 1px solid transparent;
  border-image: linear-gradient(to bottom, #000 50%, transparent 50%) 1;
}

4. box-shadow:

.border {
  box-shadow: 0 1px 0 0 #000;
}

移动端特殊处理

1. 禁止点击高亮

* {
  -webkit-tap-highlight-color: transparent;
}

2. 禁止长按菜单

* {
  -webkit-touch-callout: none;
  user-select: none;
}

3. 禁止双击缩放

let lastTouchEnd = 0;
document.addEventListener('touchend', (e) => {
  const now = Date.now();
  if (now - lastTouchEnd <= 300) {
    e.preventDefault();
  }
  lastTouchEnd = now;
}, false);

4. 禁止滚动穿透

function preventScroll(e) {
  e.preventDefault();
}

// 打开弹窗时
document.body.style.overflow = 'hidden';
document.body.addEventListener('touchmove', preventScroll, { passive: false });

// 关闭弹窗时
document.body.style.overflow = '';
document.body.removeEventListener('touchmove', preventScroll);

5. 安全区域适配(iPhone X+)

.safe-area {
  padding-bottom: constant(safe-area-inset-bottom); /* iOS 11.0-11.2 */
  padding-bottom: env(safe-area-inset-bottom); /* iOS 11.2+ */
}

触摸事件

事件类型

触摸事件:

  • touchstart:触摸开始
  • touchmove:触摸移动
  • touchend:触摸结束
  • touchcancel:触摸取消

事件对象:

element.addEventListener('touchstart', (e) => {
  const touch = e.touches[0];
  console.log(touch.clientX); // X 坐标
  console.log(touch.clientY); // Y 坐标
});

手势识别

滑动:

let startX, startY;

element.addEventListener('touchstart', (e) => {
  startX = e.touches[0].clientX;
  startY = e.touches[0].clientY;
});

element.addEventListener('touchend', (e) => {
  const endX = e.changedTouches[0].clientX;
  const endY = e.changedTouches[0].clientY;
  
  const deltaX = endX - startX;
  const deltaY = endY - startY;
  
  if (Math.abs(deltaX) > Math.abs(deltaY)) {
    // 水平滑动
    if (deltaX > 0) {
      console.log('右滑');
    } else {
      console.log('左滑');
    }
  } else {
    // 垂直滑动
    if (deltaY > 0) {
      console.log('下滑');
    } else {
      console.log('上滑');
    }
  }
});

性能优化

1. 减少重排重绘

/* 使用 transform 代替 top/left */
.element {
  transform: translateX(100px);
}

2. 使用 will-change

.element {
  will-change: transform;
}

3. 图片优化

  • 使用 WebP 格式
  • 懒加载
  • 响应式图片

4. 减少 DOM 操作

  • 使用虚拟滚动
  • 批量操作
  • 使用 DocumentFragment

调试技巧

1. Chrome DevTools

  • 设备模拟器
  • 网络节流
  • 触摸事件模拟

2. 真机调试

Android:

  • Chrome DevTools 远程调试
  • USB 调试

iOS:

  • Safari Web Inspector
  • 需要 Mac

3. vConsole

<script src="https://cdn.jsdelivr.net/npm/vconsole/dist/vconsole.min.js"></script>
<script>
  const vConsole = new VConsole();
</script>

最佳实践

1. 选择合适的适配方案

  • rem:适合复杂布局
  • vw/vh:适合简单布局
  • 媒体查询:适合响应式设计

2. 处理 1px 问题

  • 使用 transform scale
  • 或使用 viewport 缩放

3. 优化触摸体验

  • 合理设置触摸区域大小(44x44px)
  • 添加触摸反馈
  • 处理滚动穿透

4. 性能优化

  • 减少重排重绘
  • 图片优化
  • 代码分割
最近更新:: 2025/11/20 14:50
Contributors: liyulai
Next
移动端开发面试题