☰
用小米官网首页练HTML/CSS:像素级还原与布局实战
2026/9/26 20:22:58 网站建设 项目流程

简介:小米官网首页(静态页面)是一份适合前端初学者实战练习的网页源码包,覆盖HTML结构搭建与CSS样式设计两大基础模块。整个项目模拟小米官网首页的视觉风格与布局框架,能帮助学习者理解常见标签、类与ID选择器、盒模型、Flexbox/Grid布局、媒体查询以及:hover等伪类的实际用法,并对页面间距、字体、背景图片等细节有直观体验。压缩包共38个文件,约2.64MB,其中2个html文件为页面入口,8个css文件包含样式表及压缩版本,jpg/png/svg图片素材用于产品展示与图标,ttf/woff/woff2等字体文件保证页面字体效果完整,目录结构清晰,便于直接运行、改版和对照学习。已有667人学习下载。借助这份静态页面,读者能够了解电商首页的代码组织方式,学会合理拆分CSS、优化资源引用,为后续学习响应式布局与前端交互开发积累扎实基础。

1. 为什么练 HTML/CSS 首选小米官网首页:像素级还原的性价比之选

前端入门有个绕不开的坎——练手项目选什么。很多人一上来就写个人博客,结果自由度太高,配色、布局、内容全凭感觉,最后练出来的是「会搭积木」,而不是「会照着图纸施工」。而小米官网首页这个静态页面项目,是 HTML CSS 综合练习里性价比极高的一个:布局密度大、组件类型多、黑灰白配色下藏着大量 hover 状态和层级细节,能同时练到栅格、定位、导航、轮播、卡片化信息架构这几块硬功夫。

这份资源重建了官网首页的主视觉与核心信息结构,用纯 HTML + CSS 搭出顶部导航、轮播图、商品卡片区、限时活动入口和页脚等完整模块。它解决的正是新手最缺的两件事:一是像素级还原能力——对着设计稿把间距、字号、圆角、 hover 效果逐个抠出来;二是结构组织能力——一个页面几十个模块,怎么划分区块、怎么命名 class 才能不混乱。适合学过 HTML 和 CSS 基础标签、想找一个完整项目来检验自己水平的人,也适合前端讲师拿来做教学案例。别小看这个页面,能把首页还原到 90% 以上,你对盒模型和 Flex 布局的理解会远超刷一百道题。

2. 拆开看这份资源:目录结构、文件职责与还原度边界

2.1 文件组织:静态页面的骨架与前两次打开的差异

拿到压缩包先别急着双击index.html,先花两分钟把目录结构过一遍。这个项目的文件划分是典型的前端小项目布局——HTML 管内容、CSS 管表现、JS 管交互,三者各司其职。我第一次拆的时候没看结构直接打开页面,F12 一查发现样式全堆在<style>里,后来才发现那是旧版本,这份资源的结构要干净得多,适合直接上手学。

路径职责关键内容
index.html页面主体结构导航、轮播、商品卡片、页脚的所有 DOM 节点
css/reset.css样式重置清除浏览器默认 margin/padding、统一字体基线
css/style.css核心样式布局栅格、组件样式、hover 状态、媒体查询
js/banner.js轮播逻辑自动播放、指示器切换、图片渐隐渐现
img/静态资源商品图、banner 图、图标等本地图片

reset.css和style.css分开这个设计很关键。reset负责把不同浏览器默认样式拉齐,比如 Chrome 和 Safari 对body的 margin 理解不一样,不重置的话页面会在浏览器之间产生几像素偏移;style.css才放业务样式。如果你看到有的教学项目把 reset 和业务样式混在一个文件里,那后期维护时会很痛苦——你根本分不清哪个样式是清默认值的,哪个是设计稿要求的。

JS 文件只有banner.js一个,约 40 行,这也是静态页面的常态:交互越少,越能把精力放在 CSS 上。另外注意img/目录里的图片都是本地文件,不是外链。这一点很实在,意味着你断网也能打开页面,也意味着你可以直接替换图片来测试布局,不用处理防盗链和跨域问题。

2.2 先看 HTML 主体骨架:三大区块的划分逻辑

打开index.html,你会看到结构整体分为三个大块:顶部导航区、中间内容区、底部页脚区。中间内容区又可以细分为 banner 轮播、商品楼层、活动专区三小块。这种分区方式不是随便切的,它和页面视觉层次完全对应——用户从上往下扫视,眼睛依次经过品牌区、焦点图、商品陈列、服务保障,HTML 的书写顺序也应该遵循这个阅读顺序。

