标签

Tailwind CSS

Tailwind CSS 是一个非常强大且受欢迎的实用型 CSS 框架,于2017年由.Adam Wathan、Jonathan Reinink、David Hemphill 和 Steve Schoger 共同创立。 这个框架的主要目标是帮助开发者快速构建定制化的用户界面,而无需从头开始编写 CSS 代码。 Tailwind 提供了一整套预先定义好的类名,代表 CSS 的各种属性,如颜色、字体大小、间距等。这些实用类能支持你快速完成布局,同时保持简洁无冗余代码。 通过采用响应式类,Tailwind 可以帮助你无缝地构建适应各种屏幕尺寸的应用程序。 使用Tailwind 的高度可配置性,你可以根据项目需求定制自己的设计系统。举例来说,你可以轻松地添加、编辑或删除颜色、字体等相关设置。 Tailwind 采用PostCSS 插件系统,将实用类生成的 CSS 打包压缩为最小,可优化加载速度。 Tailwind 提供了一整套官方插件,如动画库、表单控件等。此外,开发社区也贡献了大量非官方插件和资源,让开发者能够选择更加丰富的功能。 Tailwind CSS 广泛应用于以下场景: - 前端项目:无论是使用纯 HTML 结构还是结合 JavaScript 框架(例如:React、Vue 和 Angular),Tailwind 都能实现高度定制化的用户界面。 - Web 应用程序: 开发具有复杂交互和列表式布局的应用界面。 - 电子邮件: 利用 "tailwindcss-inline" 工具,可以为 HTML 邮件模板生成内联样式。 - 营销页面: 使用 Tailwind 创建具有吸引力的营销页面和布局,可轻松快速地进行样式调整。 - 开发原型:快速搭建原型,并便捷地进行迭代。 如此多的优点和特性使得Tailwind CSS变得越来越受欢迎,是一个非常值得学习和尝试的框架。

