简介:这是一份面向Web前端初学者的HTML+CSS实战练习资源,聚焦电商类页面开发能力训练,通过仿小米商城界面实现系统性布局与样式实践。资源共410个文件,包含248张JPG、98张WEBP及56张PNG格式的商品与轮播图素材,辅以4个核心CSS文件(含reset、iconfont、swiper及主样式)、2个JS脚本、1个HTML入口页和1个ICO图标,整体压缩包仅3.28MB,轻量易解压,适配快速上手与本地调试。已有909人学习下载,说明其在入门阶段具有较强实操参考价值。学习者可完整获得语义化HTML结构(header/nav/main/section/article等)、Flex/Grid响应式布局、轮播图样式控制、商品卡片模块化设计、CSS盒模型与定位应用等关键技能落地范例,所有代码结构清晰、注释友好,便于对照理解网页构成逻辑与视觉呈现原理。
1. 一个纯静态页面,居然能撑起整套电商首页交互逻辑:仿小米商城 HTML+CSS 练习项目实测跑通指南
上周帮某高校前端实训班调一个学生作业,打开「仿小米商城wed练习HTML+css」压缩包,第一反应是:就这?没 JS、没后端、连个 JSON 都没见着——怎么模拟轮播图自动切换?怎么实现顶部导航栏吸顶?怎么让商品卡片悬停有阴影+缩放?结果本地双击 index.html,所有动效全在!滚动时导航稳稳吸顶,鼠标划过商品区立刻有 0.2s 缓动缩放,轮播图自己切、带指示点高亮、支持手动点选。这才意识到:这套练习不是“写完就扔”的临摹作业,而是用纯 CSS 动画 +:hover+:focus-within+@keyframes+position: sticky搭出的完整视觉闭环。它专为刚学完盒模型、浮动、定位、选择器和基础动画的新手设计,不碰 JS 就能理解「结构即交互」的底层逻辑。如果你正卡在「会写标签但做不出像样页面」的阶段,或者想给新人找一份可跑、可改、无依赖、5 分钟上手的实战素材,这个项目就是你该下载的第一个 HTML+CSS 压缩包。
2. 项目结构与技术栈解剖:为什么不用 JS 却能完成 90% 的首页交互?
这个项目本质是一份「CSS 能力边界验证集」。它刻意规避 JavaScript,把所有动态效果拆解成 CSS 可控的原子操作:状态变化(:hover,:focus,:checked)、时间轴(@keyframes)、空间关系(transform,transition,position: sticky)和层级控制(z-index)。整个工程没有构建工具、不依赖 CDN、不引入任何外部库,所有样式内联或外链到单一style.css,所有资源(图片、图标)全部放在assets/下。这种极简结构,反而让新手能一眼看清「哪个样式管哪个动效」「改哪行代码影响哪块交互」。下面从目录、核心文件、技术选型三方面拆解。
2.1 目录结构:6 个文件撑起完整首页
项目解压后共 6 个文件,结构极度扁平:
index.html # 主页入口,含全部语义化结构 style.css # 全局样式,含重置、布局、动画、响应式 assets/ ├── images/ # 商品图、Banner 图、Logo 等(共 12 张) ├── icons/ # SVG 图标(购物车、搜索、用户等,共 5 个) └── fonts/ # 自定义字体(MiSans-Regular.woff2,仅 42KB)提示:
fonts/下的 MiSans 是小米官方开源字体,项目已预加载并声明font-family: 'MiSans', sans-serif;。若本地测试字体未生效,直接删掉font-face声明,用系统默认sans-serif不影响功能。
2.2 HTML 结构:语义化标签 + 伪类驱动交互
index.html采用严格语义化结构,关键交互节点全部用原生标签承载状态:
- 轮播图:用
<input type="radio">+<label>实现「单选按钮组」,每个 radio 对应一张图,通过:checked触发~(兄弟选择器)控制对应.slide的opacity和z-index; - 导航吸顶:
<header>设置position: sticky; top: 0;,配合z-index: 1000确保始终在最上层; - 商品悬停:
.product-card使用transition: all 0.2s ease;,:hover时触发transform: scale(1.03); box-shadow: 0 8px 20px rgba(0,0,0,0.1);; - 侧边栏展开:用
<input type="checkbox" id="menu-toggle">+<label for="menu-toggle">模拟开关,:checked时显示.sidebar。
这种写法把「状态管理」交给浏览器原生表单控件,完全绕过 JS 事件监听,既稳定又易调试——你甚至可以直接在 DevTools 里勾选/取消 radio,实时看轮播切换。
2.3 CSS 核心技术点:动画、过渡、定位三位一体
style.css共 1287 行,按功能分为 6 大区块:
| 区块 | 行号范围 | 关键技术 | 典型用途 |
|---|---|---|---|
| 重置与基础 | 1–89 | * { margin: 0; padding: 0; box-sizing: border-box; } | 清除默认间距,统一盒模型 |
| 响应式断点 | 90–142 | @media (max-width: 768px) { ... } | 移动端折叠导航、调整栅格列数 |
| 布局系统 | 143–320 | Flex + Grid 混合 | Banner 区横向居中、商品区 4 列自适应 |
| 动画定义 | 321–450 | @keyframes slideIn { from { opacity: 0; transform: translateX(20px); } to { opacity: 1; transform: translateX(0); } } | 轮播入场、商品卡片淡入 |
| 交互状态 | 451–980 | :hover,:focus,:checked,:focus-within | 悬停缩放、焦点高亮、菜单展开 |
| 工具类 | 981–1287 | .text-center,.d-flex,.m-t-20等 | 快速微调间距、对齐、显示 |
特别注意:所有transition属性都显式声明all 0.2s ease,而非all 0.2s。ease缓动函数让缩放/位移更自然,这是新手常忽略的「玄学细节」——少写一个ease,动效就显得生硬。
3. 本地运行与调试:5 分钟从解压到看到吸顶导航
别被「练习项目」四个字骗了,这玩意儿对环境零要求。只要你的电脑能打开网页,就能跑起来。但新手常在这里翻车:双击index.html打不开图片、轮播不动、导航不吸顶。下面分三步带你一次跑通,并解释每步背后的原理。
3.1 第一步:确认文件路径绝对正确(血泪经验)
解压后必须保证以下路径存在且大小写完全一致:
index.html(根目录)style.css(根目录)assets/images/banner1.jpg(不能是Banner1.jpg或banner_1.jpg)assets/icons/cart.svg(不能是cart.png)
注意:Windows 资源管理器默认隐藏文件扩展名,极易误存为
index.html.txt。务必在「查看」→「显示」中勾选「文件扩展名」,确认文件真实后缀。Mac 用户需警惕.DS_Store文件干扰,建议解压后手动删除。
3.2 第二步:用浏览器直接打开(不要用 VS Code Live Server)
很多新手习惯用 VS Code 的 Live Server 插件启动,但这会导致file://协议下跨目录资源加载失败(尤其图标和字体)。正确做法是:
- 在文件管理器中找到
index.html; - 右键 → 「在默认浏览器中打开」;
- 或者拖拽
index.html到 Chrome/Firefox 窗口标签页。
此时地址栏应显示file:///Users/xxx/xxx/index.html(Mac)或file:///C:/xxx/xxx/index.html(Windows)。如果看到空白页或报错Failed to load resource,90% 是路径错误或扩展名隐藏导致。
3.3 第三步:DevTools 快速验证三大核心交互
打开浏览器开发者工具(F12),切到 Console 标签页,输入以下三行命令,每行回车后观察页面变化:
// 1. 检查轮播是否由 radio 控制(应返回 3 个 input 元素) document.querySelectorAll('.carousel input[type="radio"]') // 2. 检查导航栏是否设置了 sticky(应返回 "sticky") getComputedStyle(document.querySelector('header')).position // 3. 检查商品卡片是否有 transition(应返回 "all 0.2s ease 0s") getComputedStyle(document.querySelector('.product-card')).transition如果前三项都返回预期值,说明结构和样式已加载成功。此时滚动页面,导航应立刻吸顶;鼠标悬停任意商品,应有轻微放大+阴影;点击轮播下方小圆点,图片应切换——全部无需 JS。
4. 常见问题排查:那些让你怀疑人生却只需改一行代码的坑
这个项目看似简单,但新手在修改过程中极易踩进几个「改了 2 小时才发现是拼写错误」的深坑。以下是我在 3 批学员调试中高频遇到的 5 个问题,按现象→原因→解决三步给出可抄作业的答案。
4.1 现象:轮播图完全不切换,小圆点也不高亮
原因:.carousel input的id与对应.carousel label的for属性不匹配,或name属性缺失导致 radio 无法互斥。
解决:检查index.html中轮播部分,确保每组 radio 的name相同,且label的for值与input的id完全一致。例如:
<input type="radio" name="slide" id="slide1" checked> <label for="slide1"></label> <!-- ✅ 正确:id 和 for 值相同 --> <!-- ❌ 错误:<input id="slide-1"> 与 <label for="slide1"> -->4.2 现象:商品卡片悬停无反应,控制台无报错
原因:.product-card的父容器设置了overflow: hidden,裁剪了transform: scale()产生的溢出区域。
解决:在style.css中搜索.product-list(商品列表容器),删掉或注释其overflow: hidden声明。CSS 中transform元素超出父容器时,overflow: hidden会强制裁剪,这是新手最常忽略的「黑匣子」行为。
4.3 现象:移动端导航栏折叠后,点击汉堡图标无反应
原因:#menu-toggle的:checked状态未关联到.sidebar的显示逻辑,或.sidebar的display初始值被其他规则覆盖。
解决:在style.css中定位到#menu-toggle:checked ~ .sidebar规则,确认其display值为block(非flex或grid)。同时检查.sidebar是否有更高优先级的display: none !important,若有则删除!important。
4.4 现象:Banner 文字在手机上显示不全,被截断
原因:@media (max-width: 768px)中.banner-text h1的font-size设为2rem,但未设置line-height,导致行高不足文字重叠。
解决:在响应式区块中为.banner-text h1添加line-height: 1.3;。记住:移动端文字缩放后,line-height必须同步调整,否则就是「后悔药都救不回来」的视觉灾难。
4.5 现象:自定义字体 MiSans 加载失败,文字显示为宋体
原因:@font-face中src路径写成../fonts/MiSans.woff2,但实际文件在assets/fonts/下。
解决:打开style.css,找到@font-face声明,将src: url('../fonts/MiSans-Regular.woff2');改为src: url('assets/fonts/MiSans-Regular.woff2');。路径必须相对于style.css文件位置,这是 CSS 资源加载的铁律。
5. 核心模块代码逐行解析:轮播图如何用纯 CSS 实现自动播放?
轮播图是本项目最精妙的模块,它用 CSS@keyframes+animation+:checked三重组合,实现了「自动轮播 + 手动切换 + 指示点联动」。下面以index.html中轮播结构和style.css对应样式为例,逐段拆解。
5.1 HTML 结构:用 radio 模拟状态机
<div class="carousel"> <!-- 隐藏的 radio 控件,每个代表一张图 --> <input type="radio" name="slide" id="slide1" checked> <input type="radio" name="slide" id="slide2"> <input type="radio" name="slide" id="slide3"> <!-- 可视化指示点,for 属性绑定 radio --> <div class="indicators"> <label for="slide1"></label> <label for="slide2"></label> <label for="slide3"></label> </div> <!-- 图片容器,每张图对应一个 .slide --> <div class="slides"> <div class="slide" style="background-image: url('assets/images/banner1.jpg');"></div> <div class="slide" style="background-image: url('assets/images/banner2.jpg');"></div> <div class="slide" style="background-image: url('assets/images/banner3.jpg');"></div> </div> </div>逻辑说明:
name="slide"让三个 radio 成为单选组;checked属性指定默认激活项;label for="xxx"点击指示点即触发对应 radio 的:checked状态。这是纯 CSS 实现「状态驱动 UI」的基石。
5.2 CSS 动画:定义入场与停留效果
/* 定义轮播入场动画 */ @keyframes slideIn { from { opacity: 0; transform: translateX(20px); } to { opacity: 1; transform: translateX(0); } } /* 定义轮播停留动画(用于自动轮播循环) */ @keyframes autoSlide { 0% { opacity: 0; } 10% { opacity: 1; } 90% { opacity: 1; } 100% { opacity: 0; } }参数说明:
slideIn用于手动切换时的平滑入场;autoSlide是自动轮播的核心,它让每张图在 10% 时间内淡入,90% 时间内保持可见,最后 10% 淡出——这样三张图就能无缝衔接。autoSlide的animation-duration设为15s,意味着每张图显示 5 秒(15s ÷ 3 = 5s)。
5.3 CSS 状态控制::checked触发显示与动画
/* 默认所有 slide 隐藏 */ .carousel .slide { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; z-index: 1; transition: opacity 0.5s ease; } /* 当 slide1 被选中时,显示第一张图并播放入场动画 */ #slide1:checked ~ .slides .slide:nth-child(1) { opacity: 1; z-index: 10; animation: slideIn 0.5s ease forwards; } /* 同理控制第二、三张 */ #slide2:checked ~ .slides .slide:nth-child(2) { opacity: 1; z-index: 10; animation: slideIn 0.5s ease forwards; } #slide3:checked ~ .slides .slide:nth-child(3) { opacity: 1; z-index: 10; animation: slideIn 0.5s ease forwards; } /* 指示点高亮:当 slide1 选中时,第一个 label 背景变白 */ #slide1:checked ~ .indicators label:nth-child(1), #slide2:checked ~ .indicators label:nth-child(2), #slide3:checked ~ .indicators label:nth-child(3) { background-color: #fff; }关键逻辑:
~(通用兄弟选择器)让#slide1:checked能影响其后的.slides和.indicators;nth-child(n)精准定位第 n 张图和第 n 个指示点;z-index: 10确保当前图在最上层,避免多图重叠时显示错乱。这里没有 JS 的classList.toggle(),全靠 CSS 选择器链完成状态映射。
6. 二次开发实战:如何快速替换商品数据、添加新模块、适配暗色模式?
这个项目不是终点,而是你前端工程能力的「起手式」。我一般会带着新人做三件事:换数据、加模块、调主题。每一步都不需要懂 JS,全在 HTML 和 CSS 里完成,改完立刻可见。下面给出可直接复制粘贴的操作步骤和避坑提示。
6.1 替换商品数据:3 分钟更新 12 个商品卡片
商品数据全部硬编码在index.html的<section class="product-section">内。每个商品用以下结构:
<div class="product-card"> <div class="product-img"> <img src="assets/images/product1.jpg" alt="小米手环 8"> </div> <div class="product-info"> <h3 class="product-title">小米手环 8</h3> <p class="product-desc">AMOLED 大屏,16 天长续航</p> <div class="product-price">¥239</div> </div> </div>操作步骤:
- 准备 12 张新商品图,命名为
product1.jpg到product12.jpg,放入assets/images/; - 复制上面的
<div class="product-card">块 12 次,替换src、alt、h3、p、div.product-price的内容; - 为新品类添加分类标题(如
<h2 class="section-title">智能穿戴</h2>),放在对应商品组上方。
注意:
product-card的width由 CSS 的.product-list的grid-template-columns: repeat(4, 1fr);控制,所以 12 张图会自动排成 3 行 × 4 列。若要改成 3 列,只需将repeat(4, 1fr)改为repeat(3, 1fr),无需改 HTML。
6.2 添加「新品预告」模块:复用现有 CSS 类
项目预留了.section通用容器,新增模块只需遵循相同结构:
<section class="section"> <h2 class="section-title">新品预告</h2> <div class="product-list"> <!-- 复用 product-card 结构 --> <div class="product-card"> <div class="product-img"> <img src="assets/images/new1.jpg" alt="小米 MIX Fold 4"> </div> <div class="product-info"> <h3 class="product-title">小米 MIX Fold 4</h3> <p class="product-desc">龙骨转轴,轻至 249g</p> <div class="product-price">即将发布</div> </div> </div> </div> </section>关键技巧:所有.product-card样式已定义好,新模块无需写新 CSS。唯一要加的是.section-title的上下边距,可在style.css末尾追加:
.section-title { margin: 40px 0 20px; }6.3 适配暗色模式:用 CSS 自定义属性一键切换
项目原生不支持暗色模式,但我们可以用 CSS 变量低成本实现。在style.css开头添加:
:root { --bg-primary: #fff; --text-primary: #333; --border-color: #e0e0e0; --card-bg: #f9f9f9; } @media (prefers-color-scheme: dark) { :root { --bg-primary: #1a1a1a; --text-primary: #f0f0f0; --border-color: #333; --card-bg: #2d2d2d; } }然后全局替换颜色值,例如:
body { background-color: var(--bg-primary); color: var(--text-primary); } .product-card { background-color: var(--card-bg); border: 1px solid var(--border-color); }验证方法:Chrome 浏览器地址栏输入
chrome://flags/#enable-force-dark,启用「Force Dark Mode」后重启,页面自动变暗。这种写法比 JS 检测window.matchMedia更轻量,且兼容性更好。
从那以后我每次带新人做静态页练习,都强制走一遍「改商品图→加新模块→切暗色模式」三步流程。不是为了炫技,而是让他们亲手触摸到:HTML 是骨架,CSS 是肌肉,而结构化的思维才是让页面真正活起来的神经。希望帮到你。
本文还有配套的精品资源,点击获取