@如何在小程序使用 tailwindcss 框架(2-安装和体验)

5,659 阅读10分钟

Tailwindcss 的本质是一个 Node.JS 的应用,通过配置项来生成我们所需要的 CSS 类,使得我们不需要使用写 CSS 就能快速的快速的布局。要使用 Tailwindcss 需要的就是搞明白 Tailwindcss 应该如何配置,如果需要用到小程序中,就需要知晓小程序的类不同与浏览器的类。

原本以为写了 Tailwindcss 是不会有人关注的,后来还是有人关注了 tailwindcss ,这里就把出现的问题尽量的说明白和补齐。但是还是不推荐将其运用在生产环境,因为并没有大量的实践, 愿意国内探究 tailwindcss 人并不多, CSS 似乎也不被人很重视。同时推荐使用 vscode 进行代码编写。下面介绍关于 tailwindcss 的插件支持。

目标:(目前主要目标是小程序,因为官方网站缺失关于小程序方面使用)

  • 在原生小程序中使用 tailwindcss
  • 在 mpvue 中使用 tailwindcss
  • 在 uni-app 中使用 tailwindcss
  • 在 taro-react/taro-vue 中使用 tailwindcss

当然也可以探索更多:

  • React 当中如何使用 Tailwindcss
  • Vue 中如何使用 Tailwindcss
  • Angular 中如何使用 Tailwindcss
  • Svelte 中使用 Tailwindcss

Tailwindcss 与原生小程序

原生的小程序推荐是 gulp 来构建微信小程序,gulp 简单容易配置。我们使用小程序提供的命令行工具来创建小程序项目,主要依赖如下

  • gulp/gulp-postcss
  • @wechat-miniprogram/miniprogram-cli 生成小程序项目
  • tailwindcss
# 项目创建命令行
yarn global add @wechat-miniprogram/miniprogram-cli --dev
# 构建工具
yarn add gulp gulp-postcss  --dev 
# 主依赖
yarn add tailwindcss

Gulp 打包

// gulp 配置

初始化 tailwindcss 基本配置

安装完成之后,就可以使用 tailwindcss 的命令行工具tailwindcss进行初始化了。

  • 生成 tailwindcss.config.js 配置文件
  • 注入tailwindcss 指令,指令如下
@tailwind base; // 实际就是 normalize.css 在小程序中用不上,需要忽略不使用
@tailwind components; // 组件类
@tailwind utilities; // 工具类

注意:

  1. 类规范:使用之后发现,tailwindcss 默认的配置的生成的 css 代码中,有很大一部分是不符而小程序的 class "规范" (小程序中 class 仅仅支持中划线-和下划线_)的,他们集中的表现在 Pseudo-Class Variants, 但是小程序中,我们能够使用伪类是有限制的,或者我们可以将默认的编译 Variants 配置项全部清空(目的是不生成 Variants 的 css 代码),如果有需要直接写我们自己需要 Variants来解决问题。

  2. 不适用与小程序环境的css特性。在小程序环境中响应式布局也基本上用不上,此时,我们在配置文件中去掉这两项之后,发现原来几万行的代码,只有几千行了,一个类,基本上要占据三行,所以实际的css属性,应该就是及千行的样子。

  3. 单位和负值的处理。就是 tailwindcss 在计算 负值 的时候,识别的单位是 web 端的单位,不能识别 rpx, 所以我们需要负的 margin 的时候,我们就需 要自己处理这个负值的情况,以便适用于小程序。毕竟 tailwindcss 是老外搞出来的东西,国外可没有微信小程序,负值就需要自己来写函数来生成对应的负值。

体验

体验这一部分,自己的做了一个简单名片的例子,然后发现问题:单位是 rem, 小程序使用的rpx作为单位,我们就想着自己来配置大小和单位的事情,跟这官方网站自己摸索如何写css, 如何布局。说道这里,如果我们想要学习 tailwindcss,学会写插件,学会写工具类。有能力改写配置,才能灵活的运用

关于小程序公共部分

const cloneDeep = require('lodash/cloneDeep')
const defaultConfig = require('./stubs/defaultConfig.stub.js')

module.exports = cloneDeep(defaultConfig.theme)

自定义主题 theme

关于:官方的 theme,下面是我们简单的配置 tailwindcss theme。 有如下的点要注意:

  • 单位,使用 rpx(单位的使用要根据具体的情况开使用)
  • 添加百分比(宽度,高度等等...)
  • 添加渐变(使用插件添加渐变能力)
