通杀pc端自适应(包含可视化大屏)

最近撸项目时,需求只说了做pc端的自适应项目,结果最后验收时,领导还要在大屏看效果,而且大屏还好几种,有一种是地铁站的那种广告屏,还有一种是类似天猫双十一那种巨屏,可想而知,这种普通的pc端项目放上去是什么效果。熬夜撸代码,终于在头发没剩几根时,想出来了一种pc端的自适应解决方案,通杀pc端的自适应适配问题

pc端的显示分析

首先大致说下,px,rem,em这几个单位。

px

CSS 像素(CSS Pixel):
又称为虚拟像素、设备独立像素或逻辑像素,也可以理解为直觉像素。CSS 像素是 Web 编程的概念,指的是 CSS 样式代码中使用的逻辑像素。比如 iPhone 6 的 CSS 像素数为 375 x 667px。

虚拟像素,可以理解为“直觉”像素,CSS和JS使用的抽象单位,浏览器内的一切长度都是以CSS像素为单位的,CSS像素的单位是px。

在CSS规范中,长度单位可以分为两类,绝对(absolute)单位以及相对(relative)单位。px是一个相对单位,相对的是设备像素(device pixel)。

在同样一个设备上,每1个CSS像素所代表的物理像素是可以变化的(即CSS像素的第一方面的相对性);
在不同的设备之间,每1个CSS像素所代表的物理像素是可以变化的(即CSS像素的第二方面的相对性);

px实际是pixel(像素)的缩写,它是图像显示的基本单元,既不是一个确定的物理量,也不是一个点或者小方块,而是一个抽象概念。所以在谈论像素时一定要清楚它的上下文!一定要清楚它的上下文!一定要清楚它的上下文!

举个例子来理解css像素的相对性

假设我们用PC浏览器打开一个页面,浏览器此时的宽度为800px,页面上同时有一个400px宽的块级元素容器。很明显此时块状容器应该占页面的一半。

但如果我们把页面放大(通过“Ctrl键”加上“+号键”),放大为200%,也就是原来的两倍。此时块状容器则横向占满了整个浏览器。

吊诡的是此时我们既没有调整浏览器窗口大小,也没有改变块状元素的css宽度,但是它看上去却变大了一倍——这是因为我们把CSS像素放大为了原来的两倍。

CSS像素与屏幕像素1:1同样大小时:

在这里插入图片描述
CSS像素(黑色边框)开始被拉伸,此时1个CSS像素大于1个屏幕像素

在这里插入图片描述
也就是说默认情况下一个CSS像素应该是等于一个物理像素的宽度的,但是浏览器的放大操作让一个CSS像素等于了两个设备像素宽度。在后面你会看到更复杂的情况,在高PPI的设备上,CSS像素甚至在默认状态下就相当于多个物理像素的尺寸。

从上面的例子可以看出,CSS像素从来都只是一个相对值。

em

相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。

由于浏览器的默认字体大小是 16px,所以未经调整默认字体大小的浏览器都符合: 1em = 16px。

em 会继承父级元素的字体大小。由此,只需要改变父元素的字体大小,就可以同步放大或缩小子元素的字体。

但是也因此需要注意几点:
1、body 选择器中声明 Font-size=62.5% (10 ÷ 16 × 100% = 62.5%);
2、将你的原来的 px 数值除以 10,然后换上 em 作为单位;
3、重新计算那些被放大的字体的 em 数值。避免字体大小的重复声明。

rem

由于 em 存在对父元素继承的问题,当改变字体大小时涉及的继承关系就变得复杂起来。

rem 是相对于根元素 字体尺寸的大小。如 文本大小设为 font-size: 10px,则 1rem = 10px。使用 rem 设置字体则简单了很多。

移动设备的宽度是各种各样的,每个设备的dpr也不同,换句话说就是不同设备每一行的物理像素数不同,能显示的css的px数也不同,如果我们写死px的话,那么后果就是同样的px,在不同设备中显示的行数不同,这样整个排版就乱了,想想有啥解决的思路没?
分析一下造成显示效果不同的原因就是设备宽度不同,你可能会问,那dpr呢,其实与dpr一点关系都没有,想象一下2个宽度为1000个物理像素的设备,一个dpr为1,一个dpr为2,那么在我们看来不过一个是1000px,一个是500px而已,在这里我们感知不到dpr。那么设备宽度不同怎么做适配呢,其实很容易的会想到,每个设备每行显示的px数不同,你写死px数的话,那肯定显示的效果不一样,所以,不能写死,要动态的计算。对,实际上也是这么解决的,那怎么计算呢,很简单,你把一个设备的样式写好了,其他的根据设备的宽度(px数)的比,来动态计算就行了。

rem就是解决这个问题的,rem不是具体的px,rem具体显示多少像素,是根据根元素的font-size来计算的,比如说你设置了1.2rem,根元素的font-size是100px,那么这个元素动态算出来的px数就是120px。不同宽度,设置不同px,这样就可以适配所有宽度的设备了。

