简介:仿小米商城web练习项目是一套面向前端初学者的HTML+CSS实战资源,通过还原电商首页的页头导航、商品分类、轮播图、商品卡片、页脚等典型模块,帮助读者系统掌握语义化标签、CSS选择器、盒模型、Flexbox/Grid布局和响应式设计等核心知识点。压缩包约3.28MB,共410个文件,以jpg、webp、png图片素材为主,用于轮播图和商品展示,另含4个CSS(重置样式、Swiper轮播、字体图标、主样式)、2个JS、1个HTML页面和图标文件,目录精简清晰,适合对照源码逐模块拆解学习。目前已有906人浏览学习,说明该案例在入门练习中具备较高参考度。下载后可获得完整的电商首页静态代码、轮播组件及字体图标配置,对照代码即可梳理页面结构划分与样式实现思路,既适合自学练手,也可作为教学演示素材,为后续结合JavaScript开发动态交互页面打好基础。
1. 仿小米商城练手:为什么HTML+CSS是撕开电商首页的第一张图纸
学完浮动、盒模型、Flex之后,多数人卡在同一个地方:标签都会写,但一打开商城首页就不知道从哪下手。前阵子一个同学拿着自己的练习页给我看,说他用网格背景图临摹了一个页面,放大到200%就全碎了。我让他删掉那些取巧的背景图,重新用HTML+CSS按区块写一遍,第二版虽然像素没那么精致,但结构清清楚楚能改能调。这就是「仿小米商城web练习HTML+CSS」这个题目的价值:用一套真实、复杂的电商首页当靶子,把布局、语义化、视觉还原这些基础功一次性练扎实,而且完全不需要JavaScript参与。适合刚学完标签和CSS基础、想拿第一个综合项目练手的人,也适合想回头补布局功底的前端初学者。
2. 开工前的页面结构拆解:把商城首页切成可落地的盒子
仿站最忌讳一上来就照着设计稿写CSS。先花半小时把页面拆成盒子,后面能省下三倍调试时间。商城首页看起来元素很多,其实层次非常规整,基本就是「顶部信息栏—导航栏—轮播位—商品楼层—页脚」这条主轴,每一层再横向切出若干列。
2.1 首页模块分布与HTML语义化大纲
先看结构再谈CSS。常见做法是把页面从上到下分成五个区域:顶部的浅色信息条、带Logo和搜索框的主导航、全宽或定宽的轮播图位、若干商品楼层、最后是深色页脚。对应到HTML,标签选型也有讲究:顶部信息条用<div>就行,主导航用<nav>,楼层主体用<section>,页脚用<footer>。
下面是一份练习时可以直接参照的模块表,宽度按定宽容器来设计——这是大多数商城首页的处理方式。
| 模块 | 建议HTML语义标签 | 布局方式 | 关键样式点 |
|---|---|---|---|
| 顶部信息条 | <div class="topbar"> | Flex 水平分布 | 背景色、字体大小、行高 |
| 主导航栏 | <nav class="header-nav"> | Flex 左右分组 | Logo、搜索框、右侧菜单 |
| 轮播区域 | <section class="banner"> | 定宽容器+比例撑高 | 用padding-top保持宽高比 |
| 商品楼层 | <section class="floor"> | Grid 或 Flex 换行 | 卡片间距统一 |
| 页脚 | <footer class="footer"> | 列表+Flex | 背景色、链接列表 |
写HTML骨架时我习惯把视觉上独立的区块都加一个class,不急着写样式,先把每个区域用临时边框标出来。这个步骤能帮你确认嵌套关系有没有搞错层级——最常见的翻车是把footer塞进main里,或者商品卡片包在轮播区块内部,导致布局怎么调都不对。
2.2 为什么先画线框再写代码:栅格与栏目宽度
商城页面的统一感主要来自「栅格」:所有内容都在同一套宽度标准里对齐。被仿对象常见的页面宽度是 1226px 左右,左右留白后,内容区居中。你可以不照抄这个数值,但必须有自己固定的容器宽度,然后用margin: 0 auto居中。
我一般会先在一张纸上画线框,标出每个栏目的宽度占几格。商品列表一行排4个,容器宽度是1200px,那么每个卡片大约占280px,剩余部分用来做内边距和间距。这里有个很实用的公式:卡片宽度 =(容器宽度 - 间距总和)÷ 每行卡片数。新手最容易犯的错是把间距写死在卡片自身的margin上,导致最后一行多出半个卡片位对不齐。
栅格画完之后,你会在HTML里写一个统一的容器类,比如.container { width: 1200px; margin: 0 auto; },所有区块都套这个容器。这样页面缩放到不同窗口时,内容始终居中,不会被拉成两倍宽。先定容器,再定内部列宽,是仿站最不容易出错的顺序。
2.3 Flex与Grid的选型:静态页面布局怎么选
拆完盒子之后面临一个问题:每个区块用Flex还是Grid?我给一个偏经验性的判断:导航栏、顶部条这种「一行内左右元素的排列」用Flex;重复的商品卡片、楼层内多行多列用Grid。两者不冲突,一个页面里混用非常常见。
Flex适合处理一维排列,也就是一行上的对齐、间距、排序。比如导航栏左侧放Logo,右侧放四个入口,用justify-content: space-between一步到位,这是Flex最舒服的场景。Grid适合处理二维的规则网格,比如一个楼层里有8张商品卡,4列2行,用grid-template-columns: repeat(4, 1fr)能保证每张卡片宽度完全一致,不用手工算百分比。
再深一层就涉及到「谁负责宽度」。如果页面里的间距、尺寸都靠容器和子元素的尺寸配合,Flex的换行和gap属性在多数现代浏览器下都能正常工作,练习时可以直接用gap替代老式的margin方案。Grid的优势在于对齐是整体性的,卡片不管内容长短,边框和背景都能保持同一高度。遇到「一行固定几个卡片、数量还要保持一致」的区块,我基本都切Grid。
3. 先实现导航栏和第一屏:最小可用的HTML+CSS结构
结构拆完就到了动手环节。不从花哨的轮播特效开始,先做最硬的两块:顶部导航栏和轮播位占位。这两块做扎实,页面主框架就立住了。
3.1 顶部导航栏的HTML骨架与Flex布局
导航栏看着简单,但包含的信息层级不少:顶部一条浅色信息条,下面一行才是主导航。练习时把两者分开写,不要塞在同一个<ul>里。先写HTML:
<!-- 顶部信息条:购物提示与用户入口 --> <div class="topbar"> <div class="container topbar-inner"> <span class="topbar-left">欢迎来到商城</span> <span class="topbar-right"> <a href="#">登录</a> <a href="#">注册</a> <a href="#">购物车</a> </span> </div> </div> <!-- 主导航:Logo、搜索框、功能入口 --> <nav class="main-nav"> <div class="container nav-inner"> <h1 class="logo"><a href="#">MI商城</a></h1> <ul class="nav-list"> <li><a href="#">手机</a></li> <li><a href="#">家电</a></li> <li><a href="#">智能</a></li> <li><a href="#">配件</a></li> </ul> <form class="search-box" action="#" method="get"> <input type="text" placeholder="搜点什么"> <button type="submit">搜索</button> </form> </div> </nav>对应CSS要做的两件事:把.topbar-inner和.nav-inner变成Flex容器,同时让它们保持同一内容宽度。.container负责定宽居中,内部的Flex只负责排列。这样最外层容器管宽度,内层Flex管方向,职责不重叠。
.container { width: 1200px; margin: 0 auto; } .topbar { background: #f5f5f5; font-size: 12px; color: #666; } .topbar-inner { display: flex; justify-content: space-between; /* 左右两端对齐 */ align-items: center; height: 40px; } .main-nav { background: #fff; } .nav-inner { display: flex; align-items: center; height: 80px; } .nav-list { display: flex; list-style: none; margin-left: 40px; gap: 24px; /* 列表项间距,替代老式 margin-right */ } .search-box { margin-left: auto; /* 把搜索框推到导航栏最右侧 */ }代码逻辑说明:外层.container定了1200px宽并居中,这是全站复用的基础。.topbar-inner用justify-content: space-between让左右两组元素贴边,高度压到40px,视觉上更接近真实电商顶部条。.nav-list里的gap: 24px是Flex子项的间距属性,它避免了你给每个<li>单独设margin-right再清掉最后一个的问题。.search-box的margin-left: auto是Flex里很常用的一招:不需要手动计算宽度,直接推到最右端。
3.2 用position固定导航栏:宽度、层级与滚动遮挡
电商页面常见的交互是主导航栏在滚动时始终吸附在窗口顶部。这个效果CSS一句position: fixed就能实现,但新手往往只写固定定位,忽略了宽度和层级。
.main-nav { position: fixed; top: 0; left: 0; width: 100%; background: #fff; z-index: 999; /* 防止被轮播图或商品卡片盖住 */ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06); }这里有三个参数容易踩坑。第一是width: 100%,如果不写,fixed定位的元素宽度会收缩到内容宽度,导航背景就变短了;第二是z-index,轮播图区域的定位元素如果层级更高,滚动时导航会被顶到后面;第三是阴影,导航吸顶后需要一条浅阴影区分页面内容,没有阴影会显得背景糊在一起。还有一点容易被忽略:fixed会让导航脱离文档流,页面顶部会被遮住一截,需要在body上补一个padding-top,数值等于导航高度。
3.3 轮播位占位:不写JS也能保持宽高比
轮播图本身就是个独立模块,练习静态页时不需要把图片切换做出来,但要把这个位置的尺寸占住。常见做法是外层给宽度,内层用一个高度为0、用padding-top撑比例的子元素来保持宽高比。
.banner { width: 100%; background: #eee; } .banner-inner { width: 1200px; margin: 0 auto; height: 0; padding-top: 40%; /* 高度按宽度的40%撑开 */ background: url("../images/banner-demo.png") no-repeat center / cover; }.banner-inner的height: 0配合padding-top: 40%,让容器高度完全由比例决定,这个宽高比数值就是后续放真实轮播图时图片的裁剪比例。背景图用了background: url(...) no-repeat center / cover,center保证图片居中,cover让图片在不知道原始尺寸时尽量铺满且不变形。轮播位暂时不需要overflow: hidden,等真正做图片轮播切换时才需要。
到这里页面主框架已经清楚了:顶部条、吸顶导航、轮播占位三者的显示顺序和尺寸关系都是可控制的。网页往下拉时,导航固定不动,轮播位正常滚出视野,这就是最基础的电商首页骨架。
4. 商品卡片与楼层细节:hover、阴影和CSS变量
框架搭好后,页面真正出效果的是商品卡片。一张卡片只有图片、标题、价格三块,但把它批量排成楼层,就能练到Grid布局、交互状态、变量统一这三项基本功。
4.1 商品卡片的标准结构:图片、标题、价格三件套
先看一张卡片的HTML,注意类的命名尽量语义化,方便后续整排复制:
<div class="card"> <a href="#"> <div class="card-img"> <img src="images/phone.png" alt="手机"> </div> <h3 class="card-title">Redmi Note 12 5G</h3> <p class="card-desc">骁龙4移动平台 5000mAh</p> <p class="card-price"><span>1499元</span> <s>1699元</s></p> </a> </div>对应CSS,重点在图片尺寸控制和价格的视觉层级:
.card { background: #fff; border-radius: 8px; overflow: hidden; transition: transform 0.3s ease, box-shadow 0.3s ease; } .card-img { width: 100%; height: 220px; display: flex; align-items: center; justify-content: center; } .card-img img { max-width: 100%; max-height: 100%; object-fit: contain; /* 图片不变形,内容完整显示 */ } .card-title { font-size: 14px; margin: 12px 16px 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; /* 超长标题省略号 */ } .card-price { margin: 8px 16px 16px; font-size: 16px; color: #ff6700; } .card-price s { font-size: 12px; color: #999; }代码逻辑说明:.card-img用Flex居中图片,这样图片不管实际宽高是多少,都不会撑破卡片。object-fit: contain保证图片完整显示,不做裁剪,适合练习素材尺寸不统一的情况。标题的white-space: nowrap与text-overflow: ellipsis组成了「单行省略号」三件套,缺一不可。价格里的<s>标签自带删除线,比手动加文本装饰线更语义化,价格区用font-size区分原价与现价,主次一目了然。
4.2 hover交互:transition与box-shadow的参数搭配
卡片没交互会显得很呆。最稳妥的增强是「上浮 + 阴影加深」:鼠标悬停时卡片微微抬升,阴影范围变大。这里的关键不是写多少特效,而是控制过渡时长和缓动函数。
.card:hover { transform: translateY(-4px); /* 向上移动4px,产生抬升感 */ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12); }transition: transform 0.3s ease, box-shadow 0.3s ease写在.card而不是:hover上,这样鼠标移走时也有过渡动画。ease是默认的缓动函数,开始和结束速度慢、中间快,观感最自然。translateY(-4px)的数值不宜太大,超过8px会显得卡片飘忽;box-shadow的透明度0.12算中性,阴影太重会抢视觉焦点。如果你想模仿得更有层次,可以把box-shadow: 0 0 0 rgba(0, 0, 0, 0)写在默认态,让阴影从无到有过渡。
4.3 用CSS变量统一主题色与间距:改一处全局生效
写了不少页面后,改主题色是件很烦的事。电商页面的品牌色、价格色、热区背景色会重复出现几十次,如果每个地方都写#ff6700,改版要全局替换。练习阶段养成良好的变量习惯,后面做真实项目能少走很多弯路。
:root { --color-primary: #ff6700; --color-text: #333; --color-muted: #999; --color-border: #e0e0e0; --radius-lg: 8px; --shadow-hover: 0 8px 20px rgba(0, 0, 0, 0.12); } .card { background: #fff; border-radius: var(--radius-lg); box-shadow: var(--shadow-hover); } .card-price span { color: var(--color-primary); }| 变量名 | 默认值 | 用途 |
|---|---|---|
--color-primary | #ff6700 | 价格、按钮、高亮链接 |
--color-text | #333 | 主标题文字 |
--color-muted | #999 | 描述、辅助信息 |
--shadow-hover | 0 8px 20px rgba(...) | 卡片悬浮阴影 |
用变量的好处在换主题时最明显:只要改:root里的--color-primary,全站所有价格、按钮、Logo高亮一起变色,不需要再逐个查找替换。间距、圆角、阴影这些不常变的设计参数也可以沉淀成变量,这样不同卡片之间更容易保持一致。注意:变量定义在:root,不要定义在某个区块选择器里,否则其他区块访问不到。
5. 仿站常见坑与排查:布局翻车的五个真实问题
这一段是血泪经验合集。仿站练习里遇到的布局问题,来来回回就那几类,我把最常见的五个写出来,每个都按「现象→原因→解决」的顺序拆开讲。
5.1 父容器高度塌陷:浮动布局余毒
现象:给商品卡片设了float: left,结果父容器高度变成0,背景色和边框漏底。 原因:浮动元素脱离文档流,父容器没有子元素参与高度计算。 解决:能用Flex或Grid的地方直接换掉浮动布局;如果练习旧教程代码必须保留浮动,在父容器上加overflow: hidden触发BFC补救。另外,clear: both可以在浮动元素后面放一个空元素或使用::after伪元素清除浮动,但这属于过渡方案,新代码不要再写浮动布局。
/* 老代码常见写法,容易翻车 */ .cards::after { content: ""; display: block; clear: both; } /* 新代码直接换 */ .cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }5.2 外边距合并:垂直间距时有时无
现象:两个预设了margin-bottom和margin-top的区块,实际间距比预期小了一半。 原因:上下相邻的元素,浏览器只取较大的那个外边距,这就是垂直外边距合并。 解决:优先使用Flex或Grid的gap属性,属性本身不参与合并;真要用外边距控制间距,简单粗暴的办法是改用padding,并给父容器加上overflow: hidden或display: flow-root隔离上下文。排查间距问题时,在DevTools里看盒模型高亮区域,比反复猜CSS更管用。
5.3 图片路径与透明图:本地能开、部署就裂
现象:页面在本机预览正常,拷给同学或上传到服务器后图片全裂;还有的透明PNG图片显示成黑底或白底方块。 原因:图片引用了磁盘绝对路径C:\Users\...或某个在线临时链接;透明图异常通常是容器背景色和图片混合造成的错觉,也可能是图片本身携带着压缩工具的纯色背景。 解决:练习统一用相对路径,图片放在项目根目录的images/文件夹里,引用写images/xxx.png,不要携带../跨出项目目录;透明图放进卡片前先确认容器背景色,如果是深色背景,透明图会透出深色底,这种情况要么换一张带白底的图,要么把容器背景改成白色再配边框。仿站时我习惯把被仿页面的图片资源下载到本地,而不是直接热链远程图片,避免版权和外链失效的双重风险。
5.4 字体图标与Web Font引不进来
现象:页面里的购物车图标、搜索图标显示为一个方框或永远加载不出来。 原因:字体图标本质是特殊的文字,如果@font-face指定的字体文件路径不对、格式浏览器不支持、或者加载跨域资源失败,字就显示不出来。 解决:先打开DevTools的Network面板,看字体文件请求有没有404,这一步能定位80%的问题。其次确认@font-face的src路径是相对路径,并且.woff2格式放在最前面——它体积最小、现代浏览器都支持。如果你用的是把字体文件打包成CSS的工具,还要检查工具输出的路径前缀是否和你的目录结构一致。另外,<i>标签里如果没写对应的字符编码或者CSS里少写了font-family: "iconfont",图标同样不会渲染。
5.5 轮播区和滑片图对不齐:overflow与子元素宽度失效
现象:轮播区块的宽度正常,但里面的滑片图比容器宽出一大截,横向滚动条出现了。 原因:轮播图容器直接放了多张并排的图片,每张图片宽度设为width: 100%,但容器没有限制内部子项宽度,图片按原始尺寸展示,超级宽。 解决:给轮播图容器加上overflow: hidden,把溢出的滑片裁掉;同时给内部滑片统一设置flex: 0 0 100%,表示每个滑片固定占容器宽度的100%,多张图并排时才会左右排开而不是全部堆在第一屏。这样配合width: 100%,滑片数量再多也不会撑破页面。同样道理,任何水平滚动的容器都应该担心「子元素比父容器宽」这个隐患。
6. 像素级还原的验收技巧与下一步方向
页面写完不等于完工,怎么判断自己做得像不像?最直接的办法就是像素级对比。把被仿页面和自己的页面并排打开,浏览器窗口都拉到相同宽度,然后用DevTools的点选工具分别查看同一个区块的高度、间距、字体字号。不要凭肉眼猜,盒模型面板里白色的content区才是真实的宽高数字。
我一般会做三个快速校验:第一,把窗口宽度拉到375px左右,看页面是否出现大面积错位或横向滚动条,这能提前发现「忘写max-width」之类的疏漏;第二,在DevTools里临时给所有元素加outline: 1px solid red,快速确认每个区块的盒子边界是否符合你的线框;第三,用无痕模式重新打开页面,排除缓存干扰,确认CSS改动真生效了。这组操作十分钟内能过完,但能抓住大部分基础问题。
仿站验收通过后,推荐往上走两个方向。一个方向是把CSS练深:学BEM命名规范、CSS动画、响应式媒体查询,你会发现自己写的页面能撑起更多交互细节。另一个方向是给这个静态页注入JavaScript:轮播图切换、Tab栏切换、吸顶导航、倒计时,这些正好是电商首页最常见的前端交互,而且每一步都建立在你已经搭好的HTML结构上,难度曲线最平滑。我的习惯是保留这份仿站的第一版线框和CSS文件,之后每次做电商类页面都拿出来当基线参照——对照它检查栅格、间距和阴影参数,能省掉从零量尺寸的功夫。希望帮到你。
本文还有配套的精品资源,点击获取