Tailwind CSS
查看更多相关内容
服务端6月21日 01:58
Tailwind CSS 是什么?它和传统 CSS 框架有什么区别?如果你第一次看到 Tailwind CSS 写出来的 HTML,大概率会愣一下:一个按钮上怎么塞了这么多 class? ```html <button class="rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700">保存</button> ``` 这就是 Tailwind CSS 的核心思路:不先写一个 `.btn-primary`,而是直接用一组小颗粒度的工具类把样式拼出来。它不是 Bootstrap 那种“拿来就有按钮、卡片、导航栏”的组件框架,而是一套 utility-first CSS 工具箱。 ## Tailwind CSS 是什么? Tailwind CSS 是一个实用优先(utility-first)的 CSS 框架。它提供大量原子化 class,比如 `p-4`、`flex`、`text-sm`、`bg-blue-600`、`rounded-lg`,每个 class 通常只负责一件很小的事。 传统写法通常是这样: ```css .card-title { font-size: 20px; font-weight: 700; margin-bottom: 12px; } ``` Tailwind 写法更像这样: ```html <h2 class="mb-3 text-xl font-bold">标题</h2> ``` 你不需要先想 `.card-title`、`.main-title`、`.title-large` 哪个名字更合适,直接把字号、间距、字重写在元素上。 ## utility-first 到底是什么意思? utility-first 不是“不要 CSS”,而是优先使用工具类完成大多数样式。一个卡片可以这样写: ```html <div class="rounded-xl border border-gray-200 bg-white p-6 shadow-sm"> <h3 class="text-lg font-semibold text-gray-900">Tailwind CSS</h3> <p class="mt-2 text-sm leading-6 text-gray-600">用工具类组合界面,而不是套用预制组件。</p> </div> ``` 每个 class 都很直白,看到 `mt-4` 就知道是上边距,看到 `text-gray-600` 就知道是灰色文字,不用再去找某个 class 背后到底写了什么 CSS。 ## Tailwind CSS 是怎么工作的? Tailwind 会扫描你的 HTML、JS、TS、Vue、React 组件等文件,找到实际用到的 class,然后生成对应 CSS。Tailwind v3 默认使用 JIT;Tailwind v4 则换成新的编译引擎,安装和配置更轻。 v4 配合 Vite 可以这样安装: ```bash npm install tailwindcss @tailwindcss/vite ``` ```ts import { defineConfig } from 'vite' import tailwindcss from '@tailwindcss/vite' export default defineConfig({ plugins: [tailwindcss()] }) ``` 主 CSS 中引入: ```css @import "tailwindcss"; ``` v3 的经典方式则是 `npx tailwindcss init`,配置 `content`,再在 CSS 里写 `@tailwind base; @tailwind components; @tailwind utilities;`。 ## 常用 Tailwind 类名有哪些? 间距:`m-4`、`p-6`、`mt-8`、`gap-4`。颜色:`bg-blue-600`、`text-white`、`text-gray-700`。布局:`flex`、`items-center`、`justify-between`、`grid`、`grid-cols-3`。尺寸和边框:`w-full`、`max-w-3xl`、`rounded-lg`、`border`、`shadow-md`。 响应式写法是在类名前加断点前缀: ```html <div class="w-full md:w-1/2 lg:w-1/3"></div> ``` 状态样式也用前缀: ```html <button class="bg-blue-600 hover:bg-blue-700 focus:ring-2 active:bg-blue-800">提交</button> ``` 深色模式常见写法是 `dark:`: ```html <div class="bg-white text-gray-900 dark:bg-gray-900 dark:text-gray-100">内容</div> ``` ## Tailwind CSS 和 Bootstrap 有什么区别? | 对比项 | Tailwind CSS | Bootstrap / 传统 CSS 框架 | |---|---|---| | 核心思路 | 提供工具类,自己组合界面 | 提供预制组件和样式规范 | | 按钮、卡片、导航 | 默认不提供完整组件 | 默认提供现成组件 | | 设计自由度 | 高,不容易撞脸 | 中,默认样式辨识度强 | | 上手速度 | 需要熟悉类名体系 | 复制组件即可用 | | 定制成本 | 适合做自有设计系统 | 深度改样式时容易覆盖 CSS | | 适合项目 | 产品后台、SaaS、设计定制强的前端项目 | 快速原型、内部工具、样式要求不高的页面 | 如果想快速搭一个“能用就行”的后台页面,Bootstrap 很省事。如果有自己的视觉规范,或者不想让页面长得像默认模板,Tailwind 更灵活。 ## Tailwind 什么时候值得用? Tailwind 适合组件化框架项目、定制视觉强的产品、页面迭代快的团队,以及想用一套设计令牌约束颜色、字体、圆角、间距的项目。 它不太适合只写一两个静态页面、团队完全不熟悉工具类写法、已有成熟 CSS 体系且迁移收益不明显的项目。Tailwind 本身不是组件库,如果需要完整组件,可以搭配 Headless UI、Radix UI、shadcn/ui 等方案。 ## Tailwind 的缺点和最佳实践 Tailwind 最大的争议是 class 太长。解决办法是把重复 UI 抽成组件,而不是到处复制同一串 class。`@apply` 可以少量使用,但如果大量用它把工具类提取回 CSS,最后会变成“用 Tailwind 重新写了一套传统 CSS”。 还要避免过度动态拼接 class: ```js const className = `text-${color}-600` ``` Tailwind 的扫描依赖可识别的类名,更稳的方式是把可能值列出来: ```js const colorMap = { success: 'text-green-600', danger: 'text-red-600' } ``` Tailwind CSS 的价值,是用一套统一的工具类和设计 token 快速搭界面。它和 Bootstrap 最大的区别是:Bootstrap 偏“拿组件来用”,Tailwind 偏“拿工具类来搭”。如果团队能接受 class 较长的写法,并愿意把重复 UI 抽成组件,Tailwind 会让日常改样式变得很快。
服务端6月21日 01:58
tailwind.config.js 常用配置项有哪些?v3/v4 怎么选?在 Tailwind CSS v3 项目里,`tailwind.config.js` 通常用来控制三件事:扫描哪些源码、设计系统怎么定义、哪些框架行为需要调整。常见配置项包括 `content`、`theme`、`extend`、`plugins`、`presets`、`darkMode`、`corePlugins`、`important`、`prefix`、`separator` 和 `safelist`。 到了 Tailwind CSS v4,官方更推荐 CSS-first 配置,很多主题值、扫描路径和工具类扩展会写在 CSS 里,例如 `@theme`、`@source`、`@utility`。但旧项目迁移、共享预设、沿用已有配置时仍然可以用它,只是 v4 不会像 v3 那样自动检测配置文件,需要在 CSS 里显式引入: ```css @import "tailwindcss"; @config "../tailwind.config.js"; ``` ## 一个常见的 tailwind.config.js 长什么样? ```javascript module.exports = { content: ['./index.html', './src/**/*.{js,ts,jsx,tsx,vue,html}'], darkMode: 'class', theme: { extend: { colors: { brand: { DEFAULT: '#2563eb', dark: '#1d4ed8' } }, spacing: { 18: '4.5rem', 128: '32rem' }, fontFamily: { sans: ['Inter', 'system-ui', 'sans-serif'] }, }, }, plugins: [require('@tailwindcss/forms'), require('@tailwindcss/typography')], presets: [], corePlugins: { preflight: true }, important: false, prefix: '', separator: ':', safelist: ['prose', 'bg-red-500'], } ``` 不是每个项目都应该把这些配置全写上。默认值够用就别动,只有团队设计规范、第三方组件冲突或动态类名确实需要时,再加对应配置。 ## content:告诉 Tailwind 扫描哪些文件 `content` 决定 Tailwind 会从哪些文件里提取 class 名。动态拼接类名通常识别不到: ```jsx // 不推荐 <div className={`bg-${color}-500`} /> // 推荐 const colorMap = { red: 'bg-red-500 text-white', blue: 'bg-blue-500 text-white' } <div className={colorMap[color]} /> ``` 在 Tailwind CSS v4 里,遇到 monorepo、外部 UI 包、被默认忽略的目录时,通常改用 CSS 里的 `@source`: ```css @import "tailwindcss"; @source "../packages/ui"; ``` ## theme 和 extend 有什么区别? `theme` 负责颜色、字体、间距、断点、阴影、圆角等设计 token。直接写 `theme.colors`、`theme.spacing` 通常是在覆盖默认主题。也就是说,Tailwind 原来的 `red-500`、`blue-500`、`gray-100` 可能会没了。 `extend` 的作用是保留 Tailwind 默认设计系统,再追加自己的值: ```javascript module.exports = { theme: { extend: { colors: { brand: '#2563eb' }, spacing: { 18: '4.5rem' }, }, }, } ``` 多数项目优先用 `extend`。除非公司有一套完全独立的设计系统,并明确不想使用 Tailwind 默认色板,否则不要轻易覆盖默认主题。 ## plugins、presets、darkMode 怎么用? 官方常用插件包括 `@tailwindcss/forms`、`@tailwindcss/typography`、`@tailwindcss/aspect-ratio`。多项目共享一套 Tailwind 基础配置时,可以用 `presets`: ```javascript module.exports = { presets: [require('@acme/tailwind-preset')], theme: { extend: { colors: { brand: '#2563eb' } } }, } ``` v3 里 `darkMode: 'media'` 适合跟随系统,`darkMode: 'class'` 适合手动切换。v4 里暗色模式更多会配合 CSS 变体写法处理,不要机械照搬 v3 配置。 ## corePlugins、important、prefix、separator、safelist 什么时候用? `corePlugins` 可以关闭内置能力,最常见是关闭 `preflight`,但要慎用。`important: true` 会让生成的工具类都带上 `!important`,通常只在和旧 CSS、第三方组件库冲突时考虑;更温和的是 `important: '#app'`。`prefix` 适合微前端、组件库或老项目避免类名冲突,但会增加心智负担。 `safelist` 用来强制生成某些类,适合类名来自 CMS、数据库、接口返回值等扫描不到的场景。正则不要写太宽,否则会生成大量无用 CSS。v4 里更推荐用 CSS 的 `@source inline()` 表达这类保留类。 ## full config 和实际取舍 `npx tailwindcss init --full` 适合查看默认主题,不适合把完整配置复制进项目长期维护。完整配置太大,真正的业务改动很难找,升级 Tailwind 时也不容易同步默认值。 小到中型项目通常只需要 `content`、`theme.extend`、`plugins`、`darkMode`。组件库、后台系统、微前端或多项目共享配置时,再考虑 `presets`、`prefix`、`important`、`safelist`。最值得记住的是:`content` 决定类名能不能生成,`theme.extend` 决定设计系统怎么扩展,`plugins` 决定 Tailwind 能力怎么补充。
服务端6月21日 01:55
Tailwind CSS 响应式断点怎么用?常用类有哪些?Tailwind CSS 做响应式设计,核心不是写很多媒体查询,而是在工具类前面加断点前缀。无前缀的类先作为移动端默认样式,`md:`、`lg:` 这类前缀再从指定宽度开始覆盖它。 一句话记法:**默认写手机样式,屏幕变大后再逐步加前缀调整布局、字号、间距、显示隐藏和宽度。** ## Tailwind CSS 默认断点有哪些? Tailwind CSS 默认断点是移动优先的 `min-width` 断点:`sm` 640px,`md` 768px,`lg` 1024px,`xl` 1280px,`2xl` 1536px。 ```html <div class="text-sm md:text-base lg:text-lg">Tailwind 响应式文本</div> ``` 这段代码的含义是:默认 `text-sm`,当视口宽度达到 `768px` 后变成 `text-base`,达到 `1024px` 后变成 `text-lg`。 ## 断点前缀到底怎么生效? Tailwind 的响应式前缀默认是“从这个断点开始,一直向更大的屏幕生效”。 ```html <div class="w-full md:w-1/2 lg:w-1/3">响应式宽度</div> ``` 小于 768px 是 `w-full`,768px 到 1023px 是 `md:w-1/2`,1024px 及以上是 `lg:w-1/3`。`md:w-1/2` 不是只在平板生效,而是从 md 开始生效。 ## 常用响应式类怎么写? 移动端和桌面端切换导航时最常用: ```html <button class="block md:hidden">菜单</button> <nav class="hidden md:flex">桌面导航</nav> ``` 移动端常用纵向堆叠,桌面端改成横向: ```html <section class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between"> <div>标题区域</div> <div>操作按钮</div> </section> ``` 列表页、商品卡片、文章卡片通常这样写: ```html <div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"> <article class="rounded-lg border p-4">Card</article> </div> ``` 卡片宽度不固定时,也可以用: ```html <div class="grid grid-cols-[repeat(auto-fit,minmax(240px,1fr))] gap-4"> <article class="rounded-lg border p-4">Card</article> </div> ``` 标题、正文、间距、宽度也都可以响应式调整: ```html <h2 class="text-2xl font-semibold leading-tight md:text-4xl lg:text-5xl">Responsive Design</h2> <p class="text-sm leading-6 md:text-base md:leading-7">正文内容</p> <main class="mx-auto w-full max-w-7xl px-4 md:px-6 lg:px-8">页面内容</main> ``` ## max-*、范围断点和容器查询 `max-*` 适合低于某个断点时生效: ```html <div class="max-md:hidden">只在 md 以下隐藏</div> ``` 只在某个区间生效: ```html <div class="hidden md:max-lg:block">只在 md 到 lg 之间显示</div> ``` 如果默认断点不够,可以自定义 screens。v3 在 `tailwind.config.js` 里配置,v4 更推荐在 CSS 主题变量里定义: ```css @import "tailwindcss"; @theme { --breakpoint-xs: 30rem; --breakpoint-3xl: 120rem; } ``` 容器查询看的是父容器宽度,不是浏览器视口宽度,适合可复用卡片、侧边栏模块和 Dashboard 小组件: ```html <div class="@container"> <article class="p-4 @md:flex @md:items-center @md:gap-6"> <img class="w-full @md:w-48" src="/cover.jpg" alt="" /> <div> <h2 class="text-lg @md:text-xl">文章标题</h2> <p class="text-sm text-gray-600">摘要内容</p> </div> </article> </div> ``` 页面大框架用屏幕断点,组件内部适配用容器查询,通常更稳。 ## 常见坑和检查顺序 `md:block` 会从 768px 一直生效到更大的屏幕,不是只在平板显示。如果只想在 `md` 到 `lg` 之间显示,要写 `hidden md:max-lg:block`。 不要忘了写默认样式:`md:grid md:grid-cols-2` 在移动端没有明确布局,通常不如 `grid grid-cols-1 md:grid-cols-2` 清楚。 显示隐藏类别叠太多层,否则后面维护的人很容易误判。测试时要看真实内容:长标题、长按钮文案、空数据、图片缺失、横竖屏、浏览器缩放和系统字号。 快速检查一段响应式代码,可以先看无前缀类,再看 `sm:`、`md:`、`lg:` 是否从小到大覆盖;检查 `hidden`、`block`、`flex` 有没有互相打架;检查 `grid-cols-*`、`w-*`、`max-w-*` 是否会造成横向滚动;如果组件会放在不同容器里,考虑用容器查询而不是继续加屏幕断点。
服务端6月21日 01:55
Tailwind CSS 深色模式怎么实现,常用 dark 类有哪些?Tailwind CSS 做深色模式,核心不是写两套 CSS,而是选好触发方式,然后在需要变化的地方加 `dark:` 变体。常见写法大概分两类:跟随系统的 `media`,以及由页面上的 `.dark` 或自定义选择器控制的 `class/selector`。前者省事,后者更适合带主题切换按钮的产品。 ## 先选深色模式触发方式 `media` 使用浏览器的 `prefers-color-scheme`,用户系统是深色,页面就走深色样式。 ```js export default { darkMode: 'media' } ``` 适合页面不需要主题切换按钮、希望完全尊重系统设置的情况。缺点是用户不能在站内单独选择浅色或深色。 如果需要按钮切换,推荐用选择器控制。旧项目里常见 `class`,新一点的 Tailwind v3.4+ 更推荐 `selector`。 ```js export default { darkMode: 'selector' } ``` 页面上加: ```html <html class="dark"> ``` Tailwind v4 更偏 CSS-first。如果要用 `.dark` 或 `data-theme` 控制,可以在 CSS 里自定义变体: ```css @import 'tailwindcss'; @custom-variant dark (&:where(.dark, .dark *)); ``` 或者: ```css @custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *)); ``` ## 常用 dark: 类怎么写 Tailwind 的深色模式不是单独的一套类,而是在原有工具类前面加 `dark:`。 ```html <div class="rounded-xl border border-slate-200 bg-white p-6 text-slate-900 shadow-sm dark:border-slate-800 dark:bg-slate-950 dark:text-slate-100 dark:shadow-slate-950/40"> <h2 class="text-lg font-semibold text-slate-900 dark:text-white">账户设置</h2> <p class="mt-2 text-sm text-slate-600 dark:text-slate-400">这里会跟随当前主题切换颜色。</p> </div> ``` 项目里最常用的是背景、文字、边框、阴影、hover、表单占位文字、分割线和 focus ring: ```html <input class="border-slate-300 bg-white text-slate-900 placeholder:text-slate-400 focus:ring-blue-500 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100 dark:placeholder:text-slate-500 dark:focus:ring-blue-400" /> ``` 实际写组件时,不要所有颜色都硬编码成黑白。深色模式最舒服的搭配通常是深灰背景、浅灰文字、略低对比的边框。 ## 用 JS 和 localStorage 保存用户选择 手动切换时,至少要处理三种状态:浅色、深色、跟随系统。 ```js function applyTheme(theme) { const root = document.documentElement const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches const shouldUseDark = theme === 'dark' || (!theme && systemDark) root.classList.toggle('dark', shouldUseDark) } const savedTheme = localStorage.getItem('theme') applyTheme(savedTheme) function setTheme(theme) { if (theme) localStorage.setItem('theme', theme) else localStorage.removeItem('theme') applyTheme(theme) } ``` 如果用 `data-theme`,把 `classList.toggle('dark')` 换成设置属性即可。 ## React / Vue 接入和避免闪烁 React 或 Vue 的切换按钮可以放在组件里,但首次应用主题最好用一段很短的内联脚本提前做。否则页面会先按亮色渲染,JavaScript 加载后再切深色,产生 FOUC 闪烁。 ```html <script> try { const theme = localStorage.getItem('theme') const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches if (theme === 'dark' || (!theme && systemDark)) { document.documentElement.classList.add('dark') } } catch (e) {} </script> ``` SSR 框架里还要注意服务端无法直接读取 `localStorage`。可以用 cookie 保存主题,或者接受首次渲染由内联脚本修正。 ## 对比度和检查清单 深色模式不是把颜色反过来。正文建议至少满足 WCAG 常规文本 4.5:1 的对比度。按钮 hover、focus ring、错误提示、禁用态、图标、表格边框都要单独看。 实现前可以按这个清单过一遍:确认策略,确认 Tailwind 版本,根节点统一用 `.dark` 或 `data-theme`,常用类补齐,保存用户选择,提前执行脚本避免闪烁,测试对比度,测试系统主题变化。 Tailwind 的深色模式写起来不难,难的是别漏状态。触发方式选对,组件里坚持用 `dark:` 写差异,再把本地存储、FOUC 和对比度检查补上,这套方案就能稳定用在真实项目里。
服务端6月20日 22:04
Tailwind CSS Flexbox 布局类怎么用?常见 Flex 布局如何写?Tailwind CSS 里做 Flexbox 布局,核心就是把 CSS 的 `display: flex`、`flex-direction`、`justify-content`、`align-items`、`flex-wrap`、`flex-grow` 等属性换成原子类。它适合做一维布局:一行导航、一列菜单、左右内容区、按钮组、卡片内部对齐都很顺手。 如果页面要同时控制行和列,比如完整商品列表、后台仪表盘、复杂二维卡片墙,通常 Grid 更省心;如果只是沿着一个方向排列元素,Flex 更直接。 ## 启用 Flex:flex 和 inline-flex 有什么区别? 最常用的两个入口类是:`flex` 生成块级 Flex 容器,`inline-flex` 生成内联 Flex 容器。 ```html <div class="flex items-center gap-2"> <span>图标</span> <span>文字</span> </div> <button class="inline-flex items-center gap-1"> <span>+</span> <span>新增</span> </button> ``` `flex` 会像普通 `div` 一样占据一整行,`inline-flex` 更像 `inline-block`,宽度跟内容走,常用于按钮、标签、徽章这类小组件。 ## 方向控制:flex-row、flex-col 怎么选? ```html <div class="flex flex-row gap-4"> <div>左</div> <div>中</div> <div>右</div> </div> <div class="flex flex-col gap-3"> <label>用户名</label> <input class="border p-2" /> </div> ``` 大多数横向布局用 `flex-row`,表单、侧边栏菜单、竖向列表用 `flex-col`。反向类偶尔用于视觉顺序和 DOM 顺序不一致的场景,但不要滥用,否则键盘访问和读屏顺序可能让人困惑。 ## 主轴和交叉轴怎么对齐? `justify-*` 对应 `justify-content`,控制主轴方向上的对齐方式;`items-*` 对应 `align-items`,控制交叉轴上的对齐。 ```html <nav class="flex items-center justify-between p-4"> <div class="font-bold">Logo</div> <div class="flex gap-4"> <a href="#">首页</a> <a href="#">文章</a> <a href="#">关于</a> </div> </nav> ``` 导航栏常用 `justify-between`,头像加文字常用 `items-center`。多行文字和单行文字混排时,如果视觉上总觉得不齐,可以试试 `items-baseline`。 `content-*` 控制多行 Flex 内容在交叉轴上的整体分布,只有容器开启 `flex-wrap` 并且有多行时才明显。 ## 换行和项目伸缩怎么控制? Flex 默认不换行,也就是 `flex-nowrap`。标签列表、按钮列表、卡片行经常需要 `flex-wrap`。 ```html <div class="flex flex-wrap gap-3"> <span class="rounded bg-gray-100 px-3 py-1">Tailwind</span> <span class="rounded bg-gray-100 px-3 py-1">Flexbox</span> </div> ``` 子项自己的宽度和伸缩由 `flex-*`、`basis-*`、`grow`、`shrink` 控制。 ```html <div class="flex gap-4"> <aside class="w-64 flex-none bg-gray-100">侧边栏</aside> <main class="min-w-0 flex-1 bg-white">主内容</main> </div> ``` `flex-1` 会吃掉剩余空间,`flex-none` 不放大也不收缩,`shrink-0` 适合头像、图标按钮这类不希望被挤变形的元素。 默认 Tailwind 里没有 `flex-3`、`flex-grow-2`。如果要表达“内容区是侧边栏 3 倍宽”,可以用 `basis-1/4` + `basis-3/4`,或任意值: ```html <div class="flex gap-4"> <aside class="flex-1">Sidebar</aside> <main class="flex-[3_1_0%] min-w-0">Content</main> </div> ``` ## order、self、gap 和 space 怎么用? `order-*` 可以调整视觉顺序: ```html <div class="flex flex-col gap-4 md:flex-row"> <main class="order-2 md:order-1">正文</main> <aside class="order-1 md:order-2">筛选条件</aside> </div> ``` 但可访问性和键盘焦点顺序仍然跟 DOM 有关,不要只为了视觉方便随意颠倒重要内容。 `self-*` 可以覆盖单个项目的交叉轴对齐。 间距优先用 `gap-*`: ```html <div class="flex flex-wrap gap-x-6 gap-y-3"> <span>标签 A</span> <span>标签 B</span> </div> ``` `space-x-*` / `space-y-*` 适合不换行的简单列表。如果列表会换行,`space-x-*` 往往会出现行首多余间距,换成 `gap-*` 更稳。 ## 常见 Flex 布局怎么写? 水平垂直居中: ```html <div class="flex min-h-screen items-center justify-center"> <div class="rounded-lg bg-white p-6 shadow">居中内容</div> </div> ``` 顶部导航栏: ```html <nav class="flex items-center justify-between p-4"> <a class="font-bold" href="#">Logo</a> <ul class="hidden gap-6 md:flex"> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> </ul> <button class="inline-flex items-center rounded bg-black px-3 py-2 text-white md:hidden">Menu</button> </nav> ``` 响应式侧边栏: ```html <div class="flex flex-col gap-6 md:flex-row"> <aside class="md:w-64 md:shrink-0">Sidebar</aside> <main class="min-w-0 flex-1">Content</main> </div> ``` ## Flex 什么时候不如 Grid? 只关心一个方向的排列,用 Flex;同时关心行和列,优先 Grid。导航栏、按钮组、媒体对象、左右布局,用 Flex;商品列表、图片墙、仪表盘区域、表格式卡片布局,用 Grid。 常见坑包括:`flex-1` 子项长文本溢出时要加 `min-w-0`;`items-center` 看不出效果时先确认容器有没有高度;`content-*` 需要多行 Flex 才能体现;会换行的列表优先用 `gap-*`;`shrink-0` 用多了会造成横向滚动。 Tailwind 的 Flexbox 类可以按四类记:容器显示用 `flex` / `inline-flex`,方向用 `flex-row` / `flex-col`,整体对齐用 `justify-*`、`items-*`、`content-*`,子项伸缩用 `flex-*`、`basis-*`、`grow`、`shrink`、`order-*`、`self-*`。
服务端6月20日 22:00
TailwindCSS 响应式设计怎么写?断点、容器查询和测试怎么做?TailwindCSS 做响应式设计,不是给每个设备单独写一套样式,而是先写移动端默认样式,再在需要变宽时用断点前缀覆盖。没有前缀的类会一直生效;`sm:`、`md:`、`lg:`、`xl:`、`2xl:` 这类前缀表示“从这个宽度开始改成另一种样子”。 ## 默认断点怎么理解? TailwindCSS 默认断点是 mobile-first,也就是基于 `min-width`:`sm` 640px,`md` 768px,`lg` 1024px,`xl` 1280px,`2xl` 1536px。 ```html <div class="w-full md:w-1/2 lg:w-1/3">内容区域</div> ``` 这段代码的意思是:默认宽度 100%,屏幕到 `md` 后变成 50%,到 `lg` 后变成 33.333%。它不是“只在 md 生效”,而是“从 md 开始生效,直到被更大的断点覆盖”。 ## 响应式前缀可以加在任何工具类前 尺寸、间距、颜色、定位、显示隐藏、Grid、Flex、字体都一样。 ```html <section class="px-4 py-6 sm:px-6 md:py-10 lg:px-8"> <h2 class="text-2xl md:text-4xl lg:text-5xl">响应式标题</h2> <p class="mt-3 text-sm leading-6 md:text-base md:leading-7">正文在移动端更紧凑,在桌面端更舒展。</p> </section> ``` 常见写法是先给移动端一个舒服的默认值,再在关键宽度上调整:字体、间距、圆角、阴影、排列方向都可以这样处理。 ## hidden 和 block 怎么配合? 显示隐藏最容易写反。记住:没有前缀的是默认状态,带前缀的是达到断点后的状态。 ```html <button class="block md:hidden">打开菜单</button> <nav class="hidden md:block">桌面导航</nav> ``` 如果只在某个区间显示,可以组合: ```html <div class="hidden md:block lg:hidden">平板专用提示</div> ``` 不要用它复制两份完整内容,否则维护和无障碍都会变麻烦。 ## Grid 布局怎么响应式变化? ```html <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"> <article class="rounded-xl border p-4">项目</article> </div> ``` 如果卡片宽度比设备类型更重要,可以用自适应网格: ```html <div class="grid grid-cols-[repeat(auto-fit,minmax(16rem,1fr))] gap-4"> <article class="rounded-xl border p-4">自动换行的卡片</article> </div> ``` ## max-* 和任意断点怎么用? 默认的 `md:` 是 `min-width`,但有些样式只想在小屏生效,可以用 `max-*`: ```html <div class="max-md:rounded-none max-md:border-x-0 md:rounded-2xl md:border">移动端贴边,桌面端卡片化</div> ``` 也可以使用任意断点: ```html <div class="grid grid-cols-1 min-[720px]:grid-cols-2 min-[1100px]:grid-cols-3">内容列表</div> ``` 任意断点适合修明确的布局问题,不适合替代设计系统断点。如果同一个宽度在多处出现,最好沉淀成自定义 screen。 ## 如何自定义 screens? Tailwind v3 通常在 `tailwind.config.js` 里配置: ```js module.exports = { theme: { extend: { screens: { xs: '475px', '3xl': '1600px', tablet: { min: '640px', max: '1023px' }, }, }, }, } ``` Tailwind v4 更推荐在 CSS 主题变量里定义断点: ```css @import 'tailwindcss'; @theme { --breakpoint-xs: 30rem; --breakpoint-3xl: 100rem; } ``` ## TailwindCSS v4 的容器查询怎么用? 视口断点看的是浏览器宽度,容器查询看的是父容器宽度。组件库、侧边栏卡片、后台面板很需要它。 ```html <div class="@container rounded-2xl border p-4"> <article class="flex flex-col gap-4 @md:flex-row @lg:gap-6"> <div class="h-32 rounded-xl bg-slate-200 @md:w-48"></div> <div> <h3 class="text-lg font-semibold @lg:text-xl">容器查询卡片</h3> <p class="mt-2 text-sm text-slate-600 @lg:text-base">父容器变宽后,卡片内部再切换布局。</p> </div> </article> </div> ``` `md:` 看视口宽度,`@md:` 看最近的 `@container` 容器宽度。页面骨架用视口断点,组件内部用容器查询,通常最清楚。 ## 响应式字体、间距和测试 字体不要只想着“大屏就变大”。中文页面在移动端如果行高太紧,会比字号小更难读。可以同时调整字号、行高和容器宽度: ```html <article class="mx-auto max-w-prose px-4 py-6 sm:px-6 lg:px-8"> <h2 class="text-2xl leading-tight md:text-4xl md:leading-tight">TailwindCSS 响应式设计</h2> <p class="mt-4 text-base leading-7 text-slate-700 md:text-lg md:leading-8">移动端先保证可读,桌面端再增加留白和信息密度。</p> </article> ``` 测试时至少看默认断点前后、长标题、长按钮文案、空数据、图片缺失、横竖屏、浏览器缩放和系统字号。响应式问题很多不是“看起来能不能排下”,而是手指点起来舒不舒服、文字读起来累不累。 TailwindCSS 的响应式设计核心就是两句话:先让移动端自然可用,再在内容需要的时候逐步增强;页面级布局看视口,组件级布局看容器。
服务端6月20日 22:00
TailwindCSS 主题如何配置?v3 与 v4 怎么定制?## 什么时候需要定制 TailwindCSS 主题? TailwindCSS 默认提供了颜色、字号、间距、断点、圆角、阴影、动画等一整套设计基础。小项目直接用默认值就够了,但只要项目开始有品牌色、统一字号、暗色模式、多端断点,或者多个仓库共享同一套设计规范,就应该把这些东西沉淀到主题配置里。 主题配置的价值不是“把 CSS 写到另一个地方”,而是把设计规则变成可复用的工具类。比如按钮统一使用品牌主色,卡片统一使用一套圆角和阴影,页面间距统一使用固定 token,团队成员写出来的页面就不会各有各的风格。 ## v3:从 tailwind.config.js 开始 Tailwind v3 的主题配置集中在 `tailwind.config.js`。一个常见配置大概是这样: ```js module.exports = { content: ['./src/**/*.{js,ts,jsx,tsx,vue,mdx}'], theme: { extend: { colors: { brand: { 50: '#eff6ff', 500: '#3b82f6', 600: '#2563eb' }, success: '#16a34a', warning: '#f59e0b', danger: '#dc2626' }, fontFamily: { sans: ['Inter', 'ui-sans-serif', 'system-ui'], mono: ['JetBrains Mono', 'ui-monospace'] }, spacing: { 18: '4.5rem', 22: '5.5rem' }, screens: { xs: '375px', '3xl': '1920px' }, borderRadius: { card: '1rem', button: '0.625rem' }, boxShadow: { card: '0 12px 32px rgba(15, 23, 42, 0.08)' } } }, plugins: [require('@tailwindcss/forms'), require('@tailwindcss/typography')] } ``` `content` 决定 Tailwind 会从哪些文件里提取 class 名。Monorepo 里经常要把共享包也加进去。不要随手写过大的 `./**/*`,它可能把 `node_modules`、构建产物、测试快照都扫进去。 `theme` 是覆盖默认主题;`theme.extend` 是在默认主题上追加。大多数业务项目应该使用 `extend`,保留默认能力,只新增品牌色、特殊间距、特殊阴影。除非你真的想完全接管默认设计系统,否则不要轻易覆盖 `theme.colors`。 ## 常见主题项怎么定制? 颜色最好用语义命名。比如 `text-text-primary`、`bg-surface-muted`,比到处写 `text-slate-900` 更容易表达设计意图。字体要考虑中文字体栈,不要只写一个英文字体。间距、圆角、阴影只把高频可复用的值放进主题,设计稿里偶尔出现一次的值可以用任意值语法。 断点也不是越多越好。项目主要面向移动端,可以补一个 `xs`;大屏后台或数据看板可以补 `3xl`。断点太多会让布局规则变得难维护。 动效也可以纳入主题: ```js extend: { keyframes: { fadeIn: { from: { opacity: '0' }, to: { opacity: '1' } }, slideUp: { from: { opacity: '0', transform: 'translateY(8px)' }, to: { opacity: '1', transform: 'translateY(0)' } } }, animation: { fadeIn: 'fadeIn 160ms ease-out', slideUp: 'slideUp 220ms ease-out' } } ``` ## plugins 和 presets 怎么用? 官方常用插件包括 `@tailwindcss/forms`、`@tailwindcss/typography`、`@tailwindcss/aspect-ratio`。如果一个样式会在多个项目里反复出现,比如隐藏滚动条、文本渐变、容器安全区,就适合做成插件或 preset。 Monorepo 或多应用团队里,推荐把公共主题抽成 preset: ```js // packages/tailwind-preset/index.js module.exports = { theme: { extend: { colors: { brand: '#2563eb' } } }, plugins: [require('@tailwindcss/forms')] } ``` 业务项目里引用: ```js module.exports = { presets: [require('@acme/tailwind-preset')], content: ['./src/**/*.{js,ts,jsx,tsx}', '../../packages/ui/**/*.{js,ts,jsx,tsx}'], theme: { extend: { colors: { campaign: '#f97316' } } } } ``` 公共 preset 放品牌色、字体、圆角、基础组件规则;业务项目只放自己的活动色、特殊动画、页面级补充。 ## v4:用 @theme 做 CSS-first 配置 Tailwind v4 更强调 CSS-first。很多主题 token 可以直接在 CSS 里声明: ```css @import "tailwindcss"; @theme { --color-brand-50: #eff6ff; --color-brand-500: #3b82f6; --color-brand-600: #2563eb; --color-surface: #ffffff; --color-text-primary: #0f172a; --font-sans: Inter, ui-sans-serif, system-ui, sans-serif; --spacing-18: 4.5rem; --radius-button: 0.625rem; --shadow-card: 0 12px 32px rgb(15 23 42 / 0.08); --breakpoint-xs: 375px; --animate-fade-in: fadeIn 160ms ease-out; } ``` 这些 token 会生成对应工具类,例如 `bg-brand-600`、`rounded-button`、`shadow-card`。 暗色模式建议用语义 token: ```css @theme { --color-page: var(--page); --color-card: var(--card); --color-text-primary: var(--text-primary); } :root { --page: #ffffff; --card: #f8fafc; --text-primary: #0f172a; } .dark { --page: #020617; --card: #0f172a; --text-primary: #f8fafc; } ``` 组件里只写 `bg-page text-text-primary`,切换暗色时变的是 token,不是组件结构。 ## full config 不是越完整越好 Tailwind v3 可以生成完整配置,用来查看默认主题很方便。但不建议把 full config 原封不动放进项目长期维护。文件太大,真正的业务改动很难找;升级 Tailwind 时,默认主题变化也不容易同步。项目里只保留自己确实定制过的部分。 一个新项目可以按这个顺序来:先确定品牌色、文本色、背景色、边框色,用语义命名;再确定字体、字号、圆角、阴影、间距;组件里尽量使用语义 token;多项目共享时,把公共 token 放到 preset 或共享 CSS 文件;动态 class 和共享组件路径提前处理好,避免生产环境缺样式。 Tailwind 主题配置写得好不好,不看配置文件有多长,而看团队能不能稳定写出同一种视觉语言。v3 用好 `theme.extend`、`plugins`、`presets`;v4 用好 `@theme`、CSS 变量和语义 token,基本就能覆盖大多数项目的定制需求。
服务端6月20日 21:57
TailwindCSS 和 Bootstrap、CSS-in-JS 有什么区别?## 先说结论 TailwindCSS、Bootstrap 和 CSS-in-JS 解决的是同一个问题:怎么写样式。但它们的出发点完全不同。 Bootstrap 更像一套现成 UI 套件,按钮、表单、栅格、弹窗都有默认方案,适合快速搭页面。TailwindCSS 更像一盒低层级样式积木,用大量原子类组合出界面。CSS-in-JS 则把样式放进 JavaScript 或组件逻辑里,适合样式强依赖状态、主题和运行时变量的场景。 ## 三者的核心差异是什么? | 方案 | 样式主要写在哪里 | 核心特点 | 典型场景 | |---|---|---|---| | Bootstrap | 预设组件类和工具类 | 开箱即用,默认 UI 完整 | 管理后台、原型、低定制页面 | | TailwindCSS | HTML / JSX 的 className 中 | 原子类组合,定制空间大 | 产品页面、自定义设计系统、长期维护项目 | | CSS-in-JS | JS / TS 组件代码中 | 样式可读状态和变量 | 复杂组件库、主题切换、动态样式 | Bootstrap 先给你一套设计好的组件。TailwindCSS 不提供“按钮组件”,而是提供 `px-4 py-2 rounded bg-blue-600 text-white` 这样的工具类。CSS-in-JS 则通常会写成组件内部样式,根据 props、状态和 theme 动态生成样式。 ## Bootstrap:从组件库起步,也有 v5 工具类 Bootstrap 的优势仍然是完整组件和成熟约定。栅格、按钮、表单、导航、弹窗、下拉菜单这些常见 UI,它基本都给了默认样式和交互规范。对内部系统来说,这种默认值很有价值。 Bootstrap v5 也加强了 utilities,比如 `d-flex`、`gap-3`、`p-4`、`text-center`、`border` 等工具类。它已经不只是组件库,也有一些接近原子 CSS 的写法。 它的问题也明显:默认视觉风格很强,组件结构有既定模式,想完全改成交互复杂的品牌 UI 会比较费劲。如果项目已有成熟设计系统,Bootstrap 的默认组件可能反而成为包袱。 ## TailwindCSS:原子类让定制更快,但 className 会变长 TailwindCSS 的核心思路是 utility-first。它不鼓励你先写 `.card-title`、`.primary-button` 这样的语义类,而是直接用工具类描述样式。 ```jsx <button className="rounded-md bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700">保存</button> ``` 打开组件文件就能看到按钮的间距、颜色、字号、hover 状态,不需要在 CSS 文件和组件之间来回跳。它也很适合把 design tokens 映射到 Tailwind 主题里,让团队共享颜色、间距、字号和断点。 代价是 className 可能很长。解决办法通常不是回到传统 CSS,而是把重复样式沉淀成组件,或者用 `clsx`、`tailwind-variants`、`class-variance-authority` 这类工具管理变体。 ## CSS-in-JS:运行时灵活,也要看是否有零运行时方案 CSS-in-JS 是一类方案,常见的有 styled-components、Emotion、Stitches、Vanilla Extract、Linaria 等。它的核心价值是样式可以贴近组件逻辑。 ```tsx const Button = styled.button<{ active: boolean }>` background: ${({ active }) => active ? '#2563eb' : '#e5e7eb'}; color: ${({ active }) => active ? '#fff' : '#111827'}; `; ``` 传统运行时 CSS-in-JS 会在浏览器运行时生成样式、插入 style 标签,确实可能带来额外开销。服务端渲染也要处理样式收集、注入顺序和 hydration 一致性。但 Vanilla Extract、Linaria 这类 zero-runtime 方案会在构建阶段生成 CSS 文件,运行时负担小得多。 所以不能简单说“CSS-in-JS 一定慢”,要看具体工具是运行时生成,还是构建期抽取。 ## 性能、团队协作和设计系统怎么选? 从性能看,TailwindCSS 通常在构建阶段扫描源码,只生成用到的 CSS,运行时没有样式生成逻辑。Bootstrap 默认提供一整套 CSS,如果不做裁剪,可能包含很多没用到的样式。CSS-in-JS 要看类型:运行时方案更灵活但有运行时成本,零运行时方案性能更接近传统 CSS。 从团队协作看,Bootstrap 学习成本最低;TailwindCSS 需要团队习惯工具类和设计 token;CSS-in-JS 对组件状态、主题上下文、SSR、样式注入顺序要求更高。 设计系统落地时,Bootstrap 适合从现成组件反推规范;TailwindCSS 适合把 token 变成低层级工具类;CSS-in-JS 适合把 token 和组件逻辑绑定起来。 ## 什么时候选谁? 如果项目要快,选 Bootstrap。它的默认组件能节省大量时间。 如果项目要定制,又希望样式规则统一,选 TailwindCSS。它很适合和 design tokens、headless 组件一起用。 如果项目要做复杂主题、组件库和运行时样式逻辑,选 CSS-in-JS,并优先评估是否需要 zero-runtime。 可以混用,但边界要清楚。页面布局归 TailwindCSS,复杂交互组件归组件库,主题 token 统一来源。不要同一个按钮一半靠 Bootstrap,一半靠 Tailwind,最后再套 CSS-in-JS 覆盖。选型只要能让团队少写覆盖代码、少做重复决定、少在样式问题上内耗,就是合适的。
服务端6月20日 21:57
Tailwind CSS JIT 编译器是什么?有哪些优势?Tailwind CSS 的 JIT(Just-in-Time)编译器可以理解成“看到你用了哪个类,就生成哪个 CSS”。它不会提前把所有可能的工具类一次性打包出来,而是扫描项目里的模板、组件和脚本文件,只为实际出现的类名生成样式。 需要纠正一个常见说法:JIT 在 Tailwind CSS v2.1 作为预览功能引入,当时需要手动配置 `mode: 'jit'`;从 Tailwind CSS v3 开始,JIT 已经成为默认编译方式,不再需要写 `mode: 'jit'`。 ## JIT 编译器是怎么工作的? Tailwind 的 JIT 流程大致分成三步:扫描 `content` 配置指定的文件,提取完整类名,然后按需生成 CSS。 ```js module.exports = { content: ['./src/**/*.{html,js,ts,jsx,tsx,vue,svelte,mdx}'], theme: { extend: {} }, plugins: [], } ``` 在 Tailwind CSS v3+ 中,不要再加 `mode: 'jit'`,这已经是默认行为。 ## 它和旧的 AOT / Purge 模式有什么区别? 早期 Tailwind 更接近 AOT:先生成大量可能用到的工具类,再通过 PurgeCSS 移除没用到的部分。这会导致开发环境 CSS 文件很大、构建和热更新更慢、生产环境还要依赖 purge 配置清理无用样式。 JIT 改成了反过来的方式:先看你实际写了什么类,再生成对应样式。所以在 Tailwind CSS v3 之后,`content` 扫描就是核心配置,Purge 不再是一个单独步骤。 ## JIT 的主要优势是什么? JIT 只处理项目中真实出现的类名,不需要提前生成完整工具类集合。开发时新增一个类,Tailwind 只补生成这一小段 CSS,通常比旧模式轻很多。 因为只生成用到的样式,最终 CSS 体积通常会更可控。前提是 `content` 路径写对,如果组件目录没被扫描到,对应样式也不会生成。 JIT 还让任意值写法变得实用: ```html <div class="w-[137px] bg-[#1da1f2] text-[13px]">自定义样式</div> ``` 这类写法适合少量特殊样式。如果某个值会反复出现,仍然建议放进 `theme.extend`,否则维护会越来越散。 JIT 也可以按需生成复杂变体组合: ```html <button class="hover:bg-blue-500 focus:ring-2 active:scale-95 disabled:opacity-50">按钮</button> ``` ## 动态类名为什么经常失效? JIT 扫描的是源码里的完整类名字符串,不是运行时结果。下面这种写法通常无法被正确识别: ```jsx const size = 'lg' return <div className={`text-${size}`}>内容</div> ``` 更推荐写成完整映射: ```jsx const sizeMap = { sm: 'text-sm', lg: 'text-lg', xl: 'text-xl' } return <div className={sizeMap[size]}>内容</div> ``` 如果类名确实来自接口、CMS 或用户配置,可以使用 `safelist`: ```js module.exports = { content: ['./src/**/*.{js,jsx,ts,tsx,vue,html}'], safelist: [ 'bg-red-500', { pattern: /bg-(red|green|blue)-500/, variants: ['hover', 'focus'] }, ], } ``` ## 使用 JIT 时要注意什么? `content` 路径要覆盖完整,Monorepo 里要把共享包也加进去。不要滥用字符串拼接。任意值别当主题系统用,`w-[137px]`、`bg-[#1da1f2]` 适合个别特殊值,品牌色、字号、间距这种长期复用的值应该沉淀成设计 token。 Tailwind CSS v4 延续了按需生成的思路,并引入了新的高性能引擎。可以这样理解:v2.1 预览引入 JIT,v3 默认启用 JIT,v4 继续强化引擎性能和现代 CSS 工作流。JIT 的价值很明确:更快的开发体验、更小的 CSS 输出、更灵活的任意值和变体写法,但它要求你写出可被静态扫描到的完整类名。
服务端6月20日 19:48
TailwindCSS 如何实现复杂布局?Flex、Grid 与响应式怎么选?TailwindCSS 做复杂布局,关键不是背更多 class,而是先判断页面属于哪类布局:一维排布用 Flex,二维排布用 Grid,需要脱离文档流时再用定位。很多布局写乱,往往不是 TailwindCSS 的问题,而是一开始就把工具选错了。 比如导航栏、按钮组、表单行,更适合 Flex;商品卡片墙、仪表盘、圣杯布局,更适合 Grid;浮动徽标、固定底栏、吸顶标题,则交给 relative、absolute、fixed、sticky。 ## 先判断:Flex 还是 Grid? 一句话判断:**Flex 解决一条轴上的排列,Grid 解决行和列同时存在的布局。** 如果只关心元素横着排还是竖着排,比如头像加用户名、按钮靠右、导航菜单换行,用 Flex 更自然: ```html <div class="flex items-center justify-between gap-4"> <div class="flex items-center gap-2"> <img class="h-10 w-10 rounded-full" src="/avatar.png" alt="用户头像" /> <span>Leven</span> </div> <button class="rounded bg-blue-600 px-4 py-2 text-white">关注</button> </div> ``` 如果需要同时控制列宽、行距、跨列、响应式列数,用 Grid 会更清楚: ```html <div class="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-4"> <article class="rounded-lg border p-4">卡片 1</article> <article class="rounded-lg border p-4">卡片 2</article> </div> ``` ## Flex:处理导航、工具栏和局部对齐 Flex 的核心是主轴和交叉轴。常用类包括 `flex-row`、`flex-col`、`flex-wrap`、`justify-*`、`items-*`、`flex-1`、`shrink-0`、`basis-*`。 ```html <header class="flex flex-wrap items-center justify-between gap-4 border-b px-4 py-3"> <a class="shrink-0 text-lg font-semibold" href="/">Logo</a> <nav class="flex flex-wrap items-center gap-3 text-sm"> <a href="/docs">文档</a> <a href="/pricing">价格</a> </nav> <div class="flex items-center gap-2"> <button class="rounded px-3 py-1.5">登录</button> <button class="rounded bg-black px-3 py-1.5 text-white">注册</button> </div> </header> ``` `flex-wrap` 能让导航在小屏幕上自然换行;`shrink-0` 适合 Logo、头像、图标按钮这类不希望被压缩的元素。 ## Grid:处理二维布局、响应式列和跨列 ```html <section class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"> <article class="rounded-xl border p-5">文章卡片</article> <article class="rounded-xl border p-5">文章卡片</article> </section> ``` 需要某个卡片跨列时,用 `col-span-*`: ```html <section class="grid grid-cols-1 gap-4 md:grid-cols-4"> <article class="rounded-xl border p-5 md:col-span-2">重点内容</article> <article class="rounded-xl border p-5">普通内容</article> </section> ``` 移动端优先:`grid-cols-1` 是小屏默认值,`sm:`、`lg:` 逐步增强。 ## 用 minmax 和 auto-fit 写更耐用的卡片网格 如果卡片数量不固定,可以用任意值语法写 `repeat(auto-fit,minmax())`: ```html <section class="grid grid-cols-[repeat(auto-fit,minmax(240px,1fr))] gap-4"> <article class="rounded-xl border p-5">卡片</article> <article class="rounded-xl border p-5">卡片</article> </section> ``` 每张卡片最小 240px,空间够就自动多排几列,不够就换行。相比手动写多个断点,它更适合商品列表、文章列表、工具卡片。 固定侧边栏加自适应内容可以这样写: ```html <div class="grid grid-cols-[220px_minmax(0,1fr)] gap-6"> <aside class="rounded border p-4">侧边栏</aside> <main class="min-w-0 rounded border p-4">主内容</main> </div> ``` ## Subgrid 和 Container Queries 复杂页面里,如果内层内容想跟父级网格列线对齐,可以用 `grid-cols-subgrid`: ```html <section class="grid grid-cols-4 gap-4"> <article class="col-span-4 grid grid-cols-subgrid rounded-xl border p-4"> <h2 class="col-span-4 text-lg font-semibold md:col-span-1">标题</h2> <p class="col-span-4 md:col-span-3">内容跟随父级网格对齐。</p> </article> </section> ``` TailwindCSS v4 还可以使用容器查询。父级声明为容器,子元素根据容器宽度变化: ```html <article class="@container rounded-xl border p-4"> <div class="grid gap-4 @md:grid-cols-[160px_1fr]"> <img class="aspect-video w-full rounded-lg object-cover" src="/cover.jpg" alt="文章封面" /> <div> <h2 class="font-semibold">TailwindCSS 布局示例</h2> <p class="mt-2 text-sm text-gray-600">容器够宽时左右排,不够宽时上下排。</p> </div> </div> </article> ``` 这种写法更适合组件库和模块化页面。组件不再只看屏幕宽度,而是根据实际容器空间调整布局。 ## 定位和居中 Flex 和 Grid 负责正常布局流,定位负责特殊位置。徽标、角标适合 `relative + absolute`: ```html <div class="relative inline-block"> <button class="rounded-lg border px-4 py-2">消息</button> <span class="absolute -right-2 -top-2 rounded-full bg-red-500 px-1.5 text-xs text-white">3</span> </div> ``` 固定底部操作栏用 `fixed`,文章目录和筛选栏常用 `sticky`。注意 `sticky` 会受父元素 `overflow` 影响。 居中也不用猜:块级容器水平居中用 `mx-auto max-w-*`;水平垂直居中可以用 Flex,也可以用 `grid place-items-center`。 ## 圣杯布局和卡片网格 ```html <body class="min-h-screen bg-gray-50"> <div class="grid min-h-screen grid-rows-[auto_1fr_auto]"> <header class="border-b bg-white px-4 py-3">Header</header> <div class="grid grid-cols-1 md:grid-cols-[240px_minmax(0,1fr)]"> <aside class="border-r bg-white p-4">Sidebar</aside> <main class="min-w-0 p-4">Main Content</main> </div> <footer class="border-t bg-white px-4 py-3">Footer</footer> </div> </body> ``` 卡片网格可以外层 Grid 管列数,内层 Flex 让按钮贴底: ```html <section class="grid grid-cols-[repeat(auto-fit,minmax(260px,1fr))] gap-5"> <article class="flex flex-col overflow-hidden rounded-xl border bg-white"> <img class="aspect-video w-full object-cover" src="/cover.jpg" alt="封面" /> <div class="flex flex-1 flex-col p-5"> <h2 class="text-lg font-semibold">卡片标题</h2> <p class="mt-2 flex-1 text-sm text-gray-600">这里是卡片描述,长度可以不同。</p> <a class="mt-4 inline-flex items-center text-sm font-medium text-blue-600" href="/detail">查看详情</a> </div> </article> </section> ``` ## 实用建议 写 TailwindCSS 复杂布局时,可以按这个顺序处理:先确定内容语义,用 `header`、`main`、`section`、`article`、`aside`、`footer` 搭骨架;判断主布局用 Grid 还是 Flex;从移动端开始写默认样式,再用断点增强;特殊悬浮、角标、吸顶再使用定位;遇到组件在不同容器里表现不同,考虑 `@container`;能少嵌套就少嵌套,结构清楚比 class 看起来短更重要。 TailwindCSS 的布局能力本质上还是 CSS,只是换成了工具类表达。复杂页面真正难的不是某个 class 怎么写,而是先把布局关系想清楚:谁负责行列,谁负责对齐,谁需要脱离文档流,谁应该随容器变化。
服务端6月20日 19:19
TailwindCSS @apply 怎么用?哪些场景不该用?TailwindCSS 的 `@apply` 用来把已有的工具类写进 CSS 选择器里。它适合抽取少量重复样式,比如按钮、表单控件、第三方组件覆盖;但不适合把所有 Tailwind 工具类都“搬回 CSS”。如果大量使用 `@apply`,最后很容易写成一套披着 Tailwind 外衣的传统 CSS,还会带来样式膨胀、优先级混乱和维护成本。 ## @apply 是什么? 一句话:`@apply` 可以在 CSS 中复用 Tailwind 工具类。 ```css .btn-primary { @apply rounded-md bg-blue-600 px-4 py-2 font-medium text-white; } ``` 然后在 HTML 或组件里使用: ```html <button class="btn-primary">保存</button> ``` 编译后,`.btn-primary` 会得到这些工具类对应的 CSS 声明。这样写的好处是减少重复,尤其是多个地方都要用同一组样式时,不必每次都写一长串 class。不过 Tailwind 的主要使用方式仍然是直接在模板里写工具类,`@apply` 是补充手段,不是默认写法。 ## 应该配合 @layer 使用 自定义样式最好放进 Tailwind 的 layer 里,便于控制输出顺序和级联关系。 ```css @layer base { body { @apply bg-white text-gray-900 antialiased; } a { @apply text-blue-600 underline-offset-4 hover:underline; } } @layer components { .btn { @apply inline-flex items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors; } .btn-primary { @apply bg-blue-600 text-white; } .btn-secondary { @apply border border-gray-300 bg-white text-gray-900; } } ``` `base` 适合写全局基础标签样式,影响面大,别写太重。`components` 最适合按钮、表单、卡片、导航项这类重复出现、语义稳定的组件。少量项目级工具类可以放在 `utilities`,Tailwind v4 里如果要注册真正的工具类,更推荐用 `@utility`。 ## 适合用 @apply 的场景 按钮、表单控件、卡片和第三方组件覆盖,是比较适合 `@apply` 的场景。 ```css @layer components { .form-input { @apply w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 outline-none; } .panel { @apply rounded-xl border border-gray-200 bg-white p-6 shadow-sm; } } ``` 第三方库生成的 DOM 不一定方便直接加 Tailwind class,这时 `@apply` 很实用: ```css .select2-dropdown { @apply rounded-lg border border-gray-200 shadow-lg; } .select2-search input { @apply rounded-md border-gray-300 text-sm; } ``` ## hover、focus、响应式有什么限制? 很多人会尝试这样写: ```css .btn-primary { @apply bg-blue-600 hover:bg-blue-700; } ``` 在不同 Tailwind 版本和构建环境里,这类写法可能遇到限制。更稳的方式是把状态拆成普通 CSS 选择器,或者在 Tailwind v4 中使用 `@variant`。 ```css @layer components { .btn-primary { @apply bg-blue-600 text-white; } .btn-primary:hover { @apply bg-blue-700; } .btn-primary:focus-visible { @apply outline-none ring-2 ring-blue-500 ring-offset-2; } } ``` Tailwind v4 可以这样写: ```css .btn-primary { @apply bg-blue-600 text-white; @variant hover { @apply bg-blue-700; } } ``` 响应式如果只是某个元素在不同断点变化,直接在模板里写 `md:`、`lg:` 更直观。不要为了“HTML 看起来短一点”把所有响应式逻辑藏进 CSS。 ## CSS 变量可以和 @apply 一起用 复杂一点的组件,可以把稳定部分交给 `@apply`,动态值交给 CSS 变量。 ```css @layer components { .badge { --badge-bg: theme(colors.gray.100); --badge-color: theme(colors.gray.700); @apply inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium; background-color: var(--badge-bg); color: var(--badge-color); } .badge-success { --badge-bg: theme(colors.green.100); --badge-color: theme(colors.green.700); } } ``` 在 Tailwind v4 里,项目配置更偏 CSS-first,可以直接使用主题变量,例如 `var(--color-green-700)`。设计 token 尽量从 Tailwind 体系来,别在组件 CSS 里散落一堆魔法值。 ## 什么时候用 @apply,什么时候直接写工具类? | 场景 | 建议 | |---|---| | 只出现一次的样式 | 直接写 Tailwind 工具类 | | 重复出现 3 次以上的稳定样式组合 | 可以考虑 `@apply` | | 按钮、表单、卡片这类基础组件 | 适合 `@apply` 或组件封装 | | 状态和变体很多的 UI | 优先用组件 props 管理 class | | 第三方组件 DOM 不好加 class | 适合用 `@apply` 覆盖 | | 需要支持 `hover:`、`lg:` 等变体的自定义工具 | Tailwind v4 优先用 `@utility` | 如果项目已经有 React、Vue 组件系统,很多时候不需要用 `@apply` 抽类名,而是直接封装组件,用 props 管理 variant、size、disabled、loading 等状态。 ## 常见坑 `@apply` 不是 Sass mixin,不适合层层套娃;不要把自定义组件类再 apply 到另一个组件类里。过早抽象也会导致后面每个地方都要覆盖,最后 CSS 比原来更乱。 `@apply` 会把工具类对应的声明内联到你的选择器中。多个组件重复 `@apply` 同一批工具类,就可能生成重复 CSS。少量没问题,大量抽象会让 CSS 变厚。 用 `@apply` 时尽量保持选择器简单。如果写出 `.page .card .title` 这类复杂选择器,覆盖关系会变得难读。 Tailwind v4 更强调 CSS-first:写组件类可以继续用 `@layer components` + `@apply`;写真正的工具类更推荐 `@utility`;写 hover、dark、focus 等变体优先考虑 `@variant` 或普通伪类。`@apply` 可以用,但要克制。
服务端6月20日 19:16
TailwindCSS 任意值语法如何使用?常见场景和坑有哪些?TailwindCSS 的任意值语法(Arbitrary Values)适合处理“只出现一次、但默认工具类没有覆盖”的样式。核心写法是把具体值放进方括号里,比如 `w-[372px]`、`text-[#1f2937]`、`mt-[18px]`。这样不用临时写 CSS,也不用为了一个特殊尺寸去改 `tailwind.config.js`。 不过它不是“想写什么都往方括号里塞”。用得好,代码更快落地;用得乱,项目里会到处都是魔法值,后面维护很难受。 ## 基本写法是什么? ```html <div class="w-[372px] bg-[#f5f5f5] text-[15px] p-[18px]"></div> ``` 方括号里的内容会被 Tailwind 编译成对应 CSS。常见场景包括宽高、颜色、间距、字体、边框和布局。 ### 宽高、颜色、间距和文本 ```html <div class="w-[320px] h-[48px] max-w-[calc(100%-2rem)]"></div> <button class="bg-[#1677ff] text-[#fff] border-[#d9d9d9]"></button> <section class="mt-[18px] px-[22px] gap-[14px]"></section> <p class="text-[13px] leading-[1.65] tracking-[0.02em]"></p> ``` `calc()` 可以放进去,不过表达式里不能随便写空格,通常写成 `w-[calc(100%-2rem)]`。如果值里有空格,Tailwind 会把下划线 `_` 转成空格。 ### 阴影和 Grid ```html <div class="border-[1.5px] rounded-[10px] shadow-[0_8px_30px_rgba(0,0,0,0.12)]"></div> <div class="grid grid-cols-[minmax(180px,240px)_1fr]"></div> ``` 像 `box-shadow`、`grid-template-columns` 这种本来就有空格的值,可以用 `_` 代替空格。 ## CSS 变量怎么配合使用? ```html <div class="bg-[var(--card-bg)] text-[var(--text-primary)]"></div> <div class="w-[calc(100%-var(--sidebar-width))]"></div> ``` 如果项目里已经有设计 token,CSS 变量配合任意值会比硬编码更稳。比如主题切换、品牌换肤、暗色模式,都可以只改变量,不改 class。 ## 类型提示是什么? 有些值 Tailwind 可能判断不出应该生成哪类 CSS。比如 CSS 变量既可能是颜色,也可能是长度: ```html <div class="text-[color:var(--brand-color)]"></div> <div class="text-[length:var(--font-size-title)]"></div> <div class="bg-[color:var(--brand-bg)]"></div> ``` 类型提示的作用不是改变值,而是告诉 Tailwind:这个任意值应该生成哪一类工具样式。 ## 任意属性和任意变体怎么写? 如果 Tailwind 没有对应工具类,可以用任意属性: ```html <div class="[mask-image:linear-gradient(to_bottom,black,transparent)]"></div> <div class="[scrollbar-gutter:stable] [text-wrap:balance]"></div> ``` 任意变体可以写自定义选择器: ```html <ul class="[&>li]:mb-[8px] [&>li:first-child]:font-bold"></ul> <button class="[&:not(:disabled)]:hover:bg-[#1677ff]"></button> <div class="[&_strong]:text-[#111] [&_a]:underline"></div> ``` `&` 表示当前元素,`_` 会被当作空格。 ## 伪元素和动画可以用任意值吗? ```html <span class="before:content-['New'] before:mr-[6px]"></span> <span class="after:content-['Read_more']"></span> <span data-label="Beta" class="before:content-[attr(data-label)]"></span> ``` 伪元素内容适合小标签、装饰文本,不建议承载真正重要的正文内容。动画也可以写: ```html <div class="animate-[spin_1.5s_linear_infinite]"></div> <div class="animate-[fade-in_300ms_ease-out_forwards]"></div> ``` 但 `animate-[fade-in...]` 只是在使用某个 animation 声明,关键帧 `@keyframes fade-in` 仍然需要存在。常用动画最好写进 Tailwind 配置或全局 CSS。 ## JIT 和 content scanning 要注意什么? Tailwind v3 以后 JIT 已经是默认机制,不需要再写旧版的 `mode: 'jit'`。v3+ 正常配置 `content` 即可: ```js module.exports = { content: ['./src/**/*.{js,ts,jsx,tsx,vue,html}'], theme: { extend: {} } } ``` Tailwind 只能识别静态、完整的 class 字符串。不要这样写: ```jsx <div className={`w-[${width}px]`}></div> ``` 更稳的写法是提前列出完整 class,或对真正动态的值使用 `style`: ```jsx const widthClass = size === 'large' ? 'w-[320px]' : 'w-[240px]' return <div className={widthClass}></div> ``` ## 什么时候用任意值,什么时候写进配置? 适合用任意值的情况:一次性特殊尺寸、某个页面独有布局、临时活动页颜色、特殊 CSS 函数、新 CSS 属性。更适合写进主题配置的情况:品牌色、通用字号、圆角、阴影、多处复用的间距值、统一断点、常用动画。 如果同一个值出现三次以上,就考虑写进配置。任意值的价值,是让少量特殊样式留在 class 里快速表达;项目越大,越要克制:一次性值用方括号,稳定规范进配置,动态值交给 `style` 或 CSS 变量。
服务端6月20日 19:16
TailwindCSS 暗色模式如何实现?v3 和 v4 有什么区别?TailwindCSS 做暗色模式,核心不是写两套 CSS,而是用 `dark:` 变体给同一个元素补一组暗色样式。真正容易踩坑的地方在于:你的项目用 Tailwind v3 还是 v4?暗色状态由系统偏好决定,还是由用户手动切换?这两个问题先想清楚,后面的代码会简单很多。 ## 先决定暗色模式由谁触发 Tailwind 的暗色模式大致有两种思路:跟随系统,或由用户手动切换。如果只是文档页,跟随系统通常够用;如果是后台、SaaS、博客、控制台这类长期使用的产品,建议支持手动切换,并允许用户选择“跟随系统”。 ## Tailwind v3 怎么配置 darkMode? 在 Tailwind v3 里,常见配置写在 `tailwind.config.js`: ```js module.exports = { darkMode: 'media', content: ['./src/**/*.{html,js,ts,jsx,tsx,vue}'], theme: { extend: {} }, } ``` `media` 会根据浏览器的 `prefers-color-scheme: dark` 自动生效,不需要给 HTML 加类名。缺点是它不适合做“用户手动切换”。 如果要手动切换,v3.4.1 之后更推荐 `selector`: ```js module.exports = { darkMode: 'selector', } ``` 这时只要根节点上有 `dark` 类,所有 `dark:` 样式都会生效: ```html <html class="dark"> <body class="bg-white text-slate-900 dark:bg-slate-950 dark:text-slate-100"> ... </body> </html> ``` 老项目里还会看到 `darkMode: 'class'`,它和 `selector` 的实际思路接近,都是靠选择器触发。新项目可以优先用 `selector`。 如果想用 `data-theme="dark"` 而不是 `.dark`,可以指定选择器: ```js module.exports = { darkMode: ['selector', '[data-theme="dark"]'], } ``` ## Tailwind v4 怎么写? Tailwind v4 更偏向在 CSS 里配置。你可以用 `@custom-variant` 自定义 `dark:` 的触发条件: ```css @import "tailwindcss"; @custom-variant dark (&:where(.dark, .dark *)); ``` 如果项目用 `data-theme` 管主题: ```css @import "tailwindcss"; @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *)); ``` 页面里继续使用熟悉的 `dark:` 前缀: ```html <section class="rounded-xl border border-slate-200 bg-white p-6 text-slate-900 dark:border-slate-800 dark:bg-slate-950 dark:text-slate-100"> <h2 class="text-lg font-semibold">账户设置</h2> <p class="mt-2 text-slate-600 dark:text-slate-400">这里的颜色会跟随主题变化。</p> </section> ``` ## 原生 JavaScript 如何切换主题? 更稳的做法是保存三种状态:`light`、`dark`、`system`。 ```js const root = document.documentElement; const media = window.matchMedia('(prefers-color-scheme: dark)'); function applyTheme(theme) { const isDark = theme === 'dark' || (theme === 'system' && media.matches); root.classList.toggle('dark', isDark); root.dataset.theme = isDark ? 'dark' : 'light'; } function setTheme(theme) { localStorage.setItem('theme', theme); applyTheme(theme); } const savedTheme = localStorage.getItem('theme') || 'system'; applyTheme(savedTheme); media.addEventListener('change', () => { if ((localStorage.getItem('theme') || 'system') === 'system') applyTheme('system'); }); ``` 按钮里调用 `setTheme('light')`、`setTheme('dark')` 或 `setTheme('system')` 即可。 ## 如何避免页面加载时闪一下? 暗色模式闪烁通常叫 FOUC。原因是页面先按亮色渲染,JavaScript 加载后才补上 `.dark`。解决办法是把一小段脚本放在 `<head>` 里,尽量早于页面渲染执行: ```html <script> try { const theme = localStorage.getItem('theme') || 'system'; const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; const isDark = theme === 'dark' || (theme === 'system' && prefersDark); document.documentElement.classList.toggle('dark', isDark); document.documentElement.dataset.theme = isDark ? 'dark' : 'light'; } catch (_) {} </script> ``` 如果是 Next.js,`next-themes` 会省很多事。它已经处理了 SSR、系统偏好、持久化和闪烁问题。 ## 颜色最好用语义化 token 管起来 小页面可以直接写 `bg-white dark:bg-slate-950`。项目一大,建议把颜色抽成语义化 token,比如背景、前景、卡片、边框、强调色,而不是到处散落 `slate-900`、`gray-800`。 ```css :root { --color-bg: 255 255 255; --color-fg: 15 23 42; --color-card: 248 250 252; --color-border: 226 232 240; } .dark { --color-bg: 2 6 23; --color-fg: 241 245 249; --color-card: 15 23 42; --color-border: 51 65 85; } ``` 组件里使用这些变量: ```html <div class="bg-[rgb(var(--color-bg))] text-[rgb(var(--color-fg))]"> <section class="border border-[rgb(var(--color-border))] bg-[rgb(var(--color-card))]">内容</section> </div> ``` ## 图片、SVG、过渡和可访问性 图标优先用 `currentColor`,让它继承文字颜色: ```html <svg class="h-5 w-5 text-slate-600 dark:text-slate-300" fill="currentColor" viewBox="0 0 20 20"></svg> ``` 亮色和暗色需要不同图片时,可以用两张图切换: ```html <img src="logo-light.svg" alt="Logo" class="block dark:hidden" /> <img src="logo-dark.svg" alt="Logo" class="hidden dark:block" /> ``` 主题切换时可以加颜色过渡,但不要全站无脑 `transition-all`。颜色切换 150-250ms 足够,太慢会像页面卡了一下。 暗色模式至少要检查正文、次级文本、占位符、禁用态、按钮 hover、focus ring、错误提示的对比度。不要用纯黑背景配纯白大段文字,长时间阅读会累;深蓝黑或深灰通常更舒服。 ## 测试时别只点一次按钮 建议按这些场景测一遍:首次访问是否跟随系统偏好;手动切换是否保存;刷新页面有没有 FOUC;选择“跟随系统”时系统主题变化是否响应;SSR 页面是否 hydration 一致;hover、active、focus、disabled、error、loading 是否都有暗色样式;Logo、插图、SVG、图表在暗色下是否清晰。 TailwindCSS 暗色模式本身很简单,难的是把触发策略、持久化、闪烁、语义化颜色、第三方组件和可访问性都处理完整。新项目用 v4 可以通过 `@custom-variant` 管触发条件;v3 项目跟随系统用 `media`,手动切换用 `selector`。
服务端6月20日 19:08
TailwindCSS 动画和过渡如何实现?TailwindCSS 做动画主要分两类:一种是用 `animate-*` 直接套关键帧动画,比如加载、提示、状态闪烁;另一种是用 `transition-*` 处理状态变化,比如 hover、focus、active 时的颜色、位移、透明度变化。前者适合“自己一直动”的效果,后者适合“用户触发后平滑变化”的效果。 ## 内置动画怎么用 TailwindCSS 默认提供了几个常用动画,日常 UI 里够用一大半。 ```html <!-- 旋转:常用于 loading 图标 --> <div class="animate-spin rounded-full h-8 w-8 border-2 border-blue-500 border-t-transparent"></div> <!-- 弹跳:常用于引导或轻提示 --> <div class="animate-bounce">向下看</div> <!-- 脉冲:常用于骨架屏或占位状态 --> <div class="animate-pulse h-4 w-40 rounded bg-gray-200"></div> <!-- ping:常用于通知点、在线状态 --> <span class="relative flex h-3 w-3"> <span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-400 opacity-75"></span> <span class="relative inline-flex h-3 w-3 rounded-full bg-green-500"></span> </span> ``` `animate-spin` 是持续旋转,`animate-bounce` 是上下弹动,`animate-pulse` 是透明度脉冲,`animate-ping` 是向外扩散。不要把 `ping` 理解成摇摆,它更像雷达波纹。 ## 过渡效果怎么写 过渡靠三类工具类配合:过渡属性、持续时间、缓动方式。常见写法是先指定变化属性,再加 `duration-*` 和 `ease-*`。 ```html <button class="bg-blue-500 px-4 py-2 text-white transition-colors duration-200 ease-out hover:bg-blue-600"> 颜色过渡 </button> <div class="transition-transform duration-300 ease-in-out hover:scale-105"> 缩放过渡 </div> <div class="transition-opacity duration-200 hover:opacity-70"> 透明度过渡 </div> ``` 常用过渡类可以这样选:`transition-colors` 适合颜色变化,`transition-opacity` 适合淡入淡出,`transition-transform` 适合缩放、旋转、位移,`transition-shadow` 适合卡片阴影变化,`transition-all` 只适合快速试效果,正式代码别滥用。 按钮、输入框这类即时反馈通常用 `duration-150` 或 `duration-200`;卡片 hover、弹层淡入可以用 `duration-300`;再慢就容易让用户觉得页面拖沓。 ```html <button class="transition-colors delay-75 duration-150 ease-out hover:bg-blue-500"> 带延迟的按钮 </button> <div class="transition-transform duration-[450ms] ease-[cubic-bezier(.22,1,.36,1)] hover:-translate-y-1"> 自定义时间和贝塞尔曲线 </div> ``` ## 自定义动画:Tailwind v3 写法 Tailwind CSS v3 通常在 `tailwind.config.js` 里扩展 `keyframes` 和 `animation`。 ```js module.exports = { theme: { extend: { keyframes: { 'fade-in': { '0%': { opacity: '0' }, '100%': { opacity: '1' }, }, 'slide-up': { '0%': { opacity: '0', transform: 'translateY(12px)' }, '100%': { opacity: '1', transform: 'translateY(0)' }, }, wiggle: { '0%, 100%': { transform: 'rotate(-3deg)' }, '50%': { transform: 'rotate(3deg)' }, }, }, animation: { 'fade-in': 'fade-in 300ms ease-out both', 'slide-up': 'slide-up 400ms ease-out both', wiggle: 'wiggle 1s ease-in-out infinite', }, }, }, }; ``` 使用时和内置动画一样: ```html <div class="animate-fade-in">淡入内容</div> <div class="animate-slide-up">上滑进入</div> <button class="animate-wiggle">有提示的按钮</button> ``` ## 自定义动画:Tailwind v4 的 @theme 写法 Tailwind CSS v4 更偏 CSS-first,可以在 CSS 里通过 `@theme` 定义动画变量和关键帧。 ```css @import "tailwindcss"; @theme { --animate-fade-in: fade-in 300ms ease-out both; --animate-slide-up: slide-up 400ms ease-out both; @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } @keyframes slide-up { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } } } ``` 定义后可以直接写: ```html <div class="animate-fade-in">淡入</div> <div class="animate-slide-up">上滑</div> ``` 如果项目已经升级到 v4,优先用 `@theme` 管动画;还在 v3,就继续放在 `tailwind.config.js` 里。 ## 任意动画值怎么写 一次性的动画,不一定要进配置。Tailwind 支持任意值语法,空格用下划线代替。 ```html <div class="animate-[bounce_1s_ease-in-out_infinite]">自定义 bounce 参数</div> <div class="animate-[fade-in_400ms_ease-out_both]">一次性淡入动画</div> <div class="transition-[height] duration-300 ease-out">只过渡 height</div> ``` 这种写法适合临时效果、原型页、只出现一次的特殊动画。如果团队里很多地方都在复用同一个动画,还是放进主题配置更清楚。 ## 常见场景示例 加载动画要轻,不要抢注意力。图标旋转、骨架屏脉冲、三个点弹跳都比较常见。 ```html <div class="flex items-center gap-3"> <div class="h-5 w-5 animate-spin rounded-full border-2 border-gray-300 border-t-blue-500"></div> <span class="text-sm text-gray-600">加载中...</span> </div> <div class="space-y-3 animate-pulse"> <div class="h-4 w-2/3 rounded bg-gray-200"></div> <div class="h-4 w-full rounded bg-gray-200"></div> </div> ``` hover 最好只动一点点。按钮放大 5%、卡片上移 4px、阴影变深,已经足够让用户知道“这里能点”。 ```html <button class="rounded bg-blue-500 px-4 py-2 text-white transition-transform duration-150 ease-out hover:scale-105 active:scale-95"> 保存 </button> <div class="rounded-xl bg-white p-6 shadow transition-[transform,box-shadow] duration-300 ease-out hover:-translate-y-1 hover:shadow-lg"> <h2 class="font-semibold">卡片标题</h2> </div> ``` 页面或弹层进入时,常用淡入加轻微位移。幅度不要太大,否则会像 PPT 动画。 ```html <section class="animate-slide-up"> <h2 class="text-xl font-semibold">页面内容</h2> </section> <div class="animate-fade-in rounded-lg bg-white p-6 shadow-lg"> 弹层内容 </div> ``` ## 性能上要注意什么 动画性能先看你动了什么属性。优先动 `transform` 和 `opacity`,它们通常更容易被浏览器合成层处理,不容易频繁触发布局计算。 ```html <div class="transition-transform duration-300 hover:-translate-y-1 hover:scale-105">更流畅</div> <div class="transition-opacity duration-200 hover:opacity-70">淡入淡出</div> ``` `will-change` 不是越多越好。它是在提前告诉浏览器“这个元素马上要动”,用在少量关键动画上有帮助;如果给一堆列表项长期加 `will-change-transform`,反而可能占用更多内存。 `transition-all` 也不要长期滥用。正式组件里优先写 `transition-colors`、`transition-transform`、`transition-opacity`,确实需要多个属性时再用 `transition-[transform,box-shadow]` 这类更明确的写法。 ## 如何照顾减少动画的用户 有些用户在系统里开启了“减少动态效果”,Tailwind 可以用 `motion-safe:` 和 `motion-reduce:` 处理。 ```html <div class="motion-safe:animate-bounce motion-reduce:animate-none"> 尊重系统动画偏好 </div> <div class="transition-transform duration-300 motion-reduce:transition-none motion-safe:hover:scale-105"> 减少动态效果时不做缩放过渡 </div> ``` 持续循环、闪烁、快速位移这类动画尤其应该加上降级处理。 ## 实际使用时怎么选 如果是加载、通知点、骨架屏,先看内置的 `animate-spin`、`animate-ping`、`animate-pulse`、`animate-bounce` 能不能解决。只是 hover、focus、active 的状态变化,用 `transition-colors`、`transition-transform`、`transition-opacity` 就好。 需要复用的品牌动画,v3 放到 `tailwind.config.js`,v4 放到 `@theme`。只用一次的特殊效果,可以用 `animate-[...]` 或任意过渡值。性能上少动布局属性,多用 `transform` 和 `opacity`;可访问性上记得给明显动画配 `motion-safe` 和 `motion-reduce`。这样写出来的动效不花哨,但稳定、顺滑,也更适合真实项目维护。
服务端6月20日 11:26
TailwindCSS Typography 插件怎么用才稳?## Typography 插件适合解决什么问题? 如果页面里有 Markdown、CMS 富文本、博客正文或文档内容,直接用 Tailwind 原子类逐个给 `h2`、`p`、`ul`、`code`、`blockquote` 写样式会很累。`@tailwindcss/typography` 的作用就是给这类“长文本内容”提供一套默认排版样式。 它的核心类名是 `prose`。把 `prose` 加到内容容器上,容器里的标题、段落、列表、链接、代码、引用等元素都会获得更适合阅读的样式。 ```html <article class="prose"> <h2>标题</h2> <p>这里是一段来自 Markdown 或 CMS 的正文。</p> <a href="/docs">查看文档</a> </article> ``` 这种写法特别适合不方便逐个控制标签的内容来源,比如 Markdown 渲染后的文章页、CMS 后台录入的富文本、文档站正文、产品介绍页里的长文案模块。用户生成内容也可以用,但前提是已经做好 XSS 过滤。 ## Tailwind v3 怎么安装和配置? 在 Tailwind v3 中,Typography 是官方插件,但需要手动安装并加入 `tailwind.config.js`。 ```bash npm install -D @tailwindcss/typography ``` 然后在配置里引入插件: ```js // tailwind.config.js module.exports = { content: [ './src/**/*.{js,ts,jsx,tsx,mdx}', './content/**/*.{md,mdx}', ], theme: { extend: {}, }, plugins: [require('@tailwindcss/typography')], } ``` 如果文章内容在 `content`、`posts`、`docs` 这类目录里,记得把路径加入 `content` 扫描范围。否则 Tailwind 可能不会生成你在模板或 MDX 里用到的类名。 ## Tailwind v4 怎么使用? Tailwind v4 的配置方式更偏向 CSS 入口文件。Typography 插件可以通过 `@plugin` 引入: ```css @import "tailwindcss"; @plugin "@tailwindcss/typography"; ``` 如果项目已经升级到 v4,就不要照搬 v3 的 `plugins: [require(...)]` 写法。实际项目里最稳的做法是先确认当前 Tailwind 版本,再选对应配置方式。 ## prose 类怎么控制字号和宽度? `prose` 默认会限制正文宽度,让长段落更好读。这个限制对文章页通常是好事,但对后台预览、全宽文档、落地页模块可能会显得太窄。 ```html <article class="prose prose-lg max-w-none"> ... </article> ``` 常用类: | 类名 | 作用 | |---|---| | `prose` | 启用 Typography 默认排版 | | `prose-sm` | 更小的正文排版 | | `prose-base` | 默认尺寸 | | `prose-lg` | 更适合文章页的稍大字号 | | `prose-xl` | 更醒目的长文排版 | | `max-w-none` | 取消 Typography 默认最大宽度 | 如果是博客详情页,`prose prose-lg` 通常就够用;如果页面外层已经控制了宽度,可以加上 `max-w-none`,避免被插件再限制一次。 ## 深色模式怎么处理? Typography 插件内置了深色模式反转样式,常用类是 `dark:prose-invert`。 ```html <article class="prose prose-slate dark:prose-invert"> ... </article> ``` `prose-invert` 会让正文、标题、引用、代码等颜色更适合深色背景。如果项目本身使用 Tailwind 的 `dark` 类模式,外层切换 `dark` 后,这段内容就会自动适配。 ## prose-slate、prose-zinc 这些颜色类有什么用? Typography 提供了一组颜色主题,常见的有 `prose-slate`、`prose-gray`、`prose-zinc`、`prose-neutral`、`prose-stone`。 ```html <article class="prose prose-slate"> ... </article> ``` 它们会影响正文、标题、引用、边框、代码等元素的整体色调。一般来说,`prose-slate` 偏清爽,适合技术文章;`prose-zinc` 和 `prose-neutral` 更中性,适合后台、文档站或产品页。 颜色类不建议频繁混用。一个站点最好统一一种正文色调,否则不同文章页看起来会像拼在一起的。 ## 如何单独修改链接、代码和图片样式? Typography 插件支持元素修饰符,格式通常是 `prose-元素名:工具类`。 ```html <article class="prose prose-slate max-w-none prose-a:text-blue-600 prose-a:no-underline hover:prose-a:underline prose-code:rounded prose-code:bg-slate-100 prose-code:px-1 prose-img:rounded-xl prose-img:shadow-sm" > ... </article> ``` 常用元素修饰符包括 `prose-a:*`、`prose-headings:*`、`prose-h2:*`、`prose-p:*`、`prose-ul:*`、`prose-li:*`、`prose-code:*`、`prose-pre:*`、`prose-blockquote:*`、`prose-img:*`。 这比在全局 CSS 里写 `.article a {}` 更可控,也更符合 Tailwind 的写法。 ## not-prose 什么时候用? 如果 `prose` 容器里有一块内容不想被 Typography 接管,可以给那块内容加 `not-prose`。 ```html <article class="prose"> <p>这段会使用 Typography 样式。</p> <div class="not-prose"> <button class="rounded bg-blue-600 px-4 py-2 text-white"> 这个按钮不受 prose 影响 </button> </div> </article> ``` 典型场景是文章正文里嵌入组件,比如按钮、卡片、提示框、交互式 Demo。它们本来就有自己的样式,不应该被 `prose` 的段落、链接、列表规则改掉。 有一个细节要注意:`not-prose` 里面不要再嵌套新的 `prose`,这类嵌套在实际项目里容易出现样式不符合预期。需要新的长文区域时,最好把它放到外层结构里单独处理。 ## 如何自定义 Typography 样式? 如果只是改几个元素,优先用 `prose-a:*`、`prose-code:*` 这类修饰符。需要站点级统一样式时,再考虑在主题里扩展 typography。 Tailwind v3 可以在 `tailwind.config.js` 里这样写: ```js module.exports = { theme: { extend: { typography: ({ theme }) => ({ DEFAULT: { css: { '--tw-prose-links': theme('colors.blue.600'), '--tw-prose-bold': theme('colors.slate.900'), h2: { scrollMarginTop: '5rem', }, code: { fontWeight: '500', }, }, }, }), }, }, plugins: [require('@tailwindcss/typography')], } ``` Typography 内部大量使用 CSS 变量,例如 `--tw-prose-body`、`--tw-prose-headings`、`--tw-prose-links`、`--tw-prose-code`。改变量通常比硬改一堆选择器更稳。 ## 在 Markdown 或 CMS 页面里怎么落地? 真实项目里,Typography 最常见的用法是包住渲染后的 HTML。 ```tsx export function Article({ html }: { html: string }) { return ( <article className="prose prose-slate prose-lg max-w-none dark:prose-invert" dangerouslySetInnerHTML={{ __html: html }} /> ) } ``` 如果内容来自 CMS 或用户输入,重点不是 `prose`,而是安全处理。渲染前要做 HTML 清洗,避免把恶意脚本一起渲染出来。Typography 只负责排版,不负责内容安全。 MDX 场景会更灵活一些。普通正文交给 `prose`,交互组件放进 `not-prose`,这样排版和组件样式不互相打架。 ## 常见问题怎么避免? ### 正文太窄 这是 `prose` 默认最大宽度导致的。页面外层已经控制宽度时,给正文加 `max-w-none`。 ```html <article class="prose max-w-none"> ... </article> ``` ### 深色模式下颜色不对 检查是否加了 `dark:prose-invert`,以及项目的深色模式是否真的生效。只写 `prose-invert` 会让它一直使用暗色排版,不一定符合预期。 ### 自定义类没有生成 先看 `content` 扫描路径。Markdown、MDX、CMS 模板、组件目录如果没被扫描,Tailwind 就可能删掉没识别到的类。 对于动态拼接类名也要小心: ```js const size = 'lg' const className = `prose-${size}` ``` 这种写法可能不会被 Tailwind 正确识别。更稳的方式是写完整类名,或在配置里 safelist。 ### 组件样式被 prose 改乱 在文章里嵌按钮、卡片、表单时,用 `not-prose` 包起来。不要让 Typography 去管理本来就有设计规范的组件。 ### prose 嵌套 prose 尽量避免。外层已经是长文排版时,里面再放一个 `prose`,可能会出现间距、字体、颜色重复叠加的问题。需要分区时,用普通容器拆开更清楚。 ## 一套比较稳的默认写法 技术文章或文档页可以从下面这套类名开始: ```html <article class="prose prose-slate prose-lg max-w-none dark:prose-invert prose-a:text-blue-600 prose-a:no-underline hover:prose-a:underline prose-code:rounded prose-code:bg-slate-100 prose-code:px-1 dark:prose-code:bg-slate-800" > ... </article> ``` 这套写法覆盖了几个关键点:正文排版、阅读尺寸、深色模式、全宽控制、链接样式和行内代码样式。后续如果要调品牌色或标题间距,再放到主题配置里统一处理。 Typography 插件最适合管理不可控的长文本内容。能用 `prose` 解决的,不必给每个标签手写一遍样式;不该被它接管的组件,就用 `not-prose` 隔开。把这条边界分清,文章页和文档页的排版会省很多事。
服务端6月3日 00:08
TailwindCSS Grid 布局怎么用?常用布局模式和响应式网格实战TailwindCSS 的 Grid 类直接映射 CSS Grid 属性——grid-cols-N 设置列数,col-span-N 设置跨列,配合响应式前缀实现不同屏幕不同布局。 ## 基本网格 ```html <div class="grid grid-cols-3 gap-4"> <div>1</div> <div>2</div> <div>3</div> <div>4</div> <div>5</div> <div>6</div> </div> ``` grid-cols-3 = 三列等宽,gap-4 = 间距 1rem。TailwindCSS 预设 grid-cols-1 到 grid-cols-12。 ## 响应式网格 ```html <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <!-- 手机 1 列,平板 2 列,桌面 3 列 --> </div> ``` 最常见的卡片布局模式。移动端单列,平板双列,桌面三列。 ## 跨列和跨行 ```html <div class="grid grid-cols-4 gap-4"> <div class="col-span-2">占 2 列</div> <div>1 列</div> <div>1 列</div> <div class="col-span-4">占满整行</div> </div> ``` col-span-2 跨 2 列。row-span-2 跨 2 行。col-start / col-end 精确定位。 ## 经典布局:侧边栏 + 主内容 ```html <div class="grid grid-cols-[240px_1fr] gap-6"> <aside>侧边栏固定 240px</aside> <main>主内容自适应</main> </div> <!-- 响应式:移动端侧边栏隐藏 --> <div class="grid grid-cols-1 lg:grid-cols-[240px_1fr] gap-6"> <aside class="hidden lg:block">侧边栏</aside> <main>主内容</main> </div> ``` grid-cols-[240px_1fr] 用任意值语法设置侧边栏固定宽度。 ## 经典布局:圣杯布局 ```html <div class="grid grid-cols-1 md:grid-cols-[200px_1fr_200px] gap-4"> <header class="col-span-full">顶栏</header> <nav>左导航</nav> <main>主内容</main> <aside>右侧栏</aside> <footer class="col-span-full">底栏</footer> </div> ``` col-span-full 让 header 和 footer 跨满整行。 ## 自动填充 ```html <!-- 自动填充,每列最小 200px --> <div class="grid grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-4"> <div>卡片</div> <div>卡片</div> </div> ``` auto-fill 让列数根据容器宽度自动计算。适合不确定有多少项的列表。
服务端6月3日 00:08
TailwindCSS JIT 模式是什么?任意值语法和按需生成原理JIT(Just-In-Time)模式是 TailwindCSS v3 的默认引擎——按需生成 class,而不是预生成所有可能的组合。这让产物体积从 MB 级降到 KB 级,同时支持任意值语法。 ## JIT 之前:AOT 模式 TailwindCSS v2 及以前用 AOT(Ahead-Of-Time)模式:构建时生成所有 class 组合(所有颜色 x 所有尺寸 x 所有断点),产物可能 3-5MB。然后通过 purge 删除未使用的 class。 问题:不支持任意值(text-[13px] 这种写法不工作),构建慢,purge 配置容易出错。 ## JIT 模式的工作原理 JIT 不预生成所有 class,而是扫描源码中实际使用的 class,只生成这些。你写了 text-red-500 就生成,没写就不生成。 结果: - 开发时 CSS 只有几 KB(而不是几 MB),浏览器加载快 - 支持任意值:text-[13px]、grid-cols-[17]、top-[calc(100%-1rem)] - 不需要 purge 步骤(JIT 本身就是按需生成) ## 任意值语法 方括号 [] 里写任意 CSS 值: ```html <div class="text-[13px] mt-[27px] bg-[#1da1f2]"> <div class="grid-cols-[1fr_2fr_1fr]"> <div class="top-[calc(100%-1rem)]"> ``` 任意值是 JIT 的杀手锏——不再被预定义的断点/颜色/间距限制。但不要滥用:如果一个值在多处使用,应该加到 @theme 配置里(如 --spacing-18: 4.5rem),而不是到处写方括号。 ## JIT 的局限 - 动态拼接的 class 无法被检测(const color = 'bg-' + variant) - 某些复杂表达式在方括号里可能解析失败(包含 _ 和空格的值需要特殊转义) - 构建时需要扫描所有模板文件(大项目可能稍慢) ## v4 的改进 v4 的 Oxide 引擎进一步优化了 JIT——用 Rust 重写扫描和生成逻辑,构建速度提升 10 倍。同时改进了任意值解析,支持更多 CSS 函数和表达式。
服务端6月3日 00:08
TailwindCSS 是什么?和 Bootstrap 有什么区别?核心优势详解TailwindCSS 是一个 utility-first 的 CSS 框架——不提供预制的组件(如 .btn、.card),而是提供原子化的 utility class(如 .bg-blue-500、.text-center、.p-4),让你在 HTML 里组合出任何设计。 ## 和 Bootstrap 的区别 Bootstrap 给你现成组件:btn-primary、card、navbar。快速但长得都一样。 TailwindCSS 给你积木块:p-4、bg-blue-500、rounded-lg。慢一点但完全自定义。 选择标准:需要快速原型用 Bootstrap,需要自定义设计用 TailwindCSS。 ## 核心优势 **1. 不用起名字**。写 CSS 最烦的是想 class 名——.header-wrapper、.card-inner-container?TailwindCSS 直接写 utility class,不用起名。 **2. 不用切换文件**。样式写在 HTML 里,不用在 HTML 和 CSS 文件之间跳来跳去。修改某个元素样式时,直接改那一行 class,不用去 CSS 文件里找对应选择器。 **3. 产物小**。JIT 模式只生成你用到的 class。一个页面只用 50 个 class,CSS 就只有几 KB。Bootstrap 整包 150KB+。 **4. 响应式简单**。不用写 @media 查询: ```html <div class="text-sm md:text-base lg:text-lg"> 移动端小字,桌面端大字 </div> ``` sm/md/lg/xl/2xl 是预设断点,覆盖 99% 的响应式需求。 ## 常见反对意见 **"HTML 里一堆 class 太丑了"**:确实不如语义化 class 好看。但实用——不用起名、不用切换文件、不用怕样式冲突。团队习惯后效率反而更高。 **"和 inline style 有什么区别"**:inline style 没有响应式(@media)、没有状态变体(hover:focus)、没有设计约束(只能用预定义值)。TailwindCSS 都有。 **"难以复用"**:用 @apply 提取复用组合,或封装成组件(React/Vue 组件)。大多数情况下组件级复用比 CSS 级复用更好。 ## 快速开始 ```bash npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p ``` ```css /* app.css */ @tailwind base; @tailwind components; @tailwind utilities; ``` ```html <h1 class="text-3xl font-bold text-blue-600 hover:text-blue-800"> Hello TailwindCSS </h1> ```
服务端6月3日 00:06
TailwindCSS 性能怎么优化?构建速度和产物体积优化实战TailwindCSS 的性能分两方面:开发时的构建速度和最终 CSS 产物体积。v4 已经解决了构建速度问题(Rust 引擎),产物体积通过 tree-shaking 自动处理。需要手动优化的是避免动态 class 等性能陷阱。 ## CSS 产物体积:tree-shaking 自动处理 TailwindCSS v3+ 用 JIT 模式——只生成你实际使用的 class,不用的不会出现在 CSS 里。不需要手动 purge(v2 时代的做法)。 检查产物大小: ```bash npx tailwindcss --minify -i input.css -o output.css ``` 典型产物:5-30KB(gzip 后 2-8KB)。如果超过 50KB,说明配置有问题或写了动态 class。 ## 避免动态 class 组合 JIT 模式通过扫描源码中的完整 class 名来做 tree-shaking。动态拼接的 class 无法被检测到: ```jsx // 错误:JIT 无法检测 div className={isPrimary ? 'bg-blue-500' : 'bg-gray-200'} // 更复杂的情况用 clsx import clsx from 'clsx'; div className={clsx('px-4 py-2 rounded', { 'bg-blue-500 text-white': isPrimary, 'bg-gray-200 text-gray-800': !isPrimary, })} ``` 关键原则:所有可能的 class 名必须以完整字符串出现在源码里。 ## @apply 的使用建议 @apply 把 utility class 组合成自定义 class。不会增加产物体积,但会让 CSS 更难维护。建议:只在需要复用复杂组合时用 @apply。 ## 生产构建检查清单 1. content 配置覆盖了所有模板文件路径 2. 没有动态拼接 class 名 3. 用 --minify 压缩 CSS 4. 启用 gzip/brotli 压缩 5. 最终 CSS gzip 后小于 10KB 为理想状态
服务端6月3日 00:06
TailwindCSS v4 有什么新变化?从 v3 迁移指南TailwindCSS v4 是一次底层重写——从 PostCSS 插件变成了 Rust 编写的独立引擎,构建速度提升 10 倍。配置方式也从 tailwind.config.js 变成了 CSS 原生配置。API 变化不大,但工具链完全不同。 ## 最大的变化:Oxide 引擎 v3 用 PostCSS + Node.js 处理 CSS,大项目构建可能要 500ms+。v4 用 Rust 写的 Oxide 引擎,同样的项目降到 5ms。实际感受:v3 修改一个 class 要等几百毫秒才看到变化,v4 几乎即时。 ## 配置方式变了 v3 用 JavaScript 配置文件,v4 用 CSS 原生配置: ```css @import "tailwindcss"; @theme { --color-brand: #3b82f6; --font-sans: "Inter", sans-serif; } ``` 不再需要 tailwind.config.js。所有自定义都写在 CSS 的 @theme 块里。这个变化是 v4 迁移的主要工作量。 ## 自动内容检测 v3 需要在配置里指定 content 路径。v4 自动检测项目中的模板文件,不需要配置。 ## 新的 CSS 特性支持 v4 原生支持更多现代 CSS 特性: - 容器查询:@container 变体开箱即用 - 3D 变换:rotate-x、rotate-y、translate-z 等 - color-mix:动态混色 ```html <div class="@container"> <div class="@sm:grid-cols-2 @lg:grid-cols-3">...</div> </div> ``` ## 迁移步骤 1. 升级依赖:npm install tailwindcss@4 @tailwindcss/vite 2. 把 tailwind.config.js 的自定义迁移到 @theme 块 3. 删除 content 配置(自动检测) 4. 把 @tailwind 指令改成 @import "tailwindcss" 5. 运行 npx @tailwindcss/upgrade 自动迁移大部分代码 ## v4 的不足 - 插件生态还在迁移中,很多 v3 插件不兼容 - 文档还在完善 - 某些 @apply 嵌套行为不同 新项目直接用 v4。现有项目不急迁移——v3 仍在维护。