pc端显示比例

如下图所示,假设这么一种情况,如果pc端的实际屏幕宽度是1920px,ui给的设计稿宽度也是1920px,那么就意味着你在设计稿内量的1px就等于pc端元素实际的1px,有刚好pc端默认1rem等于16px,所以ui设计稿内量出的px除以16就是我们要的rem单位了,但是1rem等于16px比较难于换算,所以我们人为规定下,pc端1rem等于100px,这个时候就可以得到如图下的等式。

pc端实际宽度 / 设计稿设计宽度 = pc端元素实际宽度 / 设计稿设计宽度 = 1rem / 100px

换成代码就是
html.style.fontSize = (document.documentElement || document.body / designWidth) * 100 + 'px'
这样就可以设置好根节点的font-size啦,但是这样也有一个问题,pc端基本上都有一个最小宽度,我们这么写就会出现根节点继续缩小的情况。 何况万一pc端在限制了最大宽度呢?所以这也是有一丢丢问题的。

在这里插入图片描述

通杀pc端适配方案

有了上面的铺垫,我们就来写通杀的解决方案。这个是vue3.x的autoRem的插件,有需要的同学直接使用就好,别忘了use使用哦。

import { App } from 'vue';

interface Options {
  readonly designWidth?: number;
  readonly maxWidth?: number;
  readonly minWidth?: number;
  readonly base?: number;
}

export default {
  install(app: App<Element>, options: Options = {}) {
    function autoComputed({
      designWidth = 1920,
      maxWidth = 2 ** 64,
      minWidth = 1366,
      base = 100
    }) {
      const html = document.documentElement || document.body;
      const limitMax = maxWidth / designWidth;
      const limitMin = minWidth / designWidth;
      const scale = document.body.offsetWidth / designWidth;

      html.style.fontSize =
        (
          (scale < limitMin ? limitMin : scale > limitMax ? limitMax : scale) *
          base
        ).toFixed(2) + 'px';
    }
    autoComputed(options);
    window.addEventListener('resize', () => {
      autoComputed(options);
    });
  }
};

vue3.x毕竟还没普及,所以依然有vue2.x的使用方式

/**
 * @desc 自适应宽度
 * @param {number} designWidth 设计稿宽带 默认 1920
 * @param {number} maxWidth 最大宽度,缩大到一定程度不在缩大 默认 无限制
 * @param {number} minWidth 最小宽度,缩小到一定程度不在缩小 默认 1366
 * @param {number} base 基准值 默认 100(100px === 1rem)
 */
(({ designWidth = 1920, maxWidth = 2 ** 64, minWidth = 1366, base = 100 }) => {
  autoComputed();
  window.addEventListener('resize', autoComputed);
  function autoComputed() {
    const html = document.documentElement || document.body;
    const limitMax = maxWidth / designWidth;
    const limitMin = minWidth / designWidth;
    const scale = document.body.offsetWidth / designWidth;

    html.style.fontSize =
      (
        (scale < limitMin ? limitMin : scale > limitMax ? limitMax : scale) *
        base
      ).toFixed(2) + 'px';
  }
})({ minWidth: 1600 });

在入口文件那里使用一下,就可以动态的设置根节点的font-size了,而且只对rem单位有效,对px单位是无效的。满足了有的想使用px有的使用rem的需求。但是万一有ui库什么也需要等比呢?所以接下来推荐一个插件postcss-plugin-px2rem,px转rem利器。

首先是安装
npm install postcss-plugin-px2rem -D
接着在vue.config.js里面配置一下

css: {
    loaderOptions: {
      postcss: {
        plugins: [
          // eslint-disable-next-line @typescript-eslint/no-var-requires
          require('postcss-plugin-px2rem')({
            // rootValue: 100, //换算基数, 默认100  ,这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多上px了。
            // unitPrecision: 5, //允许REM单位增长到的十进制数字。
            // propWhiteList: [],  //默认值是一个空数组,这意味着禁用白名单并启用所有属性。
            // propBlackList: [], //黑名单
            // exclude: /(node_module)/, //默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值
            // selectorBlackList: [], //要忽略并保留为px的选择器
            // ignoreIdentifier: false,  //(boolean/string)忽略单个属性的方法,启用ignoreidentifier后,replace将自动设置为true。
            // replace: true, // (布尔值)替换包含REM的规则,而不是添加回退。
            mediaQuery: false, //(布尔值)允许在媒体查询中转换px。
            minPixelValue: 3 //设置要替换的最小像素值(3px会被转rem)。 默认 0
          })
        ]
      }
    }
  }

配置好换算基数100px等于1rem,那么就可以直接量设计稿的px单位值愉快的画页面了。

参考文献

CSS像素(px)、物理像素(pt)、rem、em、rpx

  • 2
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值