// tailwind.config.js
module.exports = {
    theme: {
    screens: {},
    spacing: {
      px: '1px',
      '0': '0',
      '1': '1rpx',
      '2': '2rpx',
      '4': '2rpx',
      '6': '6rpx',
      '8': '8rpx',
      '10': '10rpx',
      '12': '12rpx',
      '14': '14rpx',
      '16': '16rpx',
      '18': '18rpx',
      '20': '20rpx',
      '22': '22rpx',
      '24': '24rpx',
      '26': '26rpx',
      '28': '28rpx',
      '30': '30rpx',
      '32': '32rpx',
      '34': '34rpx',
      '36': '36rpx',
      '38': '38rpx',
      '40': '40rpx',
      '42': '42rpx',
      '44': '44rpx',
      '46': '46rpx',
      '48': '48rpx',
      '50': '50rpx',
      '60': '60rpx',
      '56': '56rpx',
      '64': '64rpx',
      '70': '70rpx',
      '80': '80rpx',
      '90': '90rpx',
      '100': '100rpx',
      '120': '120rpx',
      '140': '140rpx',
      '160': '160rpx',
      '200': '200rpx',
      '260': '260rpx',
      '300': '300rpx',
      '350': '350rpx',
      '400': '400rpx',
      '500': '500rpx',
      '600': '600rpx',
      '700': '700rpx',
      '750': '750rpx'
    },
    // 还有特殊的我们就添加特定
    width: theme => ({
      auto: 'auto',
      ...theme('spacing'),
      '1_5': '20%',
      '2_5': '40%',
      '3_5': '60%',
      '4_5': '80%',
      '5_6': '83.333333%',
      '1_12': '8.333333%',
      '2_12': '16.666667%',
      '3_12': '25%',
      '4_12': '33.333333%',
      '5_12': '41.666667%',
      '6_12': '50%',
      '7_12': '58.333333%',
      '8_12': '66.666667%',
      '9_12': '75%',
      '10_12': '83.333333%',
      '11_12': '91.666667%',
      full: '100%',
      screen: '100vw'
    }),
    height: theme => ({
      auto: 'auto',
      ...theme('spacing'),
      full: '100%',
      screen: '100vh'
    }),
    inset: {
      '20': '20rpx',
      '-20': '-20rpx',
      '-10': '-10rpx'
    },
    margin: (theme, { negative }) => {
      // 使用了 reduce 这个包 rpx 是能转换的暂时自己比变量添加
      return {
        auto: 'auto',
        ...theme('spacing'),
        ...myNegative(theme('spacing'))
      }
    },
    letterSpacing: {
      tighter: '-1px',
      tight: '-0.5px',
      normal: '0',
      wide: '1rpx',
      wider: '2rpx',
      widest: '3rpx'
    },
    fontSize: {
      xs: '12rpx',
      sm: '14rpx',
      base: '16rpx',
      lg: '18rpx',
      xl: '20rpx',
      '2xl': '24rpx',
      '3xl': '30rpx',
      '4xl': '36rpx',
      '5xl': '48rpx',
      '6xl': '64rpx'
    },
    gradients: theme => ({
      // blue to other
      'blue-green': [theme('colors.blue.500'), theme('colors.green.500')],
      'blue-purple': [theme('colors.blue.500'), theme('colors.purple.500')],

      // green to other
      'green-blue': [theme('colors.green.500'), theme('colors.blue.500')],
      'green-red': [theme('colors.green.500'), theme('colors.red.500')],
      // purple to other
      'purple-blue': [theme('colors.purple.500'), theme('colors.blue.500')],
      'purple-orange': [theme('colors.purple.500'), theme('colors.orange.500')],
      'purple-yellow': [theme('colors.purple.500'), theme('colors.yellow.500')],
      // orange to other
      'orange-purple': [theme('colors.orange.500'), theme('colors.purple.500')],
      'orange-indigo': [theme('colors.orange.500'), theme('colors.indigo.500')],
      // red to other
      'red-purple': [theme('colors.red.500'), theme('colors.purple.500')],
      'red-green': [theme('colors.red.500'), theme('colors.green.500')],

      // teal to other
      'teal-red': [theme('colors.teal.500'), theme('colors.red.500')],

      // indigo to other
      'indigo-red': [theme('colors.indigo.500'), theme('colors.red.500')],

      // pink to other
      'pink-red': [theme('colors.pink.500'), theme('colors.red.500')],
      'pink-blue': [theme('colors.pink.500'), theme('colors.blue.500')],

      // yellow to other
      'yellow-indigo': [theme('colors.yellow.500'), theme('colors.indigo.500')]

    }),
    extend: {
      boxShadow: {
        // display: '-3rpx -3rpx 10rpx 2rpx rgba(0,0,0,.3) inset, 0 0 0 6rpx rgba(255, 255, 255, .6) inset, 0 0 0 1rpx rgba(0,0,0,.5), 2rpx 2rpx 10rpx rgba(0,0,0,.6)'
        display: '-3rpx -3rpx 10rpx 2rpx rgba(0,0,0,.3) inset, 0 0 0 14rpx rgba(255, 255, 255, .6) inset, 0 0 0 1rpx rgba(0,0,0,.5), 2rpx 2rpx 10rpx rgba(0,0,0,.6)'
      }
    }
  },
}
// 处理负值
function myNegative (obj) {
  let __obj = {}
  // 负值转换
  for (let key in obj) {
    if (key === 0 || key === '0') {
      __obj[`${key}`] = `${obj[key]}`
    } else {
      __obj[`-${key}`] = `-${obj[key]}`
    }
  }

  return __obj
}

