PostCSS通过px2rem插件和lib-flexible将px单位转换为rem(root em)单位实现大屏适配

news2024/11/24 23:08:20

目录

    • 文档
    • postcss中使用postcss-plugin-px2rem
      • 安装postcss-plugin-px2rem
      • 示例
      • 默认配置
    • webpack中使用postcss-plugin-px2rem
      • 项目结构
      • 安装依赖
      • 文件内容
    • 大屏适配
    • 参考文章

文档

类似的插件

  • postcss-plugin-px2rem

    • https://www.npmjs.com/package/postcss-plugin-px2rem
    • https://github.com/pigcan/postcss-plugin-px2rem
  • postcss-pxtorem

    • https://www.npmjs.com/package/postcss-pxtorem
    • https://github.com/cuth/postcss-pxtorem
  • postcss-px2rem

    • https://www.npmjs.com/package/postcss-px2rem

amfe-flexible
lib-flexible

postcss中使用postcss-plugin-px2rem

安装postcss-plugin-px2rem

pnpm install postcss postcss-plugin-px2rem --save-dev

依赖 package.json

{
    "type": "module",
    "dependencies": {
        "postcss": "^8.4.31",
        "postcss-plugin-px2rem": "^0.8.1"
    }
}

示例

main.js

import { writeFileSync, readFileSync } from "fs";
import postcss from "postcss";
import pxtorem from "postcss-plugin-px2rem";

const css = readFileSync("./style.css", "utf8");

// 修改默认配置
const options = {};

const processedCss = postcss(pxtorem(options)).process(css).css;

writeFileSync("./style.rem.css", processedCss);

输入 style.css

h1 {
  margin: 0 0 20px;
  font-size: 32px;
  line-height: 1.2;
  letter-spacing: 1PX; /* ignored */
}

输出 style.rem.css

h1 {
  margin: 0 0 0.2rem;
  font-size: 0.32rem;
  line-height: 1.2;
  letter-spacing: 1PX;
}

默认配置

{
  rootValue: 100,
  unitPrecision: 5,
  propWhiteList: [],
  propBlackList: [],
  exclude:false,
  selectorBlackList: [],
  ignoreIdentifier: false,
  replace: true,
  mediaQuery: false,
  minPixelValue: 0
}

webpack中使用postcss-plugin-px2rem

项目结构

$ tree -I node_modules
.
├── package.json
├── src
│   ├── index.js
│   └── style.css
└── webpack.config.cjs

安装依赖

pnpm install webpack webpack-cli style-loader css-loader postcss-loader mini-css-extract-plugin --save-dev

完整依赖 package.json

{
  "type": "module",

  "scripts": {
    "build": "webpack"
  },

  "devDependencies": {
    "css-loader": "^6.8.1",
    "mini-css-extract-plugin": "^2.7.6",
    "postcss": "^8.4.31",
    "postcss-loader": "^7.3.3",
    "postcss-plugin-px2rem": "^0.8.1",
    "style-loader": "^3.3.3",
    "webpack": "^5.89.0",
    "webpack-cli": "^5.1.4"
  }
}

文件内容

webpack.config.cjs

"use strict";

const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  // 生产环境
  mode: "production",

  // 打包入口
  entry: {
    index: "./src/index.js",
  },

  // 指定输出地址及打包出来的文件名
  output: {
    path: path.join(__dirname, "dist"),
    filename: "index.js",
  },

  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  [
                    "postcss-plugin-px2rem",
                    // 配置参数
                    {
                      rootValue: 100,
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
    ],
  },

  plugins: [
    // 将 CSS 提取到单独的文件中
    new MiniCssExtractPlugin(),
  ],
};

入口文件 index.js

import "./style.css";

样式文件 style.css

h1 {
  margin: 0 0 20px;
  font-size: 32px;
  line-height: 1.2;
  letter-spacing: 1PX; /* ignored */
}

运行打包

$ npm run build

输出结果

h1 {
  margin: 0 0 0.2rem;
  font-size: 0.32rem;
  line-height: 1.2;
  letter-spacing: 1PX; /* ignored */
}

大屏适配

原理

  • 打包阶段:根据设计稿的尺寸编写css代码(px为单位),将css代码转为rem为单位的数据
  • 浏览器运行阶段:根据根节点root的字体大小,将rem为单位的尺寸还原为px单位

引入文件:lib-flexible.js

因为lib-flexible.js 原本是用来适配移动端的,所以,需要改动一些代码才能适配PC大屏,只能通过整个文件引入,不要通过npm安装,否则每次安装都需要重新修改代码

需要改动的代码如下

