主题
小兔鲜儿(三)
本页对应 小兔鲜儿,共 8 段视频,约 54 分钟。
学习目标
- 能独立完成生鲜/服饰商品模块的小
li复制与批量搭建,正确复制小li而非整个ul,并在浏览器中验证商品列表结构正常显示。 - 能使用 VS Code 快捷键
Ctrl+K Ctrl+0与Ctrl+K Ctrl+J完成代码全部折叠/展开,并在多模块代码中快速定位、复制目标结构。 - 能基于现有 HD/BD 结构搭建最新专题模块,写出
ul>li*3,并通过新增news类提高选择器权重,覆盖默认li的宽高与背景样式,在浏览器中验证三个卡片为 355×405。 - 能在卡片
PIC容器内使用定位完成txt信息层压到图片底部,设置宽 405、高 90、上 20 左右 15 的内边距,并用 Flex 实现左右分栏。 - 能完成
txt左侧标题/说明与右侧价格盒子的样式,使用 Flex、水平/垂直居中和字号颜色设置,并使用linear-gradient配合rgba/transparent实现透明到半透明黑色的背景渐变。 - 能完成底部描述区左右布局及字体图标加文字排列,去除调试背景色,并在新建
center页面中复用公共头部、底部和common.css,验证页面头尾结构与样式正常加载。
知识点
内容区为什么要先搭“左右两块”
生鲜模块的标题和“查看全部”做完后,下面就是内容区。转写稿里反复强调:先把大盒子搭起来,再往里装内容,“一层一层来,别一上来脑子全插”。内容区如果直接往里面塞图片和列表,后面很难控制位置;先分成左右两个容器,左边放宣传图,右边留给商品列表,结构就清楚了。
为什么需要:生鲜内容区左边是一张竖长宣传图,右边是一组商品小列表,两者宽度、高度都不同,必须分开控制。怎么想:把内容区看成一个“行”,里面放两个“列”,左列固定宽度,右列固定宽度,整体横向排列。怎么做:外层 .content 用 flex,里面放 .left 和 .right 两个 div。易错点:不要先把图片直接写在 .content 里,否则图片和右侧列表会变成同级兄弟,后面加间距、调对齐都会乱。
HTML 结构:content 包住 left 和 right
html
<!-- 内容区域 -->
<div class="content">
<div class="left">
<a href="#"><img src="./uploads/fresh_left.png" alt="生鲜左侧宣传图"></a>
</div>
<div class="right"></div>
</div>为什么需要:.left 里用 a 包图片,是为了以后整张宣传图可点击;.right 先空着,作为右侧商品列表的容器。怎么想:结构上只分两层,外层负责横向排列,内层负责各自内容。怎么做:先写 .content,再写 .left、.right,图片的 alt 写成中文,方便图片加载失败时识别。易错点:a 是行内元素,img 默认是行内替换元素,图片底部容易出现几像素空隙;后面给 .left 或图片设置 display: block 可以消除。转写稿里还提醒:复制列表时“千万不要再复制 ul 了,复制的是小 li”,因为一个 ul 里已经包含 8 个 li,整段复制会多出一层容器。
尺寸从哪来:248 + 968 = 1216
css
/* 生鲜内容 */
/* 内容区域 */
.fresh .content {
display: flex;
justify-content: space-between;
}
.fresh .content .left {
width: 248px;
height: 610px;
/* background-color: pink; */
}
.fresh .content .right {
width: 968px;
height: 610px;
background-color: skyblue;
}为什么需要:左右两块必须按设计稿的尺寸占位,否则右侧列表的 8 个小 li 没有稳定容器。怎么想:左侧宣传图量出来是 248×610,右侧列表区域是 968×610,248 + 968 正好等于版心宽度 1216,说明两块之间没有额外间距,是紧贴两边的。怎么做:.content 加 display: flex,两个子元素自然排成一行;再用 justify-content: space-between,只有两个子元素时就是“一个贴左、一个贴右”。.right 先给 skyblue 背景色,是为了肉眼确认盒子位置和大小,内容写完再删掉。易错点:space-between 在两个子元素时不会在中间产生固定间距,它是把剩余空间全部分配到中间;如果以后改成三个子元素,表现会变成“两端贴边、中间等分”,不要误以为它只负责左右贴边。另外 flex 默认不换行,左右宽度相加超过父容器时会挤压或溢出,所以宽度要按版心算准。
调试时先看盒子,再填内容
为什么需要:转写稿里说,“找错误我都说先打开调试工具来看”,因为代码写到上千行后,靠眼睛翻很难定位。怎么想:先确认 .content 是不是 flex、.left 和 .right 的宽高是不是生效,再往里面放图片和列表。怎么做:浏览器里右键检查,选中 .right,看它的计算宽高是不是 968×610;如果右侧没撑开,检查是不是被其他选择器覆盖,或者父级宽度不够。易错点:.right 的 skyblue 只是占位色,最后要删掉;.left 里的 background-color: pink 是注释掉的调试代码,不要误以为它参与布局。转写稿还提到用 Ctrl + K 再按 Ctrl + 0 全部折叠、Ctrl + K 再按 Ctrl + J 全部展开,代码变长后先折叠再复制模块,能避免拖选拖错位置。
小结
这一节的核心不是“写多少样式”,而是先把生鲜内容区拆成左右两个稳定容器:.content 负责一行排列和两端对齐,.left 固定 248×610 放宣传图,.right 固定 968×610 给右侧列表占位。先让盒子可见,再填图片和列表,最后删掉调试背景色,这是后面复制服饰、餐厨、居家模块时最稳的做法。
先明确本节目标
这一节要完成生鲜模块右侧内容区的小 li 搭建。转写稿里反复说的“小力”,指的是小 li;“UR”指的是 ul。所以复制时一定要复制小 li,不要把整个 ul 复制进去,否则会出现 ul 套 ul 的结构错误。
为什么需要先搭小 li:右侧区域最终要放多个内容项,先把每个小 li 的尺寸、排列和 hover 效果定下来,后面再往里面装图片和文字就不容易乱。怎么想:先骨架、后内容;先让 8 个小 li 显示出来,再考虑内部结构。怎么做:先按笔记写出 right 里的 ul 和第一个 li,确认结构无误后再复制小 li。易错点:复制时要把 <li>...</li> 整体选中,按 Ctrl+C、Ctrl+V 粘贴,不要只复制文字,也不要复制外层 ul。
本节笔记保留的 HTML 如下:
html
<div class="right">
<ul>
<li>1</li>
</ul>
</div>用 flex 与 flex-wrap 排列小 li
为什么需要:右侧宽度有限,8 个小 li 不能只排一行,需要自动换行。怎么想:ul 作为父容器开启 display: flex,再用 flex-wrap: wrap 允许换行。怎么做:按笔记给 .right ul 设置 display: flex; flex-wrap: wrap;。按尺寸可推导:右侧宽 968px,小 li 宽 242px,一行大约放 4 个;高 610px,小 li 高 304px,大约两行,正好容纳 8 个小 li。易错点:只写 display: flex 不写 flex-wrap: wrap,小 li 会被挤在一行;复制完 8 个小 li 后要检查标签闭合和数量。
小 li 的尺寸、背景与透明边框
为什么需要:每个内容项要有统一尺寸,hover 时还要有边框反馈。怎么想:先把小 li 的宽高和背景色写出来,让它可见;边框先设为透明,hover 时只改边框颜色。怎么做:按笔记设置 width: 242px; height: 304px; background-color: pink; border: 2px solid transparent;。易错点:如果一开始不写透明边框,hover 时直接加 border,盒子尺寸可能变化,页面容易抖动;透明边框相当于提前占位。
本节笔记保留的 CSS 如下:
css
.fresh .content .right {
width: 968px;
height: 610px;
background-color: skyblue;
}
.fresh .content .right ul {
display: flex;
/* 强制换行 */
flex-wrap: wrap;
}
.fresh .content .right li {
width: 242px;
height: 304px;
background-color: pink;
/* 颜色透明 transparent */
border: 2px solid transparent;
}
.fresh .content .right li:hover {
/* border: 2px solid var(--lv); */
border-color: var(--lv);
}hover 用变量统一主色
为什么需要:页面主色以后可能要统一调整,如果每个 hover 都写死颜色,改起来很麻烦。怎么想:边框颜色交给变量 --lv,hover 时只改 border-color。怎么做:保留笔记中的 border-color: var(--lv);,不要重复写 border 的全部属性。易错点:变量 --lv 没有定义时,hover 边框不会显示预期颜色;选择器层级要写完整,确保命中 .fresh .content .right li。
复制小 li 与调试检查
为什么需要:生鲜模块右侧需要多个小 li,手动写容易漏标签。怎么想:先写一个正确的小 li,再复制成 8 个,复制对象是小 li 而不是 ul。怎么做:选中一个完整的 <li>...</li>,按 Ctrl+C,在 ul 内部按 Ctrl+V 多次;完成后保存,在浏览器右击检查,确认 ul 的 display: flex 和 flex-wrap: wrap 生效。易错点:转写稿里特别提醒“这里面是有 ul 里面是包含 8 个 li,所以千万不要再复制 ul 了”;如果 hover 没反应,先用调试工具检查变量、选择器和边框是否被覆盖。
先看清结构:左边广告,右边商品列表
生鲜区的内容不是简单堆图片,而是“左侧一张固定广告图 + 右侧商品网格”。为什么先拆结构?因为左右宽度不同、排列方式也不同,先分盒子后面才好定位。
怎么想:外层 .content 让左右并排,用 display:flex 和 justify-content:space-between 把两块推到两端。左边 .left 宽 248、高 610;右边 .right 宽 968、高 610。248 + 968 正好是版心宽度,所以不要随意改数字。
怎么做:HTML 里 .content 下放 .left 和 .right,左边 a > img,右边 ul > li。图片 alt 要写清楚,比如左侧广告图写“生鲜左侧广告图”,商品图写“双味千层手抓饼”。
易错点:左边 a 里包 img 时,图片默认有缝隙,后面可用 display:block 处理;右边宽度算错,商品列就会提前换行。
html
<!-- 内容区域 -->
<div class="content">
<div class="left">
<a href="#"><img src="./uploads/fresh_left.png" alt="生鲜左侧广告图"></a>
</div>
<div class="right">
<ul>
<li>
<a href="#">
<div class="pic">
<img src="./uploads/fresh1.png" alt="双味千层手抓饼">
</div>
<div class="info">
<h5>双味千层,手抓饼烤肉组合</h5>
<p>240g/袋 4片装</p>
<p>加热即食</p>
</div>
<div class="price">
¥ <span>88.99</span>
</div>
</a>
<div class="find">
<h4>找相似</h4>
<a href="#">
发现更多宝贝
<i class="iconfont icon-arrow-right-bold"></i>
</a>
</div>
</li>
</ul>
</div>
</div>右侧列表:ul 负责换行,li 负责尺寸
为什么需要 flex-wrap?因为 8 个商品要排成 4 列 2 行,只写 display:flex 会挤在一行。
怎么想:让 ul 成为弹性容器并允许换行,每个 li 固定宽高,排满一行自动掉到下一行。
怎么做:.right ul { display:flex; flex-wrap:wrap; },li 宽 242、高 304。
易错点:li 里的 a 要 display:block; height:100%,否则行内元素设高度无效,点击区域也不对。
css
.fresh .content {
display: flex;
justify-content: space-between;
}
.fresh .content .left {
width: 248px;
height: 610px;
}
.fresh .content .right {
width: 968px;
height: 610px;
}
.fresh .content .right ul {
display: flex;
flex-wrap: wrap;
}
.fresh .content .right li {
overflow: hidden;
position: relative;
width: 242px;
height: 304px;
border: 2px solid transparent;
}卡片内部:图片、信息、价格三段
为什么拆三段?商品卡片的信息层级很清楚:图、标题规格、价格。拆开才好分别调间距和字号。
怎么想:a 统一给 padding:10px 0 0 20px 把内容往里挤;.pic 固定 200×180;.info 上边距 14;.price 上边距 5。
怎么做:h5 16px,p 行高 19px;价格颜色 #AF2F22,span 22px 只放大数字。
易错点:a 必须 display:block;价格里的 ¥ 不要包进 span,否则符号和数字一起变大。
css
.fresh .content .right li > a {
display: block;
height: 100%;
padding: 10px 0 0 20px;
}
.fresh .content .pic {
width: 200px;
height: 180px;
}
.fresh .content .info {
margin-top: 14px;
font-size: 16px;
line-height: 19px;
}
.fresh .content .info h5 {
font-size: 16px;
}
.fresh .content .price {
margin-top: 5px;
font-size: 15px;
color: #AF2F22;
}
.fresh .content .price span {
font-size: 22px;
}hover 边框:先用透明边框占位
为什么默认写 border:2px solid transparent?如果默认没边框,hover 时突然加 2px,盒子尺寸会变,内容会被挤动。
怎么想:边框一直存在,只是颜色透明;hover 只改颜色。
怎么做:li:hover { border-color: var(--lv); }。
易错点:不要 hover 时才写 border:2px solid var(--lv),那会改变盒子占位。
css
.fresh .content .right li:hover {
border-color: var(--lv);
}“找相似”悬浮层:定位 + 过渡
为什么需要?鼠标移入商品,底部要升起“找相似”条。
怎么想:li 设 position:relative 和 overflow:hidden,.find 绝对定位到 left:0,初始 bottom:-84px(自身高 84),hover 时 bottom:0。
怎么做:transition:all .3s 加在 .find 上,因为“谁做动画给谁加”;h4 下边框用半透明白,文字白色。
易错点:transition 写到 li:hover .find 上,鼠标移出会瞬间弹回;li 不加 overflow:hidden,悬浮条会露在卡片外面;.find 不设宽 242,会跟内容缩。
css
.fresh .content .find {
position: absolute;
left: 0;
bottom: -84px;
width: 242px;
height: 84px;
background-color: var(--lv);
padding: 15px 55px 0;
text-align: center;
transition: all .3s;
}
.fresh .content .right li:hover .find {
bottom: 0;
}
.fresh .content .find h4 {
border-bottom: 2px solid rgba(255, 255, 255, 0.11);
color: #fff;
padding-bottom: 4px;
margin-bottom: 4px;
font-size: 18px;
}
.fresh .content .find a {
color: #fff;
font-size: 13px;
}复制小 li 与调试习惯
转写稿里反复强调:复制商品时复制的是小 li,不是整个 ul,否则会多套一层列表。复制完把 fresh 后面的编号依次改掉。
代码变长后,用 Ctrl + K 再按 Ctrl + 0 全部折叠,Ctrl + K 再按 Ctrl + J 全部展开,靠中文注释找模块,比拖着选更不容易错。样式被覆盖时,先开调试工具看层叠关系,确认哪些样式被新选择器盖掉、哪些是继承来的,再决定加权重还是补属性。
先保留本节笔记里的快捷键
本节笔记的核心只有两组组合键,先原样保留:
全部折叠:
先按 ctrl + k 接着 ctrl + 0
全部展开:
ctrl+ k 接着 ctrl+ j
整理成代码块如下:
text
全部折叠:Ctrl + K,松开,再按 Ctrl + 0
全部展开:Ctrl + K,松开,再按 Ctrl + J转写稿里出现过“卡加K”“卡车加0”“cl加勾”“contl加O”等说法,都是口音或识别误差。实际要记的是 Ctrl+K、Ctrl+0、Ctrl+J;不是 Ctrl+Shift+K,也不是单独按 Ctrl+0。
为什么需要折叠快捷键
为什么需要: 页面代码写到上千行后,一个文件里会有生鲜模块、服饰模块、居家模块等多个大块。转写稿里反复提到:复制模块时如果直接拖选,很容易找不到“头和尾”,复制错层级,甚至把整个 ul 也复制进去。折叠后只留下模块注释和入口,复制时更干净。
怎么想: 把折叠当成“视图整理工具”,不是改代码。先折叠,再按模块复制;需要看细节时再展开。转写稿里说得很直接:写好注释后,折叠起来就知道该复制哪一块,这是好习惯。
怎么做: 在 VS Code 编辑器里先按 Ctrl+K,底部会提示“已按下 Ctrl+K,正等待按第二个键”,再按 0,所有标签层级会被折叠起来。需要展开时,按 Ctrl+K,再按 J,全部展开。
易错点: 不要把 Ctrl+K 和 0 同时按住;它是先后按。不要按成单独的 Ctrl+0。转写稿里试过 Ctrl+Shift+K,发现不对,要纠正为 Ctrl+K 后接 0。
全部折叠:Ctrl+K 再按 Ctrl+0
为什么需要: 当代码层级很深时,一层层点鼠标折叠很慢。转写稿里演示了生鲜模块复制:先折叠,再选中复制,避免拖着找尾。折叠后页面结构像目录一样,方便定位。
怎么想: 先按 Ctrl+K 是进入“组合键等待状态”,第二个键才决定动作:0 是全部折叠,J 是全部展开。不要把它理解成一个长按组合。
怎么做: 打开目标文件,确保光标在编辑器代码区域;按 Ctrl+K,看到等待提示后按 0。转写稿中的调试过程是:按完后观察代码左侧折叠箭头和层级,确认所有大块都收起来了,再复制需要的模块。
易错点: 折叠只是视图变化,不会删除代码;重新打开 VS Code 页面时,原来折叠的地方可能会自动展开,所以需要重新按 Ctrl+K、Ctrl+0。转写稿里特别提到这个现象:再次打开页面,不管原来有没有折叠,它都可能给你解开。
全部展开:Ctrl+K 再按 Ctrl+J
为什么需要: 折叠后如果只看注释不确定内容,就要快速展开检查。全部展开比一层层点开更快,尤其适合复制完模块后检查结构。
怎么想: Ctrl+K 是前缀,后面的 J 负责展开。转写稿里用“cl加勾”描述的就是 Ctrl+J,要纠正为字母 J,不是“勾”这个字。
怎么做: 按 Ctrl+K,再按 J,所有折叠层级展开。转写稿里的操作顺序是:先 Ctrl+K、Ctrl+0 折叠,复制模块,再 Ctrl+K、Ctrl+J 展开检查,确认复制的是不是生鲜、服饰、居家等对应模块。
易错点: 不要按成 Ctrl+O。转写稿里出现过“contl加O全部折叠”的口误,但后面明确是 0。另外,展开后代码很长,不要盯着上千行硬找,配合注释和调试工具定位更稳。
小结
这两个快捷键要成对记:Ctrl+K 是前缀,Ctrl+0 全部折叠,Ctrl+J 全部展开。先折叠整理结构,再复制模块;需要检查时再展开。转写稿里的实际场景已经说明:代码越多,折叠越有用,但重新打开文件后可能自动展开,需要重新按一次。

