指南与教程 - 背景图片 | Rainy Design Studio

Tailwind CSS v4 开发指南

RainyJun 01, 2026

本文章的版权归属 Rainy Design Studio - 雨点设计工作室 ,且最终解释权归站长所有。
除本站自媒体官号以外,本文的内容禁止任一组织、个人、账号或平台,以任何形式转载到 RainyDesign.cn 站外。
任何个人或组织进行非法转载的,本站工作人员可对其追究法律责任。

具体信息详见 条例与条款

Tailwind CSS 指南

一、前言

1.1 文档背景

就 Tailwind CSS 官方文档来看,单单一个 核心理念 的知识点就够我们学习十数个小时了,所以为了配合教程,我们决定还是将深度知识点单拎出来讲解。

本文会不定期更新,具体请以最新内容为准;当前内容适配的版本是 Tailwind CSS v4.1 。
搜索文章内容请按下键盘上的Ctrl(Mac为Command) + F查找,
收藏文章请按下键盘上的Ctrl / Command + D加入书签栏。

二、类名速查

本小节仅收录了 Tailwind v4.1 常用的实用类名作为一个简化列表方便查阅学习。如需了解完整的实用类名,请查阅 Tailwind CSS - 官方文档 - 布局 获取更多信息。

小提示:如需快速查阅并复制 Tailwind CSS Color 的各项属性,请访问 Tailwind v4 颜色选择器 - Rainy Design Studio | 雨点设计工作室 了解。

2.1 布局(layout)

类名属性说明
blockdisplay: block块级元素
inlinedisplay: inline内联元素
inline-blockdisplay: inline-block内联块元素
flexdisplay: flex弹性盒容器
griddisplay: grid网格容器
hiddendisplay: none隐藏元素
staticposition: static静态定位
relativeposition: relative相对定位
absoluteposition: absolute绝对定位
fixedposition: fixed固定定位
stickyposition: sticky粘性定位
top-0top: 0px顶部偏移
right-0right: 0px右侧偏移
bottom-0bottom: 0px底部偏移
left-0left: 0px左侧偏移
z-10z-index: 10层级索引
float-leftfloat: left左浮动
float-rightfloat: right右浮动
clear-bothclear: both清除浮动

2.2 弹性盒与网格(Flexbox & Grid)

类名属性说明
flex-rowflex-direction: row水平排列
flex-colflex-direction: column垂直排列
flex-wrapflex-wrap: wrap允许换行
flex-nowrapflex-wrap: nowrap不换行
justify-startjustify-content: flex-start主轴起始对齐
justify-centerjustify-content: center主轴居中对齐
justify-betweenjustify-content: space-between主轴两端对齐
items-startalign-items: flex-start交叉轴起始对齐
items-centeralign-items: center交叉轴居中对齐
items-endalign-items: flex-end交叉轴末尾对齐
flex-1flex: 1 1 0%弹性增长
flex-autoflex: 1 1 auto自动弹性
flex-noneflex: none不弹性
growflex-grow: 1允许增长
shrinkflex-shrink: 1允许收缩
grid-cols-12grid-template-columns: repeat(12, minmax(0, 1fr))12列网格
col-span-6grid-column: span 6 / span 6跨越6列
gap-4gap: 1rem网格间隙

2.3 间距(Spacing)

类名属性说明
m-0margin: 0px无外边距
m-1margin: 0.25rem4px外边距
m-4margin: 1rem16px外边距
mx-automargin-left: auto; margin-right: auto水平居中
mt-4margin-top: 1rem顶部外边距
mr-4margin-right: 1rem右侧外边距
mb-4margin-bottom: 1rem底部外边距
ml-4margin-left: 1rem左侧外边距
p-0padding: 0px无内边距
p-1padding: 0.25rem4px内边距
p-4padding: 1rem16px内边距
px-4padding-left: 1rem; padding-right: 1rem水平内边距
py-4padding-top: 1rem; padding-bottom: 1rem垂直内边距
pt-4padding-top: 1rem顶部内边距
pr-4padding-right: 1rem右侧内边距
pb-4padding-bottom: 1rem底部内边距
pl-4padding-left: 1rem左侧内边距
space-x-4> * + * { margin-left: 1rem }子元素水平间距
space-y-4> * + * { margin-top: 1rem }子元素垂直间距

2.4 版式(Typography)

类名属性说明
text-xsfont-size: 0.75rem12px字体
text-smfont-size: 0.875rem14px字体
text-basefont-size: 1rem16px字体
text-lgfont-size: 1.125rem18px字体
text-xlfont-size: 1.25rem20px字体
text-2xlfont-size: 1.5rem24px字体
font-thinfont-weight: 100极细字重
font-normalfont-weight: 400正常字重
font-boldfont-weight: 700粗体字重
italicfont-style: italic斜体
text-lefttext-align: left左对齐
text-centertext-align: center居中对齐
text-righttext-align: right右对齐
text-blackcolor: rgb(0 0 0)黑色文字
text-whitecolor: rgb(255 255 255)白色文字
text-red-500color: rgb(239 68 68)红色文字
leading-tightline-height: 1.25紧密行高
leading-normalline-height: 1.5正常行高
tracking-wideletter-spacing: 0.025em字母间距

2.5 背景(Background)

类名属性说明
bg-transparentbackground-color: transparent透明背景
bg-blackbackground-color: rgb(0 0 0)黑色背景
bg-whitebackground-color: rgb(255 255 255)白色背景
bg-red-500background-color: rgb(239 68 68)红色背景
bg-blue-500background-color: rgb(59 130 246)蓝色背景
bg-opacity-50background-color: rgb(0 0 0 / 0.5)背景透明度
bg-gradient-to-rbackground-image: linear-gradient(to right, ...)右向渐变
from-blue-500--tw-gradient-from: var(--color-blue-500)渐变起始色
via-purple-500--tw-gradient-via: var(--color-purple-500)渐变过渡色
to-red-500--tw-gradient-to: var(--color-red-500)渐变结束色
from-10%--tw-gradient-from-position: 10%渐变起始位置
via-30%--tw-gradient-via-position: 30%渐变过渡位置
to-80%--tw-gradient-to-position: 90%渐变结束位置
bg-coverbackground-size: cover背景覆盖
bg-containbackground-size: contain背景包含
bg-centerbackground-position: center背景居中
bg-no-repeatbackground-repeat: no-repeat背景不重复
bg-repeatbackground-repeat: repeat背景重复
bg-fixedbackground-attachment: fixed背景固定

2.6 边框(Border)

类名属性说明
borderborder-width: 1px1px边框
border-0border-width: 0px无边框
border-2border-width: 2px2px边框
border-tborder-top-width: 1px顶部边框
border-rborder-right-width: 1px右侧边框
border-bborder-bottom-width: 1px底部边框
border-lborder-left-width: 1px左侧边框
border-solidborder-style: solid实线边框
border-dashedborder-style: dashed虚线边框
border-dottedborder-style: dotted点线边框
border-blackborder-color: rgb(0 0 0)黑色边框
border-gray-300border-color: rgb(209 213 219)灰色边框
rounded-noneborder-radius: 0无圆角
roundedborder-radius: 0.25rem圆角
rounded-lgborder-radius: 0.5rem大圆角
rounded-xlborder-radius: 0.75remxl圆角
rounded-2xlborder-radius: 1rem2xl圆角
rounded-3xlborder-radius: 1.5rem3xl圆角
rounded-4xlborder-radius: 2rem4xl圆角
rounded-fullborder-radius: 9999px完全圆角
rounded-tborder-top-left-radius: 0.25rem; border-top-right-radius: 0.25rem顶部圆角
divide-y> * + * { border-top-width: 1px }子元素分割线

2.7 效果(Effects)

类名属性说明
shadow-2xsbox-shadow: 0 1px rgb(0 0 0 / 0.05)2xs阴影
shadow-xsbox-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05)xs阴影
shadowbox-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1)阴影
shadow-smbox-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)小阴影
shadow-mdbox-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)中阴影
shadow-lgbox-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)大阴影
shadow-xlbox-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)xl阴影
shadow-2xlbox-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25)2xl阴影
shadow-(color:<custom-property>)box-shadow: --tw-shadow-color: var(<custom-property>)阴影颜色
shadow-nonebox-shadow: 0 0 #0000无阴影
shadow-innerbox-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05)内阴影
drop-shadowfilter: drop-shadow(0 1px 2px rgb(0 0 0 / 0.1))投影滤镜
opacity-0opacity: 0完全透明
opacity-50opacity: 0.5半透明
opacity-100opacity: 1完全不透明
mix-blend-multiplymix-blend-mode: multiply混合模式
bg-blend-overlaybackground-blend-mode: overlay背景混合
outline-noneoutline: 2px solid transparent无轮廓
outlineoutline: 2px solid #3b82f6蓝色轮廓
ringbox-shadow: 0 0 0 3px rgb(59 130 246 / 0.5)环形阴影
ring-2box-shadow: 0 0 0 2px rgb(59 130 246 / 0.5)2px环形阴影

2.8 过滤器(Filters)

类名属性说明
blurfilter: blur(8px)模糊滤镜
blur-smfilter: blur(4px)小模糊
blur-nonefilter: blur(0)无模糊
brightness-50filter: brightness(0.5)亮度50%
brightness-100filter: brightness(1)正常亮度
contrast-50filter: contrast(0.5)对比度50%
contrast-100filter: contrast(1)正常对比度
grayscalefilter: grayscale(100%)灰度滤镜
grayscale-0filter: grayscale(0)无灰度
hue-rotate-90filter: hue-rotate(90deg)色相旋转
invertfilter: invert(100%)反色滤镜
saturate-50filter: saturate(0.5)饱和度50%
sepiafilter: sepia(100%)棕褐色滤镜
backdrop-blur-xsbackdrop-filter: blur(4px)背景模糊
backdrop-blur-smbackdrop-filter: blur(8px)背景模糊
backdrop-blur-mdbackdrop-filter: blur(12px)背景模糊
backdrop-blur-lgbackdrop-filter: blur(16px)背景模糊
backdrop-blur-xlbackdrop-filter: blur(24px)背景模糊
backdrop-blur-2xlbackdrop-filter: blur(40px)背景模糊
backdrop-blur-3xlbackdrop-filter: blur(64px)背景模糊
backdrop-brightness-50backdrop-filter: brightness(0.5)背景亮度

