web 使用rem方案适配PC端和移动端

303 阅读3分钟

介绍及原理

原理

rem单位的特点,是1rem对应的px值等于根元素html的font-size值。也就是说,当根元素html的font-size值变化时,1rem的值会跟随着动态变化。比如:

有一个div,他的高度设置为1rem,当页面内根元素html的font-size为16px时,这个div的高度就是16px;当页面内的根元素htmlfont-size为32px时,这个div的高度就是32px。

postcss-pxtorem插件会将我们写在样式中的px根据我们在vite.config.js中设置的rootValue值,按比例转化为rem。(要注意哦,行内样式中的px不会被转化为rem)

介绍

postcss-pxtorem:

为了进一步简化开发流程,amfe-flexible通常与postcss-pxtorem插件一起使用。

postcss-pxtorem是一个PostCSS插件,它可以自动将CSS文件中的px单位转换为rem单位。这样,开发者可以直接在CSS中使用px单位,而postcss-pxtorem会自动完成单位转换。

插件安装

npm install postcss-pxtorem

如果运行项目后报错 PostCSS plugin postcss-pxtorem requires PostCSS 8.

需要降低 postcss-pxtorem 的版本

卸载默认安装的版本 
npm uninstall postcss-pxtorem
 
安装指定版本
npm i postcss-pxtorem@5.1.1

postcss-pxtorem 插件配置

在vite.config.js中进行配置

// 引入pxtorem插件
import postCssPxToRem from "postcss-pxtorem";
 
export default defineConfig({
  css: {
    postcss: {
      plugins: [
        postCssPxToRem({
          // 配置在将px转化为rem时 1rem等于多少px
		rootValue: 1920 / 10, // 1920px设计稿的10分之一
          // 所有px均转化为rem
          propList: ["*"]
          // 若想设置部分样式不转化 可以在配置项中写出
          // 例如: 除 border和font-size外 所有px均转化为rem
          // propList: ["*", "!border","!font-size"], 
          // exclude: /node_modules/i, // 排除node_modules内的文件
        })
      ]
    }
  }
})

补充

忽略单个属性的最简单方法是在像素单位声明中使用大写字母,将px写为Px或PX

.ignore {
    border: 1Px solid; 
    border-width: 2PX; 
}

postcss-pxtorem更多配置项:

flexible.js 文件

在和main.js文件同级的目录中新建一个flexible.js 文件

内容如下:

(function flexible(window, document) {
	var docEl = document.documentElement;

	// 断点区间配置(与 variables.scss 保持一致)
	var breakpoints = [
		// 超小屏手机
		{ name: 'mobile-sm', min: 0, max: 480 },
		// 普通手机
		{ name: 'mobile', min: 481, max: 767 },
		// 平板
		{ name: 'tablet', min: 768, max: 1023 },
		// 小型笔记本/桌面
		{ name: 'laptop', min: 1024, max: 1279 },
		// 普通桌面显示器
		{ name: 'desktop', min: 1280, max: 1919 },
		// 超大桌面显示器
		{ name: 'large-desktop', min: 1920, max: Infinity },
	];
	var remBase = 100; // 每个区间最大宽度时 1rem = 100px

	function setRemUnit() {
		var width = docEl.clientWidth;
		var rem;
		for (var i = 0; i < breakpoints.length; i++) {
			var bp = breakpoints[i];
			if (width >= bp.min && width <= bp.max) {
				if (bp.max === Infinity) {
					// large-desktop使用与pc相同的字体大小
					// 计算pc区间最大宽度时的rem值
					var pcMaxWidth = 1920;
					var pcMinWidth = 1024;
					var pcRange = pcMaxWidth - pcMinWidth;
					rem = (remBase * (pcMaxWidth - pcMinWidth)) / pcRange + remBase;
				} else {
					// 线性缩放
					var range = bp.max - bp.min;
					rem = (remBase * (width - bp.min)) / range + remBase;
				}
				break;
			}
		}
		// 如果小于最小断点,继续缩放
		if (rem === undefined) {
			var minBp = breakpoints[0];
			rem = (remBase * (width - minBp.min)) / (minBp.max - minBp.min);
		}
		docEl.style.fontSize = rem + 'px';
	}

	setRemUnit();

	window.addEventListener('resize', setRemUnit);
	window.addEventListener('pageshow', function (e) {
		if (e.persisted) {
			setRemUnit();
		}
	});
})(window, document);

flexible.js 文件配置

在main.js中进行引入

// 普通引用
import './flexible.js';

// 配合pinia引用
// 使用pinia
app.use(pinia);
// 使用flexible
import('./flexible.js');