<body> <!-- 顶部导航:包含 logo、菜单、搜索、登录入口 --> <header class="site-header"> <div class="container nav-wrapper"> <div class="logo"> <a href="#"><img src="img/logo.png" alt="小米"></a> </div> <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 class="search-box"> <input type="text" placeholder="搜索"> <button class="search-btn"></button> </div> </div> </header> <!-- 主内容区:banner 轮播 + 商品卡片楼层 --> <main class="site-main"> <section class="banner-section"> <div class="banner-carousel" id="bannerCarousel"> <div class="banner-slide active"> <a href="#"><img src="img/banner-1.jpg" alt=""></a> </div> <div class="banner-slide"> <a href="#"><img src="img/banner-2.jpg" alt=""></a> </div> </div> <!-- 轮播指示器 --> <div class="banner-dots"> <span class="dot active"></span> <span class="dot"></span> </div> </section> <section class="product-floor"> <div class="container"> <h2 class="floor-title">热门手机</h2> <div class="product-grid"> <!-- 商品卡片由 JS 或模板渲染,也可直接书写静态结构 --> <div class="card"> <img src="img/phone-1.png" alt=""> <p class="card-name">小米 14</p> <p class="card-price">3999元</p> </div> <div class="card"> <img src="img/phone-2.png" alt=""> <p class="card-name">Redmi K70</p> <p class="card-price">2499元</p> </div> </div> </div> </section> </main> <!-- 页脚:服务保障、合作链接、备案信息 --> <footer class="site-footer"> <div class="container footer-links"> <a href="#">新手帮助</a> <a href="#">服务网点</a> <a href="#">售后政策</a> </div> <div class="container copyright"> <p>© 2024 小米公司版权所有</p> </div> </footer> </body>

上面这段是简化后的骨架,但关键节点都在。注意header > .nav-wrapper这一层嵌套:.container是固定宽度的居中容器(通常是 1226px,和官网一致),它把内部内容约束在一个安全可视区内,防止屏幕太宽时元素被拉伸到离谱的位置。.nav-list用无序列表承载菜单,每个菜单项是<li><a>结构——这是语义化菜单的标准写法,方便屏幕阅读器识别。

banner-slide用active类来控制当前显示哪一帧,这个类名是 JS 切换的抓手。商品楼层.product-grid里每一张卡片由图片、名称、价格三行构成,注意卡片内容没有多余装饰,良好的结构能让你后续写 CSS 时少折腾很多。

2.3 还原度边界:静态页面不是实时官网

拿到资源后要有个预期管理:官网是持续迭代的,今天打开小米官网看到的视觉和你下载的这份静态页面大概率有差异。这份资源是对某一个时间节点官网首页的重建,它的价值在于让你练习那个版本的还原手法,而不是和现在的官网逐像素对比。我见过有初学者对着最新的官网截图去改这份代码,结果越改越乱——因为新版官网的布局、配色、甚至 logo 字体都变了。

正确的用法是:把这份资源当作设计稿的替代品,先本地跑起来,再按自己的理解去调整间距和配色。你要学的不是复制某个版本的官网,而是掌握「看一个页面能拆出结构、能用 CSS 还原出来」这个能力。这也是为什么我一再强调先读懂文件结构再动手——你后续所有改动都建立在这个结构之上,结构不熟,改哪都是盲改。

3. 像素级还原的三个核心模块:栅格、卡片与吸顶导航

3.1 顶部导航实现:吸顶、子菜单缩进与 hover 切换

小米官网的顶部导航有一个典型特征:页面往下滚动时,导航条会固定在视口顶部,这就是「吸顶效果」。实现方式不算复杂,但有几个细节容易忽略——尤其是吸顶后导航的背景色、阴影和层级关系。