function refreshRem() {
    var width = docEl.getBoundingClientRect().width;
    
    // 适配移动端
    // if (width / dpr > 540) {
    //   width = 540 * dpr;
    // }

    // 适配PC端
    // 最小宽度1200px
    // if (width / dpr < 1200) {
    //   width = 1200 * dpr;
    // }
    
    // 根据这个值计算postcss-plugin-px2rem的配置参数 rootValue
    // 设置px->rem的比例是:100
    // var rem = width / 10;
    var rem = width / 100;
    docEl.style.fontSize = rem + "px";
    flexible.rem = win.rem = rem;
  }

这里可以设置一个最小宽度,配置页面也设置一个最小宽度,避免屏幕过小而变形

body{
	min-width: 1200px;
}

完整代码

/**
 * lib-flexible
 * Version 0.3.2
 * https://www.npmjs.com/package/lib-flexible?activeTab=code
 */
(function (win, lib) {
  var doc = win.document;
  var docEl = doc.documentElement;
  var metaEl = doc.querySelector('meta[name="viewport"]');
  var flexibleEl = doc.querySelector('meta[name="flexible"]');
  var dpr = 0;
  var scale = 0;
  var tid;
  var flexible = lib.flexible || (lib.flexible = {});

  if (metaEl) {
    console.warn("将根据已有的meta标签来设置缩放比例");
    var match = metaEl
      .getAttribute("content")
      .match(/initial\-scale=([\d\.]+)/);
    if (match) {
      scale = parseFloat(match[1]);
      dpr = parseInt(1 / scale);
    }
  } else if (flexibleEl) {
    var content = flexibleEl.getAttribute("content");
    if (content) {
      var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
      var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
      if (initialDpr) {
        dpr = parseFloat(initialDpr[1]);
        scale = parseFloat((1 / dpr).toFixed(2));
      }
      if (maximumDpr) {
        dpr = parseFloat(maximumDpr[1]);
        scale = parseFloat((1 / dpr).toFixed(2));
      }
    }
  }

  if (!dpr && !scale) {
    var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/iphone/gi);
    var devicePixelRatio = win.devicePixelRatio;
    if (isIPhone) {
      // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
      if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
        dpr = 3;
      } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
        dpr = 2;
      } else {
        dpr = 1;
      }
    } else {
      // 其他设备下,仍旧使用1倍的方案
      dpr = 1;
    }
    scale = 1 / dpr;
  }

  docEl.setAttribute("data-dpr", dpr);
  if (!metaEl) {
    metaEl = doc.createElement("meta");
    metaEl.setAttribute("name", "viewport");
    metaEl.setAttribute(
      "content",
      "initial-scale=" +
        scale +
        ", maximum-scale=" +
        scale +
        ", minimum-scale=" +
        scale +
        ", user-scalable=no"
    );
    if (docEl.firstElementChild) {
      docEl.firstElementChild.appendChild(metaEl);
    } else {
      var wrap = doc.createElement("div");
      wrap.appendChild(metaEl);
      doc.write(wrap.innerHTML);
    }
  }

  function refreshRem() {
    var width = docEl.getBoundingClientRect().width;
    
    // 适配移动端
    // if (width / dpr > 540) {
    //   width = 540 * dpr;
    // }

    // 适配PC端
    // 最小宽度1200px
    // if (width / dpr < 1200) {
    //   width = 1200 * dpr;
    // }
    
    // 根据这个值计算postcss-plugin-px2rem的配置参数 rootValue
    // 设置px->rem的比例是:100
    // var rem = width / 10;
    var rem = width / 100;
    docEl.style.fontSize = rem + "px";
    flexible.rem = win.rem = rem;
  }

  win.addEventListener(
    "resize",
    function () {
      clearTimeout(tid);
      tid = setTimeout(refreshRem, 300);
    },
    false
  );
  win.addEventListener(
    "pageshow",
    function (e) {
      if (e.persisted) {
        clearTimeout(tid);
        tid = setTimeout(refreshRem, 300);
      }
    },
    false
  );

  if (doc.readyState === "complete") {
    doc.body.style.fontSize = 12 * dpr + "px";
  } else {
    doc.addEventListener(
      "DOMContentLoaded",
      function (e) {
        doc.body.style.fontSize = 12 * dpr + "px";
      },
      false
    );
  }

  refreshRem();

  flexible.dpr = win.dpr = dpr;
  flexible.refreshRem = refreshRem;
  flexible.rem2px = function (d) {
    var val = parseFloat(d) * this.rem;
    if (typeof d === "string" && d.match(/rem$/)) {
      val += "px";
    }
    return val;
  };
  flexible.px2rem = function (d) {
    var val = parseFloat(d) / this.rem;
    if (typeof d === "string" && d.match(/px$/)) {
      val += "rem";
    }
    return val;
  };
})(window, window["lib"] || (window["lib"] = {}));

