一、方案概述
flexible.js 是阿里巴巴手淘团队开发的移动端自适应 JavaScript 框架,核心是通过动态调整 HTML 根节点的 font-size,结合 rem 单位替代传统 px,实现不同屏幕尺寸下的样式适配,适用于多终端设备的页面适配需求。
核心原理
- 根据设备屏幕宽度,动态为 HTML 根节点设置不同的
font-size - 开发时将 CSS 中的所有
px单位替换为rem单位(rem基于根节点font-size计算) - 框架将设备屏幕宽度划分为 10 等份,根节点
font-size为屏幕宽度的 1/10,确保不同屏幕尺寸下样式比例一致
二、使用方式
1. 直接引入(非构建项目)
在 HTML 的 <head> 标签中引入框架文件,无需额外安装依赖:
\<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.2/??flexible\_css.js,flexible.js">\</script>2. 单页面应用(webpack 等构建工具)
步骤 1:安装依赖
通过 npm 安装官方包:
npm i -S amfe-flexible步骤 2:配置与引入
- 在 HTML 中添加 viewport 元标签(控制屏幕缩放):
\<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">- 在项目入口文件(如
main.js)中引入框架:
import 'amfe-flexible';三、实战案例
1. HTML 结构
\<!DOCTYPE html>
\<html lang="en">
\<head>
  \<meta charset="UTF-8">
  \<meta http-equiv="X-UA-Compatible" content="IE=edge">
  \<!-- viewport 配置 -->
  \<meta name="viewport" content="width=device-width, initial-scale=1.0">
  \<title>flexible 适配示例\</title>
  \<!-- 引入 flexible 框架 -->
  \<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.2/??flexible\_css.js,flexible.js">\</script>
  \<!-- 引入自定义 CSS -->
  \<link href="style.css" type="text/css" rel="stylesheet" />
\</head>
\<body>
  \<div class="header">Flexible一览\</div>
\</body>
\</html>2. CSS 样式(rem 适配)
.header {
  /\* 设计稿中若为 48px,按 750px 设计稿计算(48/75 = 0.64rem,示例中按实际适配后值编写) \*/
  font-size: .48rem; 
  line-height: 1.1733rem; 
  color: #fff;
  text-align: center;
  background: #2475fd;
}3. CSS 中 px 转 rem 工具配置(VS Code)
推荐安装 cssrem 插件,自动实现 px 到 rem 的转换,配置步骤如下:
- 打开 VS Code 插件设置,找到
cssrem相关配置 - 核心配置项调整:
- Cssrem: Root Font Size:基准
font-size,取值为「设计稿宽度 / 10」(如 750px 设计稿设为 75) - Cssrem: Languages:支持的文件类型(默认包含 html、vue、css、less 等,无需额外修改)
- Cssrem: Ignores:忽略转换的文件或值(如
1px、0.5px可添加避免转换)
- 配置后,编写 CSS 时输入
px值会自动提示对应的rem值(如 22px 自动转换为 0.2933rem)
四、源码核心逻辑解析
1. 核心变量初始化
;(function(win, lib) {
  var doc = win.document;
  var docEl = doc.documentElement; // HTML 根节点
  var metaEl = doc.querySelector('meta\[name="viewport"]'); // viewport 元标签
  var flexibleEl = doc.querySelector('meta\[name="flexible"]'); // flexible 自定义元标签
  var dpr = 0; // 设备像素比
  var scale = 0; // 屏幕缩放比例
  var tid; // 定时器 ID
  var flexible = lib.flexible || (lib.flexible = {});
  // ... 后续逻辑
})(window, window\['lib'] || (window\['lib'] = {}));2. 设备像素比(dpr)与缩放比例(scale)计算
- 优先读取已有的
viewport或flexible元标签配置 - 无配置时,根据设备类型(iOS/Android)自动计算:
- iOS 设备:根据
devicePixelRatio取 1/2/3(如 iPhone 6 dpr=2) - Android 设备:默认 dpr=1
- 缩放比例
scale = 1 / dpr(确保视觉一致性)
3. viewport 元标签动态生成
若无手动配置 viewport,框架自动创建并添加:
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
docEl.firstElementChild.appendChild(metaEl); // 插入到 HTML 根节点第一个子元素前4. rem 基准值(根节点 font-size)动态计算
通过 refreshRem 函数实时更新根节点 font-size:
function refreshRem() {
  var width = docEl.getBoundingClientRect().width; // 获取屏幕可视宽度
  if (width / dpr > 540) { // 最大宽度限制(超过 540px 按 540px 计算)
  width = 540 \* dpr;
  }
  var rem = width / 10; // 屏幕宽度分为 10 等份,1rem = 屏幕宽度/10
  docEl.style.fontSize = rem + 'px'; // 设置根节点 font-size
  flexible.rem = win.rem = rem;
}5. 事件监听(确保适配实时性)
- 窗口 resize 事件:屏幕尺寸变化时重新计算 rem(延迟 300ms 避免频繁触发)
- 页面 pageshow 事件:页面从缓存加载时重新计算 rem
- DOMContentLoaded/readyState 事件:页面加载完成后设置 body 的基础字体大小(12*dpr px)
6. 工具方法
框架提供 rem 与 px 互相转换的工具函数:
flexible.rem2px(d):将 rem 转换为 px(如 0.48rem → 对应 px 值)flexible.px2rem(d):将 px 转换为 rem(如 22px → 对应 rem 值)
五、关键概念补充
1. 设备像素比(dpr)
- 定义:
设备像素比 = 物理像素 / 设备独立像素 - 示例:
| 设备型号 | 设备独立像素(pt) | 物理像素(px) | dpr |
|---|---|---|---|
| iPhone 6 | 375 × 667 | 750 × 1334 | 2 |
| iPhone 5 | 320 × 568 | 640 × 1136 | 2 |
| Nexus 5X | 411 × 731 | 411 × 731 | 1 |
2. 设计稿与 rem 换算规则
- 设计稿宽度通常为 750px(对应 iPhone 6 物理像素)
- 根节点
font-size= 设计稿宽度 / 10 = 75px(配置cssrem插件时以此为基准) - 换算公式:
CSS 中 rem 值 = 设计稿中 px 值 / 75(如设计稿 48px → 48/75 = 0.64rem)
六、参考资源
- GitHub 仓库:amfe/lib-flexible
- 官方文档:手淘移动端适配方案说明
(注:文档部分内容可能由 AI 生成)
本文著作权归作者 [ zealoner ] 享有,未经作者书面授权,禁止转载,封面图片来源于 [ 互联网 ] ,本文仅供个人学习、研究和欣赏使用。如有异议,请联系博主及时处理。