前言--css各种单位的区别
两种像素
物理像素(设备像素)
比如有一个图片,细分,最小单位就是像素。也就是说,图片由许多的像素构成。像素是小方块,这些小方块都有一个明确的位置和被分配的色彩数值,小方格颜色和位置就决定该图像所呈现出来的样子。
一个设备生产出来,它们的像素就已经确定了。比如iPhone 6的屏幕在宽度方向有750个像素点,高度方向有1334个像素点,所以iPhone 6 总共有750*1334个物理像素。
逻辑像素
也叫“设备独立像素”(Device Independent Pixel, DIP),可以理解为反映在CSS/JS代码里的像素点数。
设备像素比(Device Pixel Ratio, DPR)
一个设备的物理像素与逻辑像素之比。
像素还分物理和逻辑?这两个玩意有啥区别?
其实在很久以前,的确是没区别的,CSS里写个1px,屏幕就给你渲染成1个实际的像素点,DPR=1,多么简单自然~
但是后来事情起了变化,搞事的就是苹果的Retina技术,这种技术使用4个乃至更多物理像素来渲染1个逻辑像素,这样一来,同样的CSS代码设置的尺寸,在Retina和非Retina屏幕上看起来大小是一样的,但在Retina屏幕上要精细得多。
在Retian屏上,DPR不再是1,而是大于1,比如2(iPhone 5 6 7 8)或3(iPhone 6 Plus等一系列Plus)或者为非整数(一些Android机),说不定还会涨。
举个例子,iPhone 6的物理像素上面已经说了,是750 * 1334,那它的逻辑像素呢?我们只需在iPhone 6的Safari里打印一下screen.width和screen.height就知道了,结果是 375 * 667,这就是它的逻辑像素,据此很容易计算出DRP为2。当然,我们还可以直接通过window.devicePixelRatio这个值来获取DRP,打印结果是2,符合我们的预期。
DRP(缩放)除了是一个设备的物理像素与逻辑像素之比,也可以理解为布局视图和视觉视图的比值
视觉视口和缩放比例的关系为:
当前缩放值 = 理想视口宽度 / 视觉视口宽度
所以,当用户放大时,视觉视口将会变小,CSS 像素将跨越更多的物理像素。也就越清晰
ps:也是一个设备的物理像素与逻辑像素之比
(!高清显示屏 会有缩放比例为 200%) 改变电脑显示中的 项目大小比例 会修改
window.devicePixelRatio
对比
传统的项目开发中,我么只会用到px、%、em这几个单位,它们可以适用于大部分的项目开发,并且具有良好的兼容性。
从CSS3开始,浏览器对计量单位的支持又提升到了另外一个境界,新增了rem、vh、vw、vm等一些新的计量单位。
利用这些新的单位开发出比较良好的响应式页面,适应多种不同分辨率的终端,包括移动设备等。
在css单位中,可以分为长度单位、绝对单位,如下表所指示
| CSS单位 | |
|---|---|
| 相对长度单位 | em、ex、ch、rem、vw、vh、vmin、vmax、% |
| 绝对长度单位 | cm、mm、in、px、pt、pc |
1.px
px,表示像素,所谓像素就是呈现在我们显示器上的一个个小点,每个像素点都是大小等同的,所以像素为计量单位被分在了绝对长度单位中。有些人会把px认为是相对长度,原因在于在移动端中存在设备像素比,px实际显示的大小是不确定的。这里之所以认为px为绝对单位,在于px的大小和元素的其他属性无关。
2.em
em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸(
1em = 16px)。为了简化 font-size 的换算,我们需要在css中的 body 选择器中声明font-size= 62.5%,这就使 em 值变为16px*62.5% = 10px。这样12px = 1.2em, 10px = 1em, 也就是说只需要将你的原来的px 数值除以10,然后换上 em作为单位就行了。
特点:
- em 的值并不是固定的
- em 会继承父级元素的字体大小
- em 是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸
- 任意浏览器的默认字体高都是 16px
举个例子:
<div class="big">
我是14px=1.4em<div class="small">我是12px=1.2em</div>
</div>
<style>
html {font-size: 10px; } /* 公式16px*62.5%=10px */
.big{font-size: 1.4em}
.small{font-size: 1.2em}
</style>
这时候.big元素的font-size为14px,而.small元素的font-size为12px
3.rem
rem,相对单位,相对的只是HTML根元素font-size的值。同理,如果想要简化
font-size的转化,我们可以在根元素html中加入font-size: 62.5%。
html {font-size: 62.5%; } /* 公式16px*62.5%=10px */
这样页面中1rem=10px、1.2rem=12px、1.4rem=14px、1.6rem=16px;使得视觉、使用、书写都得到了极大的帮助
特点:
-
- rem单位可谓集相对大小和绝对大小的优点于一身
-
- 和em不同的是rem总是相对于根元素,而不像em一样使用级联的方式来计算尺寸
4.vh、vw
vw是根据窗口的宽度,分成
100等份,100vw就表示满宽,50vw就表示一半宽。(vw 始终是针对窗口的宽),同理,vh则为窗口的高度。
这里的窗口分成几种情况:
- 在桌面端,指的是浏览器的可视区域
- 移动端指的就是布局视口
像vw、vh,比较容易混淆的一个单位是%,不过百分比宽泛的讲是相对于父元素:
- 对于普通定位元素就是我们理解的父元素
- 对于position: absolute;的元素是相对于已定位的父元素
- 对于position: fixed;的元素是相对于 ViewPort(可视窗口)
5.%
一般来说就是相对于父元素的:
1)对于普通定位元素就是我们理解的父元素
2)对于position: absolute;的元素是相对于已定位的父元素
3)对于position: fixed;的元素是相对于ViewPort(可视窗口),
6.vm
相对于视口的
宽度或高度中较小的那个。其中最小的那个被均分为100单位的vm。 举个例子:浏览器高度900px,宽度1200px,取最小的浏览器高度,1 vm = 900px/100 = 9 px。
什么时候应该使用哪一个单位?
这个问题没有完美的答案。一般来说,通常最好选择一个相对单位而不是 PX,这样你的网页就有最好的机会呈现出精美的响应式设计。但是,如果你需要确保元素永远不会在任何断点处调整大小并且无论用户是否选择了不同的默认大小都保持不变,请选择PX。即使不理想,PX 装置也能确保一致的结果。
EM相对于父元素的字体大小,因此如果你希望根据父元素的大小缩放元素的大小,请使用 EM。
REM相对于根 (HTML) 字体大小,因此如果你希望根据根大小缩放元素的大小,无论父大小是什么,请使用 REM。如果你使用过 EM 并且由于大量嵌套元素而发现大小问题,那么 REM 可能是更好的选择。
VW可用于创建填充整个视口宽度的全宽元素 (100%)。当然,你可以使用视口宽度的任意百分比来实现其他目标,例如宽度的一半为 50% 等。
VH可用于创建填充整个视口高度的全高元素 (100%)。当然,你可以使用视口高度的任意百分比来实现其他目标,例如高度的一半为 50% 等。
% 类似于 VW 和 VH,但它不是相对于视口的宽度或高度的长度。相反,它是父元素宽度或高度的百分比。例如,百分比单位通常可用于设置边距的宽度。
大屏--自适应界面的前端配置
看了网上的各种方案,目前大家采用的大概有 3 种👇
| 方案 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| vm vh | 1.按照设计稿的尺寸,将px按比例计算转为vw和vh | 1.可以动态计算图表的宽高,字体等,灵活性较高 2.当屏幕比例跟 ui 稿不一致时,不会出现两边留白情况 | 1.每个图表都需要单独做字体、间距、位移的适配,比较麻烦 |
| scale | 1.通过 scale 属性,根据屏幕大小,对图表进行整体的等比缩放 | 1.代码量少,适配简单 2.一次处理后不需要在各个图表中再去单独适配 | 1.因为是根据 ui 稿等比缩放,当大屏跟 ui 稿的比例不一样时,会出现周边留白情况 2.当缩放比例过大时候,字体会有一点点模糊,就一点点 3.当缩放比例过大时候,事件热区会偏移。 |
| rem + vm vh | 1.获得 rem 的基准值 2.动态的计算html根元素的font-size 3.图表中通过 vm vh 动态计算字体、间距、位移等 | 1.布局的自适应代码量少,适配简单 | 1.因为是根据 ui 稿等比缩放,当大屏跟 ui 稿的比例不一样时,会出现周边留白情况 2.图表需要单个做字体、间距、位移的适配 |
以上 3 种方案在实际应用中该怎么选择视具体情况而定,也有看到大家说自适应在地图的适配中会有一些兼容问题,我这边还没有实践过。
-
如果想简单,客户能同意留白,选用
scale即可 -
如果需要兼容不同比例的大屏,并且想在不同比例中都有比较好的效果,图表占满屏幕,类似于移动端的响应式,可以采用 vm vh 的方案
-
至于 rem,个人觉得就是 scale 和 vm vh 的综合,最终的效果跟
scale差不多
方案一:vw vh
上效果
当屏幕的尺寸比例刚好是 16:9 时
当屏幕的尺寸比例大于 16:9 时
当屏幕的尺寸比例小于 16:9 时
实现思路
按照设计稿的尺寸,将px按比例计算转为vw和vh,转换公式如下
假设设计稿尺寸为 1920*1080(做之前一定问清楚 ui 设计稿的尺寸)
即:
网页宽度=1920px
网页高度=1080px
我们都知道
网页宽度=100vw
网页宽度=100vh
所以,在 1920px*1080px 的屏幕分辨率下
1920px = 100vw
1080px = 100vh
这样一来,以一个宽 300px 和 200px 的 div 来说,其所占的宽高,以 vw 和 vh 为单位,计算方式如下:
vwDiv = (300px / 1920px ) * 100vw
vhDiv = (200px / 1080px ) * 100vh
所以,就在 1920*1080 的屏幕分辨率下,计算出了单个 div 的宽高
当屏幕放大或者缩小时,div 还是以 vw 和 vh 作为宽高的,就会自动适应不同分辨率的屏幕
css 方案 - sass
util.scss
// 使用 scss 的 math 函数,https://sass-lang.com/documentation/breaking-changes/slash-div
@use "sass:math";
// 默认设计稿的宽度
$designWidth: 1920;
// 默认设计稿的高度
$designHeight: 1080;
// px 转为 vw 的函数
@function vw($px) {
@return math.div($px, $designWidth) * 100vw;
}
// px 转为 vh 的函数
@function vh($px) {
@return math.div($px, $designHeight) * 100vh;
}
路径配置
只需在vue.config.js里配置一下utils.scss的路径,就可以全局使用了
vue.config.js
const path = require("path");
function resolve(dir) {
return path.join(__dirname, dir);
}
module.exports = {
publicPath: "",
configureWebpack: {
name: "app name",
resolve: {
alias: {
"@": resolve("src"),
},
},
},
css: {
// 全局配置 utils.scs,详细配置参考 vue-cli 官网
loaderOptions: {
sass: {
prependData: `@import "@/styles/utils.scss";`,
},
},
},
};
在 .vue 中使用
<template>
<div class="box">
</div>
</template>
<script>
export default{
name: "Box",
}
</script>
<style lang="scss" scoped="scoped">
/*
直接使用 vw 和 vh 函数,将像素值传进去,得到的就是具体的 vw vh 单位
*/
.box{
width: vw(300);
height: vh(100);
font-size: vh(16);
background-color: black;
margin-left: vw(10);
margin-top: vh(10);
border: vh(2) solid red;
}
</style>
注意事项
echarts 的字体大小只支持具体数值(像素),不能用百分比或者 vw 等尺寸,一般字体不会去做自适应,当宽高比跟 ui 稿比例出入太大时,会出现文字跟图表重叠的情况
这里我们就需要封装一个工具函数,来处理图表中文字自适应了👇
-
默认情况下,这里以你的设计稿是 1920*1080 为例,即网页宽度是 1920px (做之前一定问清楚 ui 设计稿的尺寸)
-
把这个函数写在一个单独的工具文件
dataUtil.js里面,在需要的时候调用 -
其原理是计算出当前屏幕宽度和默认设计宽度的比值,将原始的尺寸乘以该值
-
另外,其它 echarts 的配置项,比如间距、定位、边距也可以用该函数
- 编写 dataUtil.js 工具函数
// Echarts图表字体、间距自适应
export const fitChartSize = (size,defalteWidth = 1920) => {
let clientWidth = window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;
if (!clientWidth) return size;
let scale = (clientWidth / defalteWidth);
return Number((size*scale).toFixed(3));
}
复制代码
2. 将函数挂载到原型上
import {fitChartSize} from '@src/utils/dataUtil.js'
Vue.prototype.fitChartFont = fitChartSize;
复制代码
3. 这样你可以在.vue文件中直接使用this.fitChartSize()调用
方案二:scale
上效果
当屏幕的尺寸比例刚好是 16:9 时,页面能刚好全屏展示,内容占满显示器
当屏幕的尺寸比例刚好是 16:9 时,页面能刚好全屏展示,内容占满显示器
当屏幕的尺寸比例小于 16:9 时,页面上下留白,左右占满并上下居中,显示比例保持 16:9
实现思路
如何缩放
当屏幕宽高比 < 设计稿宽高比,我们需要缩放的比例是屏幕宽度 / 设计稿宽度
当屏幕宽高比 > 设计稿宽高比,我们需要缩放的比例是屏幕高度 / 设计稿高度
const scale = document.documentElement.clientWidth / document.documentElement.clientHeight < designDraftWidth / designDraftHeight ?
(document.documentElement.clientWidth / designDraftWidth) :
(document.documentElement.clientHeight / designDraftHeight);
复制代码
如果我们拿到的设计稿宽高为: 1920 * 960 px ,而我们的屏幕大小是 1440 * 900 px,那么 1440/900 = 1.6,920/960 = 2
因为 1.6 < 2 (当前屏幕宽高比小于设计稿宽高比)
所以我们需要缩放的比例是:屏幕宽度除以设计稿宽度 = 1440/1920 = 0.75
如何居中
首先我们利用 transform:translate(-50%,-50%) ,将动画的基点设为左上角
transform-origin:设置动画的基点(中心点),默认点是元素的中心点
语法
transform-origin: x-axis y-axis z-axis;
然后利用transform:translate(-50%,-50%),将图表沿 x,y 轴移动 50%
接下来利用绝对定位将图表定位到中间位置
position: absolute;
left: 50%;
top: 50%;
实现方案
html 部分
<div className="screen-wrapper">
<div className="screen" id="screen">
</div>
</div>
js 部分
<script>
export default {
mounted() {
// 初始化自适应 ----在刚显示的时候就开始适配一次
handleScreenAuto();
// 绑定自适应函数 ---防止浏览器栏变化后不再适配
window.onresize = () => handleScreenAuto();
},
deleted() {
window.onresize = null;
},
methods: {
// 数据大屏自适应函数
handleScreenAuto() {
const designDraftWidth = 1920; //设计稿的宽度
const designDraftHeight = 960; //设计稿的高度
// 根据屏幕的变化适配的比例
const scale =
document.documentElement.clientWidth /
document.documentElement.clientHeight <
designDraftWidth / designDraftHeight
? document.documentElement.clientWidth / designDraftWidth
: document.documentElement.clientHeight / designDraftHeight;
// 缩放比例
document.querySelector(
'#screen',
).style.transform = `scale(${scale}) translate(-50%, -50%)`;
},
},
};
</script>
css部分
/*
除了设计稿的宽高是根据您自己的设计稿决定以外,其他复制粘贴就完事
*/
.screen-root {
height: 100%;
width: 100%;
.screen {
display: inline-block;
width: 1920px; //设计稿的宽度
height: 960px; //设计稿的高度
transform-origin: 0 0;
position: absolute;
left: 50%;
top: -50%;
}
}
方案三:rem+vw vh
上效果
当屏幕的尺寸比例刚好是 16:9 时,页面能刚好全屏展示,内容占满显示器 当屏幕的尺寸比例小于 16:9 时,页面上下留白,左右占满并上下居中,显示比例保持 16:9 当屏幕尺寸比例大于 16:9 时,页面左右留白,上下占满并居中,显示比例保持 16:9
实现思路
关于 rem
rem(font size of the root element),是 css3 中新增的一个大小单位,即相对于根元素 font-size 值的大小。
自适应思路
动态的计算出页面的 fontsize 从而改变 rem 的大小。
-
拿 1920 * 1080 的标准屏幕大小为例,将屏幕分为
10份,先计算rem 的基准值:1920 / 10 = 192; -
把所有元素的长、宽、位置、字体大小等原来的 px 单位全部转换成 rem;
-
网页加载后,用 js 去计算当前浏览器的宽度,并设置 html 的 font-size 为 (
当前浏览器窗口宽度 / 10) 。
这样的话 10rem 就刚好等于浏览器窗口的宽度,也就可以保证 100% 宽度,等比例缩放设计稿的页面了。
因此 rem + vm vh 方案要解决三件事
- 获得 rem 的基准值;
- 页面内写一段 js 代码,动态的计算
html根元素的font-size; - 屏幕变化后,图表自动调整和图表字体、间距、位移等的自适应。
实现方案
第一点:获得 rem 的基准值
- 首先安装
@njleonzhang/postcss-px-to-rem这个包
npm i @njleonzhang/postcss-px-to-rem -D
复制代码
2. 在项目根目录新建.postcssrc.js配置文件
module.exports = {
plugins: {
autoprefixer: {},
"@njleonzhang/postcss-px-to-rem": {
unitToConvert: 'px', // (String) 要转换的单位,默认是 px。
widthOfDesignLayout: 1920, // (Number) 设计布局的宽度。对于pc仪表盘,一般是 1920.
unitPrecision: 3, // (Number) 允许 rem 单位增长到的十进制数字.
selectorBlackList: ['.ignore', '.hairlines'], // (Array) 要忽略并保留为 px 的选择器.
minPixelValue: 1, // (Number) 设置要替换的最小像素值.
mediaQuery: false // (Boolean) 允许在媒体查询中转换 px.
}
}
}
复制代码
3. 配置完成后,页面内的 px 就会被转换成 rem 了
第二点:动态的计算html根元素的font-size
- 在工具函数文件中新建一个 rem.js 文件,用于动态计算 font-size
(function init(screenRatioByDesign = 16 / 9) {
let docEle = document.documentElement
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";
console.log(docEle.style.fontSize);
}
setHtmlFontSize()
window.addEventListener('resize', setHtmlFontSize)
})()
2. 在入口文件 main.js 中引入 rem.js 文件
import './utils/rem.js';
至此,页面就已经可以实现 16:9 自适应了。
第三点:屏幕变化,图表自适应
屏幕变化后,图表自动调整字体、间距、位移等,此处参考上面 vm vh 的实现方式即可,在此就不重复赘述了
大屏--echart开启大数据散点图
大数据量散点图的绘制;
series[i]-scatter.large
是否开启大规模散点图的优化,在数据图形特别多的时候(>=5k)可以开启。取值类型为 boolean,默认值为 true。
开启后配合 largeThreshold 在数据量大于指定阈值的时候对绘制进行优化。
缺点:优化后不能自定义设置单个数据项的样式。
series[i]-scatter.largeThreshold
散点图开启绘制优化的阈值。取值类型为 number,默认值为 2000。
大屏--echarts 离线地图的开发
china.json 里存放整个中国地图的数据
通过如下语句,就可以在echart中注册中国地图
echarts.registerMap(name,mapjson)