根据屏幕尺寸条件加载CSS样式

1,244 阅读3分钟

同一套代码逻辑,渲染不同的样式到Web端H5端

举个🌰

image.png

如图所示,当我们的屏幕尺寸小于等于768px时,我们希望内容是响应式变化的,也就是使用vw为基本单位进行页面渲染;当屏幕尺寸大于768px时,我们则认为网页在Web端进行渲染,希望使用px为基本单位进行渲染。

效果展示

css条件加载.gif

如何处理

以下例子为基于Vue Cli生成的Vue项目。

对于H5,我们可以使用postcss及其插件postcss-px-to-viewport,来进行移动端布局。

1. 安装postcss-px-to-viewport

npm install postcss-px-to-viewport -D

2. 根目录创建postcss.config.js文件

module.exports = {
  plugins: {
    'postcss-px-to-viewport': {
      unitToConvert: 'px', // 需要转换的单位
      viewportWidth: 750, // 设计稿的视口宽度
      unitPrecision: 9, // 单位转换后保留的精度
      propList: ['*'], // 能转换的vw属性列表
      viewportUnit: 'vw', // 希望使用的视口单位
      fontViewportUnit: 'vw', // 字体使用的视口单位
      selectorBlackList: [], // 需要忽略的css选择器
      minPixelValue: 1, // 设置最小的转换数值,如果为1,只有大于1的值才会被转换
      mediaQuery: true, // 媒体查询中是否需要转换单位
      replace: true, // 是否直接更换属性值
      exclude: [/node_modules/, /web.vue/], // web不进行样式转换
      landscape: false
    }
  }
}

这里的关键一步为exclude: [/node_modules/, /web.vue/],我们把web的样式给排除了,从而做到样式的条件配置。同时因为我们是使用媒体查询来进行样式的条件加载的,因此需要把mediaQuery设为true

3. 配置vue.config.js

const postcssPxToViewport = require('postcss-px-to-viewport')
const postcssConfig = require('./postcss.config.js')

module.exports = {
  css: {
    loaderOptions: {
      postcss: {
        plugins: [
          postcssPxToViewport(postcssConfig.plugins['postcss-px-to-viewport'])
        ]
      }
    }
  }
}

4. 在组件同级目录创建一个文件夹,放置CSS文件

 component
   ├── index.vue  // 组件的template、script
   └── styles
      ├── h5.vue   // h5对应的样式
      └── web.vue  // web对应的样式

h5.vue:

<style lang="scss">
@media screen and (max-width:768px) {
  .page {
    display: flex;
    min-height: 100vh;
    text-align: center;
    flex-direction: column;
    .header {
      color: #fff;
      height: 244px;
      background-color: #376ece;
      .title {
        margin-top: 36px;
        font-size: 36px;
        line-height: 36px;
        font-weight: 500;
      }
      .sub-title {
        margin-top: 20px;
        font-size: 28px;
        line-height: 28px;
        font-weight: 400;
      }
    }
  }
}

</style>

web.vue:

<style lang="scss">
@media screen and (min-width:769px) {
  .page {
    display: flex;
    min-height: 100vh;
    text-align: center;
    flex-direction: column;
    .header {
      color: #fff;
      height: 244px;
      background-color: green;
      .title {
        margin-top: 36px;
        font-size: 36px;
        line-height: 36px;
        font-weight: 500;
      }
      .sub-title {
        margin-top: 20px;
        font-size: 28px;
        line-height: 28px;
        font-weight: 400;
      }
    }
  }
}

</style>

5. 在组件中引入这两个文件

<template>
  <main class="page">
    <header class="header">
      <h1 class="title">{{ title }}</h1>
      <h2 class="sub-title">{{ subTitle }}</h2>
    </header>
  </main>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'
import './styles/h5.vue'
import './styles/web.vue'

export default defineComponent({
  setup() {
    const title = ref(window.innerWidth > 768 ? 'web' : 'h5')
    const subTitle = ref('根据屏幕尺寸条件加载CSS样式')
    window.onresize = () => {
      title.value = window.innerWidth > 768 ? 'web' : 'h5'
    }
    return {
      title,
      subTitle
    }
  }
})
</script>

这样书写之后,实际上会在header中创建两个style标签:

image.png

其中第一个为H5对应的样式,经过了postcss处理,第二个则为web样式,未经过任何处理。

其他方式

除此之外,如果我们的文件就是简单的css,不需要经过loader处理(sass、stylus、postcss等),那么我们也可以使用以下方式来进行样式的条件加载:

在HTML中

<style href="styles_mobile.css" media="screen and (max-width:768px)" />
<style href="styles_pc.css" media="screen and (min-width:769px)" />

在CSS中

@import url("styles_mobile.css") screen and (max-width:768px);
@import url("styles_pc.css") screen and (min-width:769px);

在Vue文件中

<style>
@import url("styles_mobile.css") screen and (max-width:768px);
@import url("styles_pc.css") screen and (min-width:769px);
<style>

这样书写之后,经过loader处理,实际上会在header中创建两个style标签(等同于在HTML中):

image.png

参考

CSS 按条件加载外部 css 样式文件