三份可直接双击打开的案例页、一个同屏对比页、一批本机实测数据——聊聊三种 CSS 框架的设计哲学、样式能力、交互成本和选型边界。

手上有三份"讲同一件事"的页面:它们都演示布局、排版、表单、组件、工具类、暗黑模式这几块内容,但分别用 Bootstrap、Bulma、Tailwind CSS 实现。既然内容对等,就正好可以当成一次控制变量的横评。
为了对比方便,我又做了两件事:
index.html:三栏 iframe 并排/堆叠、可缩放、可按章节跳转、可同步滚动,样式互不污染;文件清单如下。
文件 | 框架与版本 | 说明 |
|---|---|---|
index.html | — | 同屏对比页:三栏 iframe + 功能矩阵 + 代码对照(不含本文,本文单独成页) |
bootstrap-showcase.html | Bootstrap 5.3.8 | 组件全家桶,交互由官方 bundle 驱动,含 icons 与暗黑模式 |
bulma-showcase.html | Bulma 1.0.4 | 纯 CSS,交互为 183 行自写 JS,含 v1 的 grid 与 skeleton |
tailwind-showcase.html | Tailwind 4.3.3 | 原子化工具类拼装,交互为 197 行自写 JS |
三份页面结构上刻意对齐,覆盖的模块数量如下:
页面 | 章节 | 行数 | 自写 JS | 自定义 CSS |
|---|---|---|---|---|
Bootstrap | 布局 / 排版 / 图片表格 / 组件 / 表单 / 工具 | 1088 | 80 行 | 43 行 |
Bulma | 布局 / 元素 / 组件 / 表单 / 辅助 / 特性 | 1306 | 183 行 | 57 行 |
Tailwind | 布局 / 排版 / 颜色 / 按钮 / 表单 / 组件 / 工具 | 873 | 197 行 | 3 行 + 314 处 dark: |
最后一行已经剧透了三个框架的性格:Bootstrap 用别人的 JS,Bulma 用别人的 CSS,Tailwind 什么都不给你但什么都能写。
Bootstrap:把组件当一等公民。 它交付的是一套完整的 UI 套件——按钮、卡片、模态框、下拉、轮播、Toast、Offcanvas、Tooltip……每个组件既有样式也有行为,行为由官方 JS 插件驱动。你用 data-bs-toggle 写声明,剩下的(焦点陷阱、ESC 关闭、滚动锁、ARIA 状态同步)框架全包。
Bulma:把语义化类名当一等公民。 它只交付 CSS,一个字节 JS 都没有。类名高度可读(button is-primary is-outlined、has-text-danger、is-size-3),v1 之后全面变量化(--bulma-*),顺带内置了暗黑模式的变量切换和 is-skeleton 骨架屏。代价是:交互、图标、Toast 这类"行为"要你自己接。
Tailwind:把设计 token + 原子类当一等公民。 它交付的是一台编译器:你写 px-4 py-2 rounded-lg bg-sky-600,它按需生成对应的 CSS。没有"按钮"这个概念,只有零件。好处是产物最小、约束最统一;代价是模板变长、组件体系要自己长出来(或引入 shadcn/Headless UI 这类无样式组件库)。
<!-- Bootstrap:语义类组合,改颜色改尺寸都只是换类名 -->
<button type="button" class="btn btn-primary">主要按钮</button>
<button type="button" class="btn btn-outline-primary btn-sm">描边小按钮</button>
<button type="button" class="btn btn-primary" disabled>禁用</button><!-- Bulma:读起来最像英文句子 -->
<button class="button is-primary">主要按钮</button>
<button class="button is-outlined is-small">描边小按钮</button>
<button class="button is-primary" disabled>禁用</button><!-- Tailwind:一次写完所有细节,复用要靠组件化 -->
<button class="rounded-lg bg-sky-600 px-4 py-2 text-sm font-medium text-white
transition hover:bg-sky-500 disabled:cursor-not-allowed disabled:opacity-50">
主要按钮
</button>三行代码背后是三种维护模型:Bootstrap 改一次 --bs-primary 全局生效;Bulma 改一次 --bulma-primary 全局生效;Tailwind 要靠设计 token 和组件封装,否则你会在一个项目里看到 7 种蓝色。
对比项 | Bootstrap | Bulma | Tailwind |
|---|---|---|---|
栅格 | 12 列 flex 栅格,offset/order/gutter 齐全 | columns(12 等分 flex)+ v1 grid(CSS Grid) | 原生 Grid/Flex 任意拼装,grid-cols-12、gap-4 |
间距刻度 | m/p-0~5 六档 + auto | m/p-0~6 七档 | 0.25rem 基准的任意倍数,p-13 也合法 |
颜色 | 8 个语义色 + subtle/emphasis/rgb 变体 | 6 个语义色 + light/dark/invert/on-* 派生 | 22+ 色板 × 11 阶,支持任意值 |
排版 | display-*、lead、fs-*、fw-* | title、subtitle、is-size-* | text-*、font-*、leading-*、tracking-* |
圆角阴影 | 够用 | 偏少,常需自定义 | 全套 + 任意值 |
写一套新皮肤 | 低(SCSS / CSS 变量) | 低(--bulma-* 变量) | 中(要自己定义并贯穿 token) |
一句话总结:Bootstrap 提供"够用的刻度",Bulma 提供"好读的刻度",Tailwind 提供"没有刻度的尺子"。 刻度少的好处是设计一致性天然更好;刻度自由的好处是不用为了 13px 的间距去写一个自定义类。
我把三份页面里演示过的组件整理成 24 类,逐个核对:
组件 | Bootstrap | Bulma | Tailwind |
|---|---|---|---|
按钮 / 按钮组 | ✅ 内置 | ✅ 内置 | ⚠️ flex 拼装 |
卡片 | ✅ | ✅ | ⚠️ |
模态框 | ✅ + 官方 JS | ✅ 结构 + 自写 JS | ⚠️ 自绘 + 自写 JS |
下拉菜单 | ✅ 官方 JS | ✅ + 自写 JS | ⚠️ + 自写 JS |
标签页 | ✅ 官方 JS | ✅ + 自写 JS | ⚠️ role=tablist 自写 |
手风琴 / 折叠 | ✅ | ⚠️ 自写 | ⚠️ 自写 |
轮播 | ✅ | ❌ | ⚠️ 自写 |
Toast 通知 | ✅ | ⚠️ 只有静态 notification | ⚠️ 自写 + aria-live |
进度条 | ✅ 含条纹/动画 | ✅ | ⚠️ |
分页 | ✅ | ✅ 含 ellipsis | ⚠️ |
面包屑 | ✅ | ✅ 含 is-arrowed | ⚠️ |
徽章 / 标签 | ✅ | ✅ 可删除 tag | ⚠️ |
列表组 / 面板 / 消息块 | ✅ list-group | ✅ panel / message / menu | ⚠️ |
侧滑面板 | ✅ offcanvas | ❌ | ⚠️ |
提示 / 气泡 | ✅ tooltip + popover | ❌ | ⚠️ |
骨架屏 | ✅ placeholder | ✅ is-skeleton(v1) | ⚠️ animate-pulse |
导航栏(含汉堡) | ✅ 官方 JS | ✅ + 自写 JS | ⚠️ |
表格 | ✅ | ✅ | ⚠️ |
表单校验态 | ✅ | ✅ | ⚠️ 自绘 |
浮动标签 | ✅ form-floating | ⚠️ 自写 | ⚠️ peer 技巧 |
输入组 / 前后缀 | ✅ | ✅ 图标型 | ⚠️ |
开关 switch | ✅ | ⚠️ | ⚠️ |
文件上传 | ✅ | ✅ 组件较完整 | ⚠️ |
滑块 / 多选下拉 | ✅ | ⚠️ | ⚠️ |
统计结果:Bootstrap 24 类全部开箱即用;Bulma 16 类有现成样式(5 类要自己拼、3 类没有);Tailwind 一类都没有。
这就是三个框架最本质的差别:Bootstrap 卖组件,Bulma 卖样式,Tailwind 卖零件。如果你的页面里塞满了模态框、下拉、轮播、Toast,选 Bootstrap 省下的工作量是以"天"计算的;如果页面基本是内容展示,Bulma 的语义化类名会让 HTML 好读很多。
交互成本 | Bootstrap | Bulma | Tailwind |
|---|---|---|---|
交互实现者 | 官方 bundle(79 KB / gzip 23.3 KB) | 你自己 | 你自己 |
案例页自写 JS | 80 行(基本只有主题切换) | 183 行 | 197 行 |
声明式交互 | ✅ data-bs-toggle="modal" | ❌ | ❌ |
ARIA 状态同步 | 插件自动 | 手写 | 手写 |
键盘支持(ESC / Tab / 方向键) | 框架内置 | 手写 | 手写 |
有个很直观的对照:三份页面里都有"下拉菜单、标签页、模态框、导航栏汉堡菜单、主题切换"这五组交互。
aria-expanded 和 is-active 的切换都得自己来。判断法则:如果页面里超过 5 个交互组件,Bootstrap 的 79 KB JS 是划算的;如果只有一两个(比如一个移动端菜单),那 190 行自写 JS 换来的"零 JS 依赖"更干净。
路线 | Bootstrap | Bulma | Tailwind |
|---|---|---|---|
机制 | data-bs-theme="dark" | data-theme="dark" 覆盖 --bulma-* | .dark class + dark: 变体 |
切换代码 | 一行 setAttribute | 一行 setAttribute | 一行 classList.toggle |
逐元素适配 | 不需要 | 不需要(自定义组件用变量即可) | 314 处 dark: |
可控粒度 | 整套变量 | 整套变量 | 任意元素 |
主要坑 | 自定义 CSS 要用 --bs-* 变量 | v0 没有变量体系,v1 才补齐 | class 变长,token 不统一就会花 |
暗黑模式其实是判断一个框架"是否设计系统化"的试纸。Bootstrap 和 Bulma 的做法是"换一套变量",你写业务样式时只要用变量,切换就是零成本;Tailwind 的做法是"每个元素写两遍",控制力最强,但三份页面里它是唯一需要 314 处额外类名的那份——这不是 Tailwind 的缺陷,而是它的模型:它把主题决策的负担从框架转移到了你的模板和团队约定上。
以下数据在本机实测(方法见文末),原始体积按 CDN 上的 min 版本统计,gzip 为 level 9。
资源 | 原始 | gzip |
|---|---|---|
Bootstrap 5.3.8 CSS | 227 KB | 30.0 KB |
Bootstrap 5.3.8 bundle JS | 79 KB | 23.3 KB |
Bootstrap Icons CSS(另有字体文件) | 84 KB | 12.9 KB |
Bulma 1.0.4 CSS | 662 KB | 63.5 KB |
Tailwind 4.3.3 浏览器版运行时 | 276 KB | 72.1 KB |
Tailwind 为案例页按需生成的 CSS | 53 KB | 8.4 KB |
同上,minify 后(≈生产产物) | 42 KB | 7.8 KB |
Bootstrap CSS + JS + 图标合计 | 390 KB | 66.2 KB |
三点解读:
框架 | 断点档位 | 写法 |
|---|---|---|
Bootstrap | 6 档:576 / 768 / 992 / 1200 / 1400 | col-12 col-md-6 col-lg-4,断点内建在栅格类里 |
Bulma | 5 档:769 / 1024 / 1216 / 1408(+ mobile) | columns is-multiline + 修饰类,或 v1 的 grid |
Tailwind | 5 档:640 / 768 / 1024 / 1280 / 1536,可自定义 | 前缀即断点:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 |
写起来最顺手的是 Tailwind(任何工具类都能加断点前缀,不必是"栅格专属");最省心的是 Bootstrap(栅格类自带断点,不需要你记断点数值);Bulma 的断点基于 min-width,从 tablet 才开始生效,写移动优先时需要适应一下它的心智模型。
aria-expanded、aria-selected、aria-controls,模态框有焦点陷阱、ESC 关闭、滚动锁,还有 visually-hidden、RTL 支持。这一栏它领先得最多。aria-expanded、aria-selected、aria-hidden 与 focus-visible 描边;Tailwind 版手写了 role="tablist"、role="dialog"、aria-modal、aria-live、role="switch" + aria-checked。也就是说两份都补齐了,差别在于"谁保证不漏":Bootstrap 是框架保证,另两个是代码评审保证。如果你在做面向公众、有合规要求的项目,把可访问性检查写进 CI(例如 axe-core),比选哪个框架更重要。
对比项 | Bootstrap | Bulma | Tailwind |
|---|---|---|---|
是否必须构建 | 否 | 否 | 生产建议构建 |
按需裁剪 | 需自行用 SCSS 编译 | 需自行用 Sass 编译 | 天生按需生成 |
主题定制入口 | SCSS 变量 / --bs-* | Sass 变量 / --bulma-* | @theme 设计 token |
大版本升级风险 | 4 → 5 有破坏性变更 | 0.x → 1.0 变更较大 | 3 → 4 改为 CSS-first 配置 |
生态 | 极大(后台模板、企业项目多) | 中等 | 极大(Headless UI / Radix / shadcn) |
代码可读性 | 好,模板干净 | 最好 | 一般,需要组件化约束 |
学习曲线 | 低 | 低 | 中 |
AI / 脚手架友好度 | 高 | 中 | 高(但依赖团队 token 约定) |
两个容易被忽略的点:
cva、clsx、@apply 或 React 组件)。没有这层约定,半年后的模板会变成一堵 class 墙。场景 | 推荐 | 理由 |
|---|---|---|
后台管理系统、内部工具 | Bootstrap | 组件最多,表格/表单/模态框一次到位,交付最快 |
官网、落地页、内容型页面 | Bulma 或 Tailwind | 页面以展示为主,Bootstrap 的 JS 用不上 |
有设计稿、要还原度、长期迭代的 C 端产品 | Tailwind | token 化 + 任意值,最贴近设计系统 |
团队 CSS 弱、只想少写样式和 JS | Bulma | 语义化类名 + 零 JS,读起来就像 HTML |
快速原型 / Demo 给客户看 | Bootstrap 或 Tailwind + shadcn | 出效果最快 |
老项目增量改造 | Bootstrap 单组件定制,或 Tailwind 局部引入 | 都能按模块引入,不必整体迁移 |
追求极致首屏性能的静态站 | Tailwind 构建产物 | 只为用到的类生成 CSS,可压到最小 |
三条经验法则:
也可以混着用:Tailwind 写页面 + Headless UI/Radix 管交互;Bootstrap 只定制 SCSS 变量当组件库;Bulma 配少量自写 JS 做轻量站点。框架不是阵营,是成本结构。
三份页面演示的是同一批 UI,但把它们并排放在一起时,差别不在"哪个更好看",而在你把成本付给了谁:
如果今天要重做这套案例页:交互密集的管理后台我会选 Bootstrap;内容型站点选 Bulma;有设计系统、要长期演进的产品选 Tailwind。没有最好的框架,只有最合适的约束。
查看对比页
index.html:三栏 iframe 会自动加载三份案例页(首次需联网拉 CDN)。file:// 下浏览器禁止跨文档访问,页面会自动提示降级。用同目录的 启动本地服务.cmd 以 http://localhost:8931/ 打开即可启用同步滚动与章节即时跳转。测量方法
tailwind-showcase.html,等浏览器端编译完成后提取注入的样式表,再用 lightningcss 压缩得到上面的数字。dark: 计数:脚本统计三份 HTML 的行数与正则匹配数量。数据采集于 2026-10-16,版本为当日 CDN 最新稳定版:Bootstrap 5.3.8、Bulma 1.0.4、Tailwind CSS 4.3.3,三者均为 MIT 许可。



原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。