webpack参数设置

{
 loader: "postcss-loader",
  options: {
    postcssOptions: {
      plugins: [
        [
          "postcss-plugin-px2rem",
          // 配置参数
          {
            // 假设设计稿是1200px, px->rem的比例是:100
            // 1200 / 100 = 12
            rootValue: 12,
          },
        ],
      ],
    },
  },
},

比如:

设计稿尺寸为1200px

.box {
  width: 300px;
  height: 100px;
  background-color: green;
  font-size: 32px;
  line-height: 1.2;
  letter-spacing: 1px; /* ignored */
}

转换结果是

.box {
  width: 25rem;
  height: 8.33333rem;
  background-color: green;
  font-size: 2.66667rem;
  line-height: 1.2;
  letter-spacing: 0.08333rem; /* ignored */
}

在尺寸为1200px的屏幕宽度下,可以还原为代码中设置的尺寸

width: 25rem + 12px =  300px

在这里插入图片描述

在尺寸为1400px的屏幕宽度下,可以还原为代码中设置的尺寸

width: 25rem + 14px =  350px

在这里插入图片描述
这样,在不同的屏幕下,计算出来的根元素font-size就不一样,进而导致页面元素的尺寸也不一样,实现了缩放效果

需要注意的是,这个缩放是基于宽度缩放的,如果屏幕尺寸比例不一致,会导致竖向的内容会缺失,或者出现滚动

完整代码:https://github.com/mouday/webpack-lib-flexible

参考文章

  1. https://webpack.docschina.org/plugins/mini-css-extract-plugin
  2. https://webpack.docschina.org/loaders/postcss-loader/
  3. 使用lib-flexible和postcss-pxtorem解决大屏适配问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1170152.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【深度学习基础】Pytorch框架CV开发(2)实战篇

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

我的大语言模型微调踩坑经验分享

由于 ChatGPT 和 GPT4 兴起&#xff0c;如何让人人都用上这种大模型&#xff0c;是目前 AI 领域最活跃的事情。当下开源的 LLM&#xff08;Large language model&#xff09;非常多&#xff0c;可谓是百模大战。面对诸多开源本地模型&#xff0c;根据自己的需求&#xff0c;选择…

文件夹还在,里面文件没了?问题这样解决

文件夹还在但文件无故消失怎么办&#xff1f;文件的消失对于我们来说可能是个令人沮丧且困惑的问题。有时候&#xff0c;我们可能会发现文件夹依然存在&#xff0c;但其中的文件却消失了。在这篇文章中&#xff0c;我们将探讨为什么电脑文件会无故消失的原因&#xff0c;并提供…

【Kafka】基本概念

文章目录 一、消息队列的流派1.1 有Broker1.1.1 重topic1.1.2 轻topic 1.2 无Broker 二、kafka安装三、kafka基本术语四、发送消息五、消费消息六、单播消息七、多播消息八、查看消费组的详细信息九、主题topic十、分区十一、kafka中消息⽇志⽂件中保存的内容 一、消息队列的流…

微信-Native支付(扫二维码支付)工具类 2023最新保姆教程

0、照着微信开发文档 取到证书、秘钥等 好几个key 1、获取商户号merchantId 账户中心->商户信息->微信支付商户号 3、获取商户证书序列号merchantSerialNumber 账户中心->API安全->API证书管理 5、获取appID 产品中心->AppID账号管理 1、这个链接教你获取各…

1220*2440mm建筑模板木工板:桥梁工程中的覆膜板选择

在桥梁工程中&#xff0c;选择合适的建筑模板木工板至关重要。其中&#xff0c;1220*2440mm规格的建筑模板木工板作为一种常见的选择&#xff0c;特别适用于混凝土工程和桥梁建设。本文将重点介绍这种规格的木工板作为覆膜板在桥梁工程中的应用。 1220*2440mm建筑模板木工板是一…

RISC Zero zkVM架构

1. 引言 RISC Zero zkVM为&#xff1a; 基于 FRI PLONK 构建的采用Von Neumann架构的ZK Machine将RISC-V微控制器 具化为 某基于STARK的证明系统&#xff0c;的微架构和编码机制。 2. Row (Time) Structure 一个cycle对应1个memory transaction&#xff0c;对用户传入的程…

嵌入式Linux HID多指触控/触摸设备报表描述符

这里只做一下简单记录&#xff0c;更为详细的修改流程后续的文章再介绍。 报表描述符 0x05, 0x0D, // Usage Page (Digitizer) 0x09, 0x04, // Usage (Touch Screen) 0xA1, 0x01, // Collection (Application) 0x85, 0x01, // Report ID (1) 0…

jbase实现业务脚本化

