项目主题定制方式探究

前端换肤通常是对项目主题色进行更换,一般来说换肤需求通常有以下几种情况:

  1. 提供几种可供选择的颜色主题,用户可对主题进行切换,一般这种主题不会很多。
  2. 进一步的,提供输入框由用户自定义色值,或者通过取色板取色,可供选择的颜色范围就很大了。
  3. 但更多的,是标准项目针对不同客户进行定制开发,交付定制的颜色和控件样式主题。

多主题换肤

JS切换全局class

这里举例小说网站常见的夜间模式的切换。

  1. 首先,我们先在项目中建立个 day.less 文件,这是我们通常打开网站见到的网站样式。
  2. 然后,我们再在项目中建立个 night.less 文件,这个样式展示的也即夜间模式。
  3. 到这,我们可以通过js来控制样式的切换。

如下是代码示例:

<template>
  <div :class="containerClass">
    <input type="button" :value="isDayMode ? '日间模式' : '夜间模式'"  @click="isDayMode = !isDayMode" />
    ......
  </div>
</template>

export default {
  data() {
    return {
      isDayMode: true, // 默认日间模式
    }
  },
  computed: {
    containerClass() {
      return this.isDayMode ? 'day-container' : 'night-container'
    }
  }
}

<style scoped lang="less">
@import './styles/day.less';
@import './styles/night.less';
</style>

day.less

.day-container {
  background: white!important;
  color: black!important;
}

night.less

.night-container {
  background: black!important;
  color: white!important;
}

JS切换href属性值

在没有使用构建工具的项目中,可以使用 JS 切换 href 属性值,进而实现换肤功能,本质上与上面所述方法是一致的。

<link id="containerClass" href="day.css" rel="stylesheet" type="text/css">

document.querySelector('#containerClass').href = 'night.css'

css 变量实现动态色值换肤

如果要实现更灵活的动态换肤,比如自定义色值或使用从取色板上获取的颜色进行主题色的更换,那上面的方式就不适合了。

通过定义全局主题色 css 变量,方便各模块都能通过 var() 使用主题色变量,再用 setProperty 对全局主题色变量值进行动态修改。

先在顶级元素上设置css全局变量,用法就是给变量加 -- 前缀。

body {
  --themeColor:#000;
}

涉及到主题色的都改成 var(--themeColor) 这种方式

.main {
   color: var(--themeColor);
}

修改主题色

document.body.style.setProperty('--themeColor', '#ff0000');

可以看下兼容性,大部分主流浏览器还是支持的,而且操作起来够简便。

组件库换肤方式

实际业务中,交付的项目更多的是对所用到的组件进行颜色和样式定制,实际是对项目所用的组件库进行主题上的定制。那我们分析下业务上常用的组件库,如何进行主题上的定制。

Element-UI 定制主题

Element 默认提供一套主题,CSS 命名采用 BEM 的风格,方便使用者在项目中改变 SCSS 变量进行样式覆盖。

Element 的 theme-chalk 使用 SCSS 编写,如果你的项目也使用了 SCSS,那么可以直接在项目中改变 Element 的样式变量。

新建一个样式文件,例如 element-variables.scss,写入以下内容:

/* 改变主题色变量 */
$--color-primary: orange;

/* 改变 icon 字体路径变量,必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts';

@import "~element-ui/packages/theme-chalk/src/index";

上面只做了主题色的变更,如果你对其他相关颜色变量也有改动的需求,可进行变量覆盖。

注意:此处变量的覆盖需要在引入 element-ui 默认样式的前面。因为默认变量添加了 !default 属性,则当变量已经赋值后,则不进行值的替换。

如果还需要对组件进行样式上的定制,则可以翻阅主题样式文件:element-ui/packages/theme-chalk/src/common/var.scss

将需要定制的主题样式变量名复制到你的文件上,进行重写赋值。

/* 改变主题色变量 */
$--color-primary: orange;
/* 改变组件样式 */
$--button-border-radius: 10px;

之后,在项目的入口文件中,直接引入以上样式文件即可(无需引入 Element 编译好的 CSS 文件):

import Vue from 'vue'
import Element from 'element-ui'
import './element-variables.scss'

