Skip to content

小兔鲜儿(二) ​

本页对应 小兔鲜儿,共 8 段视频,约 1 小时 3 分。

学习目标 ​

  • 能在 HTML 根目录正确引入 favicon.ico,并通过浏览器标签页或强制刷新验证小图标正常显示。
  • 能新建并引入 common.css,在 :root 中声明颜色变量,并使用 var() 调用变量,验证修改变量后页面多处颜色同步更新。
  • 能使用设计稿测量工具读取盒子宽高、间距和颜色,并据此编写对应的 CSS 尺寸与样式。
  • 能搭建 .shortcut 快捷导航:设置高度和背景色,使用 .wrapper 约束版心,通过 Flex 实现内容右对齐,并用 ul > li > a 完成链接、左右内边距、分隔线及最后一项去边框。
  • 能实现快捷导航交互与图标效果:使用变量完成 a:hover 变绿,引入 iconfont,在“手机版”前添加图标,并通过 inline-block、vertical-align、margin-top 完成垂直对齐微调。
  • 能搭建 header 盒子:使用 .wrapper 约束版心,设置上下 22px 内边距,创建 200×88 的 logo 盒子并设置背景图,验证头部布局居中且各区域互不影响。

知识点 ​

本节目标与最终效果 ​

本节要完成小兔鲜页面头部最上方的“快捷导航”布局:它是一个通栏的深色条,高度 52px,背景色 #333,内部内容通过版心约束在页面中间,并且整组导航链接靠右显示。最终效果如下:

快捷导航布局效果图

先保留本节给定的 HTML 结构:

html
<!-- 快捷导航 -->
<div class="shortcut">
  <div class="wrapper">1</div>
</div>

以及对应 CSS:

css
/* 头部开始 */

/* 快捷导航 */
.shortcut {
  height: 52px;
  background-color: #333;
}

.shortcut .wrapper {
  line-height: 52px;
  /* background-color: pink; */
  display: flex;
  /* 让这个盒子里面的ul 走到右侧 */
  justify-content: flex-end;
}

为什么先写通栏容器 ​

为什么需要:快捷导航是页面头部的最上层,视觉上是一条横向铺满的深色背景条。它不能只包住中间内容,否则左右两侧会露出页面底色。

怎么想:先写外层 .shortcut,只负责“通栏、高度、背景色”,不要急着写里面链接。宽度不需要单独给,因为块级盒子默认占满父容器宽度;高度按效果图量出来是 52px,背景色是 #333。

怎么做:给 .shortcut 设置 height: 52px; background-color: #333;。转写稿中也是先量高度和底色,再写盒子:“点击它来看一下高度是多少,52像素的……底色是333”。

易错点:不要给 .shortcut 写固定宽度,也不要在这里写 margin: 0 auto。通栏负责背景,版心负责内容居中,两者职责要分开。

为什么里面要放版心 wrapper ​

为什么需要:通栏背景铺满屏幕,但内容不能贴着浏览器最左边,需要被约束在页面中间,这个约束容器就是版心 .wrapper。

怎么想:项目公共样式里通常已经定义了 .wrapper 的宽度和居中,例如宽度 1240px、margin: 0 auto。快捷导航里再放一个 .wrapper,让内部导航内容受版心控制。转写稿中反复强调“放个版心”“版心是不是已经在这儿了”,并先用粉色背景验证版心是否正常显示。

怎么做:HTML 中在 .shortcut 内放 .wrapper。CSS 中给 .shortcut .wrapper 设置 line-height: 52px;,让内部文字在 52px 高的条里垂直居中。调试时可以临时加 background-color: pink; 看版心位置,确认后删除。

易错点:line-height 要跟快捷导航高度一致,才能垂直居中;如果写到 .shortcut 上,也可能继承,但按笔记写在 .wrapper 上更清晰。不要把版心写成固定定位或绝对定位。

为什么用 flex 让内容靠右 ​

为什么需要:快捷导航里的登录、注册、我的订单等链接整体在右侧,而不是从版心左侧开始排列。

怎么想:.wrapper 里面最终要放一个 ul,ul 是块级盒子。如果只写 text-align: right,它主要影响行内内容,不能让整个 ul 盒子靠右。更稳妥的思路是让 .wrapper 成为 flex 容器,再让 flex 子项靠右。转写稿中明确说:“不是 text-align right,而是因为我们里面要装 UL 这个盒子,让盒子跑到右侧去”,并先用 123 或临时 ul 验证是否右移。

怎么做:给 .shortcut .wrapper 加:

css
display: flex;
justify-content: flex-end;

这样 .wrapper 里的子项会靠右。调试时先放 1 或 123 看是否到右边;如果没有移动,检查 display: flex 和 justify-content: flex-end 是否写在 .shortcut .wrapper 上,是否保存并刷新。

易错点:justify-content: flex-end 要写在 flex 容器上,不是写在 ul 上;不要误写成 text-align: right。另外 ul 默认有外边距和内边距,后续做链接时要做初始化,否则右对齐位置会有偏差。

布局完成后的衔接 ​

