H5适配9大高频题连环炸!第3问90%人翻车?

graph TD A[H5适配核心] --> B[布局方案] A --> C[资源加载] A --> D[性能优化] B --> B1(viewport meta) B --> B2(rem/flex/vw) B --> B3(1px border问题) C --> C1(异步加载) C --> C2(分包策略) C --> C3(base64/雪碧图) D --> D1(缓存/预加载) D --> D2(SSR/CDN) D --> D3(并发控制) style A fill:#f9f,stroke:#333 style B fill:#bbf,stroke:#333 style C fill:#bfb,stroke:#333 D --> D4(6个并发上限)

1. 如何实现H5手机端适配?

核心三板斧:viewport + 布局方案 + 屏幕密度处理

html 复制代码
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

这行代码让浏览器按设备宽度渲染,避免自动缩放。

然后选择布局方案:

方案一:rem 适配(推荐)

rem 是相对于根元素(html)字体大小的单位。我们通过 JS 动态设置 html 的 font-size,实现等比缩放。

javascript 复制代码
// 简化版 flexible.js 核心逻辑
function setRootFontSize() {
  const designWidth = 375; // 设计稿宽度
  const root = document.documentElement;
  const width = root.clientWidth; // 设备实际宽度
  const fontSize = width * 100 / designWidth; // 按比例缩放
  root.style.fontSize = fontSize + 'px';
}
window.addEventListener('resize', setRootFontSize);
setRootFontSize();

👉设计稿 750px?那我们按 375px 为基准,1rem = 100px,写样式时 width: 2rem 就是 200px。

方案二:flex 布局

flex 是弹性布局,适合动态分配空间,但不解决整体缩放问题

css 复制代码
.container {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

⚠️flex 是"内部弹性",rem 是"全局缩放"------两者常结合使用!

方案三:vw 单位(现代方案)

1vw = 1% 视口宽度,无需 JS,直接 CSS 控制:

css 复制代码
html {
  font-size: 4.166vw; /* 100px / 24rem ≈ 4.166vw */
}

👉继续看?「Q1: rem 和 vw 哪个更适合复杂项目?」


2. rem、em、px 的区别?

单位 基准 特点
px 像素(绝对) 固定大小,不随缩放变化
em 父元素 font-size 层层继承,易失控(1.2em 的 1.2em = 1.44em)
rem 根元素 html font-size 统一控制,适合响应式
css 复制代码
html { font-size: 16px; }
.parent { font-size: 20px; }
.child {
  font-size: 2em;   /* 40px (20 * 2) */
  width: 2rem;      /* 32px (16 * 2) */
}

🤯你以为懂了?「Q2: 如果用户系统字体放大,rem 会受影响吗?」

A2: 不会!rem 只认 html 的 font-size,JS 设置后就固定了,除非用户禁用 JS。


3. 如何去除 URL 中的 # 号?

# 是 hash 模式,用于前端路由。要去除它,必须使用 History 模式

javascript 复制代码
// Vue Router 示例
const router = new VueRouter({
  mode: 'history', // 默认是 'hash'
  routes: [...]
})

但注意:服务端必须配置 fallback

nginx 复制代码
# Nginx 配置
location / {
  try_files $uri $uri/ /index.html;
}

否则用户刷新 /user/123 会 404 ❌

💥面试官偷笑😏:你上线后出现白屏,怎么排查?

A3: 检查服务端是否返回 index.html,而不是 404。可以用 curl 测试:curl -I http://yourdomain.com/user/123


4. webpack 和 gulp 的优缺点?

工具 类型 优点 缺点
webpack 模块打包器 自动依赖分析、代码分割、HMR 配置复杂、学习曲线陡
gulp 构建流工具 流式处理、任务自动化 不解决模块化,需配合其他工具
javascript 复制代码
// gulpfile.js 示例
const gulp = require('gulp');
const sass = require('gulp-sass');

gulp.task('sass', () => {
  return gulp.src('src/scss/*.scss')
    .pipe(sass()) // 编译
    .pipe(gulp.dest('dist/css'));
});

👉webpack 是"智能打包",gulp 是"流水线工人"。

「Q4: 如果你有 100 个静态 HTML 页面,用哪个更合适?」

A4: gulp!webpack 适合 SPA,多页静态站用 gulp 做压缩、雪碧图更轻量。


5. 如何实现异步加载?

JS 异步加载方式:

  • async:下载不阻塞,下载完立即执行
  • defer:下载不阻塞,DOM 解析完再执行
  • 动态 import:import('./module.js').then(...)
javascript 复制代码
// 动态加载组件(React/Vue 都支持)
const LazyComponent = React.lazy(() => import('./HeavyComponent'));

CSS 异步加载:

javascript 复制代码
// 动态插入 link
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = '/async.css';
document.head.appendChild(link);

「Q5: defer 和 async 的执行顺序能保证吗?」

A5: defer 保证顺序,async 不保证!多个 async 脚本谁先下载完谁执行。


6. 如何实现分模块打包(多入口)?

webpack 支持多入口配置:

javascript 复制代码
// webpack.config.js
module.exports = {
  entry: {
    home: './src/home.js',
    user: './src/user.js',
    admin: './src/admin.js'
  },
  output: {
    filename: '[name].[contenthash].js', // home.abc123.js
    path: __dirname + '/dist'
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  }
};

👉生成:home.js、user.js、admin.js + 公共 vendors.js

「Q6: 如果 home 和 user 都用了 lodash,怎么避免重复打包?」

A6: 用 splitChunks 提取公共模块,或 externals 外链 CDN。


7. 前端性能优化六大方向

1️⃣ JS/CSS 优化

  • 压缩混淆(Terser/Uglify)
  • Tree Shaking(移除未使用代码)
  • 代码分割(Code Splitting)

2️⃣ 图片优化

  • WebP/AVIF 格式
  • 懒加载:<img loading="lazy">
  • 响应式图片:srcset

3️⃣ 缓存 & 预加载

  • 强缓存:Cache-Control: max-age=31536000
  • 协商缓存:ETag
  • 预加载:<link rel="preload">

4️⃣ SSR(服务端渲染)

  • Next.js/Nuxt.js
  • 首屏快、SEO 友好

5️⃣ 多域名加载

  • 浏览器对单域名并发请求数有限制(通常 6 个)
  • static1.domain.comstatic2.domain.com 绕过限制

6️⃣ 负载均衡

  • CDN 分发静态资源
  • Nginx 反向代理 + 轮询

「Q7: 为什么并发请求上限是6个?能突破吗?」

A7: HTTP/1.1 限制,浏览器为避免拥塞。突破方式:HTTP/2 多路复用,或域名分片。


8. base64 为什么能提升性能?缺点?

优点:

  • 减少 HTTP 请求(小图标内联)
  • 避免雪碧图复杂定位
css 复制代码
.icon {
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...);
}

