大屏数据可视化屏幕适配方案
前言
基于现目前所做数据可视化项目的不同分辨率兼容需求总结以下适配几种方案供参考。 通常而言数字大屏指的是1920*1080分辨率下的电视大屏,用于图表化的展示关键数据,然而项目大部分是在笔记本上运行,演示,测试,所以不得不把小屏笔记本纳入兼容范围。。。
一、一些前提概念
1.1 常见大屏分辨率
- 1366 * 768 : 普通液晶显示器
- 1920 * 1080: 高清液晶显示器
- 2560 * 1440: 2K高清显示器
- 4096 * 2160: 4K高清显示器
- 1280 * 720: 笔记本(1920*1080分辨率下系统默认推荐150%缩放比产生的尺寸。。。。)
1.2 设备像素
viewport
: 视窗=浏览器窗口的宽高物理像素(设备像素)
: 屏幕显示分辨率像素,每个像素可以根据操作系统设置自己的颜色 和亮度设备独立像素(dip)
:密度无关像素,可以认为是计算机坐标系统中的一个点,可用于区分视网膜设备还是非视网膜设备css像素(DIPs)
: 主要用在浏览器上,一般情况下,css像素称为与设备无关的像素屏幕密度
: 设备表面上存在的像素数量(PPI)设备像素比(dpr)
: 定义了物理像素和设备独立像素的对应关系,设备像素比=物理像素/设备独立像素
二、适配痛点
- 设计稿按照1920*1080的分辨率,16:9的比例设计, 实际开发中,document窗口不足16:9(高度减掉顶部tab及导航栏,地址栏等)
- 不同分辨率:实际应用场景中,显示场景不同,不能固定写死px单位
- 不同比例:不同的显示器宽高比与设计稿不一致
- 由于大屏数据可视化项目通常用于放在电视或广告屏上展示用,而不允许出现滚动条
三、关于rem
熟悉移动端的自适应方案的朋友对 rem 适应方案,肯定不陌生,最出名的就是阿里的 手淘lib-flexible 方案。
- rem (font size of the root element), 是 css3 的引入的一个大小单位。即相对于根元素的 font-size 值的大小。所谓根元素在网页里一般就是 html.
- 举例如下:
html{
font-size:20px;
}
test1 {
width: 1.4rem; //1.4 × 20px = 28px
}
test2 {
height: 2.4rem; //2.4 × 20px = 48px
}
- 通常如果应用场景只涉及16:9比例下,1920*1080分辨率屏幕的话,使用rem来自动计算即可实现不同大小屏幕的适配
四、关于px2rem
在采用rem作为适配方案时,避免不了将设计稿中的px单位转化为rem单位,开发过程中如果每个值都手动计算免不了麻烦,通常作法:
- 使用scss或less 函数进行计算
- webpack结合postcss-px2rem自动计算
- postcss 一种对css编译的工具,类似babel对js的处理,通过它的插件生态来实现各种功能转换,如:autoprefixer(. 自动补全浏览器前缀), px2rem(自动将px转换为rem)
这里对px2rem配置说明如下: - postcss-plugin-px2rem: 作为postcss的经典插件之一,用于自动转换px为rem postcss-px2rem文档
- 安装依赖:
npm i postcss-plugin-px2rem -D
- 配置vue.config.js
css: {
loaderOptions: {
postcss: {
plugins: [
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
}),
]
}
}
},
五、适配方案
5.1 rem自适应缩放
问题1:比例不是16:9的问题?
- 当屏幕比16:9 宽时,两侧留白
- 当屏幕比16:9 高时,上下留白【这种少见】
通常做法:
我们将pc宽度 screenWidth 分为10等份,其中1等分的值作为html的font-size值,以1920*1080分辨率为基准设置px2rem的rootValue则为192。这种方式有如下2个特点:
- 所有长度的比例必然和设计图一致。
- 实际的显示长度完全由 html 的 font-size 值决定(线性关系)
问题2:以上的做法,在16:9的内容窗口中可以做到适配,但当窗口不是16:9时就会出现滚动条,于是我们针对问题1的做法则是当非16:9时,根据超出比例的那一边,对rem对应fontSize进行缩放,
1.1 具体如下:
- 设:设计稿上有任一1条线: A, A 的长度为
x
,计算 rem 值的基准为z
,那么 css 里,A 的长度表示为 x z ( r e m ) \frac{x}{z}(rem) zx(rem) - 设: 网页在不同分辨率下运行时html的
font-size
值为 F s F_s Fs - 那么 A 的实际显示长度就分为: x F s z ( p x ) \frac{xF_s}{z}(px) zxFs(px)
- 对于任意一条线,其
x, z
是固定的值,因而其长度根据页面运行时网页html的font-size大小而线性变化, 如在1920的设计宽度下,长100px的线,设计算rem的基准值是192(宽除以10),那么在1366分辨率下html的root-size为136.6, 则100px的线实际长度为100*136.6 / 192
(px)
- 设:设计稿上有任一1条线: A, A 的长度为
1.2 进一步:
1. 取计算rem值的基准是设计稿宽度的1/q
,假设设计稿宽度为ax
, 高度为ay
, 则计算rem的基准值z
为 a x q \frac{ax}{q} qax
2. 按上面公式可以得出浏览器中画布实际的宽,高分别为:
宽 度 : a x F s a x q = F s q 宽度: \frac{axF_s}{\frac{ax}{q}} = F_sq 宽度:qaxaxFs=Fsq
高 度 : a y F s a x q = q y F s x 高度: \frac{ayF_s}{\frac{ax}{q}} = \frac{qyF_s}{x} 高度:qaxayFs=xqyFs
3. 浏览器窗口的宽度 w 要等于画布实际的宽度,即
w = F s q 由 此 推 导 F s = w q w=F_sq 由此推导 F_s = \frac{w}{q} w=Fsq由此推导Fs=qw1.3 再进一步: 不同宽高比下如何设置Fs值?
- 以常见的在浏览器窗口中举例,浏览器中画布宽度ax与设计稿一致,而高度比设计高度小,这时我们需要将高度调整为浏览器高度,而又严格按照设计稿的宽高比来进行,那么
- 设浏览器document高度为
h
, 设缩小比例为S
, 则根据_1.2中2_的公式得出, h = q y F s x S h=\frac{qyF_s}{x}S h=xqyFsS即 S = x h q y F s S=\frac{xh}{qyF_s} S=qyFsxh - 由_1.3中3_的公式中得出
Fs
的值,代入以上公式可知
S = x h y w 即 : S = 设 计 稿 长 宽 比 实 际 长 宽 比 S = \frac{xh}{yw} 即:S= \frac{设计稿长宽比}{实际长宽比} S=ywxh即:S=实际长宽比设计稿长宽比
*综上:假设设计稿为
1920*1080
其计算rem的基准值为192px (默认取宽度10等分),浏览器实际窗口为1920 * 937
时rem的基准值则为192*S
,即最终html的fontSize值为166.57px
最终方案:
- index.html
;(function (designWidth, minWidth) {
let docEle = document.documentElement
let screenRatioByDesign = 16/9
function setHtmlFontSize() {
var screenRatio = docEle.clientWidth / docEle.clientHeight;
var fontSize = (
screenRatio > screenRatioByDesign
? (screenRatioByDesign / screenRatio)
: 1
) * docEle.clientWidth / 10;
docEle.style.fontSize = fontSize.toFixed(3) + "px";
}
setHtmlFontSize()
window.addEventListener('resize', setHtmlFontSize)
})(1920, 1024);
- vue.config.js 设置
module.exports = {
// ...
css: {
loaderOptions: {
postcss: {
plugins: [
require('postcss-plugin-px2rem')({
rootValue: 192, //换算基数, 默认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: false, // (布尔值)替换包含REM的规则,而不是添加回退。
mediaQuery: false, //(布尔值)允许在媒体查询中转换px。
minPixelValue: 3 //设置要替换的最小像素值(3px会被转rem)。 默认 0
}),
]
}
}
},
}
5.2 css3缩放scale
rem的方案对于1920及以上分辨率屏幕来说基本适用,但当切换到1366*768等小分辨率时,由于浏览器默认最小字体为12px,所以会导致文字比理想效果更多大, 而echarts生成的canvas图中单位是以固定px写死的,也会出现超出画布的问题,因此衍生第二种方案: scale缩放
- 思路:浏览器body设置为设计稿宽高即1920*1080, 动态根据实际宽高对body的width,height进行缩放,从而实现内容缩放
- body固定宽高:
body{
width: 1920px;
height: 1080px;
}
- 动态获取实际文档宽高并设置body缩放系数
// index.html
;(function(win){
var bodyStyle = document.createElement('style')
bodyStyle.innerHTML=`body{width:1920px; height:1080px!important;}`
document.documentElement.firstElementChild.appendChild(bodyStyle)
function refreshScale(){
let docWidth = document.documentElement.clientWidth;
let docHeight = document.documentElement.clientHeight;
var designWidth = 1920,
designHeight = 1080,
widthRatio = docWidth / designWidth,
heightRatio = docHeight / designHeight;
document.body.style = `transform:scale(${widthRatio},${heightRatio});transform-origin:left top;`;
// 应对浏览器全屏切换前后窗口因短暂滚动条问题出现未占满情况
setTimeout(function(){
var lateWidth= document.documentElement.clientWidth,
lateHeight = document.documentElement.clientHeight;
if(lateWidth===docWidth) return;
widthRatio = lateWidth/ designWidth
heightRatio = lateHeight/ designHeight
document.body.style = "transform:scale(" + widthRatio + "," + heightRatio + ");transform-origin:left top;"
},0)
}
refreshScale()
win.addEventListener("pageshow", function (e) {
if (e.persisted) { // 浏览器后退的时候重新计算
refreshScale()
}
}, false);
win.addEventListener("resize", refreshScale, false);
})(window)
- 经过如上设置后,在项目中直接使用设计稿中px单位进行开发即可,当然这也有一个弊端,在非设计稿比例(16:9)下,界面会被压缩,但它的优势在于会对body内所有元素进行缩放,从而不会让echarts图表超出画布
六、demo演示
以下demo均在浏览器窗口下展示(即非16:9情况下绘制设计16:9图稿)
6.1 1366*768分辨率下大屏 rem适配方案
在1366*768下采用rem方案能够基本适配不出现内容超出的情况(内容少时)
6.2 1920*1080缩放150%的情况下rem方案
在1920*1080分辨率系统缩放到150%时,可以看到此时rem方案已经有缺陷,canvas内图表超出,界面字体未达到设计稿缩放效果
6.3 1920*1080分辨率150%缩放下scale方案效果
采用scale方案,字体不受浏览器最小字体限制,可以自由绽放到该分辨率下对应比例
七、更新
由于在非16:9的情况下,默认效果是保证比例的前提下,居中两边留白,这种一些需求方觉得不好,特别是在只出了16:9的设计稿情况下,需要适配到另一个公司64:27(分辨率7680*3240)这种大屏而且要求要铺满不变形。。。
新痛点:
- UI提出在非16:9的情况下,图形不能被压缩(扁了)
- 客户提出在64:27这种宽屏下,两边不能留白太空 最后想出一个最小改动的解决方案,如下先看效果:
未优化前7680*3240 (比例64:27的宽屏):
- 两侧留白,但由于屏幕比16:9宽太多,导致留白特别多
- 两侧留白,但由于屏幕比16:9宽太多,导致留白特别多
铺满后
最终解决方案
- 设置宽度为浏览器宽度(默认Vue项目)
function refreshScale(){
let baseWidth = document.documentElement.clientWidth;
let baseHeight = document.documentElement.clientHeight;
let appStyle = document.getElementById('app').style;
let realRatio = baseWidth/baseHeight
let designRatio = 16/9
let scaleRate = baseWidth/1920
if(realRatio>designRatio){
scaleRate = baseHeight/1080
}
appStyle.transformOrigin = 'left top';
appStyle.transform=`scale(${scaleRate}) translateX(-50%)`;
appStyle.width = `${baseWidth/scaleRate}px`
}
- demo代码地址
- 说明: 1. 本demo基于vue的一套简单代码, 2. 目前可适配到1280*720分辨率。 3. 项目基于vue-cli3搭建,可作为项目模板进行二次开发。 4. 基于echarts封装了基础图表组件 5. 引入了滚动表格组件vue-seamless-scroll 6. 适配代码在
assets/js/util
- clone地址: https://gitee.com/cy-edu/cli-template-dataV.git
- 仓库地址:https://gitee.com/cy-edu/cli-template-dataV
- 说明: 1. 本demo基于vue的一套简单代码, 2. 目前可适配到1280*720分辨率。 3. 项目基于vue-cli3搭建,可作为项目模板进行二次开发。 4. 基于echarts封装了基础图表组件 5. 引入了滚动表格组件vue-seamless-scroll 6. 适配代码在
本文转自 https://blog.csdn.net/Sophie_U/article/details/109582687,如有侵权,请联系删除。