先复用 hd/bd 搭骨架
为什么需要:最新专题在页面最后,但它和上面的模块一样,都是“标题区 + 内容区”的结构。转写里明确说它“不需要通栏,只要装一个版心就可以了”,所以不必从零发明结构,直接复用 wrapper 里的 hd 和 bd 最稳。
怎么想:hd 放标题“最新专题”和“查看全部”,bd 里放 ul > li。上面模块常是四个盒子,这里按设计稿改成三个盒子即可。先把大盒子搭出来,再往里装小内容。
怎么做:保留本节笔记中的 HTML 结构:
html
<!-- 最新专题 -->
<!-- 最新专题 -->
<div class="wrapper news">
<!-- 上侧 hd -->
<div class="hd">
<h2>最新专题
</h2>
<a href="#" class="all">
查看全部
<i class="iconfont icon-arrow-right-bold"></i>
</a>
</div>
<!-- 下部分 bd -->
<div class="bd">
<ul>
<li>
<div class="pic">
<img src="./uploads/topic1.png" alt="">
</div>
</li>
</ul>
</div>
</div>易错点:复制结构时要复制“小 li”,不要连整个 ul 或整块模块乱拖。转写里强调用折叠快捷键 Ctrl+K Ctrl+0 全部折叠、Ctrl+K Ctrl+J 展开,目的是复制时能看清模块边界。
用 .news 提高权重覆盖 li
为什么需要:上面的模块可能已经写过 .bd ul li 的宽高和背景,最新专题的小 li 会继承或受它影响。转写里先看到三个 li “已经有了”,但尺寸不对,所以必须用更具体的选择器覆盖。
怎么想:给外层加 news 类,写成 .news .bd ul li,权重比普通 .bd ul li 高,就能把宽高、背景层叠掉。
怎么做:本节笔记 CSS 保留如下:
css
/* 最新专题 */
/* 最新专题 */
.news {
margin-bottom: 50px;
}
.news .bd ul li {
width: 405px;
height: 355px;
background-color: pink;
}
.news .bd ul li .pic {
width: 405px;
height: 288px;
background-color: skyblue;
}调试时先用 pink、skyblue 看盒子范围,确认 405×355、图片区 405×288,再改成白色。转写中量到 li 高 355、pic 高 288,pic 下方还剩约 67px 给文字区。
易错点:不要只写 .bd ul li 就以为一定生效;用调试工具检查被谁覆盖。背景色最终要改回设计稿颜色,粉色只是调试色。
.txt 必须放在 .pic 里再绝对定位
为什么需要:文字信息要压在图片底部,如果放在 li 里,它会排在 pic 下方,压不住图。转写里反复提醒“不要放到 li 里面,而是放到 pic 里面”。
怎么想:让 .pic 作为定位父级,.txt 绝对定位到左下角,bottom:0 贴底。
怎么做:在 .pic 内追加 .txt,并补:
css
.news .bd ul li .pic { position: relative; }
.news .bd ul li .pic .txt {
position: absolute;
left: 0;
bottom: 0;
width: 405px;
height: 90px;
padding: 20px 15px 0;
display: flex;
justify-content: space-between;
}易错点:父级 .pic 忘记 position: relative,.txt 会乱跑;.txt 放到 li 里也压不住图片。
txt 内部左右分栏与渐变收尾
为什么需要:.txt 里左边是标题和说明,右边是“29.9块”一类价格/按钮,所以要左右分栏;背景还要做从透明到半透明的渐变,才能透出图片。
怎么想:.txt 用 display:flex; justify-content:space-between。左侧用 h5 + p/div 上下排,右侧给固定宽高并水平垂直居中。渐变用 background-image: linear-gradient(...),不是 background-color。
怎么做:右侧可写 width:79px; height:25px; background:#fff; display:flex; align-items:center; justify-content:center; color:#e1251b;。渐变按转写调试写成类似:
css
background-image: linear-gradient(transparent, rgba(0,0,0,.6));易错点:rgba 括号别少;渐变属性写成 background-image;右侧盒子要同时水平、垂直居中。转写还提到 hover 用 margin 移动会抖,后面就业班用 translate 解决,这里先知道即可。
整体思路:复用模块结构,改成三张卡片
为什么需要:最新专题是页面最后一个模块,结构并不复杂,但仍然要保证三张卡片横向排列、图片和底部信息对齐。直接从头写容易在宽高、间距和选择器权重上出错。
怎么想:转写稿里反复强调“复制上面最合适的模块,再改成三个盒子”。也就是先复用已有的 ul > li > a 结构,把列表项数量改成 3 个,再逐层填图片区和文字信息区。
怎么做:先写外层 ul,里面放 3 个 li,每个 li 里用 a 包住 .pic 和 .txt。先让三个盒子显示出来,再写图片和底部信息。
易错点:不要复制错整段结构;li 的数量要确认是 3 个;图片路径和 alt 要写清楚,避免图片缺失时无法判断位置。
HTML结构:先搭骨架,再填内容
html
<ul>
<li>
<a href="#">
<div class="pic">
<img src="./uploads/topic1.png" alt="最新专题图片1">
</div>
<div class="txt">
<div class="left">
<p>
<i class="iconfont icon-favorites-fill"></i>
<span>1220</span>
</p>
<p>
<i class="iconfont icon-browse"></i>
<span>1800</span>
</p>
</div>
<div class="right">
<p>
<i class="iconfont icon-comment"></i>
<span>246</span>
</p>
</div>
</div>
</a>
</li>
<li>
<a href="#">
<div class="pic">
<img src="./uploads/topic2.png" alt="最新专题图片2">
</div>
<div class="txt">
<div class="left">
<p>
<i class="iconfont icon-favorites-fill"></i>
<span>1220</span>
</p>
<p>
<i class="iconfont icon-browse"></i>
<span>1800</span>
</p>
</div>
<div class="right">
<p>
<i class="iconfont icon-comment"></i>
<span>246</span>
</p>
</div>
</div>
</a>
</li>
<li>
<a href="#">
<div class="pic">
<img src="./uploads/topic3.png" alt="最新专题图片3">
</div>
<div class="txt">
<div class="left">
<p>
<i class="iconfont icon-favorites-fill"></i>
<span>1220</span>
</p>
<p>
<i class="iconfont icon-browse"></i>
<span>1800</span>
</p>
</div>
<div class="right">
<p>
<i class="iconfont icon-comment"></i>
<span>246</span>
</p>
</div>
</div>
</a>
</li>
</ul>为什么需要:结构决定后面 CSS 能不能顺利布局。图片区和文字区分开,后面才能分别控制尺寸和排列。
怎么想:每个卡片内部就是“上图片、下信息”。信息区再分左右,左侧放收藏和浏览,右侧放评论。
怎么做:按上面的层级写,a 包住整个卡片,.pic 放图片,.txt 放底部数据。
易错点:alt 不要空着;i 和 span 要在同一个 p 里;左右分组不要混在一起。
CSS布局:列表横向、卡片定宽、图片区定位
css
.topic-bd ul {
display: flex;
justify-content: space-between;
}
.topic-bd li {
width: 405px;
height: 355px;
background-color: pink;
}
.topic-bd .pic {
position: relative;
width: 405px;
height: 288px;
}
.topic-bd .txt {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 15px;
width: 405px;
height: 67px;
/* background-color: skyblue; */
font-size: 14px;
color: #666;
}
.topic-bd .txt .left {
display: flex;
}
.topic-bd .txt .left p {
margin-right: 20px;
}
.topic-bd .txt .left p:nth-child(1) i {
color: #AA2113;
}为什么需要:三张卡片要横向排列并两端对齐,所以 ul 用 flex 和 space-between;每张卡片需要固定宽高,图片区也要固定尺寸。
怎么想:先让 li 以粉色背景出现,方便看盒子;确认三个盒子排好后,再处理图片区和底部信息。.pic 加 position: relative,是为后续可能压在图片上的元素预留定位参照。
怎么做:li 设 405×355;.pic 设 405×288;.txt 用 flex 做左右分布和垂直居中,并给左右 15px 内边距。
易错点:如果页面里已有通用 li 样式,当前选择器权重可能不够,要用更具体的外层类名覆盖;粉色只是占位色,最后要改成实际背景色;.txt 的宽高不要漏写,否则底部信息会错位。
底部信息:左右分组与图标颜色
为什么需要:底部信息区有左、右两组内容,左侧还有收藏和浏览两项,必须让它们横向排列并保持间距。
怎么想:外层 .txt 已经用 flex 做左右分布;左侧 .left 再开 flex,让两个 p 在一行;第一个 p 的图标单独改红色。
怎么做:.txt .left { display: flex; },给左侧 p 加 margin-right: 20px,再用 p:nth-child(1) i 改收藏图标颜色。
易错点:不要给所有图标都改红色;margin-right 加在左侧每个 p 上,最后一个会多出间距,调试时可接受,若要精细可再用 :last-child 处理。
调试与收尾:用检查工具看覆盖关系
为什么需要:代码写多后,靠肉眼找样式冲突很慢。转写稿里也强调先打开调试工具看元素和层叠关系。
怎么想:先确认 li 的宽高和背景是否被更早的通用样式覆盖,再看 .txt 是否继承或覆盖了字体、颜色、对齐方式。
怎么做:右键检查元素,观察最终生效的宽高、背景、display 和 color;确认 .topic-bd 作用域存在;最后把占位粉色改成实际背景色。
易错点:不要只看代码猜结果;选择器权重不够时,样式不会生效;复制模块后要检查类名是否仍然指向旧模块。转写稿中间试过绝对定位和渐变层,但本节笔记最终保留的是“图片区 + 底部信息栏”的结构,写代码时以笔记结构为准。
课件图示(PPTX)