经过晚上和早上的努力&#xff0c;终于补上框架最后一块了&#xff0c;业务脚本侦听变化后自动编译jar包和调用&#xff0c;实现维护成本低&#xff0c;开发效率高的框架的基本体系。 实现自动编译jar包的类 package appcode;import org.w3c.dom.Document; import org.w3c.do…

Android 数据恢复的顶级软件分享

人们经常向我们询问有关 Android 数据恢复软件的信息以及它们是否有用。而且&#xff0c;我们给他们讲了两个朋友的故事——凯伦和亚历克斯。他们都丢失了 Android 手机上的一些重要数据。 丢失数据确实是一个令人心碎的时刻&#xff0c;根据丢失的文件&#xff0c;可能会让您…

Linux高级命令(扩展)三

一、date命令 1、date命令的作用 date命令的主要作用&#xff1a;用于获取计算机操作系统的系统时间 2、获取计算机的系统时间 # date 3、定制时间格式 # date "%F %T %Y %m %d %H %M %S" %F : 2020-04-03 %T : 09:45:36 %Y : 年 %m : 月 %d : 日 %H : 小时 %M…

这个超实用的门禁技巧,让办公楼安全更简单高效!

门禁监控是现代社会中不可或缺的一部分&#xff0c;用于确保安全和管理进出某个区域的人员。随着科技的不断发展&#xff0c;门禁监控已经远离了传统的机械锁和钥匙&#xff0c;变得更加智能化和高效。 客户案例 企业办公大楼 无锡某大型企业在其办公大楼内部部署了泛地缘科技…

【机器学习 | PipeLine】机器学习通用管道最佳实践!!(无论什么问题都能套上,确定不来看看?)

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

任正非说:只有“有为”才会“有位”,任何组织只有在流程中创造价值,才可能获得成长的机会。

你好&#xff01;这是华研荟【任正非说】系列的第28篇文章&#xff0c;让我们聆听任正非先生的真知灼见&#xff0c;学习华为的管理思想和管理理念。 一、所有一切要符合未来的作战需要&#xff0c;组织是为了作战而存在的&#xff0c;而不是作战服从组织的。 来源于任正非先生…

RK-3399pro 萤火虫firefly 官方unbuntu 固件系统安装搜狗中文输入法

RK-3399pro 萤火虫firefly 官方unbuntu 固件系统安装搜狗输入法&#xff08;适用于所有基于Ubuntu的UI桌面系统&#xff09; 一、添加中文语言支持输入法平台fcitx 1.安装fcitx sudo apt-get install fcitx 2.然后设置fcitx为开机自启动 sudo cp /usr/share/applications/fc…

Python进阶之推导式与生成器

文章目录 一、推导式1.列表推导式2.字典推导式3.集合推导式4.元组推导式&#xff08;生成器推导式&#xff09; 二、生成器1.生成器表达式2.生成器函数3.send函数 结束语 &#x1f482; 个人主页:风间琉璃&#x1f91f; 版权: 本文由【风间琉璃】原创、在CSDN首发、需要转载请联…

【数智化人物展】华院计算董事长、创始人宣晓华:通用大模型只是起点,尚需结合专业知识方能解决行业核心问题...

宣晓华 本文由华院计算董事长、创始人宣晓华投递并参与《2023中国企业数智化转型升级先锋人物》榜单/奖项评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 大模型的出现&#xff0c;正在开启着国内新一轮AI热潮。 某种程度上&#xff0c;真正在当下决定企业成败的&#…

22款奔驰S400L升级原厂 360全景影像 高清环绕的视野

您是否经历过这种场面呢&#xff1f; 停车位&#xff0c;狭窄障碍停车困难 避免盲区&#xff0c;倒车盲区危及生命安全 狭窄路段&#xff0c;无法判断是否安全通过 视角盲区&#xff0c;小孩站在视野盲区看不到 360度无缝3D全车可见&#xff0c;解决各个视角盲区&#xff…

开发一款直播弹幕游戏需要多少钱?

开发一款直播弹幕游戏需要多少钱&#xff1f;有好多朋友在咨询过弹幕游戏的开发价格后&#xff0c;都会比较吃惊&#xff0c;一款体量这么小的游戏为什么动辄就要几万块甚至十几万&#xff1f; 我来给你们说分析一下原因&#xff0c;这种游戏如果脱离开直播间&#xff0c;可以…

算法通关村第五关-黄金挑战LRU问题

大家好我是苏麟 , 今天聊聊LRU问题 , 相信学过操作系统的小伙伴并不陌生 . LRU问题 LRU的含义 LRU是Least Recently Used的缩写&#xff0c;即最近最少使用&#xff0c;是一种常用的页面置换算法&#xff0c;选择最近最久未使用的页面予以淘汰。 图解 : 如果再有其他元素就依…