Skip to main content

核心概念 Core Concepts

功能类优先 Utility-First Fundamentals

在一组受约束的原始功能类的基础上构建复杂的组件。

受约束 (设计)
原子功能类(可组合) (原子化css)

使用传统方式时,定制的设计需要定制的 CSS
使用功能类构建自定义设计而无需编写 CSS

与传统css方式

优点:

  1. 不用浪费大量精力给类命名
  2. css 文件不用一直增长。使用传统方法,每次添加新功能css 文件都会变大。使用功能类,所有内容可重用,几乎不需要编写新的css。 tree-shaking 后,压缩后css体积可以达到10kb以下。
  3. 更改安全。 css 全局的,更改css文件可能会影响其他。通过更改html中的类修改样式,不用担心会影响到其他。

与传统内联样式

优点:

  • 基于约束的设计。
    功能类是从预定义的设计系统中选择样式,构建的ui 更统一。内联样式,样式任意设置。

  • 响应式的设计。

    内联样式不能使用媒体查询,但 Tailwind 可通过响应式功能类(responsive utilities) 构建响应式的界面。 sm:py-4 sm:flex sm:items-center

  • Hover, focus, 以及其它状态变体。

    内联样式无法设置 hover 或者 focus 这样的状态, 但 Tailwind 的状态变体(state variants)使用功能类可以非常容易的为这些状态设置样式。 hover:text-white hover:bg-purple-600

可维护性问题

<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"></button>

管理常用的重复的功能类组合

通过提取组件(通常作为模板片段或者组件)鹤 利用编辑器和语言特点循环。

维护功能优先的css 项目比维护大型css 代码库容易。html比css维护容易得多。

响应式设计 (变体)

Tailwind 中的每个功能类都可以有条件的应用于不同的断点(breakpoints)。
在html中通过添加响应式变体前缀 + 功能类,实现不同分辨率设备上属性样式切换。

根据常用的设备分辨率方案,默认内置了 5 个断点:

断点前缀最小宽度CSS
sm640px@media (min-width: 640px) { ... }
md768px@media (min-width: 768px) { ... }
lg1024px@media (min-width: 1024px) { ...}
xl1280px@media (min-width: 1280px) { ...}
2xl1536px@media (min-width: 1536px) { ...}
<img class="w-16 md:w-32 lg:w-48" src="...">
  • 移动优先:这意味着未加前缀的功能类 (像 uppercase) 在所有的屏幕上都有效,而加了前缀的功能类(如 md:uppercase)仅在指定断点及以上的屏幕上生效。 默认为min-width

  • 定位移动设备 为移动设备设计样式,应使用无前缀的功能类,而不是带sm:前缀的,sm 是在小断点处,而不是在小屏幕上。
    注意:× 不要用sm: 定位移动设备,√ 应该使用无前缀的功能类来定位移动设备,并在较大的断点处覆盖

    推荐做法: 先为移动设备布局,然后在其他断点处覆盖更改

  • 定位单个断点 tailwind的断点只有min-width, 没有max-width; 这意味着在较小的断点上添加 的任何功能类都将在更大的断点上生效。

    如果只想在一个断点上应用某个功能类,解决方案是在更大的断点上添加另一个功能类,用来抵消前一个功能类的效果。

<div class="bg-green-500 md:bg-red-500 lg:bg-green-500">
<!-- ... -->
</div>

tailwindcss 中 断点可实现重写、扩展、设置pc优先、多范围断点、完全自定义媒体查询(css媒体查询)。
配置屏幕尺寸时 注意顺序

断点:https://www.tailwindcss.cn/docs/breakpoints

version: 3.1.7

设置hover、focus 等样式(修饰符)

使用功能类设置hover、focus等元素样式。

通过在类名的前面添加一个相对应状态的修饰符,设置该状态下的样式。 tailwind中的每个功能类能被条件性地设置。

input: hover:bg-purple-700
output:

.hover\:bg-purple-700:hover {
--tw-bg-opacity: 1;
background-color: rgb(126 34 206 / var(--tw-bg-opacity));
}
<form>
<input class="border border-transparent focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent ...">
<button class="bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-purple-600 focus:ring-opacity-50 ...">
Sign up
</button>
</form>

与传统css 添加相比

hover 传统写法 需要设置指定类名,然后给类名添加hover 状态设置样式。 hover tailwind中,在html 中添加hover状态样式,该样式在默认况下,不会生效。

This is what we mean when we say a utility class can be applied conditionally — by using modifiers you can control exactly how your design behaves in different states, without ever leaving your HTML.

多种修饰可叠加 在同一个功能类

dark:md:hover:bg-fuchsia-600

多个修饰符叠加 调用是由内到外。

// These modifiers:
`dark:group-hover:focus:opacity-100`

// ...are applied like this:
dark(groupHover(focus('opacity-100')))

注意一些特殊叠加顺序 例如dark的顺序, 如果dark 模式为class dark类需要设置在html 上,dark 应该设置在最外层才起作用。

/* dark:group-hover:opacity-100 */
.dark .group:hover .dark\:group-hover\:opacity-100 {
opacity: 1;
}

