移动端适配方案

2026-06-22 · 6 阅读 · 548字
CSSHTML

移动端适配方案

移动端适配的挑战

移动设备屏幕尺寸繁多,从 320px 宽的小屏手机到 430px 宽的大屏手机,还有各种折叠屏和 Pad。适配的目标是让页面在不同设备上都有良好的显示效果。

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:禁止用户缩放(注意可访问性,谨慎使用)

常见适配方案

1. 媒体查询

最基础的方式,针对不同宽度写不同样式:

/* 小屏手机 */
@media (max-width: 374px) {
  .title { font-size: 16px; }
}

/* 标准手机 */
@media (min-width: 375px) and (max-width: 767px) {
  .title { font-size: 18px; }
}

/* 大屏手机/小平板 */
@media (min-width: 768px) {
  .title { font-size: 20px; }
}

优点:兼容性好,细粒度控制 缺点:代码量多,断点维护麻烦

2. rem 适配

rem 是相对于根元素(html)的字体大小。通过根据屏幕宽度动态设置根字体大小,实现等比缩放。

// 动态设置根字体大小
function setRootFontSize() {
  const width = document.documentElement.clientWidth;
  // 以 375px 设计稿为基准,1rem = 100px
  const fontSize = (width / 375) * 100;
  document.documentElement.style.fontSize = `${Math.min(fontSize, 150)}px`;
}

setRootFontSize();
window.addEventListener('resize', setRootFontSize);
/* 设计稿:375px,测量值 75px → 0.75rem */
.box {
  width: 0.75rem;  /* 实际 = 75px */
  height: 0.5rem;   /* 实际 = 50px */
  font-size: 0.28rem; /* 实际 = 28px */
  padding: 0.2rem;   /* 实际 = 20px */
}

优点:等比缩放,一套代码适配所有宽度 缺点:小数像素可能产生偏差

3. vw/vh 适配

视口单位 vw(视口宽度 1%)和 vh(视口高度 1%)天然与视口尺寸关联。

/* 设计稿 375px:元素宽度 75px → 75 / 375 * 100 = 20vw */
.box {
  width: 20vw;   /* 相当于 75px(在 375px 宽度下) */
  height: 13.33vw; /* 相当于 50px */
  font-size: 7.47vw; /* 相当于 28px */
}

/* 限制最大/最小尺寸 */
.box {
  width: min(20vw, 150px);
  font-size: clamp(16px, 4vw, 24px);
}

优点:纯 CSS 方案,无需 JavaScript 缺点:全面使用 vw 可能导致在大屏上过大,需要配合 clamp 或 max 限制

4. 结合使用 rem + vw

/* 设置根字体大小用 vw,子元素用 rem */
html {
  font-size: calc(100vw / 3.75); /* 375px 设计稿,1rem = 1vw × 100 / 3.75 */
}

/* 等价于:
   375px 宽度 → 1rem = 100px
   414px 宽度 → 1rem = 110.4px
   320px 宽度 → 1rem = 85.33px
*/

.box {
  width: 0.75rem; /* 自动适配 */
}

5. 像素比(DPR)适配

高清屏(Retina)需要处理 1px 边框问题:

/* 1px 物理像素边框 */
.border-bottom {
  position: relative;
}

.border-bottom::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: #ddd;
}

@media (-webkit-min-device-pixel-ratio: 2) {
  .border-bottom::after {
    transform: scaleY(0.5);
  }
}

@media (-webkit-min-device-pixel-ratio: 3) {
  .border-bottom::after {
    transform: scaleY(0.333);
  }
}

常用 CSS 工具函数

// SCSS mixin for 1px border
@mixin border-1px($color: #ddd) {
  position: relative;
  &::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 1px;
    background: $color;
    @media (-webkit-min-device-pixel-ratio: 2) { transform: scaleY(0.5); }
    @media (-webkit-min-device-pixel-ratio: 3) { transform: scaleY(0.333); }
  }
}

安全区域适配

全面屏(刘海屏)适配

/* iOS 安全区域 */
.safe-area {
  padding-top: constant(safe-area-inset-top);
  padding-top: env(safe-area-inset-top);
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: constant(safe-area-inset-left);
  padding-left: env(safe-area-inset-left);
  padding-right: constant(safe-area-inset-right);
  padding-right: env(safe-area-inset-right);
}

/* 固定底部栏适配 */
.fixed-bottom {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  padding-bottom: calc(12px + env(safe-area-inset-bottom));
}

移动端触摸事件

// 300ms 延迟问题(已由 viewport=user-scalable=no 解决)
// 或者使用 touch-action: manipulation

// 点击穿透
// 解决方案:使用 touch 事件或 fastclick 库

// 触摸事件优化
.button {
  touch-action: manipulation; /* 禁止双击缩放 */
  -webkit-tap-highlight-color: transparent; /* 去除点击高亮 */
  user-select: none; /* 禁止选中 */
}

总结

方案 推荐场景 优点 缺点
媒体查询 简单适配 精确控制 代码量大
rem 等比缩放 统一适配 需 JS 辅助
vw/vh 纯 CSS 简洁自然 大屏需限制
rem + vw 推荐组合 兼顾两者 -

推荐策略:使用 rem + vw 做页面主体适配,配合 clamp() 限制极端尺寸,再结合媒体查询处理特殊断点。1px 边框使用伪元素 + transform scale 方案。