ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

用 Tailwind 构建侧边栏标题组件:从基础样式到折叠动画的完整实践

2026/9/15 4:58:03 拓冰建站 浏览量
用 Tailwind 构建侧边栏标题组件:从基础样式到折叠动画的完整实践 用 Tailwind 做了快四年前台项目侧边栏标题这个组件我发现自己起码重写过五六遍。乍一看不就是几个字加 padding 吗真做起来才发现里面全是细节分组标题要不要大写导航项文字在什么宽度下截断折叠后标题藏哪去badge 数字怎么动才有反馈感今天把踩过的坑和最终沉淀下来的一套写法完整整理出来给准备用 Tailwind 搭侧边栏或者正在重构后台布局的朋友做个参考。这篇文章不绕弯子直接讲设计思路、完整代码、进阶动画和排查经验看完你就能照着落地。1. 从需求到设计侧边栏标题到底在解决什么问题很多新手拿到设计稿第一反应是“标题不就是个 p 标签吗”但真正做起来才发现侧边栏里的“标题”至少分成好几种每种的信息密度、交互状态、视觉权重都不一样。如果上来就写p classfont-bold菜单/p后面大概率会返工。1.1 先把侧边栏标题分个类我习惯把侧边栏里的标题性文字分成四类分类不同Tailwind 类名的组合策略也不同。类型出现位置核心作用典型样式倾向分组标题一组导航项上方说明当前区块是什么小字号、大写、字距宽、颜色弱导航项标题每个可点击链接内部告诉用户去哪、当前在哪字号正常、hover/active 反馈明显折叠面板标题可展开/收起的父级菜单承载展开状态与方向箭头左右布局、有 chevron 或徽标底部元信息标题侧边栏底部放版本号、账户名、操作入口字更小、间距更紧、常带分割线拿一个典型的后台管理系统举例左侧是“工作台 / 项目 / 设置”这类导航顶部往往会先出现一个“主导航”或“全部功能”的分组标题用来把互不相关的模块隔开而每个可点击项内部又有一个导航项标题。这两者的样式如果不做区分用户视觉上就分不清“能点的”和“不能点的”可用性立刻打折。明白这个分类后再回头看 Tailwind 的价值就清晰了——它不是在写样式而是在帮我把“视觉层级”翻译成一套可复用的类名组合。分组标题我统一用text-xs加uppercase加tracking-wider导航项标题用text-sm加font-medium底部信息用text-xs text-slate-400。长期维护下来团队新成员看到类名就能猜到设计意图。1.2 为什么用 Tailwind 来写会更省心有人会问侧边栏标题这种简单元素手写几行 CSS 不就行了吗为什么非要 Tailwind我在多个项目里对比过差别主要体现在三件事上。第一Tailwind 把“设计约束”直接做进了类名。手写 CSS 时你可能随手写一个font-size: 13px下一个同事又写一个13.5px久而久之字号体系就烂了。用 Tailwind 的text-xs、text-sm默认就活在比例系统里视觉节奏不会乱。第二暗色模式不用单独维护一套规则。手写 CSS 通常要在样式表里写media (prefers-color-scheme: dark)或者搞.dark .sidebar-title这种嵌套选择器文件一长就乱。Tailwind 的dark:变体是原子化加在元素上的哪里需要适配就在哪里加dark:text-slate-300代码结构跟着组件走删组件的时候样式也不会残留成僵尸代码。第三重构成本低。做过后台的人都知道侧边栏菜单结构经常变今天菜单三级改两级明天分组标题下面塞进一个新模块。用 Tailwind 意味着改的是模板里的类名组合而不是去 CSS 文件里翻找.sidebar-group-title定义在哪个媒体查询里。对一个活着的项目来说这个收益比想象中大得多。1.3 布局与层级设计标题也是信息架构侧边栏标题的视觉样式不能脱离整体布局单独设计。我一般先画出导航的信息架构再决定标题层级。举个例子工作空间分组标题总览导航项标题报表导航项标题成员导航项标题项目分组标题进行中导航项标题 数字徽标已完成导航项标题这种结构下分组标题的职责是“区隔”导航项标题的职责是“引导点击”。区隔不需要太强存在感所以我通常会让分组标题使用比导航项更低的对比度比如text-slate-400同时加深底色的留白导航项则保持中高对比度并用 hover 背景色强化可点击感。这个思路也可以反推如果某个标题在侧边栏里承担了很重的信息传达功能比如“进行中”后面要显示未完成任务数量那就不能简单把它当普通文字处理得预留徽标位置。所以每次动手前先花 10 分钟把信息架构画一遍比直接写代码划算得多。2. 动手实现基于 Tailwind 的侧边栏标题完整代码设计思路定了接下来就是把思路落成代码。这里我给出一个可以直接跑起来的基础版本包含分组标题、导航项标题、折叠面板标题三个最常见的场景代码里用的都是 Tailwind 3 的类名不需要额外配置也能运行。2.1 基础结构aside nav 两层标题模型先搭一个完整的侧边栏结构。注意我在这里就把“分组标题”和“导航项标题”分成两层处理而不是都堆在同一个层级里。aside classflex h-screen w-64 flex-col border-r border-slate-200 bg-white dark:border-slate-800 dark:bg-slate-900 !-- 侧边栏顶部品牌区 -- div classflex h-16 items-center gap-2 px-4 span classtext-lg font-bold text-slate-900 dark:text-whiteAcme Admin/span /div !-- 导航滚动区域 -- nav classflex-1 space-y-6 overflow-y-auto px-3 py-4 !-- 分组一 -- div p classpx-3 text-xs font-semibold uppercase tracking-wider text-slate-400 工作空间 /p ul classmt-2 space-y-1 li a href# classflex items-center gap-3 rounded-lg bg-slate-100 px-3 py-2 text-sm font-medium text-slate-900 dark:bg-slate-800 dark:text-white !-- 图标 -- svg classh-5 w-5 flex-shrink-0 fillnone viewBox0 0 24 24 strokecurrentColor stroke-width2 path stroke-linecapround stroke-linejoinround dM3 12l9-9 9 9M5 10v10a1 1 0 001 1h3a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1h3a1 1 0 001-1V10 / /svg span总览/span /a /li /ul /div !-- 分组二包含折叠面板标题示例 -- div p classpx-3 text-xs font-semibold uppercase tracking-wider text-slate-400 项目 /p ul classmt-2 space-y-1 li button typebutton classflex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium text-slate-700 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800 !-- 图标 -- svg classh-5 w-5 flex-shrink-0 fillnone viewBox0 0 24 24 strokecurrentColor stroke-width2 path stroke-linecapround stroke-linejoinround dM4 6h16M4 12h16M4 18h10 / /svg span classflex-1 text-left全部项目/span !-- 徽标数字 -- span classrounded-full bg-slate-200 px-2 text-xs font-semibold text-slate-600 dark:bg-slate-700 dark:text-slate-20012/span !-- chevron 箭头 -- svg classh-4 w-4 transition-transform fillnone viewBox0 0 24 24 strokecurrentColor stroke-width2 path stroke-linecapround stroke-linejoinround dM19 9l-7 7-7-7 / /svg /button /li /ul /div /nav /aside这段代码里最关键的几个类名我拆开讲。flex h-screen w-64 flex-col决定了侧边栏是一个固定宽度的纵向弹性盒子border-r负责右侧分割线dark:bg-slate-900让暗色模式下底色跟着切换。nav上的flex-1 overflow-y-auto px-3保证内容超出时可以滚动而且滚动条不会贴着窗口边缘视觉上更干净。分组标题p标签上我用了text-xs font-semibold uppercase tracking-wider text-slate-400这一串类名不是随手堆的稍后单独展开。导航项里的a和button都统一了flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium保证所有可点击项的尺寸一致符合 Fitts 定律里“目标越大越容易点击”的原则同时也让 hover 背景色刚好包住整个可点击区域。2.2 分组标题的细节text-xs 不是越小越好分组标题是侧边栏里最容易“用力过猛”的元素。有人觉得既然是标题就该加粗加大结果一排文字像报表表头抢走了导航项的视觉权重。我推荐的组合是text-xs font-semibold uppercase tracking-wider text-slate-400这个组合在大多数后台设计里都成立。先说text-xs。它比正文小一号视觉上退到“辅助信息”的位置不跟导航项抢注意力。但注意如果侧边栏整体很大、间距很宽text-xs可能显得过于纤细这种情况下我会改用text-[13px]但依然控制在比text-sm小的范围。再说uppercase和tracking-wider。大写加宽字距会让文字更像“标签”而不是“句子”这在英文界面里尤其明显中文界面里uppercase不生效但tracking-wider依然有效能让中文分组标题多一点呼吸感不至于挤成一团。最后是颜色。我用text-slate-400在白色背景上是中等偏浅的灰够区分但不会太跳。暗色模式下同理dark:text-slate-400或dark:text-slate-500都可以具体看你的暗色背景深浅。这里有个细节分组标题不要直接贴在上一个区块底下否则跟上一个导航项之间缺少呼吸感。我在每个分组外层用space-y-6控制组与组的间距让分组标题自带“新区块开始”的心理暗示。2.3 导航项标题可点击区域的完整拼图导航项标题不能只考虑文字本身它是一个“可点击区域的完整拼图”文字、图标、右侧徽标、hover 背景、active 状态五者要协同设计。第一图标和文字必须严格对齐。图标我用h-5 w-5固定尺寸再配合flex-shrink-0防止折叠时被压缩。文字用span包裹而不是直接裸文本这样后续要加truncate、flex-1之类的类名才有抓手。第二padding 要对称。px-3 py-2是我用得最多的组合矮胖一点用py-2需要更大点击区域就用py-2.5。这里有个经验后台侧边栏的单项目标点击区域高度最好不要低于 32px否则鼠标精准定位成本高。第三hover 和 active 状态必须成对出现。我的习惯是高亮当前页用bg-slate-100 dark:bg-slate-800配合text-slate-900 dark:text-whitehover 用hover:bg-slate-100 dark:hover:bg-slate-800。如果你用同一种背景表示当前项和悬停项用户会分不清自己现在在哪。第四如果导航项右侧带徽标要给它单独占位。像上面的“全部项目”后面那个rounded-full bg-slate-200 px-2 text-xs徽标需要设置flex-shrink-0否则数字变多时会把文字挤变形。还要注意徽标和文字之间的间距gap-3是在 flex 容器上统一控制的徽标就不用再加 margin。3. 进阶折叠状态、数字动画与暗色模式基础版本能覆盖大部分后台页面但真实项目里侧边栏还要面对三种进阶情况窄屏下折叠、数字徽标动起来、暗色模式下半透明背景的文字可读性问题。这三个问题我都在生产环境里踩过下面逐个说。3.1 折叠侧边栏时标题怎么“藏”才自然侧边栏折叠是后台系统标配但折叠后标题的处理方式非常容易翻车。最常见的错误是宽度从w-64变成w-20文字还在原来的位置结果文字溢出到容器外面icon 和文字挤成一团。我的做法是三层配合。第一层容器宽度变化后所有图标保持居中第二层文字部分用truncate加opacity-0隐藏同时宽度动画平滑过渡第三层鼠标悬停在折叠后的图标上时用绝对定位浮层显示完整标题。a href# classgroup flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium text-slate-700 hover:bg-slate-100 dark:text-slate-300 !-- 图标固定 -- svg classh-5 w-5 flex-shrink-0 fillnone viewBox0 0 24 24 strokecurrentColor stroke-width2 path stroke-linecapround stroke-linejoinround dM3 12l9-9 9 9M5 10v10a1 1 0 001 1h3a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1h3a1 1 0 001-1V10 / /svg !-- 文字在折叠时隐藏 -- span classtruncate opacity-100 transition-opacity duration-200 group-data-[collapsed]:opacity-0总览/span !-- 折叠后的浮层提示 -- span classpointer-events-none absolute left-full ml-2 whitespace-nowrap rounded-md bg-slate-900 px-2 py-1 text-xs text-white opacity-0 shadow-lg transition-opacity group-hover:opacity-100 总览 /span /a这里我用了一个自定义 data 属性>span classrelative inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-red-500 px-1.5 text-xs font-semibold text-white span classanimation-number>keyframes number-bounce { 0% { transform: translateY(0); } 30% { transform: translateY(-4px); } 60% { transform: translateY(2px); } 100% { transform: translateY(0); } } .animation-number { display: inline-block; animation: number-bounce 0.4s ease-in-out; }要实现“数字从 11 变成 12 时只跳一次”我建议在 React或 Vue里给数字元素绑定一个动态key比如key{count}。当计数变化时DOM 元素会被重新创建动画就会重新触发一次。比手动监听状态再操作 class 干净很多。span classNameanimation-number key{count} {count} /span这个方案的好处是把动画和状态解耦Tailwind 负责静态布局和视觉风格CSS keyframes 只负责“数字进入时跳那么一下”逻辑代码不需要知道动画细节。实际测下来0.4 秒的弹跳比较温和不会让人头晕也不会喧宾夺主。如果项目里用了tailwindcss-animate之类的插件也可以直接用animate-fade-in、animate-slide-in等现成动画思路一样。重点是克制徽标动画是为了提醒“有更新”不是为了炫技动画时长不长于 500ms位移不超过 4px是一个比较稳妥的经验值。3.3 暗色模式与半透明背景的对比度陷阱暗色模式移植到侧边栏时最常见的坑不是“背景变黑”而是“半透明背景 文字”的组合会让标题文字发虚。这和最近讨论的半透明侧边栏问题属于同一类原因半透明层叠加透明像素后背景明暗不确定文字对比度完全不可控。我自己遇到过一种情况侧边栏用了bg-slate-900/70 backdrop-blur-lg想让背景有一点毛玻璃质感。结果浅色文字在浅色内容滚动到下方时对比度骤降标题几乎看不清。排查下来问题出在“背景透明度的百分比是固定的但下面叠加的内容亮度不固定”。解决办法有两个思路。思路一给文字增加稳妥的底色保护比如在半透明侧边栏内部再加一层实心背景aside classfixed inset-y-0 left-0 w-64 border-r border-slate-200 bg-white/80 backdrop-blur-lg dark:border-slate-800 dark:bg-slate-900/80 !-- 顶部标题文字 -- span classtext-slate-900 dark:text-whiteAcme Admin/span /aside如果侧边栏本身已经半透明文字和背景之间的对比度依赖底下内容风险很高。我后来的经验是如果要做毛玻璃效果至少保证背景透明度不低于 80%或者在半透明层下面垫一层与底色接近的实色背景。思路二使用暗色模式下更亮的文字颜色。比如普通模式下标题用text-slate-900暗色模式下用text-white而不是text-slate-300因为slate-300在低透明度背景下对比度不够。这个建议来自我测过的一次对比度体验同一个侧边栏text-slate-300在半透明暗色背景上的可读性远不如text-white。另外要注意backdrop-blur会消耗 GPU 资源侧边栏又是常驻元素如果页面同时有大量动画或图表半透明毛玻璃可能导致滚动或切换菜单时出现卡顿。实测中低端设备上尤其明显。所以如果没有很强烈的设计需求暗色模式下我倾向用接近实心的dark:bg-slate-900只保留微弱的透明度比如dark:bg-slate-900/90兼顾质感和性能。4. 常见问题与排查技巧实录写侧边栏标题看起来简单实际项目里问题最多的是各种“差一点”的样式问题文字溢出一点、图标偏了几个像素、高亮背景盖不住浮层。下面这几个问题是我在真实项目里被问得最多的也是我自己重复踩过坑的地方。4.1 文本溢出truncate 不是万能的给侧边栏导航项加truncate之后长菜单名通常会显示成省略号这没问题。但这个方案有一个前提父容器必须是 flex 或者 grid 的子项并且元素本身要有min-w-0才能正常参与收缩计算。我遇到过的情况是导航项文字很长truncate加上了左侧图标正常右侧还有徽标结果文字把徽标挤出容器。排查后发现问题出在两个地方一是文字 span 没有设置min-w-0导致它不参与 flex 收缩二是徽标没有flex-shrink-0被压缩变形。正确的类名组合是a classflex items-center gap-3 rounded-lg px-3 py-2 text-sm svg classh-5 w-5 flex-shrink-0.../svg span classmin-w-0 flex-1 truncate这是一个非常长的项目名称/span span classflex-shrink-0 rounded-full bg-red-500 px-2 text-xs text-white3/span /amin-w-0允许 span 收缩到比内容更窄truncate才能生效flex-1让文字占满剩余空间徽标保持不收缩。这三者缺一不可。如果你发现 truncate 不生效先去检查这三兄弟在不在。4.2 高亮状态被折叠容器遮挡折叠后的侧边栏宽度很窄导航项 hover 出来一个浮层标题是很常见的交互。但浮层很容易被父容器裁掉原因通常是祖先元素设置了overflow-hidden或者overflow-y-auto。导航容器为了滚动设置overflow-y-auto是合理的但这个属性同时会创建新的滚动上下文绝对定位的浮层如果放到导航容器里面就会被滚动容器裁掉。解决办法是浮层不要放在这个滚动容器内部而是通过浮层组件挂在侧边栏根级或者至少保证浮层容器本身有足够高的 z-index并且不处在overflow裁剪链上。我的做法是把浮层提示放在导航项元素内但给整个侧边栏根节点设置overflow-visible滚动容器继续保留overflow-y-auto同时给浮层加上z-50。如果这样还是被裁可以考虑改用 JavaScript 控制的 Tooltip 组件把浮层渲染到 body 下彻底绕开容器裁剪问题。这里还要注意 z-index 不是越大越好。侧边栏里如果同时有折叠浮层和下拉菜单过大的 z-index 会导致浮层盖住页面顶部的全局导航反而不对。一般z-50到z-100够用我把 z-index 的控制范围锁在一个小组件内部避免全局污染。4.3 图标与文字垂直不对齐用 inline SVG 做图标时最常见的瑕疵是图标和文字在垂直方向上差了几个像素。表面看是“没对齐”根因多半是图标尺寸、line-height、svg 自身对齐方式三者没有统一。我建议按下面这个组合来写基本不会出问题图标统一用h-4 w-4或h-5 w-5同一个侧边栏不要混用两种尺寸svg 加flex-shrink-0避免被压缩不要依赖 svg 默认的垂直对齐而是让父元素用flex items-center让 flex 对齐接管如果图标用的是字体图标在纵向居中的同时给文字加leading-none避免文字行高把图标往下顶。如果用了items-center后仍感觉偏了几个像素可以检查 svg 的viewBox是否包含多余上下留白。不同 icon 库的 svg 内部留白不一样这种问题不在 Tailwind 控制范围内需要单独调整 svg 的preserveAspectRatio或手动给 svg 加一个极小的translate-y修正。4.4 半透明背景导致的文字发虚前面讲暗色模式时说过半透明背景的问题这里再补一个排查思路。很多人遇到的是侧边栏用了bg-white/70 backdrop-blur-md标题文字看着还行但截图发给产品经理后对方说“文字有点虚”。本质是半透明背景让文字边缘的对比度变低了尤其是白底上叠了一层浅灰半透明再叠加旁边滚动的彩色内容文字边缘会有轻微渗色。我的排查顺序是先检查透明度是不是低于 80%低于这个值基本都会有可读性风险再看文字颜色和最终合成背景的对比度用浏览器 DevTools 的 color contrast 功能测一下低于 WCAG AA 标准就要调最后检查是否有backdrop-blur如果背景本身色彩很杂模糊效果不够强文字边缘还是会被底色干扰。可以把模糊半径调大或者提高背景不透明度。这几个问题处理完之后侧边栏标题在大多数场景下都能保持清晰稳定的效果。我个人在实际项目里的建议是侧边栏这类高频操作区优先保证可读性和点击效率视觉上可以克制一点不必为了炫酷引入太多半透明和动画。把分组标题、导航项、折叠浮层、数字徽标这四件事做好整个后台的可用性就已经能超过绝大多数项目了。最后再分享一个小技巧把侧边栏标题反复用到的几组类名抽到layer components里比如.sidebar-group-title和.sidebar-nav-item用apply组合起来。这样既能享受 Tailwind 的原子化开发速度又不用在模板里写一长串重复类名团队协作时也好统一改样式。要注意的是apply不要滥用只抽那些确定会复用且不会频繁改动的组合否则又会陷入“样式继承地狱”那就跟 Tailwind 的初衷背道而驰了。