3.4 弹窗提示与卡片等杂项组件 弹层家族(modal、toast、tooltip、popover)长在「层级」上而不是栅格上:它们脱离文档流,挂到 body 末端,靠 z-index 与 Popper 定位生存,与断点几乎无关。杂项家族(card、badge、progress、accordion)则长在栅格里,断点行为全部外借。两类并成一节,用「长在哪」这把标尺统一断案。 位置:组件四案的收尾。前三案都在文档流内,本案一半在地狱层级——理解「两种生长位置」的分野,是从会用到懂用的分水岭。6.1 节会把本案的脚本 API 讲深。
弹层家族(modal、toast、tooltip、popover)长在「层级」上而不是栅格上:它们脱离文档流,挂到 body 末端,靠 z-index 与 Popper 定位生存,与断点几乎无关。杂项家族(card、badge、progress、accordion)则长在栅格里,断点行为全部外借。两类并成一节,用「长在哪」这把标尺统一断案。
位置:组件四案的收尾。前三案都在文档流内,本案一半在地狱层级——理解「两种生长位置」的分野,是从会用到懂用的分水岭。6.1 节会把本案的脚本 API 讲深。

<!-- 触发按钮:data 属性即全部接线 --> <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#confirmModal"> 删除所选项目 </button> <!-- 对话框本体:aria 属性是判例的一部分,不是可选装饰 --> <div class="modal fade" id="confirmModal" tabindex="-1" aria-labelledby="confirmTitle" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="confirmTitle">确认删除</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="关闭"></button> </div> <div class="modal-body"> 删除后三十天内可从回收站恢复,确定继续? </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button> <button type="button" class="btn btn-danger">确认删除</button> </div> </div> </div> </div>
断案要点:modal 的宽度档位由 modal-dialog 的修饰类决定——默认 500px、modal-sm 300px、modal-lg 800px、modal-xl 1140px,是固定档位而非断点条文;手机窄屏上它自动收缩到视口减边距,不需要你写媒体查询。要「小于 sm 恒全屏」,判 modal-fullscreen-sm-down,这是家族里唯一带断点的类。
<!-- alert:常驻页面的静态提示,纯 CSS,加 dismiss 按钮后带 JS 退场 --> <div class="alert alert-warning alert-dismissible fade show" role="alert"> 浏览器版本过旧,部分布局断案结果可能失真。 <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="关闭"></button> </div> <!-- toast:右下角短时通知,入场出场带动画,需 JS 才能现身 --> <div class="toast-container position-fixed bottom-0 end-0 p-3"> <div class="toast" role="status" aria-live="polite" aria-atomic="true" data-bs-delay="3000"> <div class="toast-header"> <strong class="me-auto">保存提醒</strong> <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="关闭"></button> </div> <div class="toast-body">草稿已自动保存到本地。</div> </div> </div>
分工裁决:结论性、需要用户知情到底的信息判 alert(占版面、可回看);过程性、看过即弃的反馈判 toast(自动退场、不打断)。toast 默认藏起来,要么 data 属性触发要么脚本调 show——它常驻 DOM 但不常驻视野。
<!-- card:栅格里的万能容器,断点行为全部外借 --> <div class="row row-cols-1 row-cols-md-3 g-3"> <div class="col"> <div class="card h-100"> <div class="card-body"> <h5 class="card-title">栅格体检</h5> <p class="card-text">十二列预算表与行满换行的现场验证。</p> <span class="badge text-bg-primary rounded-pill">第 2 章</span> </div> <div class="card-footer text-body-secondary">更新于八月</div> </div> </div> <div class="col"><div class="card h-100"><div class="card-body">同构卡片 B</div></div></div> <div class="col"><div class="card h-100"><div class="card-body">同构卡片 C</div></div></div> </div> <!-- 效果:手机一列、md 起三列;h-100 让矮卡片被拉到与同行最高者齐平 --> <!-- progress:进度条,与断点无关 --> <div class="progress" role="progressbar" aria-valuenow="72" aria-valuemin="0" aria-valuemax="100" aria-label="课程进度"> <div class="progress-bar progress-bar-striped progress-bar-animated" style="width: 72%">72%</div> </div> <!-- accordion:折叠面板组,手风琴行为由 JS 维护「至多一个展开」 --> <div class="accordion" id="faqBox"> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#faq1"> 为什么我的 col-md-6 在手机上不生效? </button> </h2> <div id="faq1" class="accordion-collapse collapse show" data-bs-parent="#faqBox"> <div class="accordion-body"> md 条文只在 768px 及以上生效;手机区间听 col-* 无前缀条文的。 </div> </div> </div> </div>
⚠️ 常见坑:tooltip 必须由 JS 初始化(
new bootstrap.Tooltip逐个实例化),data 属性不会自动激活它——这与 modal、toast 的「data 属性即接线」不同,是弹层家族里唯一的例外。另外 tooltip 与 popover 依赖 Popper 定位,没引 bundle 版脚本时位置会错乱。
需求一:确认框要能滚动长内容——modal-dialog-scrollable 让 body 区独立滚动,头脚固定。需求二:想要侧边抽屉而不是中央对话框——modal 没有现成的抽屉档位,工程上常用 modal-dialog 加自定义样式改判(宽 400px、贴右、高度满屏),定制幅度已触及第 5 章 CSS 覆盖的边界。需求三:卡片墙要「手机一列、平板两列、桌面四列」——改 row-cols-1 row-cols-md-2 row-cols-xl-4,card 本身一行不动,再次印证杂项家族的断点全靠外借。
modal-fullscreen-sm-down;组件案卷到此归档。下一章把散落在各节的工具类胶水正式立册归档。