快捷导航的“壳”完成后,后续再往 .wrapper 里放 ul > li > a:ul 负责一行排列,a 负责左右 padding、右边框和 hover 变绿,最后一个 li 里的 a 去掉右边框。转写稿中也是先完成 .shortcut 高度、背景、版心、右对齐,再继续写登录注册链接。布局阶段先把容器关系写对,后面填内容才不会反复改结构。

结构与样式总览 ​

本节保留笔记中的结构和样式,先整体看一遍,再逐点解释:

html
<ul>
  <li><a href="#" class="login">请先登录</a></li>
  <li><a href="#">免费注册</a></li>
  <li><a href="#">我的订单</a></li>
  <li><a href="#">会员中心</a></li>
  <li><a href="#">帮助中心</a></li>
  <li><a href="#">在线客服</a></li>
  <li><a href="#"><span class="iconfont icon-mobile-phone"></span>手机版</a></li>
</ul>
css
.shortcut .wrapper ul {
  display: flex;
}

.shortcut li a {
  font-size: 14px;
  color: #fff;
  padding: 0 15px;
  border-right: 1px solid #999;
}

.shortcut li a:hover {
  /* 变量绿色 */
  color: var(--lv);
}

.shortcut li a i {
  /* 转换为行内块 */
  display: inline-block;
  font-size: 19px;
  /* 让小图标和文字垂直居中 */
  vertical-align: middle;
  margin-top: -3px;
}

.shortcut li:last-child a {
  border-right: 0;
}

快捷导航外层与版心:先定高度和右对齐 ​

为什么需要: 快捷导航是页面顶部的一条通栏,里面内容不能贴屏幕边,而要限制在版心内并靠右显示。
怎么想: 转写里先给 .shortcut 高 52px、背景 #333,里面放 .wrapper 版心;版心用行高 52 让内容垂直居中,再用 flex 把 ul 推到右侧。
怎么做: 外层负责底色和高度,.wrapper 负责居中约束,ul 负责装导航项。
易错点: 不要给 ul 写 text-align:right 就以为能靠右,ul 是块级盒子;转写里用的是 display:flex; justify-content:flex-end 让盒子整体靠右。还有转写中“板心”就是版心 wrapper。

让 ul、li、a 横排并做链接间距 ​

为什么需要: li 默认竖排,链接之间也需要左右留白,才能形成紧凑的导航条。
怎么想: 转写里先放 7 个 li,发现竖排后,给父级 ul 加 display:flex,让 li 在一行。
怎么做: .shortcut .wrapper ul { display:flex; };再给 a 设 font-size:14px; color:#fff; padding:0 15px;。转写里量到两项间距约 30px,所以左右各 15px。
易错点: 不要只给 li 加左右 padding 和边框,转写里明确说线给 a,因为 li 高度可能更大;a 是行内元素,父级 ul 横排后它才能稳定排成一行。

分隔线与最后一项处理 ​

为什么需要: 每个导航项之间要有一条细竖线,但最后一项右边不能多一条线。
怎么想: 给每个 a 加右边框,最后一项单独去掉。
怎么做: border-right:1px solid #999;,最后用 .shortcut li:last-child a { border-right:0; }。
易错点: 转写里强调“只给 a 给线,不要给 li”;最后一条线要用 last-child 精确去掉,否则导航末尾会多一条竖线。

hover 主色用变量 ​

为什么需要: 鼠标经过链接要变成网站主色绿色,而主色以后可能统一修改。
怎么想: 转写里公共样式已经声明了绿色变量,这里不写死颜色,只调用变量。
怎么做: .shortcut li a:hover { color: var(--lv); }。
易错点: 不要把绿色写成固定色值;变量名要和公共样式里声明的一致。转写里说的“变量绿色”就是 --lv,调用时写 var(--lv)。

手机版小图标与垂直微调 ​

为什么需要: “手机版”前面要有一个小手机图标,并且和文字看起来对齐。
怎么想: 转写里先引入 iconfont 的 CSS,再复制 iconfont icon-mobile-phone 类名;图标默认和文字底部对齐,看起来偏低,所以要调。
怎么做: HTML 里放 <span class="iconfont icon-mobile-phone"></span>;CSS 里把图标设为 display:inline-block; font-size:19px; vertical-align:middle; margin-top:-3px;。转写里的调试顺序是:先 inline-block,再 vertical-align:middle,最后用 margin-top 负值微调。
易错点: 笔记 HTML 用的是 span,而 CSS 选择器写的是 i;转写中说过 span 或 i 都可以,但实际写代码时标签和选择器要统一,否则图标样式不会命中。只写 vertical-align 往往不够,因为行内元素不好精细调,先转行内块再微调。

头部整体结构:先搭盒子,再填内容 ​

头部布局效果图

头部是多个页面共用的区域,通常包含 logo、导航、搜索、购物车四块。转写稿里强调:这四块彼此没有直接联系,所以先按“四个独立盒子”来划分;它们又需要排在同一行,因此外层用 flex 最直接。写结构时先把语义和层级搭出来,不要一上来就抠细节。

为什么需要:头部在首页、列表页、详情页都会重复出现,结构清楚才方便复制和后期维护。
怎么想:外层一个 .header,里面放四个子盒子;每个子盒子先写文字占位,后面再替换成真实内容。
怎么做:保留笔记中的 HTML 结构:

