在过去的一年半中,我们团队分别使用了 Taro React 开发小程序, React 开发 Web 程序 和使用 React Native 开发 App。使用的样式构建也各种各样,并不统一,在小程序中,使用 SCSS,在 Web 中使用 tailwind, 在 React Native 中使用 StyleSheet.create 创建样式。

在这三种写法中来回切换是痛苦的。

简介

我们从 tailwind 中获得了灵感, 将 tailwind 的原子样式 与 JSX Prop 结合,开发了 Fower。Fower 在 JSX 组件外包装了一层,通过收集整合原子样式属性,生成 className 或者 style 属性,并将其注入到内层组件中。由于 Fower 组件本质是一个 JSX 组件,因而也获得了 VSCode 的智能提示,书写样式时,只需要打个首字母,就可以联想出所有的原子样式,回车即可填充属性,这种开发体验是相当爽的。

在此基础上,Fower 通过附加各种属性后缀,支持了伪类,媒体查询,主题切换,暗黑模式等功能;提供了一些布局属性,可以快速让多子元素垂直、水平居中;也有一些功能属性,可以快速裁剪文字,省略显示;可以通过一个属性,构建出一个方形或者圆;还有功能强劲的 css 属性,让你使用各种子元素选择器。。。除了内置的这些属性,Fower 也提供了相关 API,可以让你可以定制化你自己的属性实现。

我们除了对 React, Taro React, React Native 封装了组件包外,还针对 Vue, Svelte 等框架进行了部分兼容和适配,Fower 提供了 VSCode 插件,解决了在 React Like 之外的框架的智能提示。

使用 Fower,基本上可以让你不用再写烦人的 CSS 文件

对比

相比于 Tailwind, Fower 的优势是明显的。

  • VSCode 插件。Tailwind 的使用离不开 VSCode 插件。Fower 在 React Like 框架中,利用 VSCode 智能提示就可以联想出各种属性,在其他框架中,才需要安装 VSCode 插件
  • 开箱即用。Fower 只需要安装对应的框架包,即可直接使用,无需进行繁杂的配置。
  • 体积。对于类似 p1, p2p100 这种属性,Tailwind 中枚举了每一个属性的样式,导致体积异常的庞大。Fower 在 React Like 中属于运行时库,对属性具有编程性,可以动态生成样式,所以体积非常小。在非 React Like 框架中,Fower 通过收集模板的原子属性样式也是动态生成样式。
  • 多端使用。Fower 针对市面上主流的框架进行了针对性适配,你可以在 React, Preact, Vue, Svelte, React Native, Taro React 小程序, Remax 小程序等平台使用 Fower。Tailwind 不支持在 React Native 使用,并且在 Taro, Remax 等小程序环境中没有支持。

由于 Fower 是运行时 UI 库,所以相对于 Tailwind 有一定的运行时损耗。但对于设备算力越来越强大的今天,这点损耗可以忽略不计。但 Fower 还是尽可能的使用了各种手段提高运行效率,Fower 内部对所有遍历过的属性进行缓存,极大提高运行速度。

项目

官方文档(https://fower.vercel.app/)

项目地址(https://github.com/forsigner/fower)

功能一览

下面演示了使用 Fower/react 框架包的 Box 组件编写的 demo。实际上,直接使用 Box 标签也是可以用的,但需要额外的配置。

基本使用

Fower 提供了大量的原子样式属性,可以极速构建 UI。

<Box text2XL fontBold green500 className="user" style={{ fontWeight: 'bold' }}>
  Hi, Fower
</Box>

可编程/动态样式

你可以通过为属性赋值的方式,来编写动态样式

<Box
  text-14
  display="block"
  color="red"
  blue={false}
  p-10
  m-10rem
  bg="red"
  bgRed={true}
  bgBlue={false}
>
  Hi, Fower
</Box>

CSS 属性

Fower 中提供了强大的 CSS 属性,实现了大部分 CSS 的功能。

<Box
  text4XL
  css={{
    backgroundColor: '#edf2f7',
    ':hover': {
      backgroundColor: '#feebc8',
    },
    '.title': {
      fontWeight: 'bold',
    },
    span: {
      color: 'deeppink',
    },
  }}
>
  <Box className="title">Nested demo</Box>
  <span>Hi, Fower!</span>
</Box>

伪类/响应式

Fower 通过后缀的方式,支持了伪类,响应式等功能

<Box text2XL text3XL--hover red--first-child fontBold green500>
  <Box>Hi, Fower</Box>
</Box>
<Box textSM textLG--sm text4XL--md text6XL--lg>
  Lorem ipsum dolor sit amet
</Box>

颜色助手

颜色助手可以快速增加或减少颜色的亮度,透明度等等

<Box toEvenly toCenterY>
  <Box red300>normal</Box>
  <Box red300--D40>darken</Box>
</Box>

主题

Fower 内置了主题。你可以通过 setTheme API 更改和添加配置。

import { setTheme } from '@fower/core'

setTheme({
  spacings: {
    10086: 110,
  },
  color: {
    gray10086: '#FFFFFF'
  }
})

<Box textSM bgGray10086 bgGray10086--dark p10086>
  Lorem ipsum dolor sit amet
</Box>

与第三方组件库一起使用

上文中提到 Fower 原理是通过给现有组件包装了一层,通过收集整合原子样式属性,最终将 className 或 style 属性注入到内层组件。因而与第三方组件使用时,只需要利用 styled API 包装即可。

import { Button as AntdButton } from 'antd'
import { styled } from '@fower/styled'

const Button = styled(AntdButton)

<Button red300 red400={false} text={7 + 7}>
  normal
</Button>

属性冲突

Fower 组件提供的属性与三方属性冲突时,Fower 也提供了解决方案。

import { Button as AntdButton } from 'antd'
import { styled } from '@fower/styled'

const Button = styled(AntdButton)

<Button excludedProps={['block']} block>
  normal
</Button>

类名

Fower 同样支持了 tailwind 的用法

<Box className="toCenter square-400 bgRed400">
  <Box className="white">Lorem ipsum</Box>
</Box>

动画

Fower 提供了 keyframes API,可以快速创建动画。

import { Box } from '@fower/react';
import { keyframes } from '@fower/core';

const bounce = keyframes({
  'from, 20%, 53%, 80%, to': {
    transform: 'translate3d(0,0,0)',
    padding: 10,
  },
    '40%, 43%': {
    transform: 'translate3d(0, -30px, 0)',
  },
})

<Box
  text-30
  css={{
    animation: `${bounce} 1s ease infinite`,
  }}
>
  40 Lorem ipsum dolor sit amet
</Box>

扩展

Fower 提供了 addAtom API 可以快速扩展原子样式属性。但这只能在自己的项目中使用。

Fower 提供了灵活的插件机制,你可以编写自己的样式 Util,供他人使用。

import { setConfig } from '@fower/core';
import ellipsis from 'fower-plugin-ellipsis';

setConfig({
  plugin: [ellipsis],
});

结语

经过团队半年的不懈努力,Fower 日渐完善,我们也在项目中积极使用。目前在我们小程序项目中做到了仅有一个 app.scss 样式文件的地步。我们封装了很多框架包,也在积极测试与使用,但难免会遇到很多 Bug,希望大家积极试用使用 Fower,也希望 Fower 项目能够真正的帮助你解决样式开发的痛点。谢谢大家。