主题
JavaScript 插件与BootStrap 定制和主题(Bootstrap 2/2)
本页对应 课堂视频,共 7 段视频,约 1 小时 35 分。
学习目标
- 能够使用 Bootstrap 轮播图插件完成三张图片轮播,配置指示器与
data属性控制,并使用<picture>结合媒体查询实现不同视口下图片切换。 - 能够使用路径导航、缩略图、分页组件和栅格系统搭建课程列表页,并按
xs/sm/md/lg断点实现每行 1/2/3/4 列布局及响应式页脚。 - 能够下载并替换 Bootstrap 主题 CSS 文件,验证页面按钮、导航等颜色与风格变化。
- 能够不依赖 Bootstrap,使用 Flex 布局和百分比宽度实现可嵌套、可自动换行的 12 列自定义栅格系统。
- 能够使用媒体查询和移动优先策略实现响应式栅格类,说明
xs/sm/md/lg类名的生效范围与覆盖规则。 - 能够使用 Less 变量、Mixin 递归和模块化导入结构生成栅格类,并通过修改列数、断点或容器宽度变量后重新编译验证结果。
知识点
先看本节清单:插件不是“组件样式”,而是带交互的 JS 行为
本节笔记保留如下:
1. 下拉菜单
2. collapse
3. 模态框 modal.js
4. 轮播图 carousel.js
...为什么需要: 下拉菜单、折叠面板、模态框、轮播图这类东西,光靠 CSS 能做出“样子”,但点击切换、自动轮播、指示点联动等交互,需要 JavaScript 插件。Bootstrap 把它们封装好,我们主要是按文档复制结构、补数据、加 data-* 属性。
怎么想: 先查文档对应插件,再复制官方示例,最后把示例里的省略号、占位图、占位文字补全。不要一上来自己写交互。
怎么做: 以所用 Bootstrap 版本文档为准引入对应 JS 文件,不能只引 CSS。转写稿重点演示的是轮播图 carousel.js,所以下面以轮播图为主线;下拉菜单、collapse、modal 先按清单知道“去文档找现成结构”。
易错点: 插件名和组件名容易混;只复制 HTML 不引入 JS,点击没反应;官方示例常省略重复项,不能直接上线。
轮播图:先复制结构,再补全三张图和三个指示点
为什么需要: 手写轮播要处理定时器、左右按钮、小圆点索引、当前项 active,还要考虑响应式图片,成本高。Bootstrap 的 carousel 插件已经把这些行为封装好。
怎么想: 转写稿里说“轮播图属于插件,从文档里复制代码”,复制后先看缺什么:图片没有、指示点数量不够、item 不够。官方示例常用省略号省掉重复项,我们要补齐。注意“轮波图”是口误,正确是“轮播图”。
怎么做: 结构上外层给一个 id,每个指示点用 data-slide-to 关联索引,每个轮播项补 carousel-item,第一项加 active。核心示意:
html
<div id="carouselExampleIndicators" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carouselExampleIndicators" data-slide-to="0" class="active"></li>
<li data-target="#carouselExampleIndicators" data-slide-to="1"></li>
<li data-target="#carouselExampleIndicators" data-slide-to="2"></li>
</ol>
<div class="carousel-inner">
<div class="carousel-item active">
<img src="./images/play01.jpg" alt="轮播图一">
<div class="carousel-caption d-none d-md-block">
<h3>高考乐</h3>
<p>这里放轮播图说明文字。</p>
</div>
</div>
<div class="carousel-item">
<img src="./images/play02.jpg" alt="轮播图二">
</div>
<div class="carousel-item">
<img src="./images/play03.jpg" alt="轮播图三">
</div>
</div>
</div>易错点: data-slide-to 不要写成转写稿口述里的“date-slide-to”;索引从 0 开始;指示点数量要和轮播项数量一致;外层 id 与 data-target 必须对应;第一项别忘了 active。
响应式轮播图:用 picture 换源,但别忘给 img 设宽度
为什么需要: 转写稿指出,小视口下如果只把大图按 100% 缩放,文字区域和图片比例可能不好看。更稳妥的是不同屏幕加载不同尺寸图片:大屏用宽图,小屏用更扁或更合适的图。
怎么想: 用 <picture> 做换源。<source> 按顺序匹配,哪个条件先满足就用哪个;最后的 <img> 是兜底。转写稿里调试很久,一度以为 source 没生效,最后发现是图片原始尺寸太大,又少给 img 设置 width: 100%,导致判断被图片撑开效果误导。
怎么做:
html
<picture>
<source media="(min-width: 992px)" srcset="./images/play01.jpg">
<source media="(min-width: 768px)" srcset="./images/play01-sm.jpg">
<img src="./images/play01-xs.jpg" alt="响应式轮播图一">
</picture>css
.carousel-item img {
width: 100%;
display: block;
}易错点: srcset 不要拼成“SRC set”;media 不要写成“me位置”;条件顺序要清楚;picture 只负责换源,不负责尺寸,样式要落到里面的 img 上;只给 picture 设宽度往往不解决问题。转写稿最后确认:给图片加 width: 100% 后,source 的切换效果才正常显示。
边界提醒:课程列表、分页、页角不是本节插件主线
转写稿后半段还讲了面包屑、缩略图、分页、页角以及自定义栅格系统,这些主要是组件组合、栅格和 LESS 源码结构,不是“JavaScript 插件”这一节的核心。学习时不要把“复制组件结构”和“插件交互”混为一谈:本节先掌握下拉菜单、collapse、modal、carousel 的文档入口和轮播图完整调试过程,后续再展开页面组合与栅格实现。
定制 Bootstrap 与主题替换
为什么需要:项目风格不能永远长得像默认 Bootstrap,颜色、字号、间距往往要统一调整。
怎么想:先分清“定制”和“主题”。定制是改变量或源码;主题是别人已经写好的一套 CSS,直接替换即可。
怎么做:原笔记给了两个入口:
在 Bootswatch 选一套主题,下载后得到一个 CSS 文件,放到项目 css 目录;把原来引入的 bootstrap.css 注释掉,换成主题 CSS。
易错点:不要同时引入默认 Bootstrap 和主题 CSS,否则后引入的会覆盖前面的;主题本质仍是 Bootstrap 样式,不是另一套框架。
轮播图:补齐结构并用 picture 做响应式图片
为什么需要:轮播图复制官方插件代码后通常不完整,图片、指示点、文字都要补。
怎么想:轮播图靠外层 id 和每个小圆点的 data-slide-to 关联;每个 item 对应一张图。响应式图片不能只靠 img 缩放,屏幕很窄时图片会被压得很扁,最好按视口换图。
怎么做:补齐 3 个 item 和 3 个指示点,每个 item 内写 h3 与 p。图片用 picture:
html
<picture>
<source media="(min-width: 992px)" srcset="./images/play01.jpg">
<source media="(min-width: 768px)" srcset="./images/play01-sm.jpg">
<img src="./images/play01-xs.jpg" alt="轮播图一" class="img-responsive">
</picture>调试时 source 一度不生效,检查地址、media、srcset 都没拼错,最后发现图片原始尺寸太大,缺少宽度限制,导致误判。补上图片宽度 100% 后正常:
css
.carousel-inner img { width: 100%; }易错点:picture 的 source 是“先满足先加载”,和 CSS 媒体查询“后覆盖前”相反;source 要有 media 和 srcset;最后必须保留 img 兜底;图片要限制宽度。
课程列表:面包屑、缩略图、分页、页脚
为什么需要:课程列表是典型“组件拼装”页面,手写会慢,组件能快速搭结构。
怎么想:先看响应式关系:超小屏一行 1 个,小屏 2 个,中屏 3 个,大屏 4 个,对应栅格 col-sm-6 col-md-4 col-lg-3。
怎么做:面包屑用“路径导航”组件;课程卡片用“缩略图”组件,外层套 container 和 row;图片加 width:100%;按钮分别用 btn-success 和 btn-primary 一类颜色类;分页复制分页组件,可把箭头改成“上一页/下一页”;页脚没有现成组件,用栅格自己写:
html
<footer class="site-footer">
<div class="container">
<div class="row">
<div class="col-sm-6 col-md-3"><h4>标题</h4><ul><li><a href="#">链接</a></li></ul></div>
<!-- 复制多列 -->
</div>
<p class="copyright">Copyright</p>
</div>
</footer>页脚样式:背景 #333,链接和文字白色,ul 去圆点、去默认内边距,版权文字居中并加上间距。
易错点:缩略图复制后不要连它的 row/col 一起照搬,行列要由页面栅格控制;图片不设宽会撑破卡片;页脚类名写错会导致样式完全不生效。
自定义非响应式栅格:先理解“行 + 列 + 百分比”
为什么需要:会用 Bootstrap 不等于会做布局系统,理解栅格才能改列数、改断点。
怎么想:一行是 flex 容器,允许换行;列不伸不缩,宽度按 n/12 计算。
怎么做:
css
.row { display: flex; flex-wrap: wrap; }
[class*="col-"] { flex: 0 0 auto; box-sizing: border-box; padding: 0 10px; }
.col-1 { width: 8.33%; }
.col-2 { width: 16.66%; }
/* ...手写到 col-12 */易错点:百分比要算准;列宽和 padding 必须配 box-sizing;非响应式只是固定比例,不会随屏幕自动变列数。
响应式栅格:移动优先与媒体查询
为什么需要:同一张页面在手机、平板、桌面要显示不同列数。
怎么想:移动优先:xs 的类写在外层,所有屏幕默认生效;sm/md/lg 写进对应 min-width 媒体查询,大屏继承小屏,除非被更大断点覆盖。
怎么做:
less
.grid(@type: xs) {
.make-col(@n) when (@n <= 12) {
.col-@{type}-@{n} { width: percentage(@n / 12); }
.make-col(@n + 1);
}
.make-col(1);
}
.grid(xs);
@media (min-width: 768px) { .grid(sm); }
@media (min-width: 992px) { .grid(md); }
@media (min-width: 1200px) { .grid(lg); }易错点:@{type} 是变量拼选择器;除法要加括号;递归必须有 when (@n <= 12) 终止条件,否则无限生成;媒体查询里的类只在该断点以上生效。
Less 目录结构与递归混合
为什么需要:Bootstrap 源码把变量、混合、重置、布局、组件拆开,入口只负责 @import,方便维护和二次定制。
怎么想:仿照它建 bootstrap.less 入口,拆 variables.less、mixins.less、normalize.less、layout.less、grid.less;阈值、版心宽度、列数都做成变量。
怎么做:变量里定义 @sm: 768px; @md: 992px; @lg: 1200px; @columns: 12;,生成列宽时用 percentage(@n / @columns);编译只编译入口文件。
易错点:子文件单独打开会报“变量找不到”,因为变量是在入口中统一导入的;改列数只需改变量,但递归上限也要跟着改;不要编译 mixins.less 这类只供引入的文件。
为什么需要自定义栅格系统
Bootstrap 的栅格很好用,但作为前端不能只会复制类名。转写稿里说得很直接:要理解它“怎么设计出来”,才能自己搞一套页面结构框架。自定义栅格的目标不是重写 Bootstrap,而是抓住核心:一行如何分栏、列宽如何按比例计算、不同屏幕下如何切换比例。视频4先做非响应式版本,视频5再加响应式,视频6—7用 Less 组织变量、混合和入口文件,最后自动生成类名。
先做非响应式:Flex + 百分比
为什么需要:如果每列都手写宽度,页面一改就乱;用“行/列”结构才能复用。怎么想:一行是容器,列是项目,列宽用百分比表示 12 份中的几份。怎么做:转写稿中自定义栅格用 Flex,不用浮动。关键代码如下(按转写稿整理):
less
.row {
display: flex;
flex-wrap: wrap;
}
[class*="col-"] {
flex: 0 0 auto;
box-sizing: border-box;
padding: 0 10px;
}
.col-1 { width: 8.33%; }
.col-2 { width: 16.66%; }
.col-3 { width: 25%; }
.col-4 { width: 33.33%; }
/* ……一直到 .col-12 { width: 100%; } */易错点:flex-wrap: wrap 不能少,否则列多了不换行;box-sizing: border-box 要加,否则 padding 会撑宽;百分比要保留两位左右,转写稿里也是用计算器逐个算,说明手写很累,这正是后面用 Less 的原因。
响应式:移动优先与媒体查询
为什么需要:同一张页面在手机、平板、桌面要显示不同列数。怎么想:转写稿反复强调“移动优先,大的跟着小的走”。只写 col-xs-6,所有屏幕都按 6 份;写了 col-md-3,只有中等屏幕及以上才按 3 份,小屏幕仍按默认或 xs。怎么做:把 xs 类写在外层,把 sm/md/lg 放进媒体查询:
less
.col-xs-1 { width: 8.33%; }
/* …… */
@media (min-width: 768px) {
.col-sm-1 { width: 8.33%; }
/* …… */
}
@media (min-width: 992px) {
.col-md-1 { width: 8.33%; }
/* …… */
}
@media (min-width: 1200px) {
.col-lg-1 { width: 8.33%; }
/* …… */
}易错点:媒体查询里的类名必须带对应前缀,如 .col-sm-*;xs 不写媒体查询,所以任何屏幕都生效;sm 的条件是 min-width: 768px,768 以上都生效,除非 md/lg 再覆盖。转写稿中“这个弯要转过来”说的就是覆盖关系。
用 Less 变量和目录组织
为什么需要:阈值、版心宽度、列数会改,散落在 CSS 里难维护。怎么想:仿 Bootstrap 的 Less 源码结构,入口文件只负责引入。怎么做:转写稿建立 eight-strip.less 作为入口,引入变量、混合、normalize、layout、grid。变量可写成:
less
@sm-width: 768px;
@md-width: 992px;
@lg-width: 1200px;
@container-xs: 100%;
@container-sm: 750px;
@container-md: 970px;
@container-lg: 1170px;
@columns: 12;layout.less 负责全局盒模型和 .container 的媒体查询;grid.less 负责行列。易错点:变量文件不需要单独编译,入口文件引入后统一编译;转写稿里 layout 单独看会报“找不到变量”,因为变量是在入口里一起引入的。
递归混合生成类名
为什么需要:12 份 × 4 种屏幕 = 48 个类名,手写又累又容易错。怎么想:Less 没有普通循环,但混合可以自己调用自己,形成递归;加结束条件 @number <= @columns。怎么做:先写内层生成器,再套外层传类型:
less
.grid(@type: xs) {
.make-col(@number) when (@number <= @columns) {
.col-@{type}-@{number} {
width: percentage(@number / @columns);
}
.make-col(@number + 1);
}
.make-col(1);
}
.grid(xs);
@media (min-width: @sm-width) { .grid(sm); }
@media (min-width: @md-width) { .grid(md); }
@media (min-width: @lg-width) { .grid(lg); }易错点:选择器插值要写 .col-@{type}-@{number};除法要加括号 (@number / @columns);percentage() 是 Less 自带函数;递归没有结束条件会无限生成;外层 .grid(@type) 内再定义 .make-col,才能让内层使用 @type。转写稿先在单独文件里用 make-col(1) 验证能生成 1—12,再放回项目编译,编译后得到 48 个类名,改 @columns: 16 就能整体变 16 份。
调试与内容约束
转写稿里还出现一个典型误判:响应式类名写对了,但列里的图片原始尺寸太大,显示溢出,看起来像“媒体查询没生效”。后来给图片补 width: 100% 才正常。栅格只负责列宽,不负责内容尺寸;课程列表里也加了类似 .courses img { width: 100%; }。所以自定义栅格完成后,还要约束图片等替换元素,否则大图会撑破列,导致调试方向跑偏。
作业目标与使用方式
本节作业不是“抄一个页面”,而是用 Bootstrap 案例练熟文档检索、组件拼装和响应式调试,最后反过来用 Less 实现一套自己的栅格系统。先保留本节任务清单:
text
1. bootstrap页面案例
2. 读bootstrap文档
3. 尝试 4、5 的使用
4. 自己使用 less 实现栅格系统下面按这四项展开。每个知识点都按“为什么需要 → 怎么想 → 怎么做 → 易错点”来写。
一、Bootstrap 页面案例:先搭轮播图,再补响应式图片
为什么需要:轮播图、课程列表、分页、页脚是后台/课程页的高频结构。用现成组件能快速搭出页面骨架,但真正要学的是“组件如何与栅格、响应式图片配合”。
怎么想:先复制轮播图插件代码,再补齐三张图片、三组文字和三个小圆点。轮播图小圆点的控制依赖 data-slide-to 与最外层 id 关联;小屏下文字显示不全时,不要只让图片 width:100% 硬缩,而要考虑换图。
怎么做:轮播项按三份复制,图片路径分别换成 01/02/03,每个 item 内补 h3 和段落。响应式图片用 picture:
html
<picture>
<source media="(min-width: 992px)" srcset="./img/play01.jpg">
<source media="(min-width: 768px)" srcset="./img/play01-sm.jpg">
<img src="./img/play01-xs.jpg" alt="轮播图小屏图片">
</picture>转写中调试很久,最后发现不是 source 拼写错,而是图片没有限制宽度,导致“看起来一直加载小图”的误判。给图片补:
css
.course-list img {
width: 100%;
}易错点:picture 的 source 是“先有效先加载”,与 CSS 媒体查询“后覆盖前”不同;source 用 srcset,不是 src;轮播图外层 id 与 data-target 要对上;图片必须补 width:100%,否则大图会把容器撑开。
二、读 Bootstrap 文档:按组件找现成结构
为什么需要:Bootstrap 的组件名和日常叫法不完全一致。比如“面包屑导航”在文档里叫“路径导航”,课程卡片可看“缩略图”,分页就是“分页”组件。不熟文档就找不到。
怎么想:先确定页面区块:路径导航、课程列表、分页、页脚。前三个优先找组件,页脚没有现成组件就手写栅格。
怎么做:路径导航复制后改“首页 / 课程 / 推荐课程”,最后一个可不做链接;课程列表先确定响应式份数:超小屏 12 份、小屏 6 份、中屏 4 份、大屏 3 份,即 col-sm-6 col-md-4 col-lg-3。缩略图复制后只保留内部结构,外层行列自己写。分页复制后把箭头改成“上一页/下一页”。页脚用 footer + container + 行 + 列,列按 col-sm-6 col-md-3 组织。
易错点:复制组件后常把示例外层行列一起复制,导致嵌套混乱;课程图片同样要 width:100%;页脚没有组件时不要硬找,直接用栅格手写。
三、尝试 4、5 的使用:只迁移结构,不硬套类名
为什么需要:Bootstrap 3、4、5 的类名和布局方式有差异。作业要求“尝试 4、5 的使用”,目的是让你养成按版本文档查写法的习惯。
怎么想:把已有案例当作结构参考,不把 3 的类名无条件套到 4/5。重点验证栅格、容器、轮播图、分页、卡片/缩略图这些区块。
怎么做:打开对应版本文档,逐项替换类名与结构;先保证页面骨架能显示,再补样式。遇到组件结构变化,以文档示例为准。
易错点:不要凭记忆写 4/5 类名;不要同时混用多个版本的类名;迁移后要重新检查响应式断点和图片宽度。
四、自己用 Less 实现栅格系统:变量、混合、递归循环
为什么需要:会用 Bootstrap 只是“会复制”,理解栅格系统怎么生成,才算真正掌握布局框架。转写中强调:栅格系统是核心,其他组件技术含量相对低。
怎么想:先做非响应式,再做响应式。用变量保存断点、容器宽度、列数;用 Flex 做行容器;用混合生成 .col-xs-1 到 .col-xs-12。Less 没有直接循环,但混合可以递归调用自己,用条件终止。
怎么做:目录上设入口文件,只编译入口,变量、混合、重置、布局、栅格分别引入。关键混合可写成:
less
.grid(@type: xs) {
.make-col(@number) when (@number <= 12) {
.col-@{type}-@{number} {
width: percentage(@number / 12);
}
.make-col(@number + 1);
}
.make-col(1);
}外层再按媒体查询调用 .grid(sm); .grid(md); .grid(lg);。变量可把 12 换成 @columns,把断点换成 @sm-width、@md-width 等。
易错点:递归必须有终止条件,否则无限生成;选择器插值要写 @{number};只编译入口文件,变量和混合文件不单独编译;移动优先下,xs 写在外层,sm/md/lg 放进对应 min-width 媒体查询;改列数时所有百分比要跟着变量走。
五、调试记录与检查清单
转写中的调试很典型:轮播图小屏文字挤压 → 换 picture;picture 看似不生效 → 检查 source 顺序、srcset、媒体条件;最终发现图片未设 width:100%,造成“加载错图”的误判。课程列表图片撑破列,也是同一类问题。Less 递归则要检查终止条件、变量作用域和入口编译。
交作业前检查:轮播图 id/data-slide-to 是否对应;picture 是否三档图片齐全;课程列表是否按 sm-6/md-4/lg-3 响应;分页和页脚是否在版心内;Less 是否只编译入口;把列数从 12 改成 16 时是否仍能生成正确百分比。
课堂画面