html
<!-- 头部 -->
<div class="header wrapper">
  <!-- logo -->
  <div class="logo">logo</div>
  <!-- 导航 -->
  <div class="nav">导航</div>
  <!-- 搜索 -->
  <div class="search">搜索</div>
  <!-- 购物车 -->
  <div class="cart">购物车</div>
</div>

易错点:不要先把四个子盒子套进多余容器里,否则 flex 作用层级会乱;注释要保留,方便区分模块。

版心与 header 合并:wrapper 管居中,header 管布局 ​

转写稿里反复提到“版心”要写到公共样式里,宽度 1240px,左右 margin: 0 auto。笔记中 .header 同时写了 wrapper 类,这是关键:wrapper 负责版心居中,.header 负责头部自己的 padding 和 flex。不要把 flex 直接写到 .wrapper 上,因为其他模块也可能用版心,会被误伤。

为什么需要:头部内容不能贴浏览器左边,需要限制在 1240px 版心内居中;但版心是公共能力,布局是头部私有能力。
怎么想:一个元素可以同时有两个类,公共类管公共样式,模块类管模块样式。
怎么做:公共样式里保留 .wrapper { width: 1240px; margin: 0 auto; },本节只写 .header 的布局样式:

css
/* header 模块 */
.header {
  padding: 22px 0;
  display: flex;
}

易错点:不要把 .header 写成固定宽度;不要给 .wrapper 加 display:flex 来代替 .header,否则影响范围过大。

flex 一行布局:四个子盒子横向排列 ​

转写稿分析头部时明确说:logo、导航、搜索、购物车是四块,要在一行上,所以大盒子加 flex。display:flex 默认主轴水平,子项会从左到右排列;这里不需要额外写 justify-content,因为四个模块按默认顺序排即可,后续再根据效果图调间距。

为什么需要:四个模块是并列关系,用浮动或行内块会增加清除浮动、基线对齐等麻烦。
怎么想:父盒子负责“排成一行”,子盒子负责各自宽高和内容。
怎么做:在 .header 上写 display:flex,先让四个占位盒子横排;再用浏览器检查元素看父盒子范围。
易错点:如果四个盒子仍竖排,先检查 display:flex 是否写在 .header 上、类名是否拼错;不要急着给子盒子加 float。

padding 垂直留白:上下 22px,左右 0 ​

转写稿里量到头部上下距离都是 22px,所以 .header 用 padding: 22px 0。这里不是给固定高度,而是用内边距把内容“挤”到中间,内容高度变化时头部也能自然撑开。

为什么需要:头部上下需要呼吸空间,固定高度容易在内容变化时溢出。
怎么想:上下留白用 padding,左右留白交给版心和外层控制。
怎么做:保留 padding: 22px 0;,写完后给 .header 临时加背景色,观察上下留白是否对称。
易错点:不要写成 padding: 22px;,否则左右也会多出 22px;不要同时给 logo 加很大的上下 margin 来替代 header 的 padding,容易造成外边距折叠或间距翻倍。

logo 占位:背景图盒子必须给宽高 ​

转写稿中 logo 量出来是 200×88,并提醒“因为要放背景图,所以盒子必须指定宽和高才能把背景图露出来”。本节虽然还没写背景图,但布局阶段应先给 logo 占位,避免后面内容挤在一起。

为什么需要:背景图不会像 img 一样撑开盒子,不给宽高就看不到图。
怎么想:先给 logo 一个固定宽高和临时背景色,确认它在 flex 中的位置和大小。
怎么做:布局阶段可先写 .logo { width: 200px; height: 88px; background: pink; } 做测试,确认后再替换为背景图写法。
易错点:不要用文字“logo”撑高度;不要给 logo 设 flex:1,否则会抢走导航和搜索的空间。

调试顺序:先看范围,再填细节 ​

转写稿的调试过程是:先写 header 盒子,给粉色背景看范围;再放 logo,给宽高和背景色;确认版心居中、flex 生效后,再继续写导航、搜索、购物车。这样出错时能快速定位是结构问题还是样式问题。

为什么需要:头部细节多,一次性写完很难判断哪一层出错。
怎么想:按“父盒子范围 → 子盒子排列 → 单个盒子尺寸”的顺序验证。
怎么做:打开开发者工具,选中 .header 看宽度是否 1240、是否居中;选中子盒子看是否横排;临时背景色用完删除。
易错点:不要用眼睛猜间距;不要忘记保存后强制刷新;类名 header、wrapper 拼写要一致。

先明确目标:logo 是头部里的独立模块 ​

为什么需要:小兔鲜头部不是一张整图,而是由 logo、导航、搜索、购物车等模块拼起来的。logo 是用户回到首页的入口,既要显示品牌图,又要保留可点击、可被搜索引擎识别的文字。
怎么想:转写稿里先搭 header 大盒子,再给版心、上下 padding: 22px,让内容垂直居中;然后先放 logo 盒子,用粉色背景测试占位,确认宽高后再换背景图。
怎么做:logo 外层给固定宽高,内部用 h1 > a 保留“小兔鲜儿”文字语义。
易错点:不要一上来就贴背景图,先用背景色确认盒子位置和尺寸;h1 默认外边距要由初始化样式处理,避免头部被顶开。

