若只用rem实现响应式,当一个纬度变化,另一个纬度也变化,如:宽度变化,高度也变化,高度变化,宽度也变化。
所以rem 结合vw、vh实现响应式,字体使用rem,高度使用vh,宽度使用vw,
针对vue项目举例
前置工作,设置根元素字体
// 设计稿尺寸
export const designWidth = 1920;
export const designHeight = 1080;
export const remRatio = 16;
export const setFontSzie = (params = { designWidth, designHeight, remRatio }) => {
// 设计稿的宽度和高度
const designWidth = parseFloat(params.designWidth);
// 设计稿的高度
const designHeight = parseFloat(params.designHeight);
// 1920x1080的屏幕分辨率根字体大小 1rem=16px
const remRatio = parseFloat(params.remRatio);
const root = document.documentElement;
const viewportWidth = window.innerWidth || root.clientWidth;
const viewportHeight = window.innerHeight || root.clientHeight;
const scaleWidth = viewportWidth / designWidth;
const scaleHeight = viewportHeight / designHeight;
const scale = Math.min(scaleWidth, scaleHeight);
const fontSzie = remRatio * scale;
root.style.fontSize = fontSzie + 'px';
};
//也可写为hooks使用
//
// 监听屏幕变化,根据屏幕宽度动态设置根字体大小
// ResponsiveFontSzie
export const useRootRFS = (params = { designWidth, designHeight, remRatio }) => {
// 单位处理todo
// 设计稿的宽度和高度
const designWidth = parseFloat(params.designWidth);
// 设计稿的高度
const designHeight = parseFloat(params.designHeight);
// 1920x1080的屏幕分辨率根字体大小 1rem=16px
const remRatio = parseFloat(params.remRatio);
const root = document.documentElement;
const setFontSzie = () => {
const viewportWidth = window.innerWidth || root.clientWidth;
const viewportHeight = window.innerHeight || root.clientHeight;
const scaleWidth = viewportWidth / designWidth;
const scaleHeight = viewportHeight / designHeight;
const scale = Math.min(scaleWidth, scaleHeight);
const fontSzie = remRatio * scale;
root.style.fontSize = fontSzie + 'px';
};
// 初始化
setFontSzie();
// 监听窗口变化
window.addEventListener('resize', () => {
setFontSzie();
});
};
1、在css中使用
定义scss响应式方法,将设计稿尺寸改变为rem、vw、vh。
/*_responsive.scss */
@use "sass:math";
@use "sass:meta";
$design_width: 1920 !default;
$design_height: 1080 !default;
$rem_ratio: 16 !default; // 1rem = 16px
// 获取单位
@function getUnit($value) {
$unit: if(meta.type-of($value) == "number", math.unit($value), false);
@return if($unit== "px", $unit, false);
}
// px转vw
@function px2vw($px, $design: $design_width) {
$has_unit: getUnit($px) and getUnit($design);
$not_unit: (not getUnit($px)) and (not getUnit($design));
@if ($not_unit or $has_unit) {
@return math.div($px, $design) * 100vw;
} @else {
@if (getUnit($px)) {
@return math.div(math.div($px, 1px), $design) * 100vw;
} @else {
@return math.div($px, math.div($design, 1px)) * 100vw;
}
}
}
// px转vh
@function px2vh($px, $design: $design_height) {
$has_unit: getUnit($px) and getUnit($design);
$not_unit: (not getUnit($px)) and (not getUnit($design));
@if ($not_unit or $has_unit) {
@return math.div($px, $design) * 100vh;
} @else {
@if (getUnit($px)) {
@return math.div(math.div($px, 1px), $design) * 100vh;
} @else {
@return math.div($px, math.div($design, 1px)) * 100vh;
}
}
}
// px转rem
@function px2rem($px, $ratio: $rem_ratio) {
$has_unit: getUnit($px) and getUnit($ratio);
$not_unit: (not getUnit($px)) and (not getUnit($ratio));
@if ($not_unit or $has_unit) {
@return math.div($px, $ratio) * 1rem;
} @else {
@if (getUnit($px)) {
@return math.div(math.div($px, 1px), $ratio) * 1rem;
} @else {
@return math.div($px, math.div($ratio, 1px)) * 1rem;
}
}
}
你可以在vite.config.js中提前注入_responsive.scss也可以在使用的地方单独引入
// vite.config.js
css: {
preprocessorOptions: {
scss: {
additionalData: "@use '[dir]/_responsive.scss' as *;",
},
},
},
<style lang="scss" scoped>
@use '[dir]/_responsive.scss' as *;
</style>
css中应用
<style lang="scss" scoped>
@use '[dir]/_responsive.scss' as *;
.content {
height: calc(100vh - px2vh(109));
.today {
font-size: px2rem(22);
line-height: px2vh(32);
}
}
</style>
2、在js中使用
定义js响应式方法,将设计稿尺寸改变为rem、vw、vh。
// responsive.js
// 设计稿尺寸
export const designWidth = 1920;
export const designHeight = 1080;
export const remRatio = 16;
// px转vw
export const px2vw = (px, design = designWidth, unit = true) => {
const value = ((parseFloat(px) / parseFloat(design)) * 100).toFixed(7);
return unit ? `${value}vw` : value;
};
// px转vh
export const px2vh = (px, design = designHeight, unit = true) => {
const value = ((parseFloat(px) / parseFloat(design)) * 100).toFixed(7);
return unit ? `${value}vh` : value;
};
// px转rem
export const px2rem = (px, ratio = remRatio, unit = true) => {
const value = (parseFloat(px) / parseFloat(ratio)).toFixed(7);
return unit ? `${value}rem` : value;
};
// px转缩放值
export const px2value = (value, params = { designWidth, designHeight }) => {
const root = document.documentElement;
const viewportWidth = window.innerWidth || root.clientWidth;
const viewportHeight = window.innerHeight || root.clientHeight;
const scaleWidth = viewportWidth / parseFloat(params.designWidth);
const scaleHeight = viewportHeight / parseFloat(params.designHeight);
const scale = Math.min(scaleWidth, scaleHeight);
return Number((value * scale).toFixed(3));
};
js中应用
<template>
<div :style="{width:px2vw(100)}"></div>
</template>
<script setup>
import {px2vh,px2vw,px2rem,px2value} from '[dir]/responsive.js';
// echarts
chart.setOption({
xAxis: {
axisLabel: {
fontSize: px2value(10),
},
}
})
</script>