大屏REM适配方案

分辨率

常见分辨率

  • 1920 * 1080 (16:9 1080p)
  • 3840 * 2160 (16:9 近4k)
  • 3120 * 1080 (26:9 2k)
  • 3840 * 1080 (32:9 近4k)

什么是REM?

rem在css当中充当的是length的单位,这个单位代表根元素(通常为 元素)的 font-size 大小。当用在根元素的 font-size 上面时,它代表了它的初始值。意思就是说假如html的font-size: 16px;,div的 width: 10rem; 就相当于width的长度有160px。

如何决定根元素的font-size大小

如何决定根元素的font-size大小这里就要看适配的场景(移动端 or 桌面端),以rem单位适配分为两种方式设置html的font-size:宽度、高度
我这里准备了一个demo用于观测盒子和字体之间的变化的demo

以下是根据宽和高适配后随意拉伸的实际结果(原稿分辨率1920*1080)

1920 * 1080 (16:9 1080p)

在这里插入图片描述
在这里插入图片描述

3840 * 2160 (16:9 近4k)

在这里插入图片描述
在这里插入图片描述

3120 * 1080 (26:9 2k)

在这里插入图片描述
在这里插入图片描述

3840 * 1080 (32:9 近4k)

在这里插入图片描述
在这里插入图片描述

随意拉伸

上方视频为以高度适配

上方视频为以宽度适配

各分辨率实际效果的结论

  • 与UI设计原稿长宽比相同的情况下,使用高或宽几乎没有任何变化。
  • 使用宽适配时,虽然左中右的宽度比例能够很好的动态变化,但是左中右两边面板两边业务组件的高度肯定不够足以显示
  • 使用高适配时,左右的宽度几乎没有改变,中间的宽度被拉伸的空间比较大(中间的宽度 = 100% - 左宽度 - 右边度)

总结

通过高度的方式设置根节点 font-size 大小适配大屏效果更妥当!
考虑到大屏系统使用的显示设备通常都是宽比高更长,而且常见的分辨率也不会出现宽比高短的问题,相反移动端更适合使用宽度适配。

如何使用

I设计师出设计稿时仅需按照16:9的长宽比出设计即可。
前端人员在开发样式的时候使用rem作为单位,这里推荐两个编译器插件可以通过快捷键自动将px转换成rem:
WebStorm 可以使用 px2rem 插件
VSCode可以使用 px to rem & rpx & vw (cssrem) 插件

Echart或其他部分工具有的可以兼容rem单位,不兼容rem的可以使用下方方法 transformScaleWidthtransformScaleHeight ,两者的区别就是适用于宽度计算或高度计算。

核心代码

//    main.js 或 主要入口文件
setRootFontSize()
window.addEventListener('resize', setRootFontSize)
window.px2rem = px2rem
window.rem2px = rem2px


//    utils.js
export function setRootFontSize() {
    const designHeight = 1080 //  UI设计稿的高度
    const designFontSize = 16 //  UI设计稿的默认字体大小
    const html = document.documentElement //  html dom
    html.style.fontSize = html.clientHeight / designHeight * designFontSize + 'px'
}
export function px2rem(num) {
    let value = parseInt(num) || 1
    return value/16+'rem'
}
export function rem2px(num) {
    let height = document.body.clientHeight;
    return (16*num*height)/1080+'px'
}
export function transformScaleWidth(px) {
    return(px / 1920) * document.body.clientWidth
}
export function transformScaleHeight(px) {
    return(px / 1080) * document.body.clientHeight
}

问题来了,前端依赖的ui库或者其他库里的css没办法直接修改,通常会在全局引入一个样式用来覆盖,且ui库里的样式又非常多,无法完成ui库里的rem转换。这时候可以使用 node-px2rem 工具通过 NodeJS 执行将打包后dist目录里样式文件的px转换成rem。

小心Angular

Angular组件里引入的样式文件在编译后会被编译到js文件里,例如这样:

styles:["[.content[_ngcontent-%COMP%]{padding:20px}]"]

所以这个工具没办法处理Angular组件样式里的像素单位。

针对上面这个问题的解决方案:

  • 可以通过编译器插件将Angular组件引入的样式文件转换一下
  • 可以在适配的时候通过node-px2rem 将src目录里全部样式文件转换一遍

node-px2rem工具的使用

//    node-px2rem.js
const fs = require('fs')
const path = require('path')
const px2rem = require('node-px2rem')
const postLess = require('postcss-less')    //    结合项目需要是否使用过该语法再安装
const postScss = require('postcss-scss')    //    结合项目需要是否使用过该语法再安装
const postSass = require('postcss-sass')    //    结合项目需要是否使用过该语法再安装

const args = process.argv
const PATH_Index = args.findIndex(item => item === '--path')
const PATH = PATH_Index >= 0 ? PATH_Index + 1 : 'dist'
const distPath = path.join(__dirname, PATH)
const cssFiles = getCssFiles(distPath)

console.log('CSS文件列表:', cssFiles)
console.log('开始处理CSS文件...')
cssFiles.forEach(file => {
    const css = fs.readFileSync(file, 'utf8')

    const processedCSS = px2rem.process(css, {
        rootValue: 16    //    根元素字体大小
        //unitPrecision: 5,    //    允许 REM 单位增长到的十进制数
        //propertyBlackList: [],    //    不能从 px 更改为 rem 的属性
        //propertyWhiteList: [],    //    可以从 px 更改为 rem 的属性
        //replace: false,    //    替换包含 rem 的规则,而不是添加回退
        //mediaQuery: false,    //    允许在媒体查询中转换 px
        //minPx: 1,    //    如果最小 px 大于或等于 可以从 px 更改为 rem
    }, {
        syntax: getSyntax(file)
    })

    fs.writeFile(file, processedCSS, err => {
        if (err) {
            console.log(`文件 ${file} 处理失败!!!!!!!!!!!!!!!!!!`)
            throw err
        }

        console.log(`文件 ${file} 处理成功.`)
    })
})
console.log('CSS文件处理完毕.')

function getCssFiles(directory) {
    const files = fs.readdirSync(directory)

    let cssFiles = []

    files.forEach(file => {
        // const filePath = directory + '/' + file
        const filePath = path.join(directory, file)
        const stat = fs.statSync(filePath)

        if (stat.isDirectory()) {
            // 如果是子目录,则递归调用
            cssFiles = cssFiles.concat(getCssFiles(filePath))
        } else if (isStyleFile(file)) {
            // 如果是CSS文件,则添加到数组中
            cssFiles.push(filePath)
        }
    })

    return cssFiles
}

//  检查是否是样式文件(css、less、scss、sass)
function isStyleFile(file) {
    return /\.(css|less|scss|sass|stylus)$/.test(file)
}

//  返回postcss的语法解析器(less、scss、sass)
function getSyntax(file) {
    const ext = path.extname(file)
    switch (ext) {
        case '.less':
            return postLess
        case '.scss':
            return postScss
        case '.sass':
            return postSass
        default:
            return undefined
    }
}

//    package.json
{
    ...
    "scripts": {
        ...
        "build": "yarn run ng-high-memory build && node node-px2rem.js && gzipper c --include js,ts,css,html,json ./dist",
        ...
    },
    ...
}

在这里插入图片描述

  • 7
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值