HTML 结构:h1 包 a,文字不能丢 ​

为什么需要:logo 图片本身没有语义,h1 能表达站点主标题,a 负责跳转;文字“ 小兔鲜儿 ”用于无障碍和 SEO。
怎么想:结构保持“外层 logo → h1 → a”,链接地址指向首页,title 给出提示。
怎么做:保留笔记结构:

html
<!-- logo -->
<div class="logo">
  <h1>
    <a href="./index.html" title="小兔鲜儿">小兔鲜儿</a>
  </h1>
</div>

易错点:不要只写一个 img 或空 a;title 和链接文字不要写错;href 用相对路径时注意当前页面位置。

CSS 第一步:logo 盒子必须有宽高 ​

为什么需要:logo 最终用背景图显示,背景图不会自动撑开盒子;不写宽高,盒子高度可能为 0,图就露不出来。
怎么想:转写稿中先量出 logo 是 200 × 88,所以外层 .logo 直接定宽高,并用粉色背景测试。
怎么做:

css
.header .logo {
  width: 200px;
  height: 88px;
  background: pink;
}

易错点:宽高不要凭感觉写;测试色只是占位,最后要替换成背景图;选择器层级要和页面结构对应,避免样式不生效。

CSS 第二步:a 转块级并设置背景图 ​

为什么需要:a 默认是行内元素,直接设 height 往往不生效;转成块级后才能占满 logo 区域,整块都可点击。
怎么想:让 a 撑满 .logo 的 88px 高,再把 logo.png 作为背景图;图片路径相对于 CSS 文件写。
怎么做:

css
.header .logo a {
  display: block;
  height: 88px;
  background: url(../images/logo.png);
  /* 1. 隐藏文字 */
  /* font-size: 0; */
  /* 2. 隐藏文字 淘宝  小米方法 */
  text-indent: -9999em;
  overflow: hidden;
}

易错点:漏写 display: block 是常见错误;背景路径 ../images/logo.png 要确认相对的是 CSS 文件;height 要和 .logo 高度一致。

CSS 第三步:隐藏文字但保留可访问性 ​

为什么需要:页面上要显示图片 logo,但 HTML 里仍有“小兔鲜儿”文字,不隐藏会重复显示。
怎么想:转写稿明确讲了两种思路:font-size: 0,以及淘宝、小米常用的 text-indent: -9999em 配合 overflow: hidden。笔记保留后者作为主写法。
怎么做:在 a 上写负缩进,把文字移到可视区外,再用 overflow: hidden 裁掉溢出内容。
易错点:只写 text-indent 不写 overflow: hidden 可能产生横向滚动或露出文字;不要把文字从 HTML 中删掉;text-indent 要写在 a 上,不要写到 .logo 上。

调试与检查:先看盒子,再看图,最后看点击 ​

为什么需要:logo 样式短,但出错点集中在宽高、显示模式和路径。
怎么想:按转写稿顺序调试:先看粉色盒子是否在头部正确位置,再看 a 是否撑满,最后换背景图并检查点击区域。
怎么做:临时保留 background: pink 验证尺寸;替换为 url(../images/logo.png) 后刷新页面;鼠标移到 logo 上确认整块可点击。
易错点:图片不出来先查路径和文件名大小写;盒子高度不对先查 a 是否 display: block;文字没隐藏先查 overflow: hidden 是否跟着 text-indent 一起写。

先看结构:导航为什么用 ul > li > a ​

导航本质是一组同类链接,所以用列表表达最合适:ul 包住多个 li,每个 li 里放一个 a。这样做的好处是结构清晰,后续用 Flex 排列、用 a:hover 做交互都方便。

为什么需要:如果直接把“首页、生鲜、美食……”写成一行文字,点击区域、悬停效果、间距都不好控制。
怎么想:把每一项当成“列表项”,把真正可点击、可悬停的部分交给 a。
怎么做:保留本节结构:

html
<!-- nav -->
<div class="nav">
  <ul>
    <li><a href=" ">首页</a></li>
    <li><a href="#">生鲜</a></li>
    <li><a href="#">美食</a></li>
    <li><a href="#">餐厨</a></li>
    <li><a href="#">电器</a></li>
    <li><a href="#">居家</a></li>
    <li><a href="#">洗护</a></li>
    <li><a href="#">孕婴</a></li>
    <li><a href="#">服装</a></li>
  </ul>
</div>

易错点:不要只给 li 写文字而忘记 a,否则悬停变色和下边框都不好做;href="#" 会跳到页面顶部,练习时可以用,真实项目要换成有效地址。

横向排列:display:flex 加在 ul 上 ​

ul 和 li 默认是块级排列,会竖着往下走。导航要一行显示,所以转写稿里反复强调:先把 UL 变成一行。这里就是把 display:flex 给 ul,让它的子项 li 横向排列。

为什么需要:不写 Flex,九个 li 会纵向堆叠。
怎么想:控制“谁在一行”,就把 Flex 加在它们的父容器 ul 上,而不是加在 a 上。
怎么做:

