【每日一拳】打在浅谈 Windi CSS 以及在 vue3 中的实践体验上

6,713 阅读9分钟

前言

其实去年就见过 Windi CSS,只是粗浅的了解过,知道 ”Windi CSS 是下一代工具优先的 CSS 框架“(官网的描述),也没有去深入了解实践过。

最近闲下来了也花点时间去研究了一下,确实也是一次全新的体验,短短一行代码就可以囊括大多数的 css 样式,使用起来确实方便。

相较于习惯了写 less 和 sass 的我来说,还是会有一些学习成本在里头,虽然我们公司的项目中也会有一个全局的 scss 文件定义一些常用的工具类,但种类毕竟也有限,今后的项目中也可以考虑是否可以选择使用 Windi CSS 来替代了。


Windi CSS 介绍

下面是 官网 的一段描述,简而言之就是,windicss 是以 Tailwindcss 为灵感制作的库,并且兼容了 Tailwindcss、提供了更快的加载时间和热更新。

windicss官网介绍.jpg

对我们而言,windicss 就相当于一个可以让我们快速上手组件库,内置了诸如 flexitems-centerml-8bg-purple-600工具类,可以让我们不用再去写那些繁琐的 css 样式,而且只有我们使用的工具类才会产生相对应的 css;不仅如此,windicss 还提供了其他更加强大的功能供我们使用,接下来就去体验一下吧。


Windi CSS 使用

安装配置

我在此使用 vite2 + vue3 来体验 Windi CSS

  1. 首先安装依赖

    pnpm i -D vite-plugin-windicss windicss
    
  2. vite.config.ts 配置文件中添加插件

    import WindiCSS from 'vite-plugin-windicss'
    
    export default {
      plugins: [
        WindiCSS(),
      ],
    }
    
  3. 然后在入口文件 main.ts 中导入样式

    import "virtual:windi.css";
    
  4. 最后新建 Windi CSS 的配置文件 windi.config.ts

    import { defineConfig } from 'windicss/helpers'
    
    export default defineConfig({
      /* 配置项... */
    })
    

    默认情况下,Windi CSS 会在你的项目根目录下搜索配置文件。以下是有效的名称:

    • windi.config.ts
    • windi.config.js
    • tailwind.config.ts
    • tailwind.config.js

基本使用

简单使用 Windi CSS 的工具类,比较一下与正常的使用 sass 之间的区别,还是很明显的,具体的工具类可以参考 官网

<template>
  <div>
    <h3>使用 Windi CSS</h3>
    <div class="flex items-center justify-around bg-teal-100 rounded-md p-4px w-192px">
      <div class="w-[25%] h-12 bg-red-400 rounded-md m-4px"></div>
      <div class="w-[25%] h-12 bg-green-400 rounded-md m-4px"></div>
      <div class="w-[25%] h-12 bg-blue-400 rounded-md m-4px"></div>
    </div>
    <br>
    
    <h3>使用正常的 sass</h3>
    <div class="card">
      <div class="box"></div>
      <div class="box"></div>
      <div class="box"></div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.card {
  width: 200px;
  display: flex;
  justify-content: space-around;
  align-items: center;
  padding: 4px;
  border-radius: 6px;
  background-color: rgb(204, 251, 241);

  .box {
    width: 48px;
    height: 48px;
    margin: 4px;
    border-radius: 6px;
  }

  .box:nth-child(1) {
    background-color: rgb(248, 113, 113);
  }

  .box:nth-child(2) {
    background-color: rgb(52, 211, 153);
  }

  .box:nth-child(3) {
    background-color: rgb(96, 165, 250);
  }
}
</style>

使用windi和sass的区别.jpg

自动值推导

上述代码可以看到 Windi CSS 提供自动值推导功能,可以在类名中使用任意值,然后生成相应的样式,用起来比使用标准的 sass 要方便很多。例如:

  • w-192px 可以自动解析为 width: 192px;
  • w-[25%] 可以自动解析为 width: 25%; ,也相当于 width: 48px;
  • h-12 可以自动解析为 height: 3rem; ,根据当前的根元素的字体大小也相当于 height: 48px;

