响应式页面

11 阅读2分钟

若只用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>