如何在快应用开发中使用 Tailwind CSS 提升开发效率?
Tailwind CSS,在 Web 开发领域,已经成为各种框架、开发人员标配;已经有大量实例证明,基于 Tailwind CSS
来编写样式,可以为开发者节省诸多时间;而且,能够优化减小代码体积、提升运行性能,是非常棒的技术套件。 快应用 开发,同样基于 Web 技术栈,理论上也完全可以使用 Tailwind CSS;在实际开发过程中,该如何使用 Tailwind CSS 呢?请详细说说。
Tailwind CSS 的工作原理是扫描所有 HTML 文件、JavaScript 组件和任何其他模板的类名,生成相应的样式,然后将它们写入静态 CSS 文件。它快速、灵活、可靠,且运行时间为零。官方提供 Tailwind CLI 、PostCSS、Play CDN 等使用方式;下面主要讲下如何基于 Tailwind CLI 方式,在应用开发中使用 Tailwind CSS:
Tailwind CSS 可为快应用开发带来哪些好处?
Tailwind CSS 是一种现代的 CSS 框架,它提供了一组预定义的 CSS 类,用于快速开发现代 Web 应用程序。Tailwind 的核心理念是为开发者提供一种灵活的方法来构建自定义的 UI 组件,而不需要编写大量的 CSS 代码。
Tailwind CSS 的工作原理是扫描所有 HTML 文件、JavaScript 组件和任何其他模板的类名,生成相应的样式,然后将它们写入静态 CSS 文件。它快速、灵活、可靠,且运行时间为零。
在快应用开发中引入,可以为项目带来四方面的好处:更快的编写效率、更小的代码总体积、更高的运行效率、更易于项目维护。更详细说明如下:
- 预定义的 CSS 类可以减少样式的冗余,从而减小 CSS 文件的体积。
- 大量配套设施,可以提高开发效率,不必手动编写大量的 CSS 代码。
- 提供了自动优化工具,可以删除未使用的 CSS 代码。
- 不用耗时去为 CSS class 取语义化类名,不再需要关注 style 标签;
- 代码体积减小,可以减少下载、加载、解析等步骤耗时。
- 使 CSS 样式更规范化,避免冗余的样式和复杂的选择器,优化运行性能。
- Tailwind CSS 拥有活跃的社区和文档,可以帮助开发者快速上手和解决问题。
如何在项目中使用 Tailwind CSS?
安装 Tailwind CSS 依赖
通过 npm 安装 tailwindcss
并创建 tailwind.config.js
文件,具体命令如下:
pnpm install -D tailwindcss
# OR
# npm install -D tailwindcss
npx tailwindcss init
配置您的模板路径
在文件中添加所有模板文件的路径 tailwind.config.js
,参考性配置如下:
const colors = require('tailwindcss/colors')
const selfCustomColors = {
brand: {
DEFAULT: '#1e293b',
},
warn: {
DEFAULT: '#f59e0b',
},
link: {
DEFAULT: '#0ea5e9',
},
mark: {
DEFAULT: '#ff4582',
},
}
module.exports = {
mode: 'jit',
content: [
'./src/**/*.{ux,html,js,svelte,vue,ts}',
'./node_modules/flowbite/**/*.js',
],
purge: {
enabled: true,
content: [
'./src/**/*.{ux,html,js,svelte,vue,ts}',
'./node_modules/flowbite/**/*.js',
],
},
// https://tailwindcss.com/docs/configuration#core-plugins
corePlugins: {
preflight: false, // disable base/reset styles
container: false, // disable container component
content: false, // disable `content` utility
accentColor: false, // disable `accent-color` utility
accessibility: false, // disable `appearance` utility
appearance: false, // disable `appearance` utility
aspectRatio: false, // disable `aspect-ratio` utility
backgroundOpacity: false, // disable `background-opacity` utility
backdropBlur: false, // disable `backdrop-blur` utility
backdropBrightness: false, // disable `backdrop-brightness` utility
backdropContrast: false, // disable `backdrop-contrast` utility
backdropGrayscale: false, // disable `backdrop-grayscale` utility
backdropHueRotate: false, // disable `backdrop-hue-rotate` utility
backdropInvert: false, // disable `backdrop-invert` utility
backdropOpacity: false, // disable `backdrop-opacity` utility
backdropSaturate: false, // disable `backdrop-saturate` utility
backdropSepia: false, // disable `backdrop-sepia` utility
blur: false, // disable `blur` utility
borderCollapse: false, // disable `border-collapse` utility
borderOpacity: false, // disable `border-opacity` utility
borderSpacing: false, // disable `border-spacing` utility
boxShadow: false, // disable `box-shadow` utility
boxShadowColor: false, // disable `box-shadow-color` utility
boxDecorationBreak: false, // disable `box-decoration-break` utility
boxSizing: false, // disable `box-sizing` utility
breakAfter: false, // disable `break-after` utility
breakBefore: false, // disable `break-before` utility
breakInside: false, // disable `break-inside` utility
brightness: false, // disable `brightness` utility
captionSide: false, // disable `caption-side` utility
caretColor: false, // disable `caret-color` utility
clear: false, // disable `clear` utility
contrast: false, // disable `contrast` utility
divideColor: false, // disable `divide-color` utility
divideOpacity: false, // disable `divide-opacity` utility
divideStyle: false, // disable `divide-style` utility
divideWidth: false, // disable `divide-width` utility
float: false, // disable `float` utility
fontVariantNumeric: false, // disable `font-variant-numeric` utility
hyphens: false, // disable `hyphens` utility
isolation: false, // disable `isolation` utility
lineClamp: false, // disable `line-clamp` utility
mixBlendMode: false, // diable `mix-blend-mode` utility
listStyleImage: false, // disable `list-style-image` utility
listStylePosition: false, // disable `list-style-position` utility
listStyleType: false, // disable `list-style-type` utility
objectPosition: false, // disable `object-position` utility
opacity: false, // disable `opacity` utility
outlineColor: false, // disable `outline-color` utility
outlineOffset: false, // disable `outline-offset` utility
outlineStyle: false, // disable `outline-style` utility
outlineWidth: false, // disable `outline-width` utility
overscrollBehavior: false, // disable `overscroll-behavior` utility
placeContent: false, // disable `place-content` utility
placeItems: false, // disable `place-items` utility
placeSelf: false, // disable `place-self` utility
placeholderOpacity: false, // disable `placeholder-opacity` utility
resize: false, // disable `resize` utility
ringColor: false, // disable `ring-color` utility
ringOffsetColor: false, // disable `ring-offset-color` utility
ringOffsetWidth: false, // disable `ring-offset-width` utility
ringOpacity: false, // disable `ring-opacity` utility
space: false, // disable `space-between` utility
textDecorationThickness: false, // disable `text-decoration-thickness` utility
textOpacity: false, // disable `text-opacity` utility
textTransform: false, // disable `text-transform` utility
textUnderlineOffset: false, // disable `text-underline-offset` utility
touchAction: false, // disable `touch-action` utility
userSelect: false, // disable `user-select` utility
verticalAlign: false, // disable `vertical-align` utility
whitespace: false, // disable `whitespace` utility
wordBreak: false, // disable `word-break` utility
willChange: false, // disable `will-change` utility
},
darkMode: false,
theme: {
colors: { ...colors, ...selfCustomColors },
extend: {
width: ({ theme }) => ({
auto: 'auto',
...theme('spacing'),
}),
height: ({ theme }) => ({
auto: 'auto',
...theme('spacing'),
}),
spacing: {
'1/2': '2px',
'1': '4px',
'3/2': '6px',
'2': '8px',
'5/2': '10px',
'3': '12px',
'7/2': '14px',
'4': '16px',
'5': '20px',
'6': '24px',
'7': '28px',
'8': '32px',
'9': '36px',
'10': '40px',
'11': '44px',
'12': '48px',
'14': '56px',
'16': '64px',
'20': '80px',
'24': '96px',
'28': '112px',
'32': '128px',
'36': '144px',
'40': '160px',
'44': '176px',
'48': '192px',
'52': '208px',
'56': '224px',
'60': '240px',
'72': '288px',
'80': '320px',
'96': '384px',
},
borderWidth: {
'DEFAULT': '1px',
'0': '0px',
'2': '2px',
'4': '4px',
'8': '8px',
},
borderRadius: {
'none': '0',
'': '1px',
'sm': '2px',
'DEFAULT': '4px',
'md': '6px',
'lg': '8px',
'xl': '12px',
'2xl': '16px',
'3xl': '24px',
},
fontSize: {
'xm': ['12px', { lineHeight: '16px' }],
'sm': ['14px', { lineHeight: '20px' }],
'base': ['16px', { lineHeight: '24px' }],
'lg': ['18px', { lineHeight: '28px' }],
'xl': ['20px', { lineHeight: '28px' }],
'2xl': ['24px', { lineHeight: '32px' }],
'3xl': ['30px', { lineHeight: '36px' }],
'4xl': ['36px', { lineHeight: '40px' }],
'5xl': ['48px', { lineHeight: '60px' }],
'6xl': ['60px', { lineHeight: '60px' }],
'7xl': ['72px', { lineHeight: '60px' }],
'8xl': ['96px', { lineHeight: '60px' }],
'9xl': ['128px', { lineHeight: '60px' }],
}
},
},
variants: {
extend: {},
},
plugins: [],
}
将 Tailwind 指令添加到您的 CSS 中
@tailwind
将 Tailwind 每个层的指令添加到您的主 CSS 文件中。
/* input.css */
/* @tailwind base; */
@tailwind components;
@tailwind utilities;
启动 Tailwind CLI 构建过程
运行 CLI 工具来扫描模板文件中的类并构建 CSS,参考性命令如下:
npx tailwindcss -i ./src/input.css -o ./src/output.css --watch
这是看起来路径简短的方式,实际上这个 input.css
和 output.css
,无论是名字,或是它存在的路径,皆可以自行指定,您可以按照自己喜欢的方式、或是团队约定俗成的形式;譬如统一存放在:src/assets/styles
目录下。
需要补充说明的是:在团队开发中,输入上述命令,略显繁琐,可以在 package.json
注入命令(如下示例);如此以下,您只需在「终端」运行 pnpm tailwindcss
或 npm run tailwindcss
命令即可。
"scripts": {
"tailwindcss": "npx tailwindcss -i ./src/input.css -o ./src/output.css --watch",
}
开始在 UX 中使用 Tailwind CSS
将已编译的 CSS 文件,在 .ux
(非 app.ux
)文件中,通过 @import
方式引入;
<style>
@import './../../output.css';
</style>
现在,即可在 .ux
的 template
中,开始使用 Tailwind 的实用程序类来设置内容的样式,如下面这段代码示例:
<template>
<div class="bg-blue-300 w-full flex flex-col justify-center items-center">
<text class="text-red-600">TailwindCSS Area</text>
<text class="text-red-600">Awesome TailwindCSS</text>
</div>
</template>
当您写完保存之后,打开 output.css
即可如下的 CSS 代码:
/* @tailwind base; */
.flex {
display: flex
}
.w-full {
width: 100%
}
.flex-col {
flex-direction: column
}
.items-center {
align-items: center
}
.justify-center {
justify-content: center
}
.bg-blue-300 {
background-color: #93c5fd
}
.text-red-600 {
color: #dc2626
}
至此,在 快应用 开发中引入 Tailwind CSS 的准备工作,已经初步完成,您可以与 Tailwind CSS
开启愉快合作之旅,从而促使高效编码、提前完工。假如,您对 Tailwind CSS
尚不熟悉,可通过查阅 Tailwind CSS Doc ,亦可在线体验—— Tailwind Playground 。
需要补充说明的是,使用 Tailwind CSS
并不破坏您原来的 CSS 书写✍🏻方式;您完全可以结合喜欢的预处理器(如 Sass、Less、Stylus),来共同工作,而无需做更多设置(如下代码示例);但我以为当您熟悉 Tailwind CSS 之后,大有可能也会“移情而别恋”。
<style lang="scss">
@import './../../assets/styles/style.scss';
@import './../../assets/styles/output.css';
.primary-btn {
width: 90 * $size-factor;
height: 16 * $size-factor;
background-color: $brand;
border-radius: 8 * $size-factor;
color: $white;
}
</style>
如何基于 Tailwind CSS 提升开发效率?
安装 Tailwind CSS IntelliSense 扩展
您可以在应用开发工具的「扩展市场」,通过关键字 Tailwind
检索”Tailwind CSS IntelliSense“扩展——适用于 Visual Studio Code 的智能 Tailwind CSS 工具,用户提供自动完成、语法突出显示和 linting 等高级功能来增强 Tailwind 开发体验;略作适配即可支持 *.ux
;详细设置,可参见: Tailwind CSS IntelliSense 。
默认情况下,编辑“字符串”内容时(例如在 JSX 属性值中),开发工具中不会触发完成。更新设置 editor.quickSuggestions
可能会改善您的体验:
"editor.quickSuggestions": {
"strings": "on"
}
参考基于 Tailwind CSS 组件的开源库
Tailwind CSS 生态发展繁荣超乎想象,就连其衍生产品也不可胜数;如 Flowbite ——包含 600 多个 UI 组件、部分和页面的开源库进行开发,该库使用 Tailwind CSS 的实用程序类构建并在 Figma 中设计。它不仅能充当 Tailwind CSS 插件使用,也可以拷贝到项目直接使用,还可以在线查阅效果(支持多种屏幕设备类型),挑选匹配实现方案;在仍是基于组件树构建页面的时代,极大提升页面搭建效率。如: pagination 组件:
常见问题及说明
如果您熟悉 Web 开发,针对上述教程,您可能会有诸多疑惑;实际上,笔者在实践之时,也有发现,只不过因为各种机制限制,目前只能如此。下面就与诸君分享,期可解惑:
不能在 script
标签中,引入输出 CSS 文件么**?
按 Web 开发习惯,在 app.ux
文件中可以直接 import
输出 CSS 文件(如下代码所示),那为何未建议如此呢?
<script>
import './output.css'
</script>
因为这样做会报如下错误;具体是缺乏与之匹配的 loader;当然,可以使用 css-loader
和 style-loader
来处理 CSS 文件,详见 ChatGPT | You may need an appropriate loader.... 。
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| /* @tailwind base; */
但在快应用开发过程中,却不能生效;因为 style-loader 的作用是将 CSS 注入 DOM,其中用到了诸多浏览器 API(document),而快应用的开发虽然是基于前端技术栈,但其运行环境止于 v8
,实际的渲染是由 Android 底层完成,并未走浏览器这条路,因此无法工作。在构建工具优化、兼容之前,通过 style
标签中引入 CSS,成了主要选择。
为何在 tailwind.config.js
禁用如此多样式?
Tailwind corePlugins 部分允许您完全禁用 Tailwind 通常默认生成的类(如果您的项目不需要它们);这个设计对于快应用实在必要的紧,在上述示例中,对 text-opacity
等样式进行禁用,也是无奈之举。具体原因在于以下两点:
其一:快应用标准虽然基于 Web 技术栈,但只是 Web 标准子集,如蛮多 CSS 属性并不能很好的支持;其二:默认情况下,TailwindCSS 会将样式属性的值存储为 CSS 变量(例如 --tw-text-opacity
),以便进行动态计算和响应式设计。
如此一来,在 template 中使用类 text-red-300
、border-spacing-1
,输出的便是如下 CSS;这样的写法,在快应用中并不能得到正确解析,也就无法起到期待效果,于是禁用便成了必须要做之事。当然,这样禁用也好处:利于输出更小提及的 CSS 文件。其他属性亦复如是。
.text-red-300 {
--tw-text-opacity: 1;
color: rgb(252 165 165 / var(--tw-text-opacity))
}
.border-spacing-1 {
--tw-border-spacing-x: 4px;
--tw-border-spacing-y: 4px;
border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y)
}
为何要在 input.css
中移除 @tailwind base;
?
这么做主要未解决问题: How disable default styles for : before and : after 。
/* input.css */
/* @tailwind base; */
@tailwind components;
@tailwind utilities;
在一般 Web 开发过程中,会将 base、components、utilities 等指令,都添加到 CSS 文件项目中;但,在快应用开发过程中,这无疑是累赘;因为它的存在,会使得 output.css
输出较多对项目没有裨益额外内容(如下代码所示),故而移除;这与通过 corePlugins 禁用基础样式(preflight)、禁用容器组件(container)作用类似。
*, ::before, ::after {
--tw-border-spacing-x: 0;
......
}
::backdrop {
--tw-border-spacing-x: 0;
......
}
为什么要在配置中通过 theme
自定义长度单位?
修改长度单位从 rem
到 px
,这也是不得已而为之。 快应用 标准对 长度单位 的支持,在 1070 及以下版本仅支持长度单位 px
和 %
。从 1080
版本开始,新增了长度单位 dp
。它无法支持 rem
,就只能自定义设置为 px
;在通过 theme
自定义长度单位,是 Tailwind CSS 官方提供的功能,以此能够实现更精细的样式控制;虽然操作不难,但属性较多、约定繁杂。后续时间如果允许,将探索 rem to px
批量转换插件来实现,以达到快速修改。如果您感兴趣,可以查阅 Tailwind CSS 完整版本配置—— config.full.js 。
其他暂未解决问题
- 少部分类名写法,快应用构建不支持
在 Tailwind CSS 机制中,支持使用类名诸如 h-[100px] w-1/3
(对应生成 CSS 如下),然而,在快应用构建工具暂不支持这类名,于是乎这样写便不会生效,当然也不会造成什么问题;后续亟待打包工具优化。
.h-\[100px\] {
height: 100px
}
.w-1\/3 {
width: 33.333333%
}
在打包(Toolkit)未解决该问题之前,您可以手动写一个 class
,或者使用内联样式(style
)来兼容;在这种情况下,更推荐后者;因为引入 Tailwind CSS 的开发模式中,基本不用手写 class,即无需滚动到 style
标签或跳转 less、(s)css、文件,那么直接在 template
中使用内联更为便捷。
<div class="training-list-width" style="width: 326px;"></div>
<style>
.training-list-width {
width: 326px;
}
</style>
- 快应用构建,资源存在重复引用问题
前文中提到,在 script
标签中 import
CSS 资源,暂时未得到支持;但,在 style
标签中 @import
的 CSS 文件,被 A、B 两个页面(*.ux
)引入,那么对应的 css 内容,就会被打入对应页面(即便有的内容没有被使用),从而导致代码体积略有增加(即便参考 如何优化「快应用」rpk 包体积? 一文中的方法,也不可避免)。这是快应用构建本身存在的问题,使用 Tailwind CSS 也不例外。后续需要打包工具优化。
以上,就是在 快应用
开发过程中,引入 Tailwind CSS 所需的操作、以及常见问题说明。肯定还有异常更多情况没有考虑到,后续会逐步补充;如果您在实际运用过程中,欢请留言交流、反馈、分享。
2023 年 07 月 05 日写于〔深圳福田〕