主题 theme 本质就是 css 特性,使用 JavaScript 进行描述,Node.JS 根据配置生成 css。如有其他的配置项,按照自己的需求配置即可。

Tailwindcss 变异 Variants

module.exports = {
    // 置空 variants,所有的 编译都不使用
    variants: [],
}

插件

参考:编写 Tailwindcss 插件,下面是以插件的方式实现了:

  • 文本背景颜色(类名:text-clip)
  • 首字母大写 (类名:inital-capitalize:first-letter)
  • 字体方法 (类名:vertical-lr)
  • 多行的折叠 + 省略号 (类名:truncate-2/3/4)
// 插件
module.exports = function (options) {
  return function ({ addUtilities }) {
    addUtilities({
      // 文本背景颜色
      '.text-clip': {
        backgroundClip: 'text',
        '-webkitBackgroundClip': 'text',
        color: 'transparent'
      },
      // 首字母大写
      '.inital-capitalize:first-letter': {
        fontSize: '50rpx'
      },
      // 字体的垂直方向
      '.vertical-lr': {
        'writing-mode': 'vertical-lr' /* 从左向右 从右向左是 writing-mode: vertical-rl; */
        // 'writing-mode': 'tb-lr' /* IE浏览器的从左向右 从右向左是 writing-mode: tb-rl; */
      },
      // 多行的折叠 + 省略号 + 注意是 -webkit 内核使用
      '.truncate-2': {
        overflow: 'hidden',
        /* text-overflow: ellipsis;  有些示例里需要定义该属性,实际可省略 */
        'display': '-webkit-box',
        '-webkit-line-clamp': '2',
        '-webkit-box-orient': 'vertical'
      },
      '.truncate-3': {
        overflow: 'hidden',
        'text-overflow': 'ellipsis', /* 有些示例里需要定义该属性,实际可省略 */
        'display': '-webkit-box',
        '-webkit-line-clamp': '3',
        '-webkit-box-orient': 'vertical'
      },
      '.truncate-4': {
        overflow: 'hidden',
        'text-overflow': 'ellipsis', /* 有些示例里需要定义该属性,实际可省略 */
        'display': '-webkit-box',
        '-webkit-line-clamp': '4',
        '-webkit-box-orient': 'vertical'
      }
    })
  }
}

插件2:使用插件实现渐变功能 gradients

const _ = require('lodash')

module.exports = function ({ addUtilities, e, theme, variants }) {
  const gradients = theme('gradients', {})
  const gradientVariants = variants('gradients', [])

  const utilities = _.map(gradients, ([start, end], name) => ({
    [`.bg-gradient-${e(name)}`]: {
      backgroundImage: `linear-gradient(to right, ${start}, ${end})`
    },
    [`.bg-gradient-bottom-${e(name)}`]: {
      backgroundImage: `linear-gradient(to bottom, ${start}, ${end})`
    }
  }))

  addUtilities(utilities, gradientVariants)
}

配置项中加载插件:

module.exports =  {
    plugins: [
        require('./plugins/base')(),
        require('./plugins/gradients')
    ],
}

处理负值

下面是处理负值的情况,为什么要处理负值,原因在于 Tailwindcss 源码中单位,没有对 rpx 的支持,所以当我们使用的时候负值也是需要单独处理的,下面是一个简单的负值的处理函数:

function myNegative(obj) {
  let __obj = {}
  // 负值转换
  for (let key in obj) {
    if (key === 0 || key === '0') {
      __obj[`${key}`] = `${obj[key]}`
    } else {
      __obj[`-${key}`] = `-${obj[key]}`
    }
  }

  return __obj
}

Mpvue 与 Tailwindcss

  1. 安装和初始化 mpvue 项目
# 全局安装 vue-cli
$ npm install --global vue-cli

# 创建一个基于 mpvue-quickstart 模板的新项目
$ vue init mpvue/mpvue-quickstart tailwindcss-app

