Tailwindcss 在小程序中实践

5,837 阅读7分钟

了解 tainwindcss

Tailwind CSS 是一个高度可定制的基础层 CSS 框架,它为您提供了构建定制化设计所需的所有构建块,而无需重新覆盖任何内建于框架中的设计风格。

大多数 CSS 框架包揽了太多工作。 其它 CSS 框架内建了各种预先设计的组件,例如按钮(buttons)、卡片(cards)和警告框(alerts)等,这些组件在一开始可能会加速你的开发进度,但是当你需要通过定制化的设计使你的网站能够脱颖而出时,这些组件会给你带来更大的痛苦。

与其它 CSS 框架不同的是,Tailwind 并不提供预先设计好的内建组件。相反,Tailwind 提供了更基础的工具类(utility classes),可以让你直接在 HTML 源码上构建一个完全定制化的设计。

在小程序中的使用方法

因为tailwindcss知识css层工具,所以不依赖其他前端组件库,能构建postcss即可,所有我们可以我们想要的环境中使用。

小程序开发环境有不同的开发环境:

  • 原小程序开发环境,可以考虑使用 glup 来构建
  • 类 Vue 开发环境,一般是 MpVue, Wepy, Uniapp 等等其他的小程序框架
  • 类 React 开发环境出名的有 Taro, Remax 等等。

tailwindcss 配置

因为 tailwindcss 是适配web端的,所以我们要在小程中使用的话,还要注意一些区别。

  • hover 相关的在小程序端没有意义,所以对于大部分的 variants 是没有意义的,我们将其置空。
  • 响应式设计,响应式在移动端的意义也不是大。所以我们基本上用不上响应式设计。
  • 一些交互相关的只有值PC端才有的,我们也用不上。
  • 单位问题,在微信小程序端使用 rpx 作为单位。但是经过尝试 rpx 单位是不能再 tailwindcss 中识别的。所以我们要自己配置 rpx 单位。
  • 关于负值的问题,在单位是rpx时,不能正常的处理,我们也需要自己处理负值不能正常输出的问题。
module.exports = {
  prefix: '',
  separator: ':',
  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_7': '14.285714%',
      '1_8': '12.5%',
      '1_9': '11.111111%',
      '1_10': '10%',
      '1_11': '9.090909%',
      '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) => {
      // 使用了 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'
    },
    borderRadius: {
      none: '0',
      xs: '2rpx',
      sm: '4rpx',
      default: '6rpx',
      lg: '8rpx',
      xl: '10rpx',
      '2xl': '12rpx',
      '3xl': '14rpx',
      '4xl': '16rpx',
      '5xl': '20rpx',
      full: '9999px'
    },
    borderWidth: {
      default: '1rpx',
      '0': '0rpx',
      '2': '2rpx',
      '4': '4rpx',
      '8': '8rpx'
    },
    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)'
      },
      colors: {
        tred: '#FF0000',
        tgreen: '#00FF00',
        tblue: '#0000FF',

        hue0: '#FF0000',
        hue30: '#FF7F00',
        hue60: '#FFFF00',
        hue90: '#7FFF00',
        hue120: '#00FF00',
        hue150: '#00FF7F',
        hue180: '#00FFFF',
        hue210: '#007FFF',
        hue240: '#0000FF',
        hue270: '#7F00FF',
        hue300: '#FF00FF',
        hue330: '#FF007F'
      }
    },
    lineHeight: theme => ({
      ...theme('spacing'),
      none: '1',
      tight: '1.25',
      snug: '1.375',
      normal: '1.5',
      relaxed: '1.625',
      loose: '2'
    }
    )
  },
  variants: {
    accessibility: [],
    alignContent: [],
    alignItems: [],
    alignSelf: [],
    appearance: [],
    backgroundAttachment: [],
    backgroundColor: [],
    backgroundPosition: [],
    backgroundRepeat: [],
    backgroundSize: [],
    borderCollapse: [],
    borderColor: [],
    borderRadius: [],
    borderStyle: [],
    borderWidth: [],
    boxShadow: [],
    cursor: [],
    display: [],
    fill: [],
    flex: [],
    flexDirection: [],
    flexGrow: [],
    flexShrink: [],
    flexWrap: [],
    float: [],
    fontFamily: [],
    fontSize: [],
    fontSmoothing: [],
    fontStyle: [],
    fontWeight: [],
    height: [],
    inset: [],
    justifyContent: [],
    letterSpacing: [],
    lineHeight: [],
    listStylePosition: [],
    listStyleType: [],
    margin: [],
    maxHeight: [],
    maxWidth: [],
    minHeight: [],
    minWidth: [],
    objectFit: [],
    objectPosition: [],
    opacity: [],
    order: [],
    outline: [],
    overflow: [],
    padding: [],
    placeholderColor: [],
    pointerEvents: [],
    position: [],
    resize: [],
    stroke: [],
    tableLayout: [],
    textAlign: [],
    textColor: [],
    textDecoration: [],
    textTransform: [],
    userSelect: [],
    verticalAlign: [],
    visibility: [],
    whitespace: [],
    width: [],
    wordBreak: [],
    zIndex: []
  },
  plugins: [
    require('./plugins/base')(),
    require('./plugins/gradients')
  ]
}

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
}