2.9 表格(Tables)

类名属性说明
tabledisplay: table表格显示
table-rowdisplay: table-row表格行
table-celldisplay: table-cell表格单元格
table-autotable-layout: auto自动表格布局
table-fixedtable-layout: fixed固定表格布局
border-collapseborder-collapse: collapse边框合并
border-separateborder-collapse: separate边框分离
caption-topcaption-side: top标题在顶部
caption-bottomcaption-side: bottom标题在底部
empty-cells-showempty-cells: show显示空单元格
empty-cells-hideempty-cells: hide隐藏空单元格

2.10 过渡和动画(Transitions & Animation)

类名属性说明
transitiontransition-property: all; transition-duration: 150ms过渡效果
transition-nonetransition-property: none无过渡
transition-colorstransition-property: color, background-color, border-color颜色过渡
transition-opacitytransition-property: opacity透明度过渡
transition-transformtransition-property: transform变形过渡
duration-75transition-duration: 75ms75ms持续时间
duration-300transition-duration: 300ms300ms持续时间
ease-lineartransition-timing-function: linear线性缓动
ease-intransition-timing-function: cubic-bezier(0.4, 0, 1, 1)缓入
ease-outtransition-timing-function: cubic-bezier(0, 0, 0.2, 1)缓出
delay-75transition-delay: 75ms75ms延迟
animate-spinanimation: spin 1s linear infinite旋转动画
animate-pinganimation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite脉冲动画
animate-pulseanimation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite呼吸动画
animate-bounceanimation: bounce 1s infinite弹跳动画

2.11 变形(Transforms)

类名属性说明
transformtransform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))启用变形
transform-nonetransform: none无变形
translate-x-0--tw-translate-x: 0pxX轴位移0
translate-x-1--tw-translate-x: 0.25remX轴位移4px
translate-y-0--tw-translate-y: 0pxY轴位移0
translate-y-1--tw-translate-y: 0.25remY轴位移4px
-translate-x-1--tw-translate-x: -0.25remX轴负位移
rotate-0--tw-rotate: 0deg旋转0度
rotate-45--tw-rotate: 45deg旋转45度
rotate-90--tw-rotate: 90deg旋转90度
-rotate-45--tw-rotate: -45deg逆时针旋转45度
skew-x-0--tw-skew-x: 0degX轴倾斜0度
skew-x-12--tw-skew-x: 12degX轴倾斜12度
skew-y-12--tw-skew-y: 12degY轴倾斜12度
scale-0--tw-scale-x: 0; --tw-scale-y: 0缩放为0
scale-50--tw-scale-x: 0.5; --tw-scale-y: 0.5缩放50%
scale-100--tw-scale-x: 1; --tw-scale-y: 1正常缩放
scale-x-50--tw-scale-x: 0.5X轴缩放50%
origin-centertransform-origin: center变形中心点
origin-toptransform-origin: top顶部为中心

2.12 互动性(Interactivity)

类名属性说明
cursor-autocursor: auto自动光标
cursor-pointercursor: pointer手型光标
cursor-not-allowedcursor: not-allowed禁用光标
cursor-waitcursor: wait等待光标
cursor-textcursor: text文本光标
cursor-movecursor: move移动光标
pointer-events-nonepointer-events: none禁用指针事件
pointer-events-autopointer-events: auto启用指针事件
resize-noneresize: none不可调整大小
resizeresize: both可调整大小
resize-xresize: horizontal水平调整大小
resize-yresize: vertical垂直调整大小
select-noneuser-select: none不可选择文本
select-textuser-select: text可选择文本
select-alluser-select: all全选文本
select-autouser-select: auto自动选择
appearance-noneappearance: none移除默认样式
outline-noneoutline: 2px solid transparent移除焦点轮廓
focus:outline-noneoutline: 2px solid transparent焦点时移除轮廓
focus:ringbox-shadow: 0 0 0 3px rgb(59 130 246 / 0.5)焦点环形阴影

2.13 SVG

类名属性说明
fill-currentfill: currentColor填充当前颜色
fill-transparentfill: transparent透明填充
fill-blackfill: #000黑色填充
fill-whitefill: #fff白色填充
fill-red-500fill: #ef4444红色填充
fill-blue-500fill: #3b82f6蓝色填充
stroke-currentstroke: currentColor描边当前颜色
stroke-transparentstroke: transparent透明描边
stroke-blackstroke: #000黑色描边
stroke-whitestroke: #fff白色描边
stroke-red-500stroke: #ef4444红色描边
stroke-0stroke-width: 0无描边宽度
stroke-1stroke-width: 11px描边宽度
stroke-2stroke-width: 22px描边宽度

2.14 状态,伪类与伪元素(States, pseudo-classes and pseudo-elements)

  • 伪类:状态选择器
前缀说明CSS 对应
hover:指针悬停:hover
focus:元素获得焦点:focus
focus-within:元素或其后代获得焦点:focus-within
focus-visible:键盘导航获得焦点:focus-visible
active:元素被按下:active
visited:链接已访问:visited
target:元素ID匹配URL片段:target
disabled:表单元素禁用状态:disabled
enabled:表单元素启用状态:enabled
checked:复选框/单选按钮选中:checked
indeterminate:复选框不确定状态:indeterminate
default:默认选中的表单元素:default
required:必填表单元素:required
optional:可选表单元素:optional
valid:表单验证通过:valid
invalid:表单验证失败:invalid
user-valid:用户交互后验证通过:user-valid
user-invalid:用户交互后验证失败:user-invalid
in-range:输入值在范围内:in-range
out-of-range:输入值超出范围:out-of-range
placeholder-shown:显示占位符文本:placeholder-shown
autofill:浏览器自动填充:autofill
read-only:只读状态:read-only
  • 伪类:次序选择器
前缀说明CSS 对应
first:选择第一个子元素:first-child
last:选择最后一个子元素:last-child
only:选择唯一子元素:only-child
odd:选择奇数位置子元素:nth-child(odd)
even:选择偶数位置子元素:nth-child(even)
first-of-type:选择同类型第一个元素:first-of-type
last-of-type:选择同类型最后一个元素:last-of-type
only-of-type:选择同类型唯一元素:only-of-type
nth-{n}:选择第n个子元素:nth-child(n)
nth-last-{n}:从末尾选择第n个子元素:nth-last-child(n)
nth-of-type-{n}:选择同类型第n个元素:nth-of-type(n)
nth-last-of-type-{n}:从末尾选择同类型第n个元素:nth-last-of-type(n)
empty:选择无内容的元素:empty
  • 伪类:has()not()
前缀说明CSS 对应
has-{selector}:包含指定后代元素:has(selector)
has-checked:包含选中的表单元素:has(:checked)
has-[:focus]:包含获得焦点的元素:has(:focus)
has-[img]:包含图片元素:has(img)
has-[a]:包含链接元素:has(a)
group-has-{selector}:基于父级组的后代状态.group:has(selector) &
peer-has-{selector}:基于兄弟元素的后代状态.peer:has(selector) ~ &
not-{variant}:否定指定条件:not(condition)
not-focus:非焦点状态:not(:focus)
not-supports-{feature}:不支持指定特性@supports not (feature)
  • Aria 与 Data 元素前缀类
前缀说明CSS 对应
aria-busy:ARIA 忙碌状态&[aria-busy="true"]
aria-checked:ARIA 选中状态&[aria-checked="true"]
aria-disabled:ARIA 禁用状态&[aria-disabled="true"]
aria-expanded:ARIA 展开状态&[aria-expanded="true"]
aria-hidden:ARIA 隐藏状态&[aria-hidden="true"]
aria-pressed:ARIA 按下状态&[aria-pressed="true"]
aria-readonly:ARIA 只读状态&[aria-readonly="true"]
aria-required:ARIA 必填状态&[aria-required="true"]
aria-selected:ARIA 选择状态&[aria-selected="true"]
aria-[...]任意 ARIA 属性&[aria-...]
data-[...]任意 Data 属性&[data-...]
  • 媒体查询
前缀说明CSS 对应
sm:屏幕宽度大于或等于断点 sm 值时@media (width >= 40rem)
md:屏幕宽度大于或等于断点 md 值时@media (width >= 49rem)
lg:屏幕宽度大于或等于断点 lg 值时@media (width >= 64rem)
xl:屏幕宽度大于或等于断点 lg 值时@media (width >= 80rem)
2xl:屏幕宽度大于或等于断点 lg 值时@media (width >= 96rem)
max-lg屏幕宽度小于断点 lg 值时@media (width < 64rem)
@lg容器宽度大于或等于断点 lg 值时@container (width => 64rem)
@max-lg容器宽度小于断点 lg 值时@container (width < 64rem)
@md:@max-lg:容器宽度于断点 md 值与 lg 之间时@container (width >= 48rem) and (width < 64rem)
dark:深色模式@media (prefers-color-scheme: dark)
motion-safe:允许动画(用户未要求减少动画)@media (prefers-reduced-motion: no-preference)
motion-reduce:减少动画(用户要求减少动画)@media (prefers-reduced-motion: reduce)
contrast-more:高对比度模式@media (prefers-contrast: more)
contrast-less:低对比度模式@media (prefers-contrast: less)
forced-colors:强制颜色模式@media (forced-colors: active)
inverted-colors:反色模式@media (inverted-colors: inverted)
print:打印模式@media print
noscript:无脚本环境@media (scripting: none)
  • 指针设备