Vue.use(Element)

需要注意的是,覆盖字体路径变量是必需的,将其赋值为 Element 中 icon 图标所在的相对路径即可。

Ant Design Vue 定制主题

Ant Design 设计规范上支持一定程度的样式定制,以满足业务和品牌上多样化的视觉需求,包括但不限于主色、圆角、边框和部分组件的视觉定制。

antd 的样式使用了 Less 作为开发语言,并定义了一系列全局/组件的样式变量,你可以根据需求进行相应调整。

以下是一些最常用的通用变量,所有样式变量可以在 这里 找到。

@primary-color: #1890ff; // 全局主色
@link-color: #1890ff; // 链接色
@success-color: #52c41a; // 成功色
@warning-color: #faad14; // 警告色
@error-color: #f5222d; // 错误色
@font-size-base: 14px; // 主字号
@heading-color: rgba(0, 0, 0, 0.85); // 标题色
@text-color: rgba(0, 0, 0, 0.65); // 主文本色
@text-color-secondary: rgba(0, 0, 0, 0.45); // 次文本色
@disabled-color: rgba(0, 0, 0, 0.25); // 失效色
@border-radius-base: 4px; // 组件/浮层圆角
@border-color-base: #d9d9d9; // 边框色
@box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.15); // 浮层阴影

我们使用 modifyVars 的方式来进行覆盖变量。下面将针对不同的场景提供一些常用的定制方式。

在构建工具中定制主题

项目根目录下新建文件 vue.config.js(这里只举例了这种方式),其他方式可以参阅定制主题

在 webpack 配置里开启,这里使用 less@3.13.1 less-loader@6.2.0

module.exports = {
  css: {
    loaderOptions: {
      less: {
        lessOptions: {
          // If you are using less-loader@5 please spread the lessOptions to options directly
          modifyVars: {
            'primary-color': '#1DA57A',
            'link-color': '#1DA57A',
            'border-radius-base': '2px',
          },
          javascriptEnabled: true,
        },
      },
    },
  },
};

在 main.js 中进行引入,此处注意这里的 css 样式文件为 less 格式,以在构建时进行变量的覆盖。

import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.less'

Vue.use(Antd);

配置 less 变量文件

另外一种方式是建立一个单独的 less 变量文件,引入这个文件覆盖 antd.less 里的变量。

@import '~ant-design-vue/dist/antd.less'; // 引入官方提供的 less 样式入口文件
@import 'your-theme-file.less'; // 你自己的主题样式文件,用于覆盖上面定义的变量

注意:

  1. 注意样式必须加载 less 格式,一个常见的问题就是引入了多份样式,less 的样式被 css 的样式覆盖了,如果你是通过 ‘ant-design-vue/dist/antd.css’ 引入样式的,改为 ‘ant-design-vue/dist/antd.less’。
  2. 这里进行变量的覆盖与 Element-UI 的处理顺序是不一样的,因为这里的变量是按照前后顺序进行覆盖的。默认 ant-design-vue 变量值并没有进行特殊处理。
  3. 这种方式已经载入了所有组件的样式,不需要也无法和按需加载插件 babel-plugin-import 的 style 属性一起使用。如果你在使用 babel-plugin-importstyle 配置来引入样式,需要将配置值从 ‘css’ 改为 true,这样会引入 less 文件。

Vant 定制主题

Vant 提供了一套默认主题,CSS 命名采用 BEM 的风格,方便使用者覆盖样式。

Vant 使用了 Less 对样式进行预处理,并内置了一些样式变量。

完整的内置变量的文件路径为:node_modules/vant/es/style/var.less 或者 node_modules/vant/lib/style/var.less,两文件内容一致。

如下进行部分变量的罗列:

// Color Palette
@black: #000;
@white: #fff;
@gray-1: #f7f8fa;
@gray-2: #f2f3f5;
@gray-3: #ebedf0;
@gray-4: #dcdee0;
@gray-5: #c8c9cc;
@gray-6: #969799;
@gray-7: #646566;
@gray-8: #323233;
@red: #ee0a24;
@blue: #1989fa;
@orange: #ff976a;
@orange-dark: #ed6a0c;
@orange-light: #fffbe8;
@green: #07c160;

