
简介以“小米有品”为主题的购物网站前端项目面向正在学习HTML与CSS的初学者也适合需要完成购物类网页作业的学生内容贴合电商场景。项目从首页导航栏、轮播图、商品分类与新品推荐到购物车商品列表、数量修改与总价计算再到登录注册、个人信息和商品详情等页面完整呈现购物网站的主要构成。压缩包共48个文件包含7个HTML页面、4个CSS样式表、1个JavaScript文件以及31张PNG和多张JPG等图片素材整体仅3.49MB便于下载后直接运行学习。已有3316人学习下载通过对照源码可掌握HTML标签语义化分组、CSS类与ID选择器、浮动定位、响应式媒体查询等关键知识点无论是巩固前端基础还是作为作业参考都很有价值。1. HTMLCSS 购物网站实战先从“能看”做到“像样”打开小米有品首页很多人以为难在那些商品图和轮播 Banner实际拆开看整页的骨架无非是“顶部导航 商品卡片 分区标题”反复组合。用纯 HTMLCSS 搭一个小米有品风格的购物网站核心不是复刻像素级设计而是把布局结构、卡片规范、视觉层级用语义化标签和样式控制住。这个方向特别适合两类人刚学完 HTML/CSS 基础、想用完整项目把 flex、grid、定位、伪类串起来的初学者以及做前端外包或毕设、需要快速产出高完成度静态页面的开发者。本文按“拆结构 → 写布局 → 调细节 → 避坑 → 进阶”顺序给你一套能直接复现的落地方案。2. 页面结构拆解把小米有品首页变成五个可复用模块2.1 电商首页的模块化思维先画线框再写代码动手写 HTML 前我习惯先把首页拆成线框。小米有品这类电商页面的典型结构是顶部工具条登录/注册/购物车入口、主导航区Logo 搜索框 分类菜单、焦点图轮播区、商品分区每个分区有标题 商品卡片网格、底部服务保障条和版权信息。拆完之后你会发现整页只有三类元素在重复导航条、分区标题、商品卡片。商品卡片是其中最核心的复用单元它由图片、标题、副标题、价格四个部分组成CSS 写好这一张卡片整站风格就统一了。线框阶段要决定的事情不多但很关键页面宽度定多少、每行放几个商品、分区之间的间距多大。我一般设页面最大宽度 1226px对齐小米官网的经典宽度商品网格每行 4 列间距 14px。这些数值先用 CSS 变量存起来后面调整只改一处。2.2 用 HTML5 语义标签搭建骨架header、nav、main、footer结构代码遵循“先语义、后样式”的顺序让搜索引擎和屏幕阅读器都能看懂页面层次。顶部工具条用header包裹商品分区放在main里每个商品分区用section加aria-labelledby关联标题。这样写的好处是后续加 CSS 时选择器更短而且页面结构清晰后期接 JavaScript 做交互也容易定位元素。!doctype html html langzh-cn head meta charsetutf-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title小米有品风格购物首页/title link relstylesheet hrefcss/style.css /head body header classtopbar div classcontainer ul classtopbar-nav lia href#小米有品/a/li lia href#我的购物车/a/li lia href#消息通知/a/li lia href#登录/注册/a/li /ul /div /header header classmain-header div classcontainer header-flex h1 classlogoa href#小米有品/a/h1 nav classmain-nav aria-label主导航 ul lia href#手机/a/li lia href#智能家居/a/li lia href#穿戴设备/a/li /ul /nav div classsearch-box input typesearch placeholder搜索商品 button typebutton搜索/button /div /div /header main section classhero-banner aria-label促销焦点图 div classbanner-slider !-- 轮播图结构 -- /div /section !-- 商品分区重复此结构 -- section classproduct-section aria-labelledbysection-phone-title div classcontainer h2 idsection-phone-title classsection-title热卖手机/h2 div classproduct-grid !-- 商品卡片由 JavaScript 模板或静态 HTML 填充 -- /div /div /section /main footer classsite-footer div classcontainer p服务保障正品保证 | 极速发货 | 七天无理由退货/p /div /footer /body /html逻辑说明整体结构分成“顶部工具条 / 主头部 / 主体内容 / 页脚”四层。.container是页面宽度容器内部元素靠它居中.header-flex用 flex 让 Logo、导航、搜索框排成一行商品分区用aria-labelledby把h2和section关联屏幕阅读器可以跳过重复结构直接读商品标题。这些 class 名在后面写 CSS 时直接对应选择器不需要额外包一层无语义的div。参数说明meta nameviewport的content值里widthdevice-width让页面在手机上按设备宽度渲染initial-scale1.0是初始缩放比例。input typesearch和普通文本框的区别不大但在移动端会唤起带搜索键的键盘这对购物站点很重要。placeholder搜索商品是输入框占位提示用户输入后自动消失。2.3 商品卡片的 HTML 模板一张卡片结构写对整站复制商品卡片是高频复用单元我把它写成固定模板figure包图片和价格figcaption放标题和副标题。用figure的好处是图片和文字描述在语义上绑定CSS 定位时也不用担心图片和标题脱节。figure classproduct-card a href# img srcimages/product-01.jpg alt小米手机 12 width280 height280 figcaption h3 classproduct-name小米手机 12/h3 p classproduct-desc骁龙 8 处理器2K 直面屏/p p classproduct-price¥ 3499del¥ 3999/del/p /figcaption /a /figure逻辑说明整个卡片是一个链接点击任意区域都能跳转详情页这是电商卡片的通用做法。del标签显示原价浏览器默认会带删除线CSS 里再统一调颜色。alt小米手机 12必须写图片加载失败时用户能看到文字说明搜索引擎也能索引商品内容。参数说明img的width和height属性建议显式写出来避免图片加载时页面上下跳动。这里的 280px 是图片在卡片里的实际显示尺寸不是原图尺寸。商品卡片在 grid 布局里会拉伸但图片尺寸固定所以卡片内容高度是稳定的。3. CSS 布局核心Flex 与 Grid 的组合让购物页不塌不飘3.1 为什么购物网站首选 Flex Grid而不是浮动布局早期电商页面用float做多列布局缺点是清除浮动麻烦、垂直居中困难。Flex 解决一维排列一行里的对齐、间距、换行Grid 解决二维网格多行多列的商品矩阵。购物页面的典型需求是“每行 4 列、列数随屏幕变化”这正是 Grid 的强项而导航条里“Logo 在左、搜索框在右、中间菜单自适应居中”用 Flex 一行代码就能对齐。浮动并没有完全退出历史舞台处理文字环绕图片时它仍然是最简单的方案。但购物页的布局不涉及文字环绕用 Flex Grid 能让代码更短、行为更可预测。下面这段 CSS 是页面布局的基石直接抄进项目就能用。:root { --container-width: 1226px; --grid-gap: 14px; --primary-color: #ff6700; /* 小米有品标志橙 */ --text-dark: #333; --text-light: #757575; --border-light: #e0e0e0; } .container { max-width: var(--container-width); margin: 0 auto; padding: 0 14px; } .header-flex { display: flex; align-items: center; justify-content: space-between; height: 60px; } .product-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--grid-gap); } media (max-width: 768px) { .product-grid { grid-template-columns: repeat(2, 1fr); } }逻辑说明:root里定义 CSS 变量全局统一管理颜色、间距、容器宽度。.product-grid用repeat(4, 1fr)生成四列等宽布局1fr表示每列均分剩余空间gap控制卡片间距。媒体查询在屏幕宽度小于 768px 时把四列改成两列适应平板和手机。参数说明--grid-gap: 14px是卡片间距间距太小会显得拥挤太大则浪费空间。--primary-color: #ff6700是小有品代表性的橙色用在价格、按钮、导航高亮上。max-width加margin: 0 auto是水平居中的标准写法注意不要写成width: 1226px否则小屏幕下会出现横向滚动条。3.2 导航吸顶与搜索框position: sticky 的正确使用姿势购物网站的导航栏需要在页面滚动时保持可见。常见做法是position: sticky它比position: fixed好在不吸顶时导航占位正常吸顶后不遮挡下方内容。要让sticky生效父容器不能有overflow: hidden且导航需要指定top值。.main-header { position: sticky; top: 0; z-index: 1000; background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08); } .search-box { display: flex; border: 1px solid var(--border-light); border-radius: 4px; overflow: hidden; } .search-box input { border: none; outline: none; padding: 8px 12px; width: 220px; font-size: 14px; } .search-box button { border: none; background: var(--primary-color); color: #fff; padding: 8px 16px; cursor: pointer; }逻辑说明.main-header吸顶后加浅阴影让页面滚动时导航和内容有视觉分界。搜索框的overflow: hidden让输入框和按钮的圆角合并成一个整体按钮用品牌橙色。输入框的outline: none去掉默认聚焦黑边改用自定义样式。参数说明top: 0表示吸顶时导航贴在视口顶部z-index: 1000保证遮盖商品图片和轮播图。rgba(0, 0, 0, 0.08)是阴影颜色透明度 0.08 是经验值太深会显得脏太浅吸顶时看不出层次。width: 220px的搜索框在小屏可能过宽后期再加媒体查询调整。3.3 商品卡片样式悬停上浮、价格高亮、图片尺寸锁定卡片视觉是购物页的门面。米家有品的卡片风格是“白底、轻阴影、悬停上浮”。实现上浮效果只需在:hover时加transform: translateY(-2px)和稍强的阴影再配一个transition做过渡动画。价格用品牌色加粗原价用灰色删除线。.product-card { background: #fff; border-radius: 8px; overflow: hidden; transition: transform 0.3s ease, box-shadow 0.3s ease; border: 1px solid var(--border-light); } .product-card:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08); } .product-card img { display: block; width: 100%; height: auto; } .product-name { font-size: 16px; color: var(--text-dark); margin: 12px 0 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .product-desc { font-size: 14px; color: var(--text-light); margin: 0 0 8px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .product-price { color: var(--primary-color); font-size: 18px; font-weight: 600; } .product-price del { color: var(--text-light); font-size: 14px; font-weight: 400; margin-left: 8px; }逻辑说明卡片圆角 8px边框 1px 浅灰悬停上浮 2px 配合阴影增强立体感。商品名用text-overflow: ellipsis实现单行省略号商品描述用-webkit-line-clamp: 2实现两行截断。这两处细节决定卡片在商品名长短不一时是否整齐。参数说明transition: transform 0.3s ease, box-shadow 0.3s ease里0.3s是动画时长太短显得生硬太长拖沓。-webkit-line-clamp: 2是标准属性line-clamp的前缀写法现代浏览器都支持。价格删除线的margin-left: 8px让原价和现价之间留出空隙避免贴在一起。3.4 分区标题的三种样式让重复内容不呆板商品分区标题如果每个都一样页面会显得机械。我常用的做法是每个分区标题左侧加一个竖条色块右侧放一个“查看更多”链接。竖条用border-left实现不需要额外元素。.section-title { font-size: 22px; color: var(--text-dark); margin: 32px 0 20px; padding-left: 12px; border-left: 4px solid var(--primary-color); display: flex; justify-content: space-between; align-items: center; } .section-title a { font-size: 14px; color: var(--text-light); text-decoration: none; } .section-title a:hover { color: var(--primary-color); }逻辑说明border-left加在标题上等于一个不占文档流的装饰条跟文字垂直居中对齐。右侧链接用绝对定位或 flex 推到最右边这里选择 flex 方式更省心。整个分区标题的高度由字号和 margin 撑开不需要写死。参数说明padding-left: 12px让文字离竖条有呼吸空间。border-left: 4px solid var(--primary-color)的 4px 是竖条粗细太细没存在感太粗像设计事故。链接 hover 变橙色与其他交互元素保持一致。4. 视觉细节与动效没有 JavaScriptCSS 也能让页面“活”起来4.1 轮播图基础结构与自动播放CSS 动画 定时器的替代方案购物首页焦点图是用户第一眼看到的东西。纯 CSS 做轮播的经典思路是把多张图横向排列在一个容器里用transform: translateX按时间平移配合animation实现自动轮播。这种方式没有 JavaScript代码简单但无法手动点击切换适合做静态演示或给后续 JS 交互留结构。section classhero-banner div classbanner-viewport div classbanner-track div classslide img srcimages/banner-1.jpg alt新品促销 /div div classslide img srcimages/banner-2.jpg alt智能家居节 /div div classslide img srcimages/banner-3.jpg alt手机焕新季 /div /div /div /section.banner-viewport { width: 100%; overflow: hidden; position: relative; height: 360px; } .banner-track { display: flex; width: 300%; animation: slideMove 12s infinite ease-in-out; } .slide { width: 33.333%; flex-shrink: 0; } .slide img { width: 100%; height: 360px; object-fit: cover; } keyframes slideMove { 0%, 30% { transform: translateX(0); } 33%, 63% { transform: translateX(-33.333%); } 66%, 96% { transform: translateX(-66.666%); } 100% { transform: translateX(0); } }逻辑说明.banner-track宽度设为 300%3 张图的容器总宽每张.slide占 33.333%这样 flex 排列时三张图刚好横向排满。keyframes slideMove里0%~30%停留第一张33%~63%滑到第二张66%~96%滑到第三张最后100%回到第一张。12 秒一个循环每张图显示约 3.6 秒。参数说明object-fit: cover让图片按容器比例裁剪而不是拉伸变形是轮播图和商品图的标配。height: 360px是焦点图高度这个尺寸在 1226px 宽度下视觉比例接近黄金分割。animation: slideMove 12s infinite ease-in-out中ease-in-out让滑动起止速度平缓比linear看起来舒服。4.2 流光边框与涟漪光圈用伪元素和动画提升质感热门商品或会员专区可以用“流光边框”强调视觉重点。实现思路是在卡片外层加一个渐变背景利用keyframes改变background-position让一道光在边框上循环游走。也可以用伪元素::before做光圈扩散效果鼠标悬停时从中心向外扩散一圈涟漪。.product-card--glow { position: relative; overflow: hidden; border: none; background: linear-gradient(120deg, #ff6700, #ff9a00, #ff6700); background-size: 200% 100%; animation: borderFlow 3s linear infinite; padding: 2px; /* 边框厚度 */ } .product-card--glow .card-inner { background: #fff; border-radius: 6px; height: 100%; } keyframes borderFlow { 0% { background-position: 0% 50%; } 100% { background-position: 200% 50%; } }.product-card--ripple { position: relative; } .product-card--ripple::after { content: ; position: absolute; inset: 0; border-radius: 8px; box-shadow: 0 0 0 0 rgba(255, 103, 0, 0.4); opacity: 0; } .product-card--ripple:hover::after { animation: rippleEffect 0.6s ease-out forwards; } keyframes rippleEffect { to { box-shadow: 0 0 0 12px rgba(255, 103, 0, 0); opacity: 1; } }逻辑说明流光边框的原理是让渐变背景动起来padding: 2px相当于边框厚度内部白色.card-inner遮住中间区域只有边缘露出动画中的渐变光。涟漪效果则是利用box-shadow从 0 扩散到 12px、颜色透明度渐变为 0模拟水波扩散。这两个效果都不需要额外 DOM 元素::after撑起全部视觉。参数说明background-size: 200% 100%是关键背景比元素宽一倍动画才能通过位移background-position产生流动感。inset: 0是top/right/bottom/left: 0的简写让伪元素铺满卡片。forwards让动画结束后停在最后一帧避免涟漪突然消失。4.3 鼠标移入卡片显示遮罩层用:hover和opacity做过渡商品卡片 hover 时显示“加入购物车”或“查看详情”遮罩是电商页面常见交互。这里用绝对定位把一个半透明遮罩层盖在图片上默认opacity: 0hover 时变为1配transition渐变。注意遮罩层不能盖住价格区所以要把它定位在图片容器内部。.product-card { position: relative; } .card-image { position: relative; overflow: hidden; } .card-overlay { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.35); display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.3s ease; } .product-card:hover .card-overlay { opacity: 1; } .card-overlay a { color: #fff; border: 1px solid #fff; padding: 8px 20px; border-radius: 20px; text-decoration: none; }div classcard-image img srcimages/product-01.jpg alt商品图片 div classcard-overlay a href#加入购物车/a /div /div逻辑说明遮罩层是图片容器的子元素position: absolute让它相对.card-image定位inset: 0铺满。默认透明鼠标进入卡片时淡入。按钮用细边框圆角样式视觉轻盈不抢商品图的焦点。参数说明rgba(0, 0, 0, 0.35)是遮罩深度35% 的黑既保证按钮可读又不会完全遮挡商品图。transition: opacity 0.3s ease控制 0.3 秒淡入淡出。如果遮罩挡住价格导致无法点击检查.card-overlay是否设置了pointer-events: none需要交互时不能加。5. 常见问题与避坑指南HTMLCSS 购物页最容易翻车的 5 个细节5.1 图片加载导致布局抖动给 img 定宽高而不是只靠 CSS现象页面加载时商品卡片高度从 0 慢慢撑开文字和下面的商品被顶下来整个页面像在“跳动”。原因浏览器在图片加载完成前不知道图片宽高img默认高度为 0。解决在 HTML 里给img写width和height属性或者用 CSS 为图片容器设定固定宽高比。.card-image { width: 100%; aspect-ratio: 1 / 1; /* 正方形图片占位与加载后一致 */ background: #f5f5f5; /* 占位底色 */ }aspect-ratio是现代浏览器的标准属性设置 1:1 后容器高度由宽度决定图片加载前后布局保持一致。占位底色避免加载过程中一片空白观感更自然。5.2 横向滚动条是怎么冒出来的现象页面底部出现横向滚动条左右可以滑动但不是设计预期。原因某个元素的宽度超过视口宽度常见于width: 1226px写死、padding加在容器外部、轮播图translateX溢出。解决全局检查所有元素是否超出用通配选择器临时定位问题源。* { box-sizing: border-box; } body { overflow-x: hidden; }box-sizing: border-box是必须的它让padding和border计入总宽度否则.container { width: 1226px; padding: 0 14px; }实际宽度是 1254px超出视口就被截断。overflow-x: hidden是兜底方案但不能替代排查问题本身。5.3 导航吸顶后“粘住”不生效现象设置了position: sticky但滚动时导航没有吸顶直接滚出屏幕。原因sticky的生效条件是父容器高度大于导航高度且父容器没有overflow: hidden同时导航不能有overflow: auto。另一个坑是父容器的高度刚好等于导航高度导致没有可“粘”的空间。解决检查父级是否给height或min-height并把overflow改为visible。header classmain-header.../header main div classpage-wrapper !-- 不能 overflow: hidden --常见做法是给header直接放在body子级不要包在多层级容器里。如果放在某个section里sticky只对这个section生效滚出该区域导航就消失了。5.4 flex 布局的三个经典翻车现场对齐、缩窄、间距失效现象用 flex 排导航菜单项挤成一团或卡片在 flex 容器里被压扁。原因flex 子项默认flex-shrink: 1空间不足时会压缩。另一个问题是justify-content: space-between在子项数量不同时分布不均购物页的导航项忽左忽右。解决给不需要压缩的元素加flex-shrink: 0给固定宽度的元素加flex: none导航容器直接指定flex: 1让菜单区自适应。.main-nav ul { display: flex; gap: 24px; } .main-nav li { flex-shrink: 0; } .search-box { flex: none; margin-left: auto; /* 把搜索框推到最右 */ }gap: 24px比margin-right靠谱不会出现最后一个子项多余的右边距。margin-left: auto是 flex 布局里把元素推到右侧的标准做法。5.5 轮播动画“卡一下”且循环不流畅现象12 秒循环到最后一张跳回第一张时有一个明显卡顿停顿。原因keyframes里100%回到translateX(0)但位置是瞬间跳变的动画结束又从头播放视觉上就有一帧跳动。解决把最后一张复制一遍拼在末尾让动画看起来是无线滚动。.banner-track { width: 400%; /* 4 张图最后一张是第一张的复制 */ animation: slideMove 16s infinite linear; } keyframes slideMove { 0% { transform: translateX(0); } 25% { transform: translateX(-25%); } 50% { transform: translateX(-50%); } 75% { transform: translateX(-75%); } 100% { transform: translateX(-75%); } }最后一帧停在第三张的实际位置动画结束瞬间从头播放第一张因为第三张和复制的第一张视觉效果一样看不出切换。16 秒循环每张停留 4 秒。这个方法没有字符串“复制”操作只需在 HTML 末尾多加一个div classslide并把第一张图片放进去。6. 进阶玩法不用 JavaScript怎么把购物页做到“看起来能上线”6.1 用 CSS 变量做主题切换一次改一个值整站换肤购物页的配色集中在:root里的几个变量换肤只需要改变量值不需要全站搜索替换颜色。下面给出一套完整的主题变量表涵盖文字、边框、按钮、链接、价格色。变量名默认值原版暗色主题推荐值说明--primary-color#ff6700#ff8c42品牌主色按钮/价格/高亮--text-dark#333#e8e8e8一级文字--text-light#757575#a0a0a0二级文字商品描述--border-light#e0e0e0#3a3a3a卡片边框、分割线--card-bg#fff#1f1f1f卡片背景:root .dark-theme { --primary-color: #ff8c42; --text-dark: #e8e8e8; --text-light: #a0a0a0; --border-light: #3a3a3a; --card-bg: #1f1f1f; }做法是在html标签加一个classdark-theme页面全部颜色随之改变。主题切换的完整方案需要用 JavaScript 控制 class 的增删但 CSS 侧的变量定义必须提前做好这个结构是静态页就能准备的。6.2 提取公共类减少重复样式让页面体积更小购物页重复的样式很多按钮、价格、商品标题截断、卡片阴影。我习惯把所有可复用样式提取成工具类比如.btn-primary、.text-ellipsis、.card-shadow。这样新增商品分区时只需要在 HTML 里组合这些 class不用再写新的 CSS 规则。.btn-primary { display: inline-block; background: var(--primary-color); color: #fff; padding: 8px 20px; border-radius: 4px; border: none; cursor: pointer; font-size: 14px; transition: background 0.2s ease; } .btn-primary:hover { background: #e65c00; /* 主色加深 */ } .text-ellipsis { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }工具类的复用不要走极端。如果一个 class 里只有一条属性维护起来反而费劲建议一个工具类至少包含三条以上关联属性。.text-ellipsis这类三条属性组合在一起才有完整意义拆开就没用了。6.3 验证与调试三个快捷技巧让静态页“开口说话”页面写完怎么验证我按顺序做三件事第一用浏览器开发者工具的“设备模拟”切到 iPhone 12 和 iPad 尺寸看栅格是否正确切换第二用CtrlShiftI的 Lighthouse 跑一次性能体检关注“无布局抖动”和“图片尺寸”两个指标第三临时把一个商品卡片改成超长文本检验省略号是否生效商品描述超出两行是否正常截断。# 如果本地有 Node.js 环境可以用 npx 启动一个静态服务器 npx serve .用本地服务器打开页面而不是直接双击 HTML 文件能避免file://协议下的各种奇怪问题尤其在图片懒加载和 CSS 加载顺序上。npx serve .会在当前目录启动 HTTP 服务默认端口 3000浏览器访问http://localhost:3000预览。6.4 一段真实的排错记忆流光边框为什么“飞边”我复用流光边框方案时在 Safari 里看到边框边缘有锯齿状毛边检查后发现是background-size: 200% 100%的百分比值在 Safari 的渲染引擎下计算精度不一致。解决办法是把background-size改成固定像素值比如background-size: 600px 100%或者加一层border-radius: 6px配合overflow: hidden裁剪边缘。如果你做的页面主要跑 Chrome这个问题基本不会遇到但发布前用 Safari 过一遍视觉是有必要的。这段经验也说明了一个道理CSS 动效看起来简单跨浏览器验证不能省。以后我每做一个动效第一件事就是在 Chrome 和 Safari 各截图对比一次别等用户截图反馈了才回来修。希望这篇方案能帮你少踩几个坑把购物页的静态版本做扎实再接 JavaScript 交互的时候就轻松多了。本文还有配套的精品资源点击获取