前缀说明CSS 对应
pointer-fine:精确指针设备(如鼠标)@media (pointer: fine)
pointer-coarse:粗糙指针设备(如触屏)@media (pointer: coarse)
pointer-none:无指针设备@media (pointer: none)
any-pointer-fine:任一精确指针设备@media (any-pointer: fine)
any-pointer-coarse:任一粗糙指针设备@media (any-pointer: coarse)
any-pointer-none:无任何指针设备@media (any-pointer: none)
  • 屏幕方向
前缀说明CSS 对应
portrait:竖屏模式@media (orientation: portrait)
landscape:横屏模式@media (orientation: landscape)
  • 功能支持
前缀说明CSS 对应
supports-[...]支持指定 CSS 特性@supports (...)
not-supports-[...]不支持指定 CSS 特性@supports not (...)
  • 其他状态选择器
前缀说明CSS 对应
rtl:右至左布局&:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *)
ltr:左至右布局&:where(:dir(ltr), [dir="ltr"], [dir="ltr"] *)
starting:元素在 DOM 中首次渲染时@starting-style
open:打开状态(details/dialog/popover)&:is([open], :popover-open, :open)
inert:惰性元素(不可交互)&[inert]

2.15 断点,媒体与容器查询(Breakpoints, media queries and contain queries)

  • 最小宽度断点
断点前缀最小宽度CSS
sm40rem (640px)@media (width >= 40rem) { ... }
md48rem (768px)@media (width >= 48rem) { ... }
lg64rem (1024px)@media (width >= 64rem) { ... }
xl80rem (1280px)@media (width >= 80rem) { ... }
2xl96rem (1536px)@media (width >= 96rem) { ... }
  • 最大宽度断点
参数媒体查询
max-sm@media (width < 40rem) { ... }
max-md@media (width < 48rem) { ... }
max-lg@media (width < 64rem) { ... }
max-xl@media (width < 80rem) { ... }
max-2xl@media (width < 96rem) { ... }
  • 容器查询断点
参数最小宽度CSS
@3xs16rem (256px)@container (width >= 16rem) { ... }
@2xs18rem (288px)@container (width >= 18rem) { ... }
@xs20rem (320px)@container (width >= 20rem) { ... }
@sm24rem (384px)@container (width >= 24rem) { ... }
@md28rem (448px)@container (width >= 28rem) { ... }
@lg32rem (512px)@container (width >= 32rem) { ... }
@xl36rem (576px)@container (width >= 36rem) { ... }
@2xl42rem (672px)@container (width >= 42rem) { ... }
@3xl48rem (768px)@container (width >= 48rem) { ... }
@4xl56rem (896px)@container (width >= 56rem) { ... }
@5xl64rem (1024px)@container (width >= 64rem) { ... }
@6xl72rem (1152px)@container (width >= 72rem) { ... }
@7xl80rem (1280px)@container (width >= 80rem) { ... }

三、知识点

3.1 函数与指令(Functions and directives)

与官方文档顺序不同,这里先介绍一下 Tailwind CSS 文件中的各项函数与指令:

3.1.1 指令(Directives)

@import:引入一个文件,可以是 Tailwind CSS 本身:

CSS
@import "tailwindcss";

@theme:规定一个主题层,包含了项目的自定义设计令牌,比如字体、颜色、断点等内容:

CSS
@theme { --font-display: "Satoshi", "sans-serif"; --breakpoint-3xl: 120rem; --color-avocado-100: oklch(0.99 0 0); --color-avocado-200: oklch(0.98 0.04 113.22); --ease-fluid: cubic-bezier(0.3, 0, 0, 1); --ease-snappy: cubic-bezier(0.2, 0, 0, 1); /* ... */ }

@source:规定 Tailwind CSS 的输入源与排除路径:

CSS
@source "../**/*.html"; @source not "../node_modules";

@utility:注册一个实用工具类:

CSS
@utility tab-4 { tab-size: 4; }

@variant:应用一项预定义变体:

CSS
.my-element { background: white; @variant dark { background: black; } }

@custom-variant:注册一个自定义变体:

CSS
@custom-variant theme-midnight (&:where([data-theme="midnight"] *));

@apply:将 Tailwind CSS 定义的实用类名作为参数应用:

CSS
.select2-dropdown { @apply rounded-b-lg shadow-md; }

具体使用方法将于下述小节中逐条讲解。

3.1.2 函数(Functions)

--alpha():调整颜色不透明度:

输入的 CSS


.my-element { color: --alpha(var(--color-lime-300) / 50%); }

编译的 CSS


.my-element { color: color-mix(in oklab, var(--color-lime-300) 50%, transparent); }

--spacing():调整间距:

输入的 CSS


.my-element { margin: --spacing(4); }

编译的 CSS


.my-element { margin: calc(var(--spacing) * 4); }

calc() 结合使用时,对于任意值也非常好用:

<div class="py-[calc(--spacing(4)-1px)]"> <!-- ... --> </div>

其默认值为 0.25rem(4px) ,如 .mt-4 {margin-top: 1rem}

注意:修改该值会决定全局的比例单位,如 margin、padding、inset 等等,请谨慎修改。

3.2 检测源文件中的类(Detecting classes in source files)

我们来一起理解 Tailwind CSS 是如何工作的,以及怎样设置能使 Tailwind CSS 的工作效率达到一个理想状态。

默认情况下 Tailwind 将扫描项目中的每个文件以查找类名,但默认排除下列文件:

  • .gitignore 中声明的文件
  • node_modules 目录下的文件
  • 二进制文件如图像、视频或 zip 等
  • CSS 文件
  • 常见的包管理文件如 yarn.lockpackage.json

由此我们可以进行显示注册源的设置,以我们刚才搭建好的 my-project/static 项目为例:

静态项目结构
static ├── fonts │ └── ... ├── img │ └── ... ├── styles │ ├── globals.css # 输入文件 │ └── theme.css # 输出文件 ├── index.html └── tailwindcss
my-project/static/globals.css
@import "tailwindcss" source("../**/*.html");

上述代码意味着 Tailwind CSS 在引入时仅检测项目中所有的 HTML,如需忽略一些目录或文件也可直接在 .gitignore 中设置,Tailwind 会同步进行忽略。当然你也可以手动设置这些参数:

my-project/static/globals.css
@import "tailwindcss"; @source "../**/*.html"; @source not "../node_modules";

此外我们还可添加 source(none) 以禁用自动检测,这在具有多个 Tailwind 样式表的项目中非常有用,举例如下:

@import "tailwindcss" source(none); @source "../admin"; @source "../shared";

设置 Tailwind CSS 引入源对于大型项目的开发与构建效率而言尤为重要,对于本教程的 Next.JS 课程项目而言,我们仅需设置以下目录作为输入源:

my-project/nextjs/src/styles/globals.css
@import "tailwindcss"; @source "@/pages"; @source "@/components";

至此,Tailwind CSS 会将声明的源文件作为输入源,视为纯文本且不做代码解析,仅是基于 Tailwind 内建或自设的类名进行标记,然后对这些标记生成一个完整的 CSS 进行输出。这句话听起来比较绕,我们可以解释得接地气一点:

  1. Tailwind CSS 会依据你设定好的源文件目录与类型作为输入源;
  2. 输入的总是文字格式,Tailwind CSS 并不会做解析;
  3. 仅当输入的文字包含某个实用类名时,这个类名才会被标记;
    • 比如你的输入里只有 relativew-full 这两个类名,它就只标记这两个
  4. Tailwind CSS 会将所有标记好的类名逐个生成样式,放在一个文件里输出。

由此可见调整输入源的范围与内容就变得极其重要:

输入的类名


<span class="relative block w-full h-4"></span>

输出文件中包含的 CSS


... @layer utilities { .relative { position: relative } .block { display: block } .h-4 { height: calc(var(--spacing)*4) } .w-full { width: 100% } }

以官方的例子来说,动态构造类名或用 props 拼接类名将不能被 Tailwind CSS 检测到:

❌ Don‘t
function Button({ color, children }) { return ( <div class="text-{{ error ? 'red' : 'green' }}-600"> <button className={`bg-${color}-600 hover:bg-${color}-500 ...`}>{children}</button> </div> ); }
✅ Do it
function Button({ color, children }) { const colorVariants = { blue: "bg-blue-600 hover:bg-blue-500", red: "bg-red-600 hover:bg-red-500", }; return ( <div class="{{ error ? 'text-red-600' : 'text-green-600' }}"> <button className={`${colorVariants[color]} ...`}>{children}</button> </div> ); }

前者由于本身不包含某个实用类名,输出文件中将不再包含这些 Tailwind CSS 实用类名,而后者则能正确生成。看到这里相信部分宝子会发现一个大问题,如果我们的输入源中不包含相关类名,但我们希望 Tailwind CSS 无论如何都要生成特定类名,又该如何操作呢?

3.2.1 保存特定类名(Safelisting specific utilities)

Tailwind CSS 使用 SafeList 参数来满足这一需求。有别于 Tailwind CSS v3 的一点是,v4 的 SafeList 不仅不存在于已弃用的 tailwind.config.mjs 文件当中,甚至连名称、使用方法对比前者都大相径庭。

Tailwind CSS v4 使用 @source inline("utilitie-name") 语法保存特定的类名,示例如下:

输入文件


@import "tailwindcss"; @source inline("underline");

输出文件


.underline { text-decoration-line: underline; }

我们也可以为其添加参数,比如选择 :hover:focus 两个状态:

输入文件


@import "tailwindcss"; @source inline("{hover:,focus:,}underline");

输出文件