css
/* nav */
.header .nav ul {
  display: flex;
  /* background-color: pink; */
  margin: 25px 0 0 41px;
}

.header .nav li a {
  display: block;
  line-height: 42px;
  margin-right: 42px;
}

.header .nav li a:hover {
  color: var(--lv);
  border-bottom: 2px solid var(--lv);
}

这里的 margin: 25px 0 0 41px 是设计稿定位:上方留 25px,左侧留 41px。易错点:flex 不要误加到 li 或 a 上;如果页面有默认的 ul 内外边距,要先靠 base.css 初始化,否则位置会偏。

链接盒子:display:block、行高和右间距 ​

a 默认是行内元素,直接给它设置 line-height、margin-right 虽然可能看到效果,但点击区域和盒子行为不够稳定。转写稿里讲快捷导航时也是这个思路:先让 a 具备盒子特点,再给尺寸、内边距或间距。

为什么需要:导航项要有稳定的可点击高度和统一间距。
怎么想:把 a 变成块级盒子,用 line-height: 42px 让文字在 42px 高度内垂直居中,用 margin-right: 42px 控制项与项之间的距离。
怎么做:就是上面的 .header .nav li a 三条声明。
易错点:间距给 li 还是给 a 要统一;最后一项也会带 margin-right,如果设计稿要求贴边,需要单独处理最后一项;line-height 要和字体大小配合,否则文字偏上或偏下。

hover 效果:用变量统一主色,再补下边框 ​

转写稿里专门讲了 CSS 变量:把网站主色声明在 :root 里,使用时写 var(--lv)。本节 hover 正好用到这个思路,颜色不写死,后期改主色只改变量。

为什么需要:导航悬停要有反馈;主色多处使用,写死绿色后期维护麻烦。
怎么想:悬停时改文字颜色,并加一条下边框模拟“选中/经过”的横线。
怎么做:

css
.header .nav li a:hover {
  color: var(--lv);
  border-bottom: 2px solid var(--lv);
}

易错点:如果 --lv 没有在公共样式里声明,var(--lv) 会失效,要在 :root 中定义并确认 common.css 已引入;a 没有 display:block 时,下边框不一定贴合整个导航块;加边框可能让高度变化,调试时用 F12 看盒子有没有抖动,必要时给透明边框预留位置。

调试顺序:先看一行,再看盒子,最后验变量 ​

转写稿的调试习惯是:先确认父盒子是否 Flex 成一行,再确认 a 是否成为块级盒子,最后鼠标经过验证颜色变量。检查时重点看三点:.header .nav ul 选择器是否和 HTML 对得上;ul 是否真的 display:flex;a:hover 里的 var(--lv) 是否被解析成绿色。按这个顺序查,比一上来改数值更稳。

本节目标与代码落点 ​

本节完成小兔鲜头部中的搜索模块:一个放大镜图标 + 一个输入框。转写稿里头部被拆成 logo、导航、搜索、购物车四块,搜索是独立一块,最终要和其它三块在一行上用 flex 排列;头部外层用 wrapper 版心居中,并给上下 22px 内边距。搜索模块本身按笔记代码落地,重点掌握“父相子绝”、输入框内边距、下边框和聚焦过渡。

搜索为什么独立成块 ​

为什么需要:搜索和 logo、导航、购物车没有结构上的包含关系,硬塞进同一个盒子会让布局和样式互相干扰。
怎么想:转写稿明确说“搜索是没有关系……独立的一块儿”,所以先把它当成 header 里的一个独立子项。
怎么做:header 大盒子用 flex 让四块在一行;搜索自己写 .search,内部再放图标和 input。
易错点:不要把 .search 写成 position: absolute 去硬定位;本节只在 .search 内部用相对定位给图标做参照。

HTML结构:图标与输入框 ​

为什么需要:搜索由“图标”和“输入框”组成,结构要简单,方便图标叠在输入框左侧。
怎么想:图标不是 input 的背景图,而是独立 i,后面用绝对定位压到 input 左边。
怎么做:保留笔记结构:

html
<!-- search  -->
<div class="search">
  <i class="iconfont icon-search"></i>
  <input type="text" placeholder="搜一搜">
</div>

易错点:iconfont 和 icon-search 是字体图标类名,不要抄错;转写稿讲小图标时也强调类名要复制,不要凭记忆写。

容器与图标:父相子绝 ​

为什么需要:图标要压在输入框左侧,如果两个都是普通文档流,图标会占位置,输入框被挤开。
怎么想:给父盒子 .search 设 position: relative,图标设 position: absolute,图标的 left/top 就相对 .search 计算。
怎么做:.search 宽 220px、高 40px、margin-top: 22px;i 设 left: 0; top: 5px; font-size: 20px; color: #ccc; cursor: pointer;。
易错点:父盒子忘了 relative,图标会跑到页面其它参照物上;top 不要凭感觉大改,按笔记 5px 起步,再用效果图微调。

输入框:宽度、内边距与下边框 ​

