Skip to content

小兔鲜儿(三) ​

本页对应 小兔鲜儿,共 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) ​

day12 课件图

day12 课件图

day12 课件图

代码示例 ​

代码一:生鲜模块 —— 内容布局 + 小 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

常见错误 ​

  1. 右栏 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 模拟边框。

  2. 鼠标移入时整块内容抖动、错位 现象:hover 的瞬间 li 变宽,图片和文字整体位移。 原因:默认没边框,:hover 时才加 border: 2px solid,盒子尺寸被撑开,触发重排。 修法:默认写 border: 2px solid transparent 占住位置,hover 只改 border-color;动画一律改不引起重排的属性。

  3. "找相似"面板不贴底、或从图片上方滑下来 现象:面板位置跑到 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 自己身上。

  4. 最新专题的三个 li 尺寸还是生鲜那一套 现象:改了宽高没反应,仍是 242×304、背景粉。 原因:只写了 .bd ul li,与前面同权重且位置靠前,被后面的规则覆盖;或漏写父级类名导致权重不够。 修法:加上模块类名提高权重,如 .news .bd ul li { width: 405px; height: 355px; background: #fff; },并用调试工具确认是哪个选择器生效。

  5. 半透明文字条跑到图片下面,把 li 撑高了 现象:.txt 没压在图上,而是排在图片之后,li 高度超出 355。 原因:.txt 放进了 li 而非 .pic 内;或 .pic 没有 position: relative,绝对定位以 li 为参照。 修法:把 .txt 移到 .pic 内部,.pic 加 position: relative,.txt 用 left: 0; bottom: 0。

  6. 渐变背景不生效,只有一片纯色 现象:写了渐变但看不到过渡效果,或者整块变白/变黑。 原因:写成了 background-color: linear-gradient(...);或 rgba() 少写括号、写成 rgb 导致整条声明失效。 修法:用 background-image: linear-gradient(...) 或简写 background,颜色值括号成对检查,transparent → rgba(0,0,0,.6) 方向默认从上到下。

练习 ​

  1. 补齐生鲜右栏 8 个 li,要求:968px 内一行正好 4 个,鼠标移入只有边框变色、页面零抖动。完成后用调试工具验证每个 li 的 offsetWidth。
  2. 把"找相似"的滑入动画从 bottom 改成 transform: translateY(),对比两种方案在 hover 时的表现差异,并说明为什么后者不会引起重排。
  3. 给最新专题增加第 4 个 li,观察布局变化;再尝试把每个 li 改成 300px 宽,说明为什么没有按预期排列。
  4. 在 common.css 中把主色变量改成紫色,刷新页面记录哪些元素变了、哪些没变,找出没变的原因(提示:硬编码颜色)。
  5. 新建 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
8center部分05:49

小结 ​

  • 布局顺序永远是先搭盒子定尺寸、再填内容,li 的宽高背景先调通再往里放图。
  • 边框、hover、动画三件事要一起想:占位要提前、动画只改不引起重排的属性。
  • 绝对定位的参照物是最近的定位祖先,放错父级盒子,定位再对也白搭。
  • 复用模块时必须重新起类名或加父级选择器,否则继承来的样式会"帮倒忙"。
  • 遇到样式不生效,第一反应是打开调试工具看谁覆盖了谁,而不是盯着代码找。
  • 代码过千行后,注释 + Ctrl+K Ctrl+0 / Ctrl+K Ctrl+J 折叠是复制粘贴不出错的前提。
  • 公共头尾和变量抽到 common.css,新增页面只写中间部分,这是组件化思维的第一课。