.underline { text-decoration-line: underline; } @media (hover: hover) { .hover\:underline:hover { text-decoration-line: underline; } } @media (focus: focus) { .focus\:underline:focus { text-decoration-line: underline; } }

此外,它也可以取值为一个区间:

输入文件


@import "tailwindcss"; @source inline("{hover:,}bg-red-{50,{100..900..100},950}");

输出文件


.bg-red-50 { background-color: var(--color-red-50); } .bg-red-100 { background-color: var(--color-red-100); } .bg-red-200 { background-color: var(--color-red-200); } /* ... */ .bg-red-800 { background-color: var(--color-red-800); } .bg-red-900 { background-color: var(--color-red-900); } .bg-red-950 { background-color: var(--color-red-950); } @media (hover: hover) { .hover\:bg-red-50:hover { background-color: var(--color-red-50); } /* ... */ .hover\:bg-red-950:hover { background-color: var(--color-red-950); } }

上述内容中的 bg-red-{50,{100..900..100},950} ,其 50950 不言而喻,而中间的 100900100 则为从 100 到 900 递进 100。

3.2.2 排除特定类名(Explicitly excluding classes)

如果你不希望 Tailwind CSS 应用某个实用工具类,则可以使用 @source not inline() 进行排除:

@import "tailwindcss"; @source not inline("{hover:,focus:,}bg-red-{50,{100..900..100},950}");

3.2.3 引用检测逻辑

这里我们额外补充一点官方没有声明的情况: 引入文件引用了未引入文件,导致相关类名被检测并注入。 听起来有点绕口是吧,那假设我们有 ComponentA.jsComponentB.js 这两个组件,直接上代码:

@/styles/globals.css


@import "tailwindcss" source("../components/ComponentA.js");

@/components/ComponentA.js


import { ModuleA, ModuleB } from "@/components/ComponentB" return ( <> <ModuleA data={data.moduleA} /> <ModuleB data={data.moduleB} /> </> )

@/components/ComponentB.js