/* group-hover:dark:opacity-100 */
.group:hover .dark .group-hover\:dark\:opacity-100 {
opacity: 1;
}

修饰符 种类

伪类
伪元素
媒体查询
属性选择
特殊变体(dark, 响应式变体)
自定义变体 [&:nth-child(3)]: 、 addVariant plugin API

<li class="[&:nth-child(3)]:underline">{item}</li>

If you need spaces in your selector, you can use an underscore. You can also use at-rules like @media or @supports in arbitrary variants

<button type="button" class="[@media(any-hover:hover){&:hover}]:opacity-100">
<!-- ... -->
</button>
let plugin = require('tailwindcss/plugin')

module.exports = {
// ...
plugins: [
plugin(function ({ addVariant }) {
// Add a `third` variant, ie. `third:pb-0`
addVariant('third', '&:nth-child(3)')
})
]
}

这些修饰符 也可以作用在自定义的类中,使用layers 与 plugin 添加的自定义功能类。

默认修饰符 附录表: https://tailwindcss.com/docs/hover-focus-and-other-states?contrast-example=00-00-00#ordering-stacked-modifiers

深色模式

Tailwind 包含一个 dark 变体,当启用深色模式时,您可以为您的网站设置不同的样式。

默认情况下,使用prefers-color-scheme用户偏好设置,也可使用class 模式手动设置切换暗黑模式。

class 模式需要在html 标签添加dark 类名,如果配置了prefix,dark 也需要加前缀。

// tailwind.config.js
module.exports = {
darkMode: 'media', // prefers-color-scheme
// darkMode: 'class' // <html class="dark"></html> class 模式,可手动切换模式
// darkMode: ['class', '[data-mode="dark"]'] // 使用自定义的dark 模式选择器名称设置
// ...
}

js 判断系统偏好 window.matchMedia('(prefers-color-scheme: dark)').matches

样式复用

  • 多光标编辑

  • 循环遍历

  • 创建组件/模板片段
    不要根据css 类提取复杂组件。要使用模板片段或者js组件, HTML结构与css一起结合。

  • 通过@apply 提取类 (不提倡多使用,适用按钮,表单控件等小且高度可复用的组件)

不要过早抽象,为了看起来干净整洁过早使用@apply,虽然html模板中充斥着tailwind类难看,但是在大量自定义css项目中进行更改更糟糕。

如果过渡使用@apply 违背tailwind初衷,造成命名困难,维护困难,css bundle 变大等问题。

自定义与扩展

自定义主题 tailwind.config.js -> theme

使用任意值

使用任意值 class="text-[f60]"

.text-\[\#f60\] {
--tw-text-opacity: 1;
color: rgb(255 102 0 / var(--tw-text-opacity));
}

如果多处使用 class="text-[f60]" css 文件只生成一个

使用任意属性

<div class="[mask-type:luminance]"><div>

也可用于设置css 变量: <div class="[--scroll-offset:56px] lg:[--scroll-offset:44px]"></div>

可以添加各种修饰符

任意变量使用语法

  • []

  • 需要空格时候 用_ 代替 有些下划线转义成空格无效的情况下,tailwind 会保留下划线,不会转换成空格

  • 需要使用下划线时候_ 使用反斜杠转义下划线 <h1 class="before:content-['hello\_world']">测试文字</h1>

  • 解析模糊歧义属性值 text-black 与 text-lg 都是text- 命名,但分别表示color 与 font-size。如果通过[]设置值 会自动根据传入的值判断生成什么类。

    如果传入的是变量或者难以判断传入的css值属于哪种类型,可以在值之前添加css数据类型来提示。 https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types

    <!-- Will generate a font-size utility -->
    <div class="text-[length:var(--my-var)]">...</div>

    <!-- Will generate a color utility -->
    <div class="text-[color:var(--my-var)]">...</div>

@layer 使用@layer指令在css 中添加自定义样式

@layer 指令 通过自动将样式定位到相应的@tailwind 指令来控制声明顺序,并且能够为自定义的css 启用修改器tree-shaking等功能。

3 个不同的层:base | components | utilities

  • base: 重置和默认样式

    /* 注意顺序 */
    @tailwind base;
    @tailwind components;
    @tailwind utilities;

    @layer base {
    h1 {
    @apply text-2xl;
    }
    h2 {
    @apply text-xl;
    }
    /* ... */
    }
  • components: 基于类的样式

  • utilities: 小的、单一功能类,层级应始终优先于其他样式,方便覆盖

    任何添加到base, components, or utilitieslayers的样式,会启用tree-shaking, 只有在被使用监测到时候才会被编译到css bundle中。

    如果有不想被tree-shaking 移除的未使用到的样式(js 特殊设置等)不要使用@layer. 注意样式定义位置 如果是自定义组件类需要编写在组件下面, 功能类上面, 确保原子类的优先级大于组件类。

使用多个css文件

写多个css 文件时候,需要每个css文件都注入@tailwind...层 ,不然,使用@layer @variants之类的就会报错; 可以通过 postcss-import 插件帮助解决@import 导入问题,但是@import 被要求放在文件顶部, 这样生成的bundle样式顺序就会可能存在问题。