为什么需要:图标绝对定位后不占位,input 必须用 padding-left 给图标留出空间,否则文字会压到放大镜下面。
怎么想:input 常态宽 170px,左内边距 28px;只保留下边框,做出搜索框的轻量线条感。
怎么做:width: 170px; height: 40px; padding-left: 28px; border-bottom: 2px solid #F4F4F4; transition: all .3s;。
易错点:如果项目没有做 base 初始化,input 默认四周边框会露出来;本节只写 border-bottom,是建立在前面初始化样式之上的。转写稿也反复强调 base 是每个页面都要引入的初始化样式。

placeholder、focus 与过渡 ​

为什么需要:默认 placeholder 颜色偏深,和设计稿不一致;聚焦时搜索框变宽,需要平滑动画。
怎么想:placeholder 用伪元素单独改色;宽度变化写在 input 上,:focus 只负责改目标宽度。
怎么做:.search input::placeholder { color: #ccc; };.search input:focus { width: 220px; },过渡由 input 的 transition: all .3s 承担。
易错点:不要把 transition 写到 :focus 里,否则失焦时没有过渡;cursor: pointer 只改鼠标样式,不等于图标已有搜索点击功能,本节只做样式。

完整代码 ​

html
<!-- search  -->
<div class="search">
  <i class="iconfont icon-search"></i>
  <input type="text" placeholder="搜一搜">
</div>
scss
/* search  */
.search {
  position: relative;
  width: 220px;
  height: 40px;
  /* background-color: pink; */
  margin-top: 22px;
}

.search i {
  position: absolute;
  left: 0;
  top: 5px;
  font-size: 20px;
  color: #ccc;
  /* 鼠标变成小手 */
  cursor: pointer;
}

.search input {
  width: 170px;
  height: 40px;
  padding-left: 28px;
  border-bottom: 2px solid #F4F4F4;
  transition: all .3s;
}

/* 修改 placeholder 里面的文字样式 */
.search input::placeholder {
  color: #ccc;
}

/* input获得光标 */
.search input:focus {
  width: 220px;
}

调试与易错点清单 ​

转写稿搭 header 时习惯先用粉色背景确认盒子范围和位置,本节也可临时打开 .search 的 background-color: pink 自检,确认宽高和 margin-top 后再注释掉。检查顺序:先看 .search 是否在 header 一行内,再看图标是否压在 input 左侧,最后看聚焦时宽度是否从 170px 过渡到 220px。常见错:relative 漏写、padding-left 漏写、placeholder 选择器写成普通选择器、focus 宽度写反。

课件图示(PPTX) ​

day10 课件图

代码示例 ​

代码段1:快捷导航

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;
    }

    .wrapper {
      width: 1240px;
      margin: 0 auto;
    }

    /* 快捷导航 */
    .shortcut {
      height: 52px;
      background-color: #333;
    }

    .shortcut .wrapper {
      line-height: 52px;
      display: flex;
      /* 让这个盒子里面的ul 走到右侧 */
      justify-content: flex-end;
    }

    .shortcut .wrapper ul {
      display: flex;
    }

    .shortcut li a {
      font-size: 14px;
      color: #fff;
      padding: 0 15px;
      border-right: 1px solid #999;
    }

    .shortcut li a:hover {
      /* 实际项目中 --lv 在 common.css 中定义,这里加 green 便于单文件运行 */
      color: var(--lv, green);
    }

    .shortcut li a i {
      /* 转换为行内块 */
      display: inline-block;
      font-size: 19px;
      /* 让小图标和文字垂直居中 */
      vertical-align: middle;
      margin-top: -3px;
    }

    .shortcut li:last-child a {
      border-right: 0;
    }
  </style>
</head>
<body>
  <!-- 快捷导航 -->
  <div class="shortcut">
    <div class="wrapper">
      <ul>
        <li><a href="#" class="login">请先登录</a></li>
        <li><a href="#">免费注册</a></li>
        <li><a href="#">我的订单</a></li>
        <li><a href="#">会员中心</a></li>
        <li><a href="#">帮助中心</a></li>
        <li><a href="#">在线客服</a></li>
        <li>
          <a href="#">
            <i class="iconfont icon-mobile-phone"></i>手机版
          </a>
        </li>
      </ul>
    </div>
  </div>
</body>
</html>

要点解释:

  • .shortcut 只给高度和背景色,宽度不写,默认通栏。
  • .wrapper 负责版心宽度 1240px 和水平居中。
  • .shortcut .wrapper 使用 display:flex; justify-content:flex-end; 让内部 ul 靠右。
  • ul 也要 display:flex,否则 li 默认竖排。
  • 分隔线给 li a 的 border-right,最后一项用 li:last-child a { border-right:0; } 去掉。
  • 易错点:笔记 HTML 中小图标用 span,CSS 写的是 li a i;标签和选择器要统一,否则图标样式不生效。
  • 易错点:var(--lv) 需要先定义变量;单文件演示可用 var(--lv, green) 作为回退。