const ModuleA = (data) => { return <span className="text-red-500"></span> // ✅ 会被识别,因为被父组件引用,且是完整声明 } const ModuleB = (data) => { return <span className={`text-${data.textColor}-500`}></span> // ❌ 不会被识别,因为非完整显式声明 } const ModuleC = (data) => { return <span className="bg-white"></span> // ❌ 不会被识别,因为没有被父组件引用 } export { ModuleA, ModuleB, ModuleC }

这种情况下,由于 ModuleAModuleBComponentA 所引用,所以会被 Tailwind CSS 视作 ComponentA 源码需做编译的一部分。不过由于 ModuleB 中的类名并非完整的显式声明(使用了动态字符串拼接),所以不会被 Tailwind CSS 识别并输出;而 ModuleC 虽然有完整的类名 bg-white,但因为没有被 ComponentA 引用,所以也不会被扫描到。最终结果是只有 ModuleA 中的 text-red-500 被注入到输出的 CSS 文件中。

3.3 状态,伪类与伪元素(States, pseudo-classes and pseudo-elements)

以下是常见的状态、伪类与伪元素选择参考:

<div> <!-- 标准 --> <span class="block"></span> <!-- 伪类 --> <!-- 伪类:状态 --> <span class="hover:block"></span> <span class="active:block"></span> <span class="checked:block"></span> <!-- 伪类:次序 --> <span class="first:block"></span> <span class="odd:block"></span> <span class="nth-3:block"></span> <span class="nth-last-of-type-6:block"></span> <!-- 伪类:has() 与 not() --> <span class="has-[a]:block"></span> <span class="has-checked:block"></span> <span class="not-invalid:block"></span> <!-- 伪元素 --> <span class="before:block"></span> <span class="after:content-['lorem ipsum']"></span> <span class="placeholder:italic"></span> <ul class="marker:text-lg"></ul> <!-- 媒体查询 --> <span class="md:block"></span> <span class="max-lg:block"></span> <span class="dark:block"></span> ... </div>

请查阅 状态,伪类与伪元素(States, pseudo-classes and pseudo-elements) 了解所有前缀。 如欲查阅官方指南,详询 Tailwind CSS 官方文档 - 悬停,聚焦与其他状态 - 速查表

小提示:考虑到 Tailwind CSS 每个大版本迭代(如 v3 - v4)会带来一些破坏性的类名调整,如 nth-child 的类名逻辑变更,因此请务必对应正确版本,如上述后缀名仅适用于 Tailwind CSS v4 。

3.4 响应式设计(Responsive Design)

Tailwind CSS 正是在移动互联网时代下讲究小屏优先的主要推动力,因此与其相得益彰的设计稿也应从移动端扩展端点至平板端,我们的设计稿也遵循这一原则,且作为一个网站项目,我们得考虑到笔记本与台式机浏览的应用情景,所以需要将宽度进一步扩展到桌面端。

我们可以为先前示例里的卡片添加一些断点(md:...):

代码片段


<div class="relative w-36 h-48 rounded-3xl border border-neutral-400 bg-[url('https://shorturl.at/ErgWw')] bg-center font-serif text-slate-700 transition duration-1000 ease starting:-translate-x-12 starting:opacity-0 md:w-48 md:h-64"> <span class="absolute block h-full w-full rounded-3xl bg-linear-to-b from-neutral-200/0 from-33% via-neutral-200/75 via-67% to-neutral-200"></span> <div class="relative flex h-full flex-col justify-end p-4 md:p-6"> <h4 class="font-bold md:text-lg">Title</h4> <p class="text-sm md:text-base">Lorem ipsum</p> <a href="javascript:void(0)" class="w-full px-2 py-1 mt-2 rounded-full font-sans font-medium text-xs text-center uppercase text-white bg-linear-to-r from-green-500/50 to-emerald-500 transition duration-300 ease hover:from-green-600/50 hover:to-emerald-600 md:px-3 md:py-1.5 md:mt-3 md:text-sm">View more</a> </div> </div>

渲染结果


Title

Lorem ipsum

好的,现在我们会发现当屏幕宽度 ≥ 48rem(768px)之时,卡片的尺寸、内部盒模型与按钮的内边距、字体的大小以及按钮的上边距都明显变大了一些。

3.4.1 响应式设计:断点与媒体查询(Breakpoints and media queries)

让我们先了解一下预设的几个断点:

断点前缀最小宽度CSS
sm40rem (640px)@media (width >= 40rem) { ... }
md48rem (768px)@media (width >= 48rem) { ... }
lg64rem (1024px)@media (width >= 64rem) { ... }
xl80rem (1280px)@media (width >= 80rem) { ... }
2xl96rem (1536px)@media (width >= 96rem) { ... }

这些断点前缀作用于 Tailwind CSS 所有的实用类名,这意味着你可以为任何 HTML 元素按需配置合适的 CSS 样式,且无需撰写任何媒体查询代码块。

接下来,我们还可以定义一个 @media (max-width) 值,就像这样:

<div class="w-60 max-sm:w-48"></div>

也就是说,上述 div 在屏幕宽度小于 40rem (640px) 时,宽度将设置为 192px。以下是官方对应的预设参数:

参数媒体查询
max-sm@media (width < 40rem) { ... }
max-md@media (width < 48rem) { ... }
max-lg@media (width < 64rem) { ... }
max-xl@media (width < 80rem) { ... }
max-2xl@media (width < 96rem) { ... }
注意此处类名均为断点前缀,需要加 : 使用,如 max-sm:,这与 max-w-sm 是完全不同的两个概念,后者不是媒体查询,而是 max-width 样式,需要区别理解。

综合以上,如果你只想控制在一个范围区间,比如 max-width 从 768px ~ 1280px,那我们还可以这么写:

<div class="w-60 md:max-xl:w-96 xl:w-full"></div>

这意味着上述盒模型会在 0 ~ 767px 视窗宽度下设定宽度为 15rem,并在 768 ~ 1279px 视窗宽度下设定宽度为 24rem,再在视窗宽度大于 1280px 时根据父级元素尺寸撑满宽度。当然你也可以采用一个自设值来临时限定宽度:

<div class="w-60 md:max-[1080px]:w-96 xl:w-full"></div>

那么问题来了,我们该如何调整上述默认值呢?比如说我就想要修改默认的断点值,比如将 xs 调整为 30rem (480px) 而非 40rem (640px) ,或者增添新的断点呢?

请查阅 自定义主题 小节了解如何自定义。

3.4.2 响应式设计:容器查询(Container Queries)

作为一项现代 CSS 特性,我们可以根据父元素的大小而不是整个视图的大小来设置某些子元素的样式,而 Tailwind CSS 为我们提供简便的类名,就像这样:

<div class="@container"> <div class="flex flex-col @md:flex-row"> <!-- ... --> </div> </div>

与断点前缀一样,Tailwind CSS 在容器查询上总是移动端优先。所以上述内容等价于 .@container 在最小尺寸 >= 48rem 时,其 flex-direction 属性变更为 row

此外,我们也可以为其添加 max-width 容器查询:

<div class="@container"> <div class="flex flex-col @max-md:flex-row"> <!-- ... --> </div> </div>

我们同样可以组合上述两者进行范围查询:

<div class="@container"> <div class="flex flex-col @sm:@max-md:flex-row"> <!-- ... --> </div> </div>

此外,如果我们有多个嵌套容器,我们还可以为容器命名以便于子元素选择。此外我们当然也可以使用任意值以及 cqw(容器查询宽度(Container query width),1cqw 即为查询容器宽度的 1%):

<div class="@container/main"> <!-- ... --> <div class="@container/sub flex flex-row @sm/main:flex-col"> <!-- ... --> <span class="w-full @min-[400px]/sub:w-[50cqw]"> </div> </div>

具体断点列表请查阅 断点,媒体与容器查询

3.5 颜色(Tailwind Colors)

Tailwind CSS 内建了一套颜色系统来实现色彩使用的统一,使开发者们得以简单、快速地将其应用到背景、边框、阴影等常见的参数中去,以下是一些例子:

示例代码


<div class="py-4 space-x-2"> <span class="relative inline-block px-3.5 py-2 rounded-xl text-rose-100 border border-rose-300 bg-rose-900/75 shadow-xl shadow-rose-500/25 duration-300 ease hover:-translate-y-2 hover:shadow-rose-500/50">Example</span> <span class="relative inline-block px-3.5 py-2 rounded-xl text-sky-100 bg-sky-500/75 shadow-xl shadow-sky-500/25 inset-shadow-sm inset-shadow-sky-200/50 duration-300 ease hover:-translate-y-2 hover:shadow-sky-500/50 hover:inset-shadow-sky-200/75">Example 2</span> </div>

渲染结果


Example Example 2

Tailwind CSS v4 目前支持的色彩如下:

工具类描述
bg-*设置元素的背景颜色
text-*设置元素的文本颜色
decoration-*设置文本装饰的颜色
border-*设置元素的边框颜色
outline-*设置元素的轮廓颜色
shadow-*设置盒阴影的颜色
inset-shadow-*设置内阴影的颜色
ring-*设置环形阴影的颜色
inset-ring-*设置内环形阴影的颜色
accent-*设置表单控件的强调色
caret-*设置表单控件中光标的颜色
fill-*设置 SVG 元素的填充颜色
stroke-*设置 SVG 元素的描边颜色

具体的写法如 decoration-violet-400/75 来设置一个名为 violet-400 的内置主题颜色,并将其透明度设置为 75%:这里是渲染结果

此外我们可以访问 https://tailwindcolor.com/ 来实时获取 Tailwind Color,也可以访问 Tailwind CSS 官方文档 - 颜色 页面了解更多信息。

Tailwind CSS v4 已全面支持 oklch 色彩模式,以适配更新的浏览器特性,对比 sRGB 或 HSL ,该色彩模式更能带来统一舒适的视觉体验。

此外,我们优先实现项目,再在有限的条件下做深入教学,因此 Darkmode 用例将暂定为进阶课程中讲解。

3.6 主题参数(Theme variables)

与需要在 v3 中设置 tailwind.config.mjs 不同,我们仅需在 v4 调用的 CSS 文件中引入 tailwindcss ,然后直接定义 @theme 中的内容即可。

3.6.1 默认主题参数

与 v3 不同的是,现在我们仅需在全局 CSS 文件 import Tailwind CSS 即可。这其中发生了什么?

Tailwind CSS v3


globals.css
@tailwind base; @tailwind components; @tailwind utilities; ...

Tailwind CSS v4


globals.css
@import "tailwindcss";
node_modules/tailwindcss/index.css
@layer theme, base, components, utilities; @import "./theme.css" layer(theme); @import "./preflight.css" layer(base); @import "./utilities.css" layer(utilities);

这里很好的解释 v3 升级到 v4 之后导入语句究竟做了些什么,显然作为主题层(layer(theme))导入的 theme.css 的优先级较低,是可在外部根据 @theme{...} 代码块直接替换样式的,但在框架层面硬编码写死的类名如 flex-colpointer-events-none 则是无法改动的。

3.6.2 自定义主题

我们可以直接在 @theme 层中增删改内置参数:

globals.css
@import "tailwindcss"; @theme { /* 覆盖断点 */ --breakpoint-xs: 30rem; --breakpoint-2xl: 100rem; --breakpoint-3xl: 120rem; /* 删除断点 */ --breakpoint-md: initial; /* 覆盖容器查询宽度 */ --container-8xl: 96rem; }

或是添加一个颜色与字体:

@import "tailwindcss"; @theme { --color-mint-500: oklch(0.72 0.11 178); --font-poppins: Poppins, sans-serif; }

现在跟颜色有关的属性如 text-mint-500bg-mint-500border-mint-500 均已生效,而使用 font-poppins 则可以让元素使用 Poppins 字体。以下是官方支持自定义的全局变量:

命名空间工具类名
--color-*颜色工具类,如 bg-red-500text-sky-300
--font-*字体族工具类,如 font-sans
--text-*字体大小工具类,如 text-xl
--font-weight-*字体粗细工具类,如 font-bold
--tracking-*字母间距工具类,如 tracking-wide
--leading-*行高工具类,如 leading-tight
--breakpoint-*响应式断点变体,如 sm:*
--container-*容器查询变体,如 @sm:* 和尺寸工具类,如 max-w-md
--spacing-*间距和尺寸工具类,如 px-4max-h-16
--radius-*边框圆角工具类,如 rounded-sm
--shadow-*盒阴影工具类,如 shadow-md
--inset-shadow-*内阴影工具类,如 inset-shadow-xs
--drop-shadow-*投影滤镜工具类,如 drop-shadow-md
--blur-*模糊滤镜工具类,如 blur-md
--perspective-*透视工具类,如 perspective-near
--aspect-*宽高比工具类,如 aspect-video
--ease-*过渡缓动函数工具类,如 ease-out
--animate-*动画工具类,如 animate-spin

如需了解整个默认主题变量,请参阅 Tailwind CSS 官方文档 - 默认主题变量参考

此外,你也可以把所有的断点与颜色都清空掉,再重新自定义:

@import "tailwindcss"; @theme { --breakpoint-*: initial; --breakpoint-tablet: 40rem; --breakpoint-laptop: 64rem; --breakpoint-desktop: 80rem; --color-*: initial; --color-white: #fff; --color-purple: #3f3cbb; --color-midnight: #121063; --color-tahiti: #3ab7bf; --color-bermuda: #78dcca; }

甚至你可以完全自设属于自己的主题,而不调用任何 Tailwind CSS 默认主题样式:

@import "tailwindcss"; @theme { --*: initial; --spacing: 4px; --font-body: Inter, sans-serif; --color-lagoon: oklch(0.72 0.11 221.19); --color-coral: oklch(0.74 0.17 40.24); --color-driftwood: oklch(0.79 0.06 74.59); --color-tide: oklch(0.49 0.08 205.88); --color-dusk: oklch(0.82 0.15 73.09); }

此外,我们还可以设置一些动画关键帧:

@import "tailwindcss"; @theme { --animate-fade-in-scale: fade-in-scale 0.3s ease-out; @keyframes fade-in-scale { 0% { opacity: 0; transform: scale(0.95); } 100% { opacity: 1; transform: scale(1); } } }

这样我们便可以在所需的元素上使用 animate-fade-in-scale 类名来实现动画。

补充一点:对应章节 3.2 检测源文件中的类 所讲解的内容,此处 @theme 中定义的类同样不会自动填充到输出文件,如果你总是需要 @theme 中的所有内容被输出,请使用 @theme static 。下例:

@import "tailwindcss"; @theme static { --color-primary: var(--color-red-500); --color-secondary: var(--color-blue-500); }

3.7 级联层(@layer)

此处与官方 Document 略有不同,我们将官方的 @layer 独立拆分出来做讲解。

时间来到 2022 年,为适配 W3C 官方推出的新标准,Chrome / Edge 99+、Firefox 97+ 及 Safari 15.4+ 均已支持 Cascade Layers 特性。而 Tailwind CSS 作为 CSS Framework 领域的领头羊及技术革新的推动者,自然也在第一时间适配了这一特性。

总的来说,@layer 规定了各层级的优先级,并有效地为混乱的选择器或分布式文件规范地做好分类。参照官方层命名约定,Tailwind CSS 使用下列层命名分别管理对应的内容并设定好了优先级:

级联层用途说明
@layer theme主题层管理颜色、字体、间距等设计令牌和主题变量
@layer base基础层包含重置样式和基础 HTML 元素的默认样式
@layer components组件层存放可复用的 UI 组件样式,如按钮、卡片等
@layer utilities实用层包含原子化的工具类,具有最高的样式优先级
@layer layout布局层(已移除)定义页面整体布局结构和容器样式 (v4已移除)
请注意,Tailwind CSS 的各个级链层的优先级严格遵守上述排序,即 utilities 层的优先级最高;此外,无论如何我们都应避免使用 !important 来造成混乱的样式优先级争夺。

以下是一个包含了各层应用标准的 CSS 示例:

globals.css
/* 引入 Tailwind CSS */ @import "tailwindcss"; /* 在 theme 层中定义 */ @layer theme{ /* 移除所有内置行高,并设置主要与次要颜色 */ --leading-*: initial; --color-primary: var(--color-sky-500); --color-secondary: var(--color-sky-800); } /* 在 base 层中定义 */ @layer base { /* 为所有 a 标签设置字体颜色为次要色 */ a {color: var(--color-secondary);} /* 选择 section 标签 */ section { /* 选择 section 标签下的指定标签,将部分标签的字体颜色设置为主要色,并为 h1 h2 设置字体大小 */ h1, h2, h3, h4, p, span, li {color: var(--color-primary);} h1 {font-size: var(--text-2xl);} h2 {font-size: var(--text-xl);} } } /* 在 components 层中定义 */ @layer components { /* 选择 .card 类 */ .card { /* 设置各个 css 样式 */ content-visibility: hidden; background-color: var(--color-white); border-radius: var(--radius-lg); padding: --spacing(6); box-shadow: var(--shadow-xl); transition: .3s all ease; /* 应用 Tailwind CSS 命名规则中的变量值,如 :hover、:dark 等 */ @variant hover { transform: translate-y(-.25rem); } } } /* 设置实用类 */ /* 注册名为 “content-auto“ 的类 */ @utility content-auto { content-visibility: auto; }

上述提到过,级链层的优先级为 theme < base < component < utilities,所以在设置 .card.content-auto 类的元素时(即 class="card content-auto"),.content-auto 便会覆盖 .card 中的 content-visiblity 属性优先级,使其变为 auto

接下来会讲到 utilities 的具体管理,而 component 层的组件样式将于开发项目的过程中给出例子。

3.8 增设自定义实用工具类(Adding Custom Utitlites)

3.8.1 简单实用类名(Simple utilities)

我们继续来看这一例子:

@utility content-auto { content-visibility: auto; }

新增的实用类名和预定义实用类在使用方法上没有区别:

<div> <!-- 常规 --> <span class="content-auto"></span> <!-- 状态伪类 --> <span class="hover:content-auto"></span> <span class="active:content-auto"></span> <!-- 媒体查询伪类 --> <span class="md:content-auto"></span> <span class="dark:content-auto"></span> ... </div>

3.8.2 复杂实用类名(Complex utilities)

如果没有预定义的常用变量值(如 @variant hover),则仍需通过标准的嵌套语法添加至引入文件:

@utility scrollbar-hidden { &::-webkit-scrollbar { display: none; } }

3.8.3 功能性实用类名(Functional utilities)

我们还可以注册接收传参的功能性实用类名,它们能接受以下几种参数输入:

参数名称参考 CSS 代码
匹配主题值(Matching theme values)tab-size: --value(--tab-size-*);
裸值(Bare values)tab-size: --value(integer);
文字值(Literal values)tab-size: --value("inherit", "initial", "unset");
任意值(Arbitrary values)tab-size: --value([integer]);
负值(Negative values)tab-size: calc(--value(integer) * -1);
分数(Fractions)tab-size: --value(ratio)

关于各项功能实用类的注册方法,由于内容较长做成了折叠列表,请按需查阅理解。

匹配主题值(Matching theme values)
@theme { --tab-size-2: 2; --tab-size-4: 4; --tab-size-github: 8; } @utility tab-* { tab-size: --value(--tab-size-*); }

这样一来,以 tab- 作为前缀的实用类就匹配上了三个设定好的变量。

如果我们想让参数变得更灵活,比如随意设置 tab-size 时,就需要用到下述的裸值、文字值与任意值了。

裸值(Bare values)
@utility tab-* { tab-size: --value(integer); }

这样一来,我们就可以输入整数作为参数传入以设置 tab-size 的值了,如 tab-size-108 ;如果需要添加更多裸值类型,我们可以直接设置一个数组:

@utility tab-* { tab-size: --value(integer, ratio); }

这样我们便可以使用 tab-size-108tab-size-1/2 两种类型的值了。下表为支持的裸值数据类型:

裸值类型说明示例
number数值10, 0.5
integer整数5, -15
ratio比例值1/2, 3/4
percentage百分比50%, 25%

裸值的类名格式为 class="tab-size-*"

文字值(Literal values)
@utility tab-* { tab-size: --value("inherit", "initial", "unset"); }

我们同样可以传入一个数组来同时设定一系列合法的值,这样我们便可以使用 tab-size-inherittab-size-initialtab-size-unset 了。

传参的解析顺序总是从左到右。
任意值(Arbitrary values)
@utility tab-* { tab-size: --value([integer], [percentage]); }

看上去与裸值很像,但请注意参数需要被 [] 包裹。

这样一来我们便可以使用 tab-size-[10]tab-size[50%] 了。下表为支持的任意值数据类型:

任意值类型说明示例
absolute-size绝对尺寸关键词xx-small, x-small, small, medium, large, x-large, xx-large
angle角度值45deg, 0.25turn, 1.57rad, 50grad
bg-size背景尺寸cover, contain, auto, 100px 50px
color颜色值red, #ff0000, rgb(255,0,0), hsl(0,100%,50%)
family-name字体家族名称"Times New Roman", Arial, serif
generic-name通用字体族serif, sans-serif, monospace, cursive, fantasy
image图像值url(), linear-gradient(), radial-gradient()
integer整数1, 42, -5
length长度值10px, 2rem, 50%, 3em, 1vh
line-width线条宽度thin, medium, thick, 2px
number数值1.5, 0, 3.14159
percentage百分比50%, 100%, 25%
position位置值top, center, bottom, left, right, 50% 25%
ratio比例值16/9, 4/3, 1/1
relative-size相对尺寸关键词larger, smaller
urlURL 值url("image.jpg"), url(https://example.com/bg.png)
vector矢量值SVG 路径数据等
*通配符接受任何值类型

任意值的类名格式为 class="tab-size-[*]" ;可以看到对比裸值,任意值可以设置相当多的参数类型,所以请根据需求进行设置。

同时支持多种类型的值
@theme { --tab-size-github: 8; } @utility tab-* { /* 请注意,以下三项是允许被同时添加到一个实用类名的 */ tab-size: --value(integer); /* 使裸值支持整数类型,如 tab-size-6 */ tab-size: --value([integer]); /* 使任意值支持整数类型,如 tab-size-[6] */ tab-size: --value(--tab-size-*); /* 使值能勾匹配 @theme 中设置的以 --tab-size- 开头的所有自定义变量,如 --tab-size-github */ }

这样一来 tab-size 将同时支持如 tab-size-2tab-size-[2]tab-size-github 这类参考值。

此外,与上述文字值支持传入一个数组相同的,我们也可把它们合并到一起;但请务必注意,值的解析顺序永远是从左到右:

@utility tab-* { /* 同时支持整数裸值、整数任意值与匹配的自定义变量,且解析顺序为 裸值 > 任意值 > 自定义变量 */ tab-size: --value(integer, [integer], --tab-size-*); }

除此以外我们可以加入计算,以匹配角度与百分比等非整数或浮点值,如原生的 transform: rotate() 等,此处以 opacity 举例:

@utility opacity-* { opacity: calc(--value(integer) * 1%); /* 有需要计算的场景,calc(--value()) 必须单拎出来写 */ opacity: --value([percentage], --opacity-*); }
负值(Negative values)
@utility inset-* { inset: --spacing(--value(integer)); inset: --value([percentage], [length]); } @utility -inset-* { inset: --spacing(--value(integer) * -1); inset: calc(--value([percentage], [length]) * -1); }

其本质就是使用 calc() 直接乘以一个 -1 来实现负值结果。

修饰符(Modifier)
@utility text-* { font-size: --value(--text-*, [length]); line-height: --modifier(--leading-*, [length], [*]); }

语法为 --modifier(),工作方式与 --value() 没什么不同,只是传入的值是 Tailwind CSS 内置的预定义值;这也就合理解释了预定义的文字大小类(如 text-lg) 是如何包含了预定义的 line-height 值的。

3.8.4 添加自定义变体(Adding custom variants)

先前我们已经提到过一个运用于 .card 组件类名中的悬停变体(@variant hover {...})。

对于常见的预定义变体如 :before:hover:active:dark:md 等,我们建议使用 @variant 属性代替 &: 属性,如使用 @variant before 而非 &:before

但这里也有例外,比如考虑到兼容性问题的 -webkit- 前缀,Tailwind CSS 并没有自带这些变体,那我们可以为其手动设置:

@custom-variant webkit-scrollbar { &:where(::-webkit-scrollbar) { @slot; } } /* 不需要嵌套时可以简写为 */ @custom-variant webkit-scrollbar (&:where(::-webkit-scrollbar)); /* 将该变体应用至对应的类名 */ @utility scrollbar-hidden { @variant webkit-scrollbar { display: none; } }
@webkit-scrollbar 作为一个复用变体,意味着所有的 Tailwind CSS 自设类名都可以对其进行调用;如果它不像是 hover 这类常见的变体,且没有复用需求的话,使用原生嵌套语法 &::-webkit-scrollbar 会是更好的选择。

如果需要选择包含某项参数的 HTML 元素,则参考下列内容撰写:

@custom-variant theme-midnight { &:where([data-theme="midnight"] *) { @slot; } } /* 不需要嵌套时可以简写为 */ @custom-variant theme-midnight (&:where([data-theme="midnight"] *));

当自定义变体有多个规则时,它们可以相互嵌套:

@custom-variant any-hover { @media (any-hover: hover) { &:hover { @slot; } } }

3.9 样式重置(Preflight)

由于浏览器自带一些默认样式,所以开始定义样式前,有经验的前端都会引入一张预检样式表,比如 normalize.cssreset.css 之类。

理所当然的,Tailwind CSS 也会对页面进行预检。以下是 Tailwind CSS v4.1 的预检样式表:

Tailwind CSS v4.1 Preflight stylesheets
/* 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 2. Remove default margins and padding 3. Reset all borders. */ *, ::after, ::before, ::backdrop, ::file-selector-button { box-sizing: border-box; /* 1 */ margin: 0; /* 2 */ padding: 0; /* 2 */ border: 0 solid; /* 3 */ } /* 1. Use a consistent sensible line-height in all browsers. 2. Prevent adjustments of font size after orientation changes in iOS. 3. Use a more readable tab size. 4. Use the user's configured `sans` font-family by default. 5. Use the user's configured `sans` font-feature-settings by default. 6. Use the user's configured `sans` font-variation-settings by default. 7. Disable tap highlights on iOS. */ html, :host { line-height: 1.5; /* 1 */ -webkit-text-size-adjust: 100%; /* 2 */ tab-size: 4; /* 3 */ font-family: --theme( --default-font-family, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji' ); /* 4 */ font-feature-settings: --theme(--default-font-feature-settings, normal); /* 5 */ font-variation-settings: --theme(--default-font-variation-settings, normal); /* 6 */ -webkit-tap-highlight-color: transparent; /* 7 */ } /* 1. Add the correct height in Firefox. 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 3. Reset the default border style to a 1px solid border. */ hr { height: 0; /* 1 */ color: inherit; /* 2 */ border-top-width: 1px; /* 3 */ } /* Add the correct text decoration in Chrome, Edge, and Safari. */ abbr:where([title]) { -webkit-text-decoration: underline dotted; text-decoration: underline dotted; } /* Remove the default font size and weight for headings. */ h1, h2, h3, h4, h5, h6 { font-size: inherit; font-weight: inherit; } /* Reset links to optimize for opt-in styling instead of opt-out. */ a { color: inherit; -webkit-text-decoration: inherit; text-decoration: inherit; } /* Add the correct font weight in Edge and Safari. */ b, strong { font-weight: bolder; } /* 1. Use the user's configured `mono` font-family by default. 2. Use the user's configured `mono` font-feature-settings by default. 3. Use the user's configured `mono` font-variation-settings by default. 4. Correct the odd `em` font sizing in all browsers. */ code, kbd, samp, pre { font-family: --theme( --default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace ); /* 1 */ font-feature-settings: --theme(--default-mono-font-feature-settings, normal); /* 2 */ font-variation-settings: --theme(--default-mono-font-variation-settings, normal); /* 3 */ font-size: 1em; /* 4 */ } /* Add the correct font size in all browsers. */ small { font-size: 80%; } /* Prevent `sub` and `sup` elements from affecting the line height in all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.5em; } /* 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 3. Remove gaps between table borders by default. */ table { text-indent: 0; /* 1 */ border-color: inherit; /* 2 */ border-collapse: collapse; /* 3 */ } /* Use the modern Firefox focus style for all focusable elements. */ :-moz-focusring { outline: auto; } /* Add the correct vertical alignment in Chrome and Firefox. */ progress { vertical-align: baseline; } /* Add the correct display in Chrome and Safari. */ summary { display: list-item; } /* Make lists unstyled by default. */ ol, ul, menu { list-style: none; } /* 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) This can trigger a poorly considered lint error in some tools but is included by design. */ img, svg, video, canvas, audio, iframe, embed, object { display: block; /* 1 */ vertical-align: middle; /* 2 */ } /* Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) */ img, video { max-width: 100%; height: auto; } /* 1. Inherit font styles in all browsers. 2. Remove border radius in all browsers. 3. Remove background color in all browsers. 4. Ensure consistent opacity for disabled states in all browsers. */ button, input, select, optgroup, textarea, ::file-selector-button { font: inherit; /* 1 */ font-feature-settings: inherit; /* 1 */ font-variation-settings: inherit; /* 1 */ letter-spacing: inherit; /* 1 */ color: inherit; /* 1 */ border-radius: 0; /* 2 */ background-color: transparent; /* 3 */ opacity: 1; /* 4 */ } /* Restore default font weight. */ :where(select:is([multiple], [size])) optgroup { font-weight: bolder; } /* Restore indentation. */ :where(select:is([multiple], [size])) optgroup option { padding-inline-start: 20px; } /* Restore space after button. */ ::file-selector-button { margin-inline-end: 4px; } /* Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) */ ::placeholder { opacity: 1; } /* Set the default placeholder color to a semi-transparent version of the current text color in browsers that do not crash when using `color-mix(…)` with `currentcolor`. (https://github.com/tailwindlabs/tailwindcss/issues/17194) */ @supports (not (-webkit-appearance: -apple-pay-button)) /* Not Safari */ or (contain-intrinsic-size: 1px) /* Safari 17+ */ { ::placeholder { color: color-mix(in oklab, currentcolor 50%, transparent); } } /* Prevent resizing textareas horizontally by default. */ textarea { resize: vertical; } /* Remove the inner padding in Chrome and Safari on macOS. */ ::-webkit-search-decoration { -webkit-appearance: none; } /* 1. Ensure date/time inputs have the same height when empty in iOS Safari. 2. Ensure text alignment can be changed on date/time inputs in iOS Safari. */ ::-webkit-date-and-time-value { min-height: 1lh; /* 1 */ text-align: inherit; /* 2 */ } /* Prevent height from changing on date/time inputs in macOS Safari when the input is set to `display: block`. */ ::-webkit-datetime-edit { display: inline-flex; } /* Remove excess padding from pseudo-elements in date/time inputs to ensure consistent height across browsers. */ ::-webkit-datetime-edit-fields-wrapper { padding: 0; } ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field { padding-block: 0; } /* Center dropdown marker shown on inputs with paired `<datalist>`s in Chrome. (https://github.com/tailwindlabs/tailwindcss/issues/18499) */ ::-webkit-calendar-picker-indicator { line-height: 1; } /* Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) */ :-moz-ui-invalid { box-shadow: none; } /* Correct the inability to style the border radius in iOS Safari. */ button, input:where([type='button'], [type='reset'], [type='submit']), ::file-selector-button { appearance: button; } /* Correct the cursor style of increment and decrement buttons in Safari. */ ::-webkit-inner-spin-button, ::-webkit-outer-spin-button { height: auto; } /* Make elements with the HTML hidden attribute stay hidden by default. */ [hidden]:where(:not([hidden='until-found'])) { display: none !important; }

3.10 前缀(Prefix)

我们可以通过在导入 Tailwind CSS 时添加 prefix() 参数以应用自定义前缀:

globals.css
@import "tailwindcss" prefix(tw); @theme { --font-display: "Satoshi", "sans-serif"; --breakpoint-3xl: 120rem; --color-avocado-100: oklch(0.99 0 0); --color-avocado-200: oklch(0.98 0.04 113.22); --color-avocado-300: oklch(0.94 0.11 115.03); /* ... */ }
output.css
:root { --tw-font-display: "Satoshi", "sans-serif"; --tw-breakpoint-3xl: 120rem; --tw-color-avocado-100: oklch(0.99 0 0); --tw-color-avocado-200: oklch(0.98 0.04 113.22); --tw-color-avocado-300: oklch(0.94 0.11 115.03); /* ... */ }

输出的所有参数都会应用自定义前缀,以避免代码冲突。

四、代码优化

优化 Tailwind CSS 实用类名顺序,使其兼具可读性、易维护性的同时尽可能降低性能开销。

4.1 优化实用类次序

首先让我们为实用类分类排序以易于阅读及维护,我个人倾向于在撰写期间就按照自己喜欢的顺序排序:

  1. 命名、分组与去格式:自定义类名如 group, peer, appearance-*
  2. 自身布局flex-1, grow, shrink-*, self-*, justify-self-*, place-self, basis-*, col-span-*, row-start-*
  3. 定位static, absolute, relative, fixed, sticky
  4. 容器、层级与混合container, z-*, isolate
  5. 布局与显示flex, grid, block, inline, inline-block, hidden. float, clear, invisible
  6. 容器配置flex-row, flex-col, items-*, justify-*, content-*, gap-*, grid-cols-*, grid-rows-*
  7. 尺寸与比例w-*, h-*, size-*, aspect-* 及所有尺寸的 min / max 变体
  8. 定位偏移left-*, right-*, top-*, bottom-*, inset-*
  9. 间距p-*, m-* 及方向变体如 px-*, mr-*
  10. 边框与圆角border-*, rounded-*, ring-*, outline-*
  11. 子元素间距space-x-*, space-y-*, divide-x-*, divide-y-*
  12. 排版text-*, font-*, leading-*, tracking-*, line-clamp-*, whitespace-*, break-*
  13. 背景与图片bg-*, via-*, to-*, object-*
  14. 效果与变换shadow-*, opacity-*, origin-*, transform, scale-*, rotate-*, mix-blend-mode
  15. 遮罩效果blur-*, brightness-*, contrast-* 等所有的 filter 效果,以及对应的 backdrop-*
  16. 交互overflow-*, scroll-*, snap-*, touch-*, user-select-*, resize-*, cursor-*
  17. 过渡与动画transition-*, duration-*, animate-*
  18. 状态修饰符hover:*, focus:*, active:*, group:*, peer:*, nth-*:*
  19. 响应式修饰符sm:*, md:*, lg:*, xl:*, 2xl:*

梳理顺序有助于提升易读性,同时筛选出冲突类名以做删减(示例中 block 会被 flex 覆盖:

❌ Don't:


mt-2 md:mt-4 w-full block opacity-50 flex rotate-45 absolute

✅ Do it:


absolute flex w-full mt-2 opacity-50 rotate-45 md:mt-4

此外,如果你想像本章节 4.1.3 在线演练 小节中那样实现一键排序,我们推荐以下三种优化建议:

  1. 使用 VSCode 插件 Headwind 进行自定义实用类排序
  2. 使用 VSCode 插件 Prettier 进行代码自动格式化
  3. 使用 Prettier 依赖进行排序

特性对比如下:

特性Headwind 插件Prettier 插件Prettier 依赖
安装方式VSCode 扩展VSCode 扩展npm/pnpm
格式范围仅注册的VSCode 扩展npm/pnpm
配置难度中等简单中等
自定义排序
任意值支持
团队协作需同步配置
代码格式化仅类名排序
CI/CD 集成
适用场景自定义排序需求快速上手团队/生产环境

我们按照这个顺序讲解,不过无论你选用哪一种,格式化之前别忘了备份项目:

Terminal
# 进入目录 cd ~/Documents/my-project # 将项目文件备份到 backup/nextjs rsync -av --progress --exclude='node_modules' --exclude='.next' --exclude='build' nextjs/ backup/nextjs

4.1.1 VSCode 插件 Headwind

一个面向 Tailwind CSS 简单实用的格式化工具,唯一的缺点是任意值不支持,所以不推荐保存时自动格式化,而是按需使用。

直接在插件商店搜索 Headwind,在安装完毕后打开 VSCode 的 settings.json(按下⌘ / CTRL + ⇧ / SHIFT + P 然后输入 user settings json 并回车),按需新建对象并填充内容即可:

... // 可选,添加前缀判断,如果你有使用 @import "tailwindcss" prefix() 参数的话,这里需要对应填写 "headwind.customTailwindPrefix": "", // 在保存时格式化,默认为 true "headwind.runOnSave": false, // 格式属性 Regex,此处对应 JSX TSX 中的 className 属性,默认格式 HTML、CSS、JavaScript、TypeScript、JSX、TSX ,识别 class、className 与 CSS 中的 @apply 属性 "headwind.classRegex": { "javascriptreact": "\\bclassName\\s*=\\s*[{\"'`]([^{\"'`]*)[\"'`}]", "typescriptreact": "\\bclassName\\s*=\\s*[{\"'`]([^{\"'`]*)[\"'`}]" }, // 按照下列顺序排序,默认内容比较长,请访问 https://rainydesign.cn/blog/headwind-default-sort-order.json 查看 "headwind.defaultSortOrder": [ "container", // ... ] // 将自定义类名排序到 Tailwind Utilities 之前,默认为 false "headwind.prependCustomClasses": true, // 删除重复类名,默认为 true "headwind.removeDuplicates": true ...

该插件的快捷键是:

  • MacOS: + + T
  • Windows / Linux:CTRL + SHIFT + T

4.1.2 VSCode 插件 Prettier

最方便快捷的一个,直接搜索插件 Prettier 安装,格式化时选择 Prettier 即可。VSCode 格式化快捷键如下:

  • MacOS: + + F
  • Windows / Linux:CTRL + SHIFT + F

很遗憾的是 Prettier 不支持自定义顺序,并且会顺带格式化其他内容,所以建议团队协作环境下使用。以下是 Prettier 的默认实用类名排序:

  1. 布局container, flex, grid, block, inline, hidden
  2. 定位absolute, relative, fixed, sticky, top-*, left-*
  3. 尺寸w-*, h-*, min-w-*, max-w-*
  4. 间距m-*, p-*, space-*
  5. 排版text-*, font-*, leading-*
  6. 背景bg-*
  7. 边框border-*, rounded-*
  8. 效果shadow-*, opacity-*
  9. 过渡transition-*, duration-*
  10. 变换transform, scale-*, rotate-*
  11. 交互cursor-*, select-*
  12. 状态修饰符hover:*, focus:*, active:*
  13. 响应式修饰符sm:*, md:*, lg:*, xl:*, 2xl:*

如果要清除默认格式化插件,请按下⌘ / CTRL + ⇧ / SHIFT + P 然后输入 user settings json,打开用户设置并清除相关内容:

... "[javascript]": { // 删除这个对象 "editor.defaultFormatter": "esbenp.prettier-vscode" } ...

4.1.3 使用 Prettier 依赖进行排序

使用 Prettier 依赖的好处是不进一步扩充 VSCode 插件库,并能在部署后于服务器端直接使用命令行格式化。让我们回到项目安装依赖:

Terminal
# 使用 yarn 安装依赖
yarn add -D prettier prettier-plugin-tailwindcss # 或使用 npm 安装依赖:npm install -D prettier prettier-plugin-tailwindcss

# 然后在项目根目录下创建 .prettierrc 与 .prettierignore
touch .prettierrc .prettierignore

然后把下列内容粘贴进 .prettierrc

my-project/nextjs/.prettierrc
{ "semi": false, "singleQuote": true, "tabWidth": 2, "trailingComma": "es5", "printWidth": 100, "plugins": ["prettier-plugin-tailwindcss"] }

再编辑项目根目录下的 .prettierignore

my-project/nextjs/.prettierignore
# 依赖 node_modules .pnp .pnp.js # 构建产物 .next out build dist # 缓存 .cache .parcel-cache # 日志 *.log npm-debug.log* yarn-debug.log* yarn-error.log* # 环境变量 .env .env.local .env.development.local .env.test.local .env.production.local # 其他 .DS_Store *.min.js *.min.css public/ coverage/

最后添加格式化到 package.json 之中:

my-project/nextjs/package.json
... "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "eslint", "lint:fix": "eslint --fix", "format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css,md}\"", "format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json,css,md}\"" }, ...

保存以上文件,再在终端中执行 yarn format:check 检查语法:

Terminal
yarn run v1.22.22 $ prettier --check "**/*.{js,jsx,ts,tsx,json,css,md}" Checking formatting... [warn] jsconfig.json [warn] next.config.js [warn] src/components/article/ArticleDynamicZone.js [warn] src/components/blog/FeaturedArticles.js [warn] src/components/course/Courses.js [warn] src/components/course/SpecializedCourses.js [warn] src/components/global/Background.js [warn] src/components/global/CustomizedHead.js [warn] src/components/global/Footer.js [warn] src/components/global/Nav.js [warn] src/components/global/Nav2.js [warn] src/components/global/Subscription.js [warn] src/components/home/Comparisons.js [warn] src/components/home/GuideChapters.js [warn] src/components/home/Playground.js [warn] src/components/home/Frameworks.js [warn] src/components/Layout.js [warn] src/components/NestedLayout.js [warn] src/components/shared/About.js [warn] src/components/shared/ArticleCard.js [warn] src/components/shared/ArticleCardContainer.js [warn] src/components/shared/Information.js [warn] src/lib/api.js [warn] src/lib/formatDate.js [warn] src/lib/markdown.js [warn] src/pages/_app.js [warn] src/pages/_document.js [warn] src/pages/_error.js [warn] src/pages/404.js [warn] src/pages/500.js [warn] src/pages/about.js [warn] src/pages/blog.js [warn] src/pages/blog/[...slug].js [warn] src/pages/category/[slug].js [warn] src/pages/course.js [warn] src/pages/index.js [warn] src/styles/globals.css [warn] src/utils/handleFormSubmit.js [warn] Code style issues found in 38 files. Run Prettier with --write to fix. error Command failed with exit code 1. info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Prettier 会自动检查除 .prettierignore 声明以外的文件,上述报告显示它认为我们写的所有文件都有格式问题,不过我们仅需要格式特定的文件就行了,命令如下:

操作命令行示例受影响的文件说明
格式化文件yarn format src/components/global/Subscription.js@/components/global/Subscription.js格式化指定目录下的特定文件
格式化目录yarn format src/components/global@/components/global/ 目录下的格式化指定目录
格式化指定文件名yarn format Nav.js@/components/global/Nav.js, @/components/global/Nav2.js格式化指定文件名,如果存在多个同名文件则会一并格式化

按照上述命令行提示按需格式化文件即可。

4.2 限定范围

通过减小范围避免撰写更多 class,缩短类名长度:

❌ Don't:


class=" group-has-peer-checked:bg-slate-50 group-has-peer-checked:shadow-xl group-has-peer-checked:shadow-primary/12 lg:group-has-peer-checked:bg-none lg:shadow-none lg:group-has-peer-checked:shadow-none "

✅ Do it:


class=" max-lg:group-has-peer-checked:bg-slate-50 max-lg:group-has-peer-checked:shadow-xl max-lg:group-has-peer-checked:shadow-primary/12 "

4.2 提取重复样式组合

便于统一修改全局复用样式,增加可读性,但需注意避免过度抽象,仅对真正复用的样式使用 @apply:

❌ Don't:


<div class="max-w-8xl mx-auto px-6 md:px-9 lg:px-18"></div> <div class="max-w-8xl mx-auto px-6 md:px-9 lg:px-18"></div>

✅ Do it:


globals.css
@layer components { .customized-container { @apply max-w-8xl mx-auto px-6 md:px-9 lg:px-18; } }
example.html
<div class="customized-container"></div> <div class="customized-container"></div>

4.3 向下控制优先

在父元素上汇总通用样式,既能减少子元素的重复定义,也便于统一修改继承或相关样式。因此,撰写 Tailwind 实用类时,请尽可能地采用 “自外而内、由上而下” 的组织顺序。

❌ Don't:

参考代码


<ul class="relative flex bg-neutral-200 rounded-lg"> <li class="grow my-1 py-2 px-4 border-r border-neutral-600 text-neutral-900 text-center">Lorem ipsum</a> <li class="grow my-1 py-2 px-4 border-r border-neutral-600 text-neutral-900 text-center">Lorem ipsum</a> <li class="grow my-1 py-2 px-4 text-neutral-900 text-center">Lorem ipsum</a> </ul>

渲染结果


  • Lorem ipsum
  • Lorem ipsum
  • Lorem ipsum

✅ Do it:

参考代码


<ul class="relative flex justify-items-stretch py-1 bg-neutral-200 rounded-lg divide-x divide-neutral-600 text-center text-neutral-900"> <li class="grow py-2 px-4">Lorem ipsum</a> <li class="grow py-2 px-4">Lorem ipsum</a> <li class="grow py-2 px-4">Lorem ipsum</a> </ul>

渲染结果


  • Lorem ipsum
  • Lorem ipsum
  • Lorem ipsum

可见实际渲染出来的视觉效果并无区别。

4.4 变形代替位移

position 属性会触发重排与重绘,而 transform 属性(translate)不影响文本流的情况下还会触发 GPU 加速,相比之下后者性能更好:

❌ Don't:


left-2 top-6 duration-500 checked:top-0

✅ Do it:


translate-x-2 translate-y-6 duration-500 checked:translate-y-0

4.5 限定动画类型

使用 transition-transform 限定过渡属性。duration-* 默认等同于 transition-all,会对所有可动画属性(如 padding、opacity)计算过渡,显式指定 transition-transform 可减少不必要的计算开销:

❌ Don't:


translate-x-4 px-2 duration-300 hover:translate-x-0 md:px-4

✅ Do it:


translate-x-4 px-2 transition-transform duration-300 hover:translate-x-0 md:px-4

五、原生 CSS 知识点

5.1 小技巧

内容仍在编辑,敬请期待

5.1.1 利用 border 画三角形

待撰写。

如需返回主课程,请 点击此处 回到相关页面。

订阅

解锁深度且前沿的前端技术、设计理念与用户交互探寻之道。