简介:以小米有品为主题的购物网站前端项目,适合网页设计课程作业、前端入门实战,或希望快速搭建电商静态页面的学习者参考。项目覆盖在线购物常见流程,包含首页商品陈列导航、商品分类、购物车、登录注册、个人中心等页面,用HTML搭结构、CSS做样式,并通过媒体查询与swiper轮播实现响应式布局和图片切换效果。资源共48个文件,以HTML、CSS、JS及多张PNG/JPG商品图片为主,压缩包仅3.49MB,解压即可在浏览器中打开运行,便于阅读与合并修改。swiper-bundle库已内置,登录、验证码等页面亦有完整样式与素材对应。已有3314人下载学习,适合点击资源链接获取完整代码,作为电商类页面布局与样式设计的对照模板。
1. 这个HTML+CSS购物网站练的不是排版,是还原度
用纯 HTML+CSS 把小米有品首页做出来,看着像“照猫画虎”,实际上练的是还原度——盯着设计稿把结构拆对、把间距调准、把 hover 状态做完整。这门功夫不依赖任何框架,是所有前端岗位的底层能力,也是新手学完 HTML 和 CSS 基础之后最值得投入的第一个完整项目。它适合刚学完语法、缺一个“能拿得出手”的作品的人;也适合要交课程设计、想转行前端但简历上只有练习题的人。做这个项目,你不需要会 JavaScript 也能完成 90% 的页面效果,因为电商首页的骨架和质感,本来就应该由 HTML 结构和 CSS 样式撑起来。
2. 先拆结构:把首页从上到下切成五层
打开小米有品官网,别急着写代码,先做一件很多新手跳过的事:把页面当乐高拆开。我一般会把首页拆成顶栏、头部搜索区、导航区、内容主区和底部版权区这五层,每一层再往下拆成独立的模块。这个动作决定了后续 CSS 写起来顺不顺,也决定了代码能不能维护。
2.1 顶栏、搜索区、导航区的结构写法
先用语义化标签把大骨架搭出来,常见的做法是<header>包顶栏和搜索区,<nav>放商品分类导航,<main>包主体内容,<footer>放底部信息。注意:不要一上来就用<div>把一切包住,语义标签对后续样式挂载和阅读都友好得多。
<header class="site-header"> <div class="topbar"> <div class="container"> <span class="topbar-left">小米有品 官网</span> <span class="topbar-right">登录 | 注册</span> </div> </div> <div class="search-area"> <div class="container header-flex"> <a href="#" class="logo">小米有品</a> <form class="search-form" action="#"> <input type="text" placeholder="手机 家电 数码"> <button type="submit">搜索</button> </form> <a href="#" class="cart-link">购物车</a> </div> </div> <nav class="category-nav"> <div class="container"> <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> </div> </nav> </header>这套结构里值得注意的点有三个。一是.container用固定宽度居中,页面内容在 1920 宽屏幕下不至于摊成一片;二是.header-flex是留给 Flex 排版的类名,后面搜索区要横向对齐;三是导航列表用ul > li而不是散落的div,逛过电商页面的都知道,频道导航本质上就是一组链接列表,列表语义在这里最合适。.topbar是顶栏,做电商页的人习惯把登录注册和通栏公告放这,这是我见过绝大多数商城项目的标准布局。
2.2 商品卡片和主区楼层的语义选择
主体内容区是整个项目工作量最大的部分。首先要决定卡片列表用什么标签,我一般坚持ul > li包商品卡片,而不是把一堆div.card平铺。原因很简单:ul自带“同样层级的内容集合”语义,而且用 CSS 选择器控制子项时,.goods-list > li比.goods-list > div的意图明确得多,不容易误伤内部嵌套的元素。
<main class="site-main"> <section class="banner-section"> <div class="banner-item">主视觉横幅</div> </section> <section class="category-grid"> <div class="section-title">热门分类</div> <ul class="goods-list"> <li class="goods-item"> <a href="#"> <img src="images/product-1.webp" alt="商品名称"> <h3>商品标题这里放两行</h3> <p class="price"><span class="sale-price">1999元</span></p> <p class="tags">标签一 标签二</p> </a> </li> <li class="goods-item"> <!-- 重复N项 --> </li> </ul> </section> <section class="promo-floor"> <!-- 楼层模块 --> </section> </main>这段代码里有个细节常被忽略:img的alt属性要和商品名对应,而不是写“图片”。搜索引擎看这个,爬虫看这个,如果你后面做性能排查,空alt还会造成干扰。另一个细节是每个楼层模块用<section>包一层,里面写一个.section-title,后面用 CSS 统一控制标题字号和底线距离就不需要逐个调。楼层之间如果需要区分背景色,给section加不同背景类即可。
2.3 骨架搭完别急着写样式,先做一次“无CSS方言检查”
这一步是很多速成教程不会带你做的,但实战里特别有用。骨架写好之后,把 CSS 文件先不引入,在浏览器里看一眼裸的 HTML 页面。此时页面没有任何颜色和定位,唯一的信息传达方式就是标题层级、列表结构和文字顺序。
检查三件事:第一,从上往下滚一遍,确认页面内容的阅读顺序和真实站点的楼层顺序一致;第二,看h1、h2、h3是否按层级出现——电商首页常见的翻车是h1用在商品卡片的标题上,一页出现几十个h1,对搜索引擎很不友好;第三,确认每个链接都有实际的href,哪怕是占位的#也行,否则 hover 样式在后续调试时会出现“点了没反应”的假象。
常见做法是以<h1>给整站名称或主视觉用一次,各楼层标题用<h2>,卡片内部商品名用<h3>。这样语义树的层级和视觉层级保持一致,后续写 CSS 也会自然很多。骨架阶段不需要纠结美观,重点是把信息架构定住——这一步稳了,后面所有样式代码都是在给已经定好型的建筑做装修,而不是敲掉承重墙重砌。
3. 让页面像小米有品的三套CSS关键手法
骨架搭好之后,进入真正的 CSS 主战场。电商首页的观感,说到底由三件事决定:布局方式、间距与字号的统一性、hover 细节的完整度。这三件事做扎实了,页面就算没有配图,也能有“商城味”。
3.1 用Flex布局解决导航和卡片横排
现在的电商页面已经很少有人用浮动做整页布局了,主流的做法是 Flex。拿第 2 章的头部结构举例,.header-flex要解决“logo 在左、搜索框居中、购物车在右”这个问题,一行代码就够。
.header-flex { display: flex; align-items: center; justify-content: space-between; } .nav-list { display: flex; gap: 28px; margin: 0; padding: 0; list-style: none; } .goods-list { display: flex; flex-wrap: wrap; gap: 16px; margin: 0; padding: 0; list-style: none; } .goods-item { flex: 0 0 calc(25% - 12px); background: #fff; border-radius: 8px; }这里几个参数不是随便写的,值得逐个说清楚。.nav-list的gap: 28px是导航项之间的间距,比给每个li设margin-right更省事,也避免最后一个子项多出边距;.goods-list的flex-wrap: wrap允许卡片在宽度不够时换行,这是响应式的基础;.goods-item的flex: 0 0 calc(25% - 12px)意思是固定基底宽度为父容器 25% 再减去间距的补偿值,让每行四张卡片且刚好填满。如果我不减去这个 12px,四张卡片加三个 16px 的 gap 会把容器撑破换行,这是新手最容易看半天找不到原因的布局翻车。
3.2 间距与字号:页面质感的根本来源
很多同学从教程里抄来一堆组件,拼在一起却总觉得“不够高级”,问题往往不在配色,而在间距和字号没有体系。小米有品这类商城页面的质感,本质是统一的白底、克制的阴影、整齐的间距节奏。我一般用 CSS 变量先把这几个基础令牌定义好。
:root { --gap-sm: 8px; --gap-md: 16px; --gap-lg: 24px; --text-title: 18px; --text-body: 14px; --text-price: 16px; --color-text: #333; --color-muted: #999; --color-accent: #ff6700; --radius-sm: 4px; --radius-md: 8px; } .section-title { font-size: var(--text-title); color: var(--color-text); margin-bottom: var(--gap-md); } .price .sale-price { font-size: var(--text-price); color: var(--color-accent); font-weight: 600; }这套 CSS 变量的价值在于全局一致性。标题字号 18、正文字号 14、价格强调 16,后面写一二十个模块都复用同一个变量,不会出现“这个标题 17px,那个标题 18px”的肉眼难察、统一时又痛苦的情况。间距变量同理,8、16、24 是电商页面最常用的间隔档位,三层递进足够覆盖绝大多数场景。行内还推荐加一条line-height: 1.6给正文,尤其是商品描述区域,行距太挤会让大批文字显得杂乱。
3.3 hover状态设计:边框、阴影、位移一套做完
这是和“css 鼠标移入事件”最直接相关的一块。很多页面的卡片 hover 只改了一个背景色,显得很单薄。小米有品这类商城页面的卡片 hover 通常是“边框颜色变浅、阴影抬起来、卡片轻微上移”三联动作。一次做全套,比一个一个加省心。
.goods-item { transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease; border: 1px solid #e5e5e5; } .goods-item:hover { transform: translateY(-4px); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08); border-color: #ff6700; } .goods-item img { display: block; width: 100%; transition: transform 0.4s ease; } .goods-item:hover img { transform: scale(1.04); }参数说明:translateY(-4px)的 4px 是经过验证的舒适位移,太大显得飘,太小没反馈;box-shadow的0 8px 20px rgba(0,0,0,0.08)意思是垂直方向 8px 的投影、20px 模糊半径、8% 透明度,这个透明度是重点——电商页面的阴影一旦超过 12%,页面就会显得灰蒙蒙,失去清爽感;border-color: #ff6700是小米生态最常见的橙色强调色。图片的scale(1.04)是内层放大,配合外层的overflow: hidden使用,不然图片放大后会顶破卡片的圆角边框。这里有一个关键习惯,transition写在默认状态,而不是写在:hover里。写在 hover 里时,鼠标移入有动画、移出瞬间“啪”地弹回;写在默认状态,移入移出都有过渡效果,观感柔和很多。
4. 避坑:还原电商首页最容易翻车的5个细节
这个项目走到一半,几乎所有人都会遇到几个莫名其妙的状况。样式没生效、图片不见、布局塌了、hover 闪烁。下面五条是从各种本地页面和课设项目里反复出现的高频问题,按“现象 → 原因 → 解决”写成排查清单。
4.1 本地打开页面只有光秃秃的HTML,CSS完全没加载
现象:双击index.html,页面显示的是裸排版,所有颜色、布局全部缺失,控制台还有一条类似Access to CSS stylesheet at file:///...的报错。
原因:大多数情况是 CSS 文件的引入路径不对。新手最常犯的错误是把<link rel="stylesheet" href="css/style.css">写在了head里但文件实际放在别的目录,或者文件名大小写对不上。另一个隐蔽原因是一个<!doctype html>文档头缺失导致的怪异盒模型,但那是样式“变丑”而不是“全丢”,两者要区分。先看控制台报错指向哪个文件,再对照相对路径。
解决:确认你的 CSS 文件和 HTML 是同级的css文件夹时,href 应该写成href="css/style.css";如果是同级目录就写href="style.css"。建议所有资源都用相对路径,不要用file:///C:/...这种绝对路径,换台电脑或者上传到服务器就全断。另外确认 HTML 第一行必须是<!doctype html>,并且<html lang="zh-cn">可以加上,这对中文页面的解析和搜索引擎识别都有好处。
4.2 盒子里外尺寸对不上总宽,越改越乱
现象:设置了一个width: calc(25% - 12px)的卡片,加完padding: 16px之后发现四个卡片把容器撑爆了,换行后每行只剩三个。
原因:CSS 默认的box-sizing是content-box,也就是说你写的宽度只包含内容区,padding 和 border 还要另加。四张卡片每张多出 32px 的 padding,加起来就把容器挤爆了。
解决:在项目最开头写一条全局声明:
*, *::before, *::after { box-sizing: border-box; }这条规则让所有元素的 width 直接包含 padding 和 border,后面你写width: 25%就是实实在在的 25%,不会再因为内边距偷偷变胖。这是我见过的几乎所有成型项目的标配,越早加,后面越省心。
4.3 hover时卡片疯狂抖动,鼠标还没移到位就开始闪
现象:鼠标从卡片一端划过,卡片边缘忽上忽下地抖动,有时候甚至像闪烁。
原因:过渡效果只写了 transform 和 box-shadow,但transition属性里还把border-color也加了进去,而且.goods-item默认没有边框宽度而 hover 时加了边框,这种“没有边框→有边框”的跳变会触发布局回流的抖动。还有更常见的原因:transition写了all,鼠标划过任意子元素都会触发重绘。
解决:给.goods-item设置固定border: 1px solid transparent,hover 只改颜色,不让宽度变化;transition明确列出需要过渡的属性,不要写all。还有一个习惯问题:不要把 hover 效果作用在子元素上,统一在li:hover里通过后代选择器控制,避免鼠标移动到文字上时就触发整个卡片的状态变化。把默认边框宽度和 hover 后的边框宽度保持一致,是消除抖动最立竿见影的办法。
4.4 列表的 margin 和坑:垂直外边距塌陷
现象:给.section-title设置了margin-bottom: 24px,但标题和下方商品列表之间几乎没有间距,看起来只有几像素。
原因:这是margin塌陷。父容器.category-grid没有设 padding、没有 border、也没有overflow: hidden,此时子元素的垂直margin会“穿透”到父元素外面,和父元素外部的 margin 合并,最终取两者中的最大值,而你不一定算得到这笔账。
解决:给父容器加任意一个创建 BFC 的属性,最省事的是overflow: hidden或者padding-top: 1px,也有的人直接用display: flow-root,这是专门为此设计的现代属性,兼容性已经很好了。另外注意:兄弟元素之间不要同时用上下的 margin,统一用margin-bottom,避免两个 margin 合并导致总间距不可控。
4.5 选择器优先级失控:为什么我的样式不生效
现象:某个li想要白色背景,但无论写background: #fff还是带!important,页面展示的仍是灰色或其他颜色。
原因:前面某处写了更高优先级的选择器,比如.goods-list .goods-item或#content .goods-item,ID 选择器的特殊性太高,class 根本盖不过去。新手还容易把样式写在直接在 HTML 标签上的style属性里,那玩意的优先级高于任何选择器,导致你在 CSS 里根本改不动。
解决:先按 F12 打开控制台选中该元素,右侧 Styles 面板里能直接看到“被划掉”的样式和实际生效的规则,找到胜出的那条规则是谁写的,再决定怎么调整。生产上的一般做法是:不要用 ID 写样式,保持类选择器的层级尽量浅,比如.goods-item就够了,不需要.category-grid .goods-list .goods-item。如果一行类名写三层以上,说明结构已经过度嵌套,考虑把样式直接挂在目标类上。!important不是后悔药,它是下一任维护者的噩梦,尽量少用。
5. 进阶玩法:用纯CSS把静态页面做出“动态感”
用户留在页面上的前几秒,视觉反馈占了很大权重。HTML+CSS 项目里不带 JavaScript 也能做出相当有质感的动态效果,下面三种是电商页面最常见也最容易出彩的纯 CSS 手段。
5.1 主视觉横幅的渐变与光效
小米有品首页上方通常是全宽主视觉图,图片没到位时,可以用 CSS 渐变先撑住场景,并且加一个缓动的光晕扫过效果。
.banner-item { min-height: 260px; background: linear-gradient(120deg, #ff6700, #ff9500); position: relative; overflow: hidden; border-radius: 12px; } .banner-item::before { content: ""; position: absolute; top: 0; left: -100%; width: 50%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); animation: scan 3.5s ease-in-out infinite; } @keyframes scan { 0% { left: -100%; } 100% { left: 200%; } }这段代码的思路是:用::before伪元素做一条透明的白色渐变带,animation控制它从左往右周期性扫过,这就是被检索圈里常说的“涟漪光圈扩散”类效果在电商横幅里的变体。left从一个负值扫到正值,注意动画要配合overflow: hidden,不然光带扫出边框后会撑出横向滚动条。做这类装饰动效时,克制是第一原则——一条横幅一个扫光就够,全都动起来页面会显得很廉价。
5.2 商品图里的伪三维旋转展示
热词里有transform: rotateY(60deg) translateZ(300px)这类写法,做轮播或展示区时确实能让主推商品转起来。理解它的核心规则其实不复杂:rotateY 是绕竖直轴旋转,正负决定转动的方向;先转还是先移动,顺序不同结果也不同。
.promo-item:hover { transform: perspective(800px) rotateY(-12deg) translateZ(30px); }这段 CSS 加在鼠标悬停时,能让商品块产生一点“从货架上探出头”的立体感。perspective: 800px是透视距离,数值越小变形越夸张,800 是比较自然的范围;rotateY(-12deg)负值表示向右偏转,配合translateZ(30px)把元素朝眼睛方向拉近。如果你前面哪一步写出了rotateY(60deg) translateZ(300px)然后发现商品转得看不见了,不用慌——那是因为垂直翻转角度过大,元素几乎转到了侧面。把角度降到 12 到 20 度,同时把位移控制在 20 到 40px,就能得到肉眼舒适的伪 3D 手感。这种写法的正负判断,经验之谈是:先写正角度看效果,不对再改负角度,比空算坐标更快。
5.3 购物车角标的小圆点动效
购物车链接旁边常见红色数字角标,很多同学会想用 JS 去改,实际上纯 CSS 也能完成“出现 + 抖动”的反馈。
<div class="cart-box"> <a href="#" class="cart-link">购物车</a> <span class="cart-badge">3</span> </div>.cart-box { position: relative; } .cart-badge { position: absolute; top: -8px; right: -14px; min-width: 18px; height: 18px; padding: 0 4px; background: #ff6700; color: #fff; font-size: 12px; line-height: 18px; text-align: center; border-radius: 9px; animation: pop 0.4s ease; } @keyframes pop { 0% { transform: scale(0); } 60% { transform: scale(1.3); } 100% { transform: scale(1); } }这里的圆角值是高度的一半,border-radius: 9px配height: 18px,出来的就是胶囊形,这是“n/2 规则”里最快出效果的一个。角标位置用position: absolute相对于.cart-box,所以父级要有position: relative,忘了这个角标会飘到页面左上角。pop动画在元素首次渲染时执行,做课程设计展示时也能唬唬人,不用 JS,刷新页面就能看到弹跳效果。这种小动效的细节,恰恰是电商页面“完成度”和普通静态练习页拉开差距的地方。
6. 页面做完了:怎么验证它真的能扛住使用
项目合上之前,我习惯做三轮验证,每一轮都能发现前面没注意到的问题。
第一轮是窄屏测试。打开浏览器开发者工具,把页面切到 390px 宽度模拟手机,从上往下滚一遍。重点看三件事:导航栏有没有横向溢出的滚动条,商品卡片的calc(25% - 12px)是否变成三列或两列,搜索框是否被压缩得只剩下一个按钮。如果你希望手机端也整齐,给.goods-item加一条min-width: 140px,防止分数宽度算出来的卡片窄到没法看。
第二轮是无样式检查。把 CSS 文件从<link>里暂时注释掉,再滚一遍页面。如果这时信息顺序仍然完整,说明你的 HTML 结构经得起“皮肤被扒掉”的考验。这个习惯来自一次线上事故排查——某个页面上线后样式文件挂了,整个页面乱成一团,从那以后我做的每个页面都要确认裸结构能读通。
第三轮是控制台清零。打开控制台看有没有样式层级的红色警告、资源加载失败和图片 404。图片加载失败在本地目录里很常见,路径写成/images/xxx.webp的绝对根路径在本地直接打不开,改成相对的images/xxx.webp就正常。另外把页面打包或发送给别人时,整个项目文件夹一起打包,不要只发一个 HTML 单文件,否则对方看到的就是缺图少样式的“半成品”。
做这个项目的最后阶段,我还会顺手做一件小事:把文件目录整理干净,css文件夹里放样式,images文件夹里放图片,HTML 文件按页面对应命名。这不算技术含量,但面试官打开压缩包的那一刻,“印象分”就在这些细节里。
我当年的第一个完整页面做得一团糟——卡片间距不统一、hover 效果闪烁、发出去给同学打开全是样式丢失。后来养成一个习惯:每写完一个模块,立刻切到窄屏和控制台各看一眼,别攒到全部做完再一起查。希望这个习惯也能帮到你。
本文还有配套的精品资源,点击获取