// Gradient Colors
@gradient-red: linear-gradient(to right, #ff6034, #ee0a24);
@gradient-orange: linear-gradient(to right, #ffd01e, #ff8917);

// Component Colors
@text-color: @gray-8;
@active-color: @gray-2;
@active-opacity: 0.7;
@disabled-opacity: 0.5;
@background-color: @gray-1;
@background-color-light: #fafafa;
@text-link-color: #576b95;

// Padding
@padding-base: 4px;
@padding-xs: @padding-base * 2;
@padding-sm: @padding-base * 3;
@padding-md: @padding-base * 4;
@padding-lg: @padding-base * 6;
@padding-xl: @padding-base * 8;

// Font
@font-size-xs: 10px;
@font-size-sm: 12px;
@font-size-md: 14px;
@font-size-lg: 16px;
@font-weight-bold: 500;
@line-height-xs: 14px;
@line-height-sm: 18px;
@line-height-md: 20px;
@line-height-lg: 22px;
@base-font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue',
  Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'miui', 'Hiragino Sans GB',
  'Microsoft Yahei', sans-serif;
@price-integer-font-family: Avenir-Heavy, PingFang SC, Helvetica Neue, Arial,
  sans-serif;

// Animation
@animation-duration-base: 0.3s;
@animation-duration-fast: 0.2s;
@animation-timing-function-enter: ease-out;
@animation-timing-function-leave: ease-in;

// Border
@border-color: @gray-3;
@border-width-base: 1px;
@border-radius-sm: 2px;
@border-radius-md: 4px;
@border-radius-lg: 8px;
@border-radius-max: 999px;

通过替换样式变量即可定制你自己需要的主题。

引入样式源文件

定制主题时,首先需要引入组件对应的 Less 样式文件,支持按需引入和手动引入两种方式。

  • 按需引入样式(推荐)

按需引入首先需要安装插件:npm i babel-plugin-import -D

babel-plugin-import 是一款 babel 插件,它会在编译过程中将 import 的写法自动转换为按需引入的方式。

在 babel.config.js 中配置按需引入样式源文件,注意 babel6 不支持按需引入样式,请手动引入样式。

module.exports = {
  plugins: [
    [
      'import',
      {
        libraryName: 'vant',
        libraryDirectory: 'es',
        style: (name) => `${name}/style/less`, // 自动处理组件样式路径,这里的name是组价名
      },
      'vant',
    ],
  ],
};
  • 手动引入样式(不推荐)
// 引入全部样式
import 'vant/lib/index.less';

// 引入单个组件样式
import 'vant/lib/button/style/less';

修改样式变量

使用 Less 提供的 modifyVars 即可对变量进行修改,下面是参考的 webpack 配置。

// webpack.config.js
module.exports = {
  rules: [
    {
      test: /\.less$/,
      use: [
        // ...其他 loader 配置
        {
          loader: 'less-loader',
          options: {
            // 若 less-loader 版本小于 6.0,请移除 lessOptions 这一级,直接配置选项。
            lessOptions: {
              modifyVars: {
                // 直接覆盖变量
                // 'text-color': '#111',
                // 'border-color': '#eee',
                // 或者可以通过 less 文件覆盖(文件路径为绝对路径)
                hack: `true; @import "your-less-file-path.less";`, // 推荐这种,更为灵活且方便后续维护
              },
            },
          },
        },
      ],
    },
  ],
};

如果 vue-cli 搭建的项目,可以在 vue.config.js 中进行配置。

// vue.config.js
module.exports = {
  css: {
    loaderOptions: {
      less: {
        // 若 less-loader 版本小于 6.0,请移除 lessOptions 这一级,直接配置选项。
        lessOptions: {
          modifyVars: {
            // 直接覆盖变量
            // 'text-color': '#111',
            // 'border-color': '#eee',
            // 或者可以通过 less 文件覆盖(文件路径为绝对路径)
            hack: `true; @import "your-less-file-path.less";`, // 推荐这种,更为灵活且方便后续维护
          },
        },
      },
    },
  },
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

定栓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值