缺点:

  • 体积增大约 33%(Base64 编码)
  • 无法被浏览器缓存
  • 阻塞 CSS 解析(大文件慎用)

「Q8: 什么时候该用 base64?什么时候不该?」

A8: ≤2KB 小图标可用,大文件必须外链!否则首屏卡死。


连环追问链(5连炸💥)

「Q1: rem 和 vw 哪个更适合复杂项目?」

A1: rem 更可控(JS 可干预),vw 更现代(纯 CSS),推荐 vw + rem 混合方案。

「Q2: 如果用户系统字体放大,rem 会受影响吗?」

A2: 不会,rem 只认 html 的 font-size,JS 设置后固定。

「Q3: History 模式上线后白屏,怎么排查?」

A3: 检查服务端是否 fallback 到 index.html,用 curl 测试路径。

「Q4: 100 个静态页用 webpack 还是 gulp?」

A4: gulp 更轻量,适合批量处理静态资源。

「Q5: defer 和 async 执行顺序能保证吗?」

A5: defer 保证,async 不保证!多个 async 脚本执行顺序不确定。

「Q6: lodash 重复打包怎么解决?」

A6: splitChunks 提取公共模块,或 externals 外链。

「Q7: 并发上限6个,能突破吗?」

A7: 用 HTTP/2 多路复用,或域名分片(static1/static2)。

「Q8: base64 什么时候该用?」

A8: ≤2KB 小图标可用,大文件必须外链!👉继续看?「Q9: 如何自动判断图片是否转 base64?」

A9: webpack 的 url-loader 可配置 limit,超限自动发请求。

「Q10: 移动端 1px 边框怎么实现?💥」

A10: transform: scale(0.5)border-image,rem 方案需结合设备像素比!

相关推荐
一只韩非子6 分钟前
AI时代,程序员如何优雅地搞定页面设计?
前端·ai编程
新中地GIS开发老师12 分钟前
2025Mapbox零基础入门教程(14)定位功能
前端·javascript·arcgis·gis·mapbox·gis开发·地理信息科学
tager15 分钟前
Vue 3 组件开发中的"双脚本"困境
前端·vue.js·代码规范
烛阴1 小时前
Int / Floor
前端·webgl
excel1 小时前
使用 PWA 时,为什么你必须手动添加更新逻辑,否则会报错?
前端
Moment1 小时前
Node.js 这么多后端框架,我到底该用哪个?🫠🫠🫠
前端·后端·node.js
尚学教辅学习资料1 小时前
SpringBoot3.x入门到精通系列: 2.3 Web开发基础
前端·springboot·web开发
han_2 小时前
前端遇到页面卡顿问题,如何排查和解决?
前端·javascript·性能优化
拾光拾趣录3 小时前
给Electron-Claude应用构建全面的数据统计体系 - 从0到1的实践总结
前端·electron