/* 实现吸顶的核心:position: fixed */ .site-header { position: fixed; top: 0; left: 0; width: 100%; z-index: 1000; background-color: #ffffff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08); } /* 给 main 加一个顶部外边距,补偿导航占位 */ .site-main { margin-top: 80px; /* 导航高度约 80px,具体以实际为准 */ } /* 菜单 hover 状态:橙色下划线 + 文字颜色加深 */ .nav-list li a { display: inline-block; padding: 0 15px; line-height: 80px; color: #333333; font-size: 16px; transition: color 0.2s ease; } .nav-list li a:hover { color: #ff6700; text-decoration: none; }

这里有三处关键决策。第一,position: fixed让导航脱离文档流,不再参与页面占位,所以main需要手动加margin-top把内容往下推——否则吸顶导航会盖住 banner 上半部分。第二,z-index: 1000不是随便写的,导航要盖住页面所有内容,包括轮播图和商品卡片里的浮层元素,所以层级必须比它们高。第三,transition: color 0.2s ease是给 hover 变色加过渡,不加的话颜色是瞬间切换的,视觉上会很生硬。

如果你还想要更丰富的子菜单效果——比如鼠标悬停「手机」弹出型号列表——可以用position: absolute配合opacity和visibility来做:

.dropdown-menu { position: absolute; top: 100%; left: 0; min-width: 180px; background: #ffffff; box-shadow: 0 8px 16px rgba(0, 0, 0, 0.12); opacity: 0; visibility: hidden; transition: opacity 0.3s ease; } .nav-list li:hover .dropdown-menu { opacity: 1; visibility: visible; }

子菜单的top: 100%是关键:它会贴着父菜单项的底部边缘弹出,不会把按钮顶到别的位置。至于为什么用visibility: hidden而不是display: none——因为display: none会阻止过渡动画触发,菜单会「啪」地跳出来而不是「滑」出来。这个细节很多人容易翻车,先记着。

3.2 轮播图:position 叠放、指示器与图片过渡的取舍

轮播图是首页的视觉焦点,也是最容易出 bug 的组件。这份资源的轮播实现采用的是「图片叠放」方案——所有 slide 叠加在同一个位置,通过控制透明度来切换显示。这样做的好处是切换动画平滑,且容器高度恒定,不会出现内容跳动。

.banner-carousel { position: relative; width: 1226px; height: 460px; margin: 0 auto; overflow: hidden; } .banner-slide { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; transition: opacity 0.8s ease-in-out; } .banner-slide.active { opacity: 1; z-index: 2; } .banner-slide img { width: 100%; height: 100%; object-fit: cover; }

每个 slide 都是绝对定位,所以它们上下重叠在同一块区域。默认透明度为 0,只有挂在active类上的那一帧显示出来。.active的z-index: 2是为了确保当前帧盖住其他帧——虽然 opacity 为 0 的元素不占视觉空间,但为了保险起见,显式设置层级更稳妥。

对应地,banner.js里的自动播放逻辑用一个定时器和索引计数器来切换active类:

// 获取所有 slide 和指示器点 const slides = document.querySelectorAll('.banner-slide'); const dots = document.querySelectorAll('.banner-dot'); let index = 0; const interval = 4000; // 4 秒切换一次 function goToSlide(nextIndex) { // 越界处理:到达末尾回到第一张 nextIndex = nextIndex >= slides.length ? 0 : nextIndex; slides[index].classList.remove('active'); dots[index].classList.remove('active'); index = nextIndex; slides[index].classList.add('active'); dots[index].classList.add('active'); } // 定时器是轮播的心脏,注意先清除再设定,避免叠加 setInterval(function () { goToSlide(index + 1); }, interval);

interval参数控制自动播放速度,4000ms 是官网常见节奏,太快会让用户来不及看文案,太慢又显得迟钝。手动切换的点击事件通常也要绑定到指示器dot上——常见的做法是循环给每个 dot 挂 click 事件,点击后调用goToSlide(i)。

这里要提一个有意思的取舍:官网的 banner 是整张宽幅图片,而这份资源的容器宽度是 1226px,图片拉伸方式用了object-fit: cover。这意味着如果你的图片比例和容器不一致,图片会被裁切一部分而不是被压扁。在实际做页面时,最好先把图片尺寸裁好,因为cover只会在固定尺寸下才能保证视觉完整,否则每次加载都有可能裁到不同区域。

3.3 商品卡片栅格:Flex 间距计算与行内尺寸的玄学

商品卡片区是首页信息密度最大的区域,也是最考验栅格基本功的地方。小米官网的手机列表通常是 4 列布局,每张卡片包含图片、名称、描述、价格和一个小标签。栅格间距如果算不对,看起来最明显的问题就是「列数对了但左右留白不均」。

.product-grid { display: flex; flex-wrap: wrap; margin: -20px 0 0 -20px; /* 用负 margin 抵消间距 */ } .card { width: calc(25% - 20px); margin: 20px 0 0 20px; background: #fafafa; border-radius: 8px; padding: 20px; box-sizing: border-box; text-align: center; }

这里用的是一种比较巧妙的间距处理方式:父容器设置负 margin,子元素设置正 margin,最终视觉上网格对齐到父容器边缘。具体逻辑是——如果.product-grid不设负 margin,第一行第一张卡片的margin-top: 20px会把整行往下推,同时左侧 20px 的 margin 会让卡片整体比标题往右缩进 20px。父容器用margin: -20px 0 0 -20px把这两个方向的外溢补齐,视觉上就完全对齐了。

而width: calc(25% - 20px)这个写法是给 margin 留出航向——如果不减去 20px,四张卡片加上各自的 margin 会超过父容器宽度,最后一行会被挤下去,在 4 列布局里表现成「第三张卡片掉到第二行」。这个坑非常隐蔽,因为只在特定宽度下才会暴露。我也会用gap替代负 margin 方案:

.product-grid { display: flex; flex-wrap: wrap; gap: 20px; } .card { width: calc(25% - 20px); margin: 0; }

gap是 Flexbox 和 Grid 都支持的属性,它自动处理元素之间的间距,不会额外产生外溢,如果你不需要兼容老旧浏览器,gap其实更省心。但注意,写calc(25% - 20px)时 25% 是相对父容器宽度的 25%,而gap: 20px是行间距和列间距的合计。如果你同时用了gap和 margin,间距会叠加,视觉上比预期宽一倍。这种组合造成的「幽灵间距」是静态页面里最容易忽视的事。

4. 避坑记录:静态页面复刻时最容易翻车的五个场景

4.1 图片加载后布局跳动

现象:页面打开后,banner 下方的内容区域先挤在一起,图片加载完突然往下弹开一段距离,视觉上像是页面自己“跳”了一下。

原因:<img>标签在没有显式尺寸的情况下,高度是 0,只有等图片加载进来后,才根据图片实际比例撑开容器。banner 区域和商品卡片区的高度变化,导致后续所有内容跟着位移。

解决:给每张图片的容器设置固定宽高,或者给<img>设置width和height属性。这份资源的做法是给.banner-carousel设了height: 460px,卡片图片用aspect-ratio: 1锁定比例。我平时还会在 CSS 里给所有图片加一行img { display: block; },避免图片底部的间隙影响高度计算。

4.2 hover 后子菜单闪烁甚至消失

现象:鼠标从父级菜单移向子菜单的过程中,子菜单闪了一下就消失了,必须非常快速且精准地划过才能保持打开。

原因:子菜单绝对定位后,父菜单的hover区域和子菜单之间存在缝隙——这个缝隙通常是因为padding或top的值不够取整而产生的,鼠标移经缝隙时就触发了mouseout。

解决:把子菜单的top: 100%改成贴近父菜单的top: 100%同时消除缝隙,或者给父菜单的 hover 区域增加padding-bottom把缝隙填上。也可以让子菜单在 hover 时使用pointer-events: auto,默认pointer-events: none,这样鼠标在非打开状态下不容易误触,打开状态下也能稳定保持。

4.3 商品卡片文字底部不对齐

现象:一张卡片显示 3 行文字(名称、描述、价格),另一张卡片只有 2 行,两张卡片高度一致,但价格文字的下边线不在同一水平线。

原因:卡片内文本行数不同,导致卡片底部空白高度不一致。Flex 布局下卡片默认是自动高度,内容少的卡片会有多余空白。

解决:给卡片的文本区域设置min-height,给描述行强制固定行数:

.card { display: flex; flex-direction: column; height: 100%; } .card-desc { flex: 1; line-height: 1.6; overflow: hidden; }

关键是.card-desc的flex: 1,它把多出来的高度分配给了描述部分,让下方的价格区域被推到同一水平线上。这个方法比min-height更保险,因为不需要猜文字内容多长。

4.4 圆角卡片边缘出现锯齿感

现象:卡片设置了border-radius: 8px,但在某些浏览器缩放下,图片或背景的边缘会出现一行不自然的白边或锯齿。

原因:这是圆角裁剪精度和浏览器渲染引擎之间的兼容问题。尤其是当卡片内嵌图片、背景色是深色时,半透明像素在圆角区域没有被完全裁剪干净。

解决:给有圆角的容器加transform: translateZ(0)或will-change: transform,强制浏览器开启硬件加速来提升圆角裁剪精度。另外不要在同一层上同时使用border-radius和overflow: hidden时配合filter——filter: blur()这类效果会被循环应用到圆角边缘,造成更明显的锯齿。

4.5 点击按钮出现蓝色半透明遮罩

现象:在移动端或触屏设备上,点击搜索按钮或菜单项时,出现一个蓝色半透明方块,过一会儿才消失。

原因:这是浏览器默认的:hover或-webkit-tap-highlight-color行为。在触屏设备上点击任何可点击元素,都会有一个高亮闪烁来反馈触摸区域。

解决:在 reset 样式里加上一行:

* { -webkit-tap-highlight-color: transparent; }

这是移动端开发的常规操作,在静态页面里加上它也让你后续做响应式适配时少一个干扰项。要注意这行代码只对触屏设备生效,桌面浏览器不受影响。

5. 把页面改造成自己的:移动端适配、组件抽离与性能收尾

5.1 移动端适配三板斧:viewport、媒体查询断点与 rem 替换

这份资源默认是按桌面端设计的,宽度 1226px。如果你希望页面在手机上也能看,需要做三件事。第一,确认index.html的<head>里已经包含了 viewport 标签——缺少这个标签,手机浏览器会以 980px 的宽度渲染页面再缩放,字体小到无法阅读。

<meta name="viewport" content="width=device-width, initial-scale=1.0">

第二件事,加一组媒体查询断点。常用的断点设置是 768px 以下切换为单列布局,768px 到 1226px 之间保持双列或四列弹性。

/* 平板:两列布局 */ @media (max-width: 768px) { .product-grid { gap: 12px; } .card { width: calc(50% - 12px); } } /* 手机:单列布局 */ @media (max-width: 480px) { .card { width: 100%; } .banner-carousel { height: 200px; } }

媒体查询的核心是让卡片宽度从桌面端的calc(25% - 20px)逐步降级。断点值不是拍脑袋定的——480px 是常见手机逻辑宽度,768px 是老 iPad 的竖屏宽度,这两个值能覆盖绝大多数手持设备。

第三件事,考虑把固定像素字号改成相对单位。桌面端使用font-size: 16px没问题,但移动端屏幕宽度变小后,16px 在小屏上看起来偏大。常见做法是给html设一个基准字号,再配上rem单位:

html { font-size: 16px; } @media (max-width: 480px) { html { font-size: 14px; } } .nav-list li a { font-size: 1rem; }

这样你把所有字号改成rem后,改基准字号就能整体缩放文字,不用逐条改 media query。这一步做完,你的页面在手机上至少是能读的。如果你还想更精细,可以把img的加载方式改成懒加载,但静态页面没有大量图片时,这不是必须项。

5.2 组件抽离与 CSS 变量:从单页改写到多页面复用

把这份资源的 CSS 通读一遍,你会发现有很多重复的段落——比如.card和.banner-slide里都写了border-radius、overflow: hidden、position: relative这类基础样式。单独维护一份静态页面没问题,但如果你想新增一个「购物车页面」或「商品详情页」,这些重复代码就会膨胀到难以维护。

我常用的做法是先看哪些样式是多个组件共用的,把它们以类名的形式抽出来:

/* 通用卡片容器 */ .panel { background: #ffffff; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); padding: 16px; } /* 两种页面方向 */ .product-card { font-family: "Helvetica Neue", Arial, sans-serif; } .simple-card { font-family: "PingFang SC", "Microsoft YaHei", sans-serif; }

然后再抽取设计变量。官网的主色是橙色#ff6700,如果你需要换成自己的品牌色,只在 CSS 变量里改一处即可,不用满篇找十六进制颜色码:

:root { --primary-color: #ff6700; --text-color: #333333; --text-secondary: #999999; --card-radius: 8px; --container-width: 1226px; }

之后所有用到这些值的地方都替换成var(--primary-color)。这样做的直接收益是改主题色时只动一处——两个类都不需要改,你的视觉统一性也不会被破坏。

5.3 验证与收尾:用性能面板查重排、看字体加载

页面改完后,别急着关浏览器——打开开发者工具的 Performance 面板,点一下录制再刷新页面,看两条关键信息:一是脚本执行耗时,二是布局和绘制耗时。如果布局时间明显偏高,多半是某些元素在加载后发生了重排,比如图片没有预设宽高导致容器高度变化,或者轮播切换时不断改opacity和z-index造成额外合成层。

字体加载是另一个容易被忽视的细节。如果你的页面引入了自定义字体,看 Network 面板里字体文件是不是在首屏就被下载了。字体未加载时,浏览器会用 fallback 字体渲染文本,字体加载完成后又会替换成正式字体——这会造成文字跳动,视觉上非常明显。这份资源用的字体是系统默认字体栈,没有这个问题,但如果你给卡片标题加过特殊字体,一定要检查这一步。

最后,一行一行对比你的页面和官网首页的视觉效果。不用在意像素级完全一致——这不现实,但间距、字号、圆角这些维度的差异要在肉眼不可见的范围内。我第一次做静态页面复刻时,卡片边距从 20px 调成 18px 就看了老半天,一个像素的偏差往往会导致整体观感从「舒适」变成「局促」。从那以后我每次做完页面,都会强制走一遍这个流程:先验证结构,再查间距差异,最后用性能面板看有没有多余的重排操作——整条路走下来,项目不会再出那种让你半夜抓头发的低级问题。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询