# 安装依赖
$ cd tailwindcss-app
$ npm install
# 启动构建
$ npm run dev
  1. 配置 postcss
// https://github.com/michael-ciniawsky/postcss-load-config
const purgecss = require('@fullhuman/postcss-purgecss')

module.exports = {
  plugins: [
    require('postcss-import'),
    require('tailwindcss'),
    require('autoprefixer')({grid: false}),
    // purgecss({
    //   content: ['./**/*.vue']
    // }),
    require('postcss-mpvue-wxss')
  ]
}
  1. 添加指令
<style lang="scss">
@import './styles/aminate.css';
@import './icons.scss';
@import './styles/layout';

@tailwind utilities;

page {
  font-family: PingFang SC, 'Helvetica Neue', Arial, sans-serif;
}

view {
  box-sizing: border-box;
  font-family: PingFang SC, 'Helvetica Neue', Arial, sans-serif;
}
.container {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: 200rpx 0;
  box-sizing: border-box;
}
</style>

打包之后,会生成 dist/wx 目录,可以在该目录中查看tailwindcss生成的 CSS 类。

  1. 删繁就简 tree-shaking

控制大小,tailwindcss 是机器生成代码,没有使用到的代码还有很多,Tailwindcss 官方也提供了方案:purgecss。

Taro 与 Tailwindcss

Taro Next 中也有了对 Vue 的支持,但是 Taro 不一样的是 Taro 有自己的配置文件,Postcss 文件就能够自定义,我们就只能使用最原始的方式来定义.

Vue Next 的配置文件

  1. 初始化一个 Taro 项目
# 安装 taro
# yarn add @taro/cli
taro init tailwindcss-taro-app
  1. 添加 tailwindcss 配置

如上 mpvue 的配置即可,仅仅是作为示例,说明问题即可。

  1. 添加postcss配置

由于 taro 有自己专有的配置文件,位于 config 文件夹下面,官方配置postcss插件只是提供几种,我们需要自己将tailwindcss插件添加到其中:

// config/dev.js
module.exports = {
  env: {
    NODE_ENV: '"development"'
  },
  defineConstants: {},
  mini: {
    postcss: {
      tailwindcss: {
        enable: true,
      }
    }
  },
  h5: {}
}
  1. 运行

使用 taro 提供的命令进行打包编译即可。

Uni-app 与 Tailwindcss

  1. 使用命令行初始化一个 uni-app 项目
vue create -p dcloudio/uni-preset-vue tailwindcss-app
  1. 添加 tailwindcss
# 进入工作目录
cd tailwindcss-app
# 添加 tailwincss 支持
yarn add tailwindcss
# 使用 tailwind 命令初始化配置文件
tailwind init # 默认生成 tailwind.config.js

tailwindcss 配置文件,根据自己的实际情况而定,也可参考上面关于建议

  1. 配置 postcss
// postcss.config.js
module.exports = {
  parser: require('postcss-comment'),
  plugins: [
    // ...
    require('tailwindcss'),
    require('autoprefixer')({
      remove: process.env.UNI_PLATFORM !== 'h5'
    })
    // ...
  ]
}
  1. 添加指令

默认的uni-app项目使用 scss css 预处理器,我们可以在合适地方,如全局的css入口使用@tailwind指令生成配置的 css 代码。例如在 App.vue 中注入指令:

<style lang="scss">
/*每个页面公共css */
@tailwind utilities;
</style>

编译之后,对应的代码就会打包到 dist/dev/mp-weixin/common/main.wxss 中。

  1. vscode 插件

vscode 插件支持智能感知,vscode 可能不能及时生效,可以重新启动 vscode, 即可。

  1. 删繁就简

控制大小,tailwindcss 是机器生成代码,没有使用到的代码还有很多,Tailwindcss 官方也提供了方案:purgecss

// tailwind.config.js
module.exports = {
     purge: [
    './src/**/*.html',
    './src/**/*.vue',
    './src/**/*.jsx',
  ],
}

后面

tailwindcss 是一个快速的构建布局样式的css框架,基于postcss, 在原子css的思想上,提供了可配置,插件化的增强 ACSS 的能力。是天生响应式。

解析来要做的事情

  • [ x ] Tailwindcss 源码分析,更加深入的理解 tailwindcss。
  • [ x ] 分析源码,修正文章

参考

  1. Tailwindcss 各种适合的安装方法
  2. Gulp 快速开始构建项目
  3. 微信小程序关于 WXML 中内联样式规定
  4. WXML 命名问题: 微信小程序的wxss 的 class 命名的问题,不支持形如 .xl:yu-z-40 吗?
  5. Tailwindcss 源码解析