https://tailwindcss.com/docs/using-with-preprocessors#build-time-imports

推荐做法

@import "tailwindcss/base";
@import "./custom-base-styles.css";

@import "tailwindcss/components";
@import "./custom-components.css";

@import "tailwindcss/utilities";
@import "./custom-utilities.css";

layers 和 per-component CSS(组件内<style>块)

组件内<style>中不能使用 @layer 能使用theme(), 但不推荐样式写在组件的style 中,而是推荐写在html行内

使用插件

也可以使用插件添加自定义样式。

const plugin = require('tailwindcss/plugin')
module.exports = {
// ...
plugins: [
plugin(function ({ addBase, addComponents, addUtilities, theme }) {
addBase({
'h1': {
fontSize: theme('fontSize.2xl'),
},
'h2': {
fontSize: theme('fontSize.xl'),
},
})
addComponents({
'.card': {
backgroundColor: theme('colors.white'),
borderRadius: theme('borderRadius.lg'),
padding: theme('spacing.6'),
boxShadow: theme('boxShadow.xl'),
}
})
addUtilities({
'.content-auto': {
contentVisibility: 'auto',
}
})
})
]
}

函数与指令

tailwind 暴露在css 中的函数与指令。

指令

自定义的 tailwind中 @规则,可以在css 中提供特定功能。

@tailwind

插入 base, components, utilities and variants 样式。(注意注入位置顺序与生成的css样式作用位置)

/**
* 注入 重置样式/默认样式 和 通过插件注册的base styles
*/
@tailwind base;

/**
* 注入 组件类 和 通过插件注册的 component classes
*/
@tailwind components;

/**
* 注入原子功能类 和 通过插件注册的 utility classes
*/
@tailwind utilities;

/**
*控制各种变体/修饰符的注入位置, 如果忽略 tailwind 默认插入这些修饰类 在样式表最后面
*/
@tailwind variants;

@layer

声明自定义样式时候,指明属于是哪层的css, Tailwind会自动将样式移到@tailwind相对应的该层插入位置,而不用担心自定义样式的编写位置。

通过@layer添加的自定义样式,(tree-shaking自动生效) 只有在HTML的中使用了才会被打包到bundle 中,与默认classes 一样。 通过@layer添加的自定义样式,(modifiers自动生效) 可以添加修饰类前缀。

@apply

将现有的功能类内联到自定义的css 中。

如果自定义的css中想添加tailwind 中的设计的功能类。可以使用@apply

通过@apply 内联的规则,默认移除!important 避免特殊问题。

@layer components {
.test-imp {
@apply red;
color: blue;
}
}

@layer utilities {
.red {
color: red !important;
}
}

/* 输出 red 的!important 已移除,被后面的 blue 覆盖 */
.test-imp {
color: red;
color: blue;
}

可以将!important 添加在 @apply 后面

.test-imp {
@apply red !important;
color: blue;
}

/* 输出 */
.test-imp {
color: red !important;
color: blue;
}

如果是使用Sass/SCSS, 需要使用其自己的插值特点生效。

@apply 与 per-component CSS

像Vue和Svelte 等组件框架支持在每个组件文件中的<style>块中添加样式。 如果你在这些组件的<style>块中使用@apply来使用全局css中定义的自定义类,将报错不存在该类。 这是因为在底层,像Vue和Svelte 等框架是独立处理每个<style>块,并且针对每个块单独运行postcss插件。 这意味着如果你有10个组件且每个组件都有一个<style>块, tailwind 将会被独立运行10次,并且相互没有关联,没有影响。 因此当你想要在组件的css块中使用@apply引用在全局自定义的类时候,会报错,因为Tailwind在当前组件的css 中找不到自定义的全局类,因为Tailwind 处理当前组件css 与 全局main.css 是完全隔离的。

解决方案就是通过plugins添加全局自定义类,这样Tailwind 处理任何 使用到此配置文件的文件都可以访问这些样式。但是最好是不要有这些奇怪的行为。

Functions

Tailwind 提供一些自定义函数,你可以在css通过这些函数来访问Tailwind中设定的特定的值。 这些函数在构建时进行评估,在最终css中被静态值替换。

theme()

使用.或者[],访问Tailwind 配置值。

.content-area {
height: calc(100vh - theme(spacing.12));
}
/* 带 . 的值 可以使用 [] 访问 */
.content-area {
height: calc(100vh - theme(spacing[2.5]));
}
/* 不要用下划线访问color值 颜色是嵌套object语法定义的 */
.btn-blue {
background-color: theme(colors.blue.500);
}
/* 设置颜色不透明度 可以通过斜线 + opacity值 设置 */
.btn-blue {
background-color: theme(colors.blue.500 / 75%);
}

screen()

在css中写媒体查询时候,可以用断点名称,设定屏幕范围值。它将在构建时解析该断点下的屏幕值,生成与断点匹配的媒体查询。

@media screen(sm) {
/* ... */
}
/* 输出 */
@media (min-width: 640px) {
/* ... */
}