代码段2:头部布局、logo、导航、搜索

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;
    }

    .wrapper {
      width: 1240px;
      margin: 0 auto;
    }

    /* header 模块 */
    .header {
      padding: 22px 0;
      display: flex;
    }

    /* logo */
    .header .logo {
      width: 200px;
      height: 88px;
      background: pink;
    }

    .header .logo a {
      display: block;
      height: 88px;
      background: url(../images/logo.png);
      /* 1. 隐藏文字 */
      /* font-size: 0; */
      /* 2. 隐藏文字 淘宝 小米方法 */
      text-indent: -9999em;
      overflow: hidden;
    }

    /* nav */
    .header .nav ul {
      display: flex;
      margin: 25px 0 0 41px;
    }

    .header .nav li a {
      display: block;
      line-height: 42px;
      margin-right: 42px;
      color: #333;
    }

    .header .nav li a:hover {
      color: var(--lv, green);
      border-bottom: 2px solid var(--lv, green);
    }

    /* search */
    .search {
      position: relative;
      width: 220px;
      height: 40px;
      margin-top: 22px;
    }

    .search i {
      position: absolute;
      left: 0;
      top: 5px;
      font-size: 20px;
      color: #ccc;
      /* 鼠标变成小手 */
      cursor: pointer;
    }

    .search input {
      width: 170px;
      height: 40px;
      padding-left: 28px;
      border: 0;
      outline: 0;
      border-bottom: 2px solid #F4F4F4;
      transition: all .3s;
    }

    /* 修改 placeholder 里面的文字样式 */
    .search input::placeholder {
      color: #ccc;
    }

    /* input获得光标 */
    .search input:focus {
      width: 220px;
    }
  </style>
</head>
<body>
  <!-- 头部 -->
  <div class="header wrapper">
    <!-- logo -->
    <div class="logo">
      <h1>
        <a href="./index.html" title="小兔鲜儿">小兔鲜儿</a>
      </h1>
    </div>

    <!-- 导航 -->
    <div class="nav">
      <ul>
        <li><a href=" ">首页</a></li>
        <li><a href="#">生鲜</a></li>
        <li><a href="#">美食</a></li>
        <li><a href="#">餐厨</a></li>
        <li><a href="#">电器</a></li>
        <li><a href="#">居家</a></li>
        <li><a href="#">洗护</a></li>
        <li><a href="#">孕婴</a></li>
        <li><a href="#">服装</a></li>
      </ul>
    </div>

    <!-- 搜索 -->
    <div class="search">
      <i class="iconfont icon-search"></i>
      <input type="text" placeholder="搜一搜">
    </div>

    <!-- 购物车 -->
    <div class="cart">购物车</div>
  </div>
</body>
</html>

要点解释:

  • .header 同时使用 .wrapper,既负责版心居中,又负责头部 padding:22px 0 和 display:flex。
  • .logo 必须给宽高,因为后面用背景图实现 logo。
  • .logo a 使用 text-indent:-9999em; overflow:hidden; 隐藏文字,同时保留链接语义。
  • 导航 ul 用 display:flex 横排,margin:25px 0 0 41px 控制与 logo 的间距和垂直位置。
  • 搜索框用 position:relative 做定位父级,小图标绝对定位到输入框左侧。
  • input:focus 改变宽度,配合 transition 做搜索框展开效果。
  • 易错点:input 默认有边框,笔记只写 border-bottom 时,实际项目通常在 base 中重置边框;示例中加了 border:0; outline:0;。
  • 易错点:logo.png 路径不存在时背景图不显示,示例保留父级 background:pink 便于看到盒子;实际项目要换成正确图片路径。
  • 易错点:导航 hover 加 border-bottom 可能影响高度,实际项目可给 a 固定高度或预留透明边框。

代码段3:CSS 变量声明与使用

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>CSS变量</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    :root {
      --my-color: pink;
    }

    .wrapper {
      width: 1240px;
      margin: 0 auto;
    }

    .box {
      color: var(--my-color);
    }

    .box1 {
      background-color: var(--my-color);
    }

    .box2 {
      border: 1px solid var(--my-color);
    }
  </style>
</head>
<body>
  <div class="wrapper">
    <div class="box">文字颜色使用变量</div>
    <div class="box1">背景色使用变量</div>
    <div class="box2">边框色使用变量</div>
  </div>
</body>
</html>