windicss自动值推导.jpg

Important 前缀

在 Windi CSS 中使用 important 也是非常方便,只需在任意工具类的前面使用 ! 前缀,使它们变为 !important,就可以覆盖之前的样式规则中指定的属性了。

比如给 w-192px 添加 ! 前缀为 !w-192px

<h3>使用 Windi CSS</h3>
<div class="flex items-center justify-around bg-teal-100 rounded-md p-4px !w-192px">
  <div class="w-[25%] h-12 bg-red-400 rounded-md m-4px"></div>
  <div class="w-[25%] h-12 bg-green-400 rounded-md m-4px"></div>
  <div class="w-[25%] h-12 bg-blue-400 rounded-md m-4px"></div>
</div>

windicss添加important.jpg

Shortcuts

当我们经常使用相同的工具类合集时,会出现很多重复性的代码,Windi CSS 提供了 Shortcuts 特性可以工具类的名字组合在一起定义成一个新的名字,在任何地方使用,就免去了大量重复冗余的代码。

在 Windi CSS 的配置文件 windi.config.ts 中添加 shortcuts 字段:

export default {
  theme: {
    /* ... */
  },
  shortcuts: {
    'box view': 'w-[25%] h-12 rounded-md m-4px',
  },
}

就可以把页面代码修改为下面这样,页面展示效果是一样的,但是代码更加简洁明了。

<h3>使用 Windi CSS</h3>
<div class="flex items-center justify-around bg-teal-100 rounded-md p-4px w-192px">
    <div class="bg-red-400 box-view"></div>
    <div class="bg-green-400 box-view"></div>
    <div class="bg-blue-400 box-view"></div>
</div>

windicss使用shortcuts.jpg

响应式设计

在 Windi CSS 中也可以很轻松实现响应式设计。只需要将可变修饰(variant)的前缀加到对应的工具类前,比如 md:lg:

断点

默认带有 < 前缀带有 @ 前缀
sm(min-width: 640px)(max-width: 639.9px)(min-width: 640px) and (max-width: 767.9px)
md(min-width: 768px)(max-width: 767.9px)(min-width: 768px) and (max-width: 1023.9px)
lg(min-width: 1024px)(max-width: 1023.9px)(min-width: 1024px) and (max-width: 1279.9px)
xl(min-width: 1280px)(max-width: 1279.9px)(min-width: 1280px) and (max-width: 1535.9px)
2xl(min-width: 1536px)(max-width: 1535.9px)(min-width: 1536px)
<h3>使用 Windi CSS</h3>
<div class="flex items-center justify-around bg-teal-100 rounded-md p-4px !w-192px">
    <div class="lg:bg-red-400 md:bg-red-200 sm:bg-red-100 box-view"></div>
    <div class="bg-green-400 box-view"></div>
    <div class="bg-blue-400 box-view"></div>
</div>

在不同的断点下,效果如下:

windicss响应式.jpg

不仅如此,你也可以根据业务需求来自定义断点,在 windi.config.ts 中配置,如命名为 tablet、laptop……

import { defineConfig } from 'windicss/helpers'

export default defineConfig({
  theme: {
    screens: {
      tablet: '640px',
      laptop: '1024px',
      desktop: '1280px',
    },
  },
})

指令

Windi CSS 还提供了五个指令,可以配合 CSS 让我们更好的使用。

@apply

可以将 @apply 在 style 块中同一行的、一些已存在的工具类上使用,和 Shortcuts 的效果差不多,很适合抽取成一个通用工具类。

<template>
  <div>
    <!-- 使用 Windi CSS-->
    <h3>使用 Windi CSS</h3>
    <div class="flex items-center justify-around bg-teal-100 rounded-md p-4px w-192px">
      <div class="bg-red-400 box-view2"></div>
      <div class="bg-green-400 box-view2"></div>
      <div class="bg-blue-400 box-view2"></div>
    </div>
    <br>

    ...
</template>

<style lang="scss" scoped>
...