代码示例
代码一:生鲜模块 —— 内容布局 + 小 li 网格
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>生鲜 - 内容布局</title>
<style>
/* 基础重置 */
* { margin: 0; padding: 0; box-sizing: border-box; }
ul { list-style: none; }
a { text-decoration: none; }
/* 主色调变量(原项目在 common.css 中定义) */
:root { --lv: green; }
.wrapper { width: 1216px; margin: 0 auto; }
/* 生鲜内容 */
.fresh .content {
display: flex;
justify-content: space-between;
}
.fresh .content .left {
width: 248px;
height: 610px;
background-color: pink; /* 占位色,有图后可删 */
}
.fresh .content .left img {
display: block;
width: 100%;
}
.fresh .content .right {
width: 968px;
height: 610px;
background-color: skyblue; /* 占位色,有图后可删 */
}
.fresh .content .right ul {
display: flex;
/* 强制换行 */
flex-wrap: wrap;
}
.fresh .content .right li {
width: 242px;
height: 304px;
background-color: pink;
/* 颜色透明 transparent */
border: 2px solid transparent;
}
.fresh .content .right li:hover {
/* border: 2px solid var(--lv); */
border-color: var(--lv);
}
</style>
</head>
<body>
<div class="fresh">
<div class="wrapper content">
<!-- 左侧大图 -->
<div class="left">
<a href="#"><img src="./uploads/fresh_left.png" alt=""></a>
</div>
<!-- 右侧 8 个小 li -->
<div class="right">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
</ul>
</div>
</div>
</div>
</body>
</html>要点解释
.content用display: flex+justify-content: space-between,左右两块固定宽 248 + 968,合起来就是wrapper的内容宽度,中间自动撑开。ul用display: flex+flex-wrap: wrap做网格:242 × 4 = 968,正好一行 4 个,两行 8 个。- 易错点①:
border: 2px solid transparent会额外撑大盒子(242 → 246),4 个就放不下 968 的容器,一行只显示 3 个。必须配合box-sizing: border-box(或全局重置),让边框算在宽度里。 - 易错点②: 初始状态就写透明边框,而不是 hover 时才加边框——否则鼠标移上去盒子会被挤动、整行抖动。hover 只改
border-color。 - 宽度 242 不是随便给的,是设计稿 968 ÷ 4 得来的,改宽度要同步改容器。
代码二:生鲜 —— 产品内容(图片 + 信息 + 价格 + 悬停"找相似")
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>生鲜 - 产品内容</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
ul { list-style: none; }
a { text-decoration: none; color: #333; }
:root { --lv: green; }
.wrapper { width: 1216px; margin: 0 auto; }
.fresh .content { display: flex; justify-content: space-between; }
.fresh .content .left {
width: 248px;
height: 610px;
background-color: pink;
}
.fresh .content .left img { display: block; width: 100%; }
.fresh .content .right {
width: 968px;
height: 610px;
}
.fresh .content .right ul {
display: flex;
flex-wrap: wrap;
}
.fresh .content .right li {
overflow: hidden; /* 把藏在下方的 find 裁掉 */
position: relative; /* find 的定位基准 */
width: 242常见错误
右栏 4 个 li 只排得下 3 个 现象:968px 宽的区域里,一行只显示 3 个 242px 的 li,第 4 个被挤到下一行。 原因:li 写了
width: 242px又加了 2px 边框,默认box-sizing: content-box,实际占位 246px,4×246=984 超出 968。 修法:给 li 加box-sizing: border-box,或改用outline/box-shadow: inset 0 0 0 2px模拟边框。鼠标移入时整块内容抖动、错位 现象:hover 的瞬间 li 变宽,图片和文字整体位移。 原因:默认没边框,
:hover时才加border: 2px solid,盒子尺寸被撑开,触发重排。 修法:默认写border: 2px solid transparent占住位置,hover 只改border-color;动画一律改不引起重排的属性。"找相似"面板不贴底、或从图片上方滑下来 现象:面板位置跑到 li 外、hover 时图片被顶起、面板盖不住内容。 原因:
.find写在了a里而不是 li 的直接子级,或者 li 缺position: relative;用margin-top负值做动画会推挤布局。 修法:.find作为 li 的子元素,li 设position: relative; overflow: hidden,.find用position: absolute; bottom: -84px,hover 改bottom: 0,transition写在.find自己身上。最新专题的三个 li 尺寸还是生鲜那一套 现象:改了宽高没反应,仍是 242×304、背景粉。 原因:只写了
.bd ul li,与前面同权重且位置靠前,被后面的规则覆盖;或漏写父级类名导致权重不够。 修法:加上模块类名提高权重,如.news .bd ul li { width: 405px; height: 355px; background: #fff; },并用调试工具确认是哪个选择器生效。半透明文字条跑到图片下面,把 li 撑高了 现象:
.txt没压在图上,而是排在图片之后,li 高度超出 355。 原因:.txt放进了 li 而非.pic内;或.pic没有position: relative,绝对定位以 li 为参照。 修法:把.txt移到.pic内部,.pic加position: relative,.txt用left: 0; bottom: 0。渐变背景不生效,只有一片纯色 现象:写了渐变但看不到过渡效果,或者整块变白/变黑。 原因:写成了
background-color: linear-gradient(...);或rgba()少写括号、写成rgb导致整条声明失效。 修法:用background-image: linear-gradient(...)或简写background,颜色值括号成对检查,transparent → rgba(0,0,0,.6)方向默认从上到下。
练习
- 补齐生鲜右栏 8 个 li,要求:968px 内一行正好 4 个,鼠标移入只有边框变色、页面零抖动。完成后用调试工具验证每个 li 的
offsetWidth。 - 把"找相似"的滑入动画从
bottom改成transform: translateY(),对比两种方案在 hover 时的表现差异,并说明为什么后者不会引起重排。 - 给最新专题增加第 4 个 li,观察布局变化;再尝试把每个 li 改成 300px 宽,说明为什么没有按预期排列。
- 在
common.css中把主色变量改成紫色,刷新页面记录哪些元素变了、哪些没变,找出没变的原因(提示:硬编码颜色)。 - 新建
center.html,只引入公共 CSS 并复制头尾结构,中间区域自己写一个.wrapper,验证"样式复用、结构复用"的可行性。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 生鲜模块结束 | 07:39 |
| 2 | 最新专题模块布局开始 | 03:01 |
| 3 | 最新专题模块小li搭建 | 07:40 |
| 4 | 最新专题模块-txt模块布局 | 06:16 |
| 5 | 最新专题txt左侧制作 | 05:25 |
| 6 | 最新专题txt部分完成 | 08:58 |
| 7 | 最新专题结束 | 09:40 |
| 8 | center部分 | 05:49 |
小结
- 布局顺序永远是先搭盒子定尺寸、再填内容,li 的宽高背景先调通再往里放图。
- 边框、hover、动画三件事要一起想:占位要提前、动画只改不引起重排的属性。
- 绝对定位的参照物是最近的定位祖先,放错父级盒子,定位再对也白搭。
- 复用模块时必须重新起类名或加父级选择器,否则继承来的样式会"帮倒忙"。
- 遇到样式不生效,第一反应是打开调试工具看谁覆盖了谁,而不是盯着代码找。
- 代码过千行后,注释 +
Ctrl+K Ctrl+0/Ctrl+K Ctrl+J折叠是复制粘贴不出错的前提。 - 公共头尾和变量抽到
common.css,新增页面只写中间部分,这是组件化思维的第一课。