要点解释:

  • CSS 变量分两步:先声明,后使用。
  • :root 是根伪元素,变量挂在 :root 上,页面中其他位置都可以使用。
  • 声明变量用两个减号开头,如 --my-color: pink;。
  • 使用变量固定写法是 var(--变量名),如 `color: var(--my

常见错误 ​

1. favicon 加了却不显示 现象:标签页仍是空白页图标,Ctrl+F5 后依旧。 原因:<link rel="icon"> 被写进了 <body> 或 .wrapper 内部;或 href 写成了 assets/favicon.ico 而文件实际在根目录。 修法:把 link 放在 <head> 内、与 meta 同级的最外层,href="./favicon.ico" 与 index.html 同目录;改完 Ctrl+F5 强刷,排除缓存干扰。

2. 快捷导航的 li 竖着堆叠 现象:请先登录、免费注册……一条一行往下掉。 原因:只给 a 写了 padding,没给父级 ul 开 flex,li 仍是块级独占一行。 修法:.shortcut .wrapper ul { display: flex; },一行话解决,不要去改 li 的 float 或 display:inline。

3. 内容没靠右,反而居中或贴左 现象:给 .wrapper 写了 justify-content: flex-end 无效,或误用 text-align: right。 原因:flex 属性加错了层级——加在了 ul 上,或 wrapper 没开 flex 就直接写 justify-content。 修法:display:flex 与 justify-content:flex-end 必须写在同一个盒子(.shortcut .wrapper)上;text-align 只管行内内容,管不动块级 ul。

4. 最后一条竖线去不掉 现象:手机版右侧多一条 1px 分隔线。 原因:选择器写成 .shortcut li:last-child { border-right: 0 },但边框是加在 a 上的,li 上本来就没有边框可去。 修法:.shortcut li:last-child a { border-right: 0; },选择器要落到真正带边框的那一层。

5. logo 文字露出来 / 背景图不显示 现象:logo 区域出现"小兔鲜儿"四个字,或整块空白。 原因:a 没转 display:block 也没给高度,背景图没有盒子可撑;或只写了 text-indent 没配 overflow:hidden。 修法:a 设 display:block; height:88px; background:url(...),再用 text-indent:-9999em + overflow:hidden(或 font-size:0)隐藏文字。

6. 用了 var() 颜色没生效 现象:hover 颜色没变,控制台该行被划掉。 原因:变量声明处漏了分号或没写在 :root 里;使用处把 var(--lv) 写成了 var(lv)、$lv 或直接写 --lv。 修法:声明 :root { --lv: #xx; },调用统一 color: var(--lv);——两个减号是变量名的一部分,var 小写加小括号,缺一不可。

7. 小手机图标怎么都调不齐 现象:vertical-align: middle 写了,图标仍偏下;改 margin-top 把"手机版"三个字也带偏了。 原因:i 是行内元素,vertical-align 与 margin 对它只能粗调,行内元素不吃上下 margin。 修法:先 display:inline-block 再 vertical-align:middle,最后用 margin-top:-3px 这种小负值微调——转成行内块后调它不影响旁边文字。

8. header 上下留白把版心挤歪了 现象:给 .header 加完 padding 后内容偏左,不再居中。 原因:padding:22px 0 写在了 .wrapper 上,或 .header.wrapper 上又叠了 margin 覆盖掉 margin:0 auto。 修法:版心只负责 width:1240px; margin:0 auto,垂直留白交给 .header 的 padding:22px 0,两个类各管一件事。

练习 ​

练习 1|favicon 落地 把素材里的 favicon.ico 放到与 index.html 同级目录,用 <link> 引入,强刷验证标签页出现小兔子;再故意把 link 挪进 body 里,观察是否失效,写出结论。

练习 2|两个变量 + 一处修改 在 common.css 的 :root 中声明 --lv(主色绿)与 --gray(灰),然后在快捷导航 a:hover、头部导航 a:hover 两处用 var() 调用。最后只改变量声明里的色值,验证两处同时变色。

练习 3|快捷导航完整还原 用 ul > li > a 结构写 7 条链接,a 上下 padding 为 0、左右 15px,右侧 1px #999 边框,最后一条去掉边框,hover 变绿,文字 14px 白色,整条 52px 高、背景 #333、内容靠右。

练习 4|小图标对齐 在"手机版"前加 <span class="iconfont icon-mobile-phone">,字号 19px,做到与文字视觉垂直居中;再用注释写清 display / vertical-align / margin-top 三句各自解决了什么问题。

练习 5|header 四块一行 搭出 .header.wrapper 内含 logo、nav、search、cart 四块,一行排布,上下留白 22px;logo 200×88 用背景图 + 文字隐藏,search 220×40 内图标绝对定位、input 只留下边框。

原视频对照 ​

#视频时长
1favicon小图标04:14
2公共样式和变量22:48
3效果图03:03
4小兔鲜-快捷导航开始08:05
5小兔鲜-快捷导航链接制作06:35
6小兔鲜顶部导航结束06:47
7小兔鲜顶部修改小图标04:28
8header盒子搭建07:22

小结 ​

  1. 先分层,再写字:base.css(初始化)→ common.css(版心 + 变量 + 头尾公共样式)→ index.css(页面独有),引入顺序不能反,否则页面样式会被公共样式覆盖。
  2. "有联系才包一起"是划分布局的唯一标准:header 拆成 logo / nav / search / cart 四块,依据是彼此无关联;快捷导航整条靠右,是因为 ul 是一个整体。
  3. flex 属性认父级:display:flex 与 justify-content 必须写在同一个盒子上,写错层级是最常见的"代码没问题但没效果"。
  4. 边框、padding 加在真正承载内容的元素上:竖线给 a 不给 li,去线时选择器也要落到 a 上。
  5. 变量是给"以后要改"准备的:主色、灰色这类高频值才值得抽成变量,一次定义、多处调用、一处修改——写的时候略麻烦,改的时候极省事。
  6. 装饰性图标要转行内块:inline-block + vertical-align + margin-top 三件套是微调图标位置的标准组合,行内元素做不到精细控制。
  7. 隐藏文字优先用 text-indent + overflow:font-size:0 写法更短但会连带影响子元素字号,二者择一后要在团队内统一。
  8. 测量工具只是手段:高度、间距、色值都从设计稿取,取完立刻写进 CSS 并注释来源,别靠记忆——52px、22px 这些数字是还原度的底线。