.box-view2 {
  @apply w-[25%] h-12 rounded-md m-4px;
}
</style>

windicss-@apply.jpg

@variants

我们也可以通过把 css 工具类定义包装在 @variants 中,用来生成带有一些屏幕可变修饰,状态可变修饰,主题可变修饰的工具类。

<template>
  <div>
    <!-- 使用 Windi CSS-->
    <h3>使用 Windi CSS</h3>
    <div class="flex items-center justify-around bg-teal-100 rounded-md p-4px w-192px">
      <div class="bg-red-400 box-view2"></div>
      <div class="bg-green-400 box-view2"></div>
      <div class="bg-blue-400 box-view2"></div>
    </div>
    <br>

    ...
</template>

<style lang="scss" scoped>
...

.box-view2 {
  @apply w-[25%] h-12 rounded-md m-4px;
}

@variants focus, hover {
  .box-view2 {
    @apply bg-red-200;
  }
}
</style>

windicss-@variants.jpg

@screen

@screen 指令可以让我们来媒体查询,通过名称来引用断点,以此来取代通过复制你 CSS 里面的值来实现。

<style lang="scss" scoped>
...

.box-view2 {
  @apply w-[25%] h-12 rounded-md m-4px;
}

// lg 就是上文响应式设计中的断点 (min-width: 1024px)
@screen lg {
  .box-view2 {
    @apply bg-red-200;
  }
}

// 上下效果一样
@media (min-width: 1024px) {
  .box-view2{
    // background-color: rgba(254, 202, 202) = bg-red-200
    background-color: rgba(254, 202, 202)
  }
}
</style>

windicss-@screen.jpg

@layer

@layer 指令用来确认每个 class 的排序。合法的层级为 基础 (base), 组件 (components)工具类 (utilities)

这个指令我也没用过多地去使用,有兴趣可以自己去研究研究,暂贴一段 官方 提供的代码:

windicss-@layer.jpg

theme()

theme() 函数可以让我们通过 . 运算符来获取想要设置的值。

<template>
  <div>
    <!-- 使用 Windi CSS-->
    <h3>使用 Windi CSS</h3>
    <div class="flex items-center justify-around bg-teal-100 rounded-md p-4px w-192px">
      <div class="bg-red-400 box-view2 light-red"></div>
      <div class="bg-green-400 box-view2"></div>
      <div class="bg-blue-400 box-view2"></div>
    </div>
    <br>

    ...
</template>

<style lang="scss" scoped>
...

.box-view2 {
  @apply w-[25%] h-12 rounded-md m-4px;
}

.light-red {
  background-color: theme("colors.red.200");
}
</style>

windcss-theme().jpg

属性化模式

属性化在 Windi CSS 中 默认情况下是可选的,可以在你的 windi.config.ts 配置中开启,并根据需要来使用。

import { defineConfig } from 'windicss/helpers'

export default defineConfig({
  attributify: true,
})

就可以把我们上面的代码改为下面的方式,效果和上面讲到的响应式设计是一样的,但是这样写可以让我们的目录更加清晰。

<h3>使用 Windi CSS</h3>
<div class="flex items-center justify-around bg-teal-100 rounded-md p-4px w-192px">
    <div
        lg="bg-red-400 box-view"
        md="bg-red-200 box-view"
        sm="bg-red-100 box-view"
      ></div>
    <div class="bg-green-400 box-view"></div>
    <div class="bg-blue-400 box-view"></div>
</div>

如果担心命名冲突,可以在 windi.config.ts 配置中通过属性化方式添加自定义前缀:

import { defineConfig } from 'windicss/helpers'

export default defineConfig({
  attributify: {
    prefix: 'w:',
  },
})
<h3>使用 Windi CSS</h3>
<div class="flex items-center justify-around bg-teal-100 rounded-md p-4px w-192px">
    <div
        w:lg="bg-red-400 box-view"
        w:md="bg-red-200 box-view"
        w:sm="bg-red-100 box-view"
      ></div>
    <div class="bg-green-400 box-view"></div>
    <div class="bg-blue-400 box-view"></div>
</div>