代码示例
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 轮播图 + picture 响应式图片</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<style>
/* 关键:必须限制图片宽度,否则大图会撑开容器,导致误判响应式图片没生效 */
.carousel-inner .item img {
width: 100%;
}
.carousel-inner .item picture {
display: block;
}
.carousel-caption {
background: rgba(0, 0, 0, .35);
}
</style>
</head>
<body>
<div class="container">
<div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
<!-- 小圆点:data-target 指向最外层轮播图 id,data-slide-to 对应索引 -->
<ol class="carousel-indicators">
<li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li>
<li data-target="#carousel-example-generic" data-slide-to="1"></li>
<li data-target="#carousel-example-generic" data-slide-to="2"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="item active">
<picture>
<!-- picture 的 source 是“先匹配先生效”,与 CSS 媒体查询覆盖顺序相反 -->
<source media="(min-width: 992px)"
srcset="https://via.placeholder.com/1170x400/337ab7/ffffff?text=play01+LG">
<source media="(min-width: 768px)"
srcset="https://via.placeholder.com/768x400/5cb85c/ffffff?text=play01+SM">
<img src="https://via.placeholder.com/480x300/f0ad4e/ffffff?text=play01+XS" alt="play01">
</picture>
<div class="carousel-caption">
<h3>高考乐</h3>
<p>第一张轮播图文字,屏幕变小时图片会自动切换。</p>
</div>
</div>
<div class="item">
<picture>
<source media="(min-width: 992px)"
srcset="https://via.placeholder.com/1170x400/d9534f/ffffff?text=play02+LG">
<source media="(min-width: 768px)"
srcset="https://via.placeholder.com/768x400/5bc0de/ffffff?text=play02+SM">
<img src="https://via.placeholder.com/480x300/8e44ad/ffffff?text=play02+XS" alt="play02">
</picture>
<div class="carousel-caption">
<h3>高考乐高二</h3>
<p>第二张轮播图文字,使用 picture 切换不同尺寸图片。</p>
</div>
</div>
<div class="item">
<picture>
<source media="(min-width: 992px)"
srcset="https://via.placeholder.com/1170x400/2c3e50/ffffff?text=play03+LG">
<source media="(min-width: 768px)"
srcset="https://via.placeholder.com/768x400/18bc9c/ffffff?text=play03+SM">
<img src="https://via.placeholder.com/480x300/e67e22/ffffff?text=play03+XS" alt="play03">
</picture>
<div class="carousel-caption">
<h3>高考乐高三</h3>
<p>第三张轮播图文字,轮播图整体也是响应式的。</p>
</div>
</div>
</div>
<a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">上一张</span>
</a>
<a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">下一张</span>
</a>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
</body>
</html>关键行与易错点:
- 轮播图最外层必须有
id="carousel-example-generic",小圆点的data-target要指向这个 id,data-slide-to对应 0、1、2。 - 第一个
.item必须加active,第一个小圆点也必须加active。 picture中source是“先匹配先生效”,所以先写min-width: 992px,再写min-width: 768px,最后用img src兜底超小屏。- 最容易错的是忘记给图片设置
width: 100%。大图会把容器撑开,看起来像source没生效,其实是被大图尺寸误判了。 - 实际项目把占位图地址换成
play01.jpg、play01-sm.jpg、play01-xs.jpg即可。
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 课程列表页面</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<style>
.my-breadcrumb {
margin: 20px 0;
}
.course-list img {
width: 100%;
}
.my-footer {
background: #333;
color: #fff;
padding: 40px 0;
margin-top: 20px;
}
.my-footer a {
color: #fff;
}
.my-footer ul {
list-style: none;
padding-left: 0;
}
.copyright {
text-align: center;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<ol class="breadcrumb my-breadcrumb">
<li><a href="#">首页</a></li>
<li><a href="#">课程</a></li>
<li class="active">推荐课程</li>
</ol>
<div class="row course-list">
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3">
<div class="thumbnail">
<img src="https://via.placeholder.com/400x250/337ab7/ffffff?text=HTML5" alt="HTML5">
<div class="caption">
<h3>HTML5</h3>
<p>HTML5 课程介绍文字,共二十个字左右。</p>
<p>
<a href="#" class="btn btn-success">立即购买</a>
<a href="#" class="btn btn-primary">在线试看</a>
</p>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3">
<div class="thumbnail">
<img src="https://via.placeholder.com/400x250/5cb85c/ffffff?text=CSS3" alt="CSS3">
<div class="caption">
<h3>CSS3</h3>
<p>CSS3 课程介绍文字,共二十个字左右。</p>
<p>
<a href="#" class="btn btn-success">立即购买</a>
<a href="#" class="btn btn-primary">在线试看</a>
</p>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3">
<div class="thumbnail">
<img src="https://via.placeholder.com/400x250/f0ad4e/ffffff?text=JavaScript" alt="JavaScript">
<div class="caption">
<h3>JavaScript</h3>
<p>JavaScript 课程介绍文字,共二十个字左右。</p>
<p>
<a href="#" class="btn btn-success">立即购买</a>
<a href="#" class="btn btn-primary">在线试看</a>
</p>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3">
<div class="thumbnail">
<img src="https://via.placeholder.com/400x250/d9534f/ffffff?text=Bootstrap" alt="Bootstrap">
<div class="caption">
<h3>Bootstrap</h3>
<p>Bootstrap 课程介绍文字,共二十个字左右。</p>
<p>
<a href="#" class="btn btn-success">立即购买</a>
<a href="#" class="btn btn-primary">在线试看</a>
</p>
</div>
</div>
</div>
</div>
<div class="text-center">
<ul class="pagination">
<li><a href="#">上一页</a></li>
<li class="active"><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">下一页</a></li>
</ul>
</div>
</div>
<footer class="my-footer">
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-3">
<h4>关于我们</h4>
<ul>
<li><a href="#">公司介绍</a></li>
<li><a href="#">联系方式</a></li>
</ul>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<h4>课程中心</h4>
<ul>
<li><a href="#">前端课程</a></li>
<li><a href="#">后端课程</a></li>
<li><a href="#">移动开发</a></li>常见错误
- 现象:轮播图小圆点有 3 个,但图片只轮播 2 张或点击圆点错位。原因:复制官方示例时保留了省略号,未补齐
.item,且data-slide-to与条目索引未一一对应。修法:补齐轮播项数量,统一外层id,逐项核对data-slide-to的 0/1/2 索引。 - 现象:
picture响应式图片不按断点切换,总显示某一张图。原因:只怀疑source写错,实际常是img未限制宽度,大图撑开后造成误判。修法:先给picture内图片设置width:100%,再检查source的media条件和顺序。 - 现象:自定义响应式栅格类名在部分屏幕不生效。原因:把
XS也写进媒体查询,或只写MD却期望小屏生效。修法:按移动优先处理,XS放全局,SM/MD/LG分别放入对应min-width媒体查询,并核对阈值变量。 - 现象:修改 Less 栅格列数后,生成结果仍是 12 份。原因:递归混合中写死
12,或编译的不是入口文件。修法:统一改用@columns变量,只编译入口atstrip.less,检查编译产物是否按新列数生成。 - 现象:替换 Bootswatch 主题后样式不生效或旧样式残留。原因:新主题 CSS 未替换原 Bootstrap 引用,或引入顺序、缓存有问题。修法:替换原
bootstrap.css引用,确认主题 CSS 顺序正确,清理缓存后刷新。 - 现象:单独打开
layout.less报变量找不到。原因:变量文件只由入口文件统一导入,单独编译该分文件时作用域中没有变量。修法:不要单独编译分文件,只编译统一入口文件,由入口先导入变量、混合和分模块。
练习
- 用 Bootstrap 完成一个页面:轮播图、面包屑、课程列表、分页、页脚,并检查各断点下列数是否符合预期。
- 用
picture改造轮播图图片,准备大、中、小三种尺寸,验证 992px、768px 附近图片切换是否正确,并记录一次排错过程。 - 用 Less 自定义栅格系统,分别生成 12 列和 16 列版本,验证一行分列、嵌套分列和自动换行。
- 从 Bootswatch 选择一套主题替换现有页面样式,记录替换了哪个 CSS、是否清理缓存、页面哪些颜色发生变化。
- 给定一个“
picture不切换图片”的页面,按“DOM 数量→图片宽度→source条件→浏览器渲染结果”的顺序写出排查步骤。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | Bootstrap页面案例02-轮播图 | 23:57 |
| 2 | Bootstrap页面案例03-课程列表 | 13:17 |
| 3 | Bootstrap主题 | 02:30 |
| 4 | 自定义栅格系统 | 09:57 |
| 5 | 自定义响应式栅格系统 | 11:36 |
| 6 | less实现栅格系统01-目录结构 | 08:40 |
| 7 | less实现栅格系统02 | 25:40 |
小结
- 复制插件示例后必须补齐 DOM 数量,并核对
data-*与目标索引,不能保留示例省略号。 - 响应式图片排错应先看图片实际渲染尺寸和 CSS 约束,再检查
source条件。 - 响应式栅格的关键不是类名多少,而是移动优先下媒体查询的生效范围与覆盖关系。
- 自定义栅格应把阈值、容器宽度、列数变量化,避免在循环和类名中写死。
- Less 递归混合必须有明确终止条件,且只编译统一入口文件。
- 主题定制本质上是变量和 CSS 覆盖,替换后要检查引入顺序与缓存。
- 页面拼装效率来自对组件文档的熟练度,但真正排错仍要回到 DOM、CSS 和编译产物。