使用 gulp 构建的时候

gulp.task('css', function () {
  const postcss = require('gulp-postcss')

  return gulp.src('src/styles.css')
    // ...
    .pipe(postcss([
      // ...
      require('tailwindcss'),
      require('autoprefixer'),
      // ...
    ]))
    // ...
    .pipe(gulp.dest('build/'))
})

postcss 配置

  1. postcss 配置
  2. gulp 构建微信小程序
  3. 其他的配置

快速开发微信小程序

快速开发微信小程序是我们的愿景,那我们如何才能快速的开发小程序而且还方便维护呢? 可以尝试 tailwindcss 框架来帮你管理 css 的样式问题。

写这个的目的是记录自己的学习历程,一方可以分享自己一些经验,来帮助那些需要或者对这个感兴趣的人。

首先

  • 首先 ACSS 的原子思想是很简单的,每一个样式都是一个原子,使用原子的时候,我们可以如同堆积木的方式来处理 css 的问题,但是越来越大了管理和维护就成了问题
  • tailwindcss 是 ACSS 的集大成者,出于好奇想全面的解析 tailwindcss 原子类 css 处理方法,并运用到实践当中。
  • tailwindcss 是基于 postcss 的。是后处理 css 样式,不同于 scss、less 等预处理器。
  • tailwindcss 是配置驱动的,跟 webpack 差不多,配置驱动的,本质是通过配置,添加一些原子 css 类,我们在使用的时候,就可以直接在 css 上书写这个类了。
  • tailwindcss 有良好支持,和较为良好的生态。官方文档齐全,明确。
  • tailwindcss 是插件的机制,根据我们的需求可以自行增删改查。
  • tailwindcss 是天生的响应式设计。
  • tailwindcss 更好的理解设计。

想做的

学习 tailwindcss 并在微信小程序中实践。今天是我学习 tailwincss 的第三天了。初步了解了 tailwindcss 的使用方式。下一步就是了解 tailwindcss 深入的东西。

入到了坑,躺了

没有选择 h5 作为开发环境,是因为官方文档就是基于 web 端的,支持 IE11以上以及主流的浏览器。选择小程序是因为目前小程序还是比较流行。

坑1: class 命名问题,tailwindcss 在命名设计, 命名是有反斜杠和冒号这种字符的,这种字符在小程序里面 class 命名是没有办法用的,所以我们如果还是要使用 tailwindcss 的话,就要想办法解决这些问题。

<div class="clearfix">
  <div class="float-left w-1/3"><!-- ... --></div>
  <div class="float-left w-1/3"><!-- ... --></div>
  <div class="float-left w-1/3"><!-- ... --></div>
</div>

注意

我们在使用 tainwindcss 的时候,我们要搞明白一些问题。

后面

ACSS 的思想是我们不直接写 css 了,使用类来接管,我们需要什么就用什么,这样可以直接关注业务。优点有很多,但是缺点也是不会少的。学习 tailwindcss这个集大成者,能帮我们更好的理解 css 的思想,有组织,有设计的去管理我们自己 css。

参考

  1. 【tailwindcss官方网址】https://tailwindcss.com/

  2. 【tailwindcss官方网址】https://tailwindcss.cn/

  3. 【tailwindcss官方github网址】https://tailwindcss.com/