windicss使用属性化模式.jpg

同样的,我们也可以根据工具类来分组,也还是很方便的:

windicss属性化模式分组.jpg

Plugin 插件

Windi CSS 的官方以及社区提供了很多 plugin 插件供我们去使用,让我们操作 css 更加方便和高效,而且我们也可以通过 Windi CSS 的接口,来开发自己的插件。

插件同样需要在 Windi CSS 的配置文件 windi.config.ts 中引入即可。

export default {
  theme: {
    // ...
  },
  // 引入插件
  plugins: [
    require('windicss/plugin/typography'),
    // ...
  ],
}

而且插件功能也非常强大,有兴趣也可以自己去摸索一下:

VS Code 插件

Windi CSS 还为 VS Code 编译器提供了一个叫做 Windi CSS Intellisense 的插件,可以直接在 VS Code 插件商店里找到并安装,配合 VS Code 可以拥有一个更好的 Windi 的开发体验,例如:自动补全、语法高亮、代码折叠和构建等等,就和我们平时写标准 css 一样方便。

  • 自动补全:为工具类 (utilities) 和可变修饰 (variants) 提供智能建议。
  • 悬停预览:悬停于一个 class name 的上方时可以看到其完整的 CSS。
  • 语法高亮:高亮工具类、可变修饰和重要的部分。
  • 颜色预览:预览颜色和色谱。
  • 代码折叠:折叠超长的 classes 以提高可读性。
  • 编译命令:内置编译命令,一键操作。

windicss自动补全.jpg

windicss悬停预览.jpg

其他功能

除此之外,Windi CSS 还有很多我没用研究到的功能,也是很强大的。

  • 暗色模式:Windi CSS 拥有开箱即用的暗色模式支持,只需要对工具类添加可变修饰前缀 dark: 即可
  • RTL:Windi CSS 拥有开箱即用的从右到左(RTL)书写方式支持,且无需任何配置,只需要对工具类增加 rtl: 可变修饰前缀即
  • 可视化分析器:一个为 Windi CSS 提供的可视化分析工具。浏览你所有的工具类 (utilities) 使用情况,综观你的设计系统,识别"糟糕的使用",以及更多!
  • ……

Windi CSS 总结

优点

Windi CSS 的写法与传统 css 相比,确实可以让人眼前一亮,它内置了大量的工具类确实可以解决大部分的业务需求,也可以更好的进行 css class 的复用;而且它的内置功能也趋于完善,无论是提供 shortcuts 功能、响应式功能,还是提供了指令和 plugin 插件等,都可以让我们开发起来更加方便。而且很多第三方组件也是提供 Windi CSS 支持的,比如我上一篇文章写的 slidev 等。

简而言之,Windi CSS 就是想做一个通用的可定制化的 css “组件库”,省去了我们前期大量思考如何来完成和写好这个样式的时间成本,同时还可以让我们养成一套良好的开发和 UI 规范。

缺点

当然可能也不算是缺点,谨代表我个人的观点。

大量的工具类和功能也会增加短期的学习成本,以及基于你的项目继续开发的阅读成本,在多人协作维护的项目上确实增加一些团队负担。同时页面中很多 class 中使用的大量的工具类,也会大大降低代码的优雅性,造成了 html 结构上的一种拥挤感。而且 css 世界本就丰富多彩,很多的样式还需要 css 搭配 js 来使用,仅凭一个 Windi CSS 是否就可以满足我们所有的需求呢;当我们使用 Windi CSS 和第三方组件搭配使用,就一定可以确保没用问题吗。

更早出来的 Tailwind CSS 还处于舆论的风口浪尖,而 Windi CSS 只是被看作是按需供应的 Tailwind 替代方案,所以 Windi CSS 依然需要经得起时间的考验。


写在最后

无论是在项目中继续使用 less / sass,还是使用那些原子样式的 css 框架 Windi CSS / Tailwind CSS,找到一款适合自己适合团队需求的才是最重要的。

如果你也对 Windi CSS 感兴趣的话,也去自己动手操作操作吧,也许会给你带来意想不到的收获呢。