
简介一份仿小米官网的前端页面模板面向HTML/CSS初学者与前端实战练习者帮助读者理解现代网页从结构搭建到交互实现的全流程。资源内容涉及HTML5语义化标签header、nav、section等、video/audio多媒体嵌入、表单验证以及CSS3响应式布局、Flexbox/Grid和JavaScript动态效果覆盖企业官网常见的导航、轮播、注册登录等模块。压缩包约2.65MB文件总数未单独列出内部文件类型以HTML、CSS、JavaScript前端代码为主下载后可直接用浏览器打开预览适合对照小米官网进行拆分练习与二次开发。目前已有426人学习可作为前端入门阶段的完整案例参考其页面组织方式与代码分层能较快提升网页还原能力和布局调试技巧。1. 为什么拿小米官网当练手靶子如果去知乎、B站搜前端练手项目跳出来的十个有八个是仿小米官网。说实话我第一次看到这个选题的时候也有点不屑觉得不就是个商城首页吗能有多难直到自己动手做了一遍才明白这个看起来平平无奇的页面藏着前端开发里几乎所有基础且核心的功夫。我建议大家拿小米官网做仿写不是因为它的设计有多惊艳而是因为它恰好卡在一个非常微妙的位置页面足够复杂能逼你处理真实项目里会遇到的各种问题又不像淘宝京东那样庞大到让人无从下手。一个完整的仿小米官网模版做下来布局能力、交互设计、状态管理、性能优化、响应式适配这些硬功夫全部能覆盖到做完之后你手里拿着的是一套能写进简历的完整作品而不是一个照猫画虎的静态页面。很多人仿官网失败问题通常出在只看表面——照着截图把颜色、字号调得差不多就觉得自己完事了。我写这篇内容是想告诉你一套完整的仿写思路从页面拆解到技术选型从核心模块的实现细节到那些看着不起眼但其实特别讲究的坑每一个环节都讲清楚。无论你现在是刚学完HTML/CSS/JS想做第一个综合项目还是已经工作想补一补基础这篇内容都值得你花十几分钟读完然后对着抄。2. 动手之前先把仿写这个词拆开看2.1 仿小米官网到底在仿什么我在带新人做这个项目时经常问一个问题小米官网首页上有多少个功能模块多数人憋半天只能答出导航栏、轮播图、商品卡片这几个。但真正把页面从头到尾捋一遍你会发现它的复杂程度远超你想象。我拆出来的模块至少包括这些顶部的全局通知条、主导航栏、二级下拉菜单、搜索框、吸顶效果、巨型轮播图、倒计时秒杀模块、多Tab切换商品区、瀑布流式卡片列表、优享会员推广位、分类推荐区、底部服务保障栏、友情链接和版权区块。每一个模块单独拎出来都不算难但把它们组合在一个页面上还要保证滚动性能、切换流畅度、不同设备下的展示效果这就是一道综合大题。所以仿写之前我强烈建议你打开小米官网按 F12 打开开发者工具一份份把截图截下来用纸笔或者Figma这类工具做一个页面分区的线框图。不用画得多精细关键是标清楚每个区块的宽度占比是多少几个元素之间间距大概多少哪些区域是通栏哪些区域是定宽居中的容器。这一步做完你对整个页面的结构就已经做到心中有数后面写代码的效率会翻倍。2.2 技术栈和目录结构怎么定技术选型是很多人卡住的第一道关。我见过有纯用原生三件套硬写的也有直接用Bootstrap搭栅格拼出来的还有用Vue/React配组件库、把官网做成套壳页面的。我的建议是分阶段来第一次做用原生HTML/CSS/JavaScript底子打得最扎实如果你已经掌握一个前端框架或者想做一个更有亮点的作品那就用Vue 3或者React 18来写配合Vite做工程化构建。我最终做这个仿小米官网模版时用的是Vue 3全家桶加Vite组件库基本没怎么用除了Swiper轮播库之外几乎全部手写。为什么只引入Swiper因为轮播这种组件自己写起来其实不难难的是要兼容触摸滑动、自动播放、循环跳转、指示器联动这一整套交互没必要重复造轮子。其他部分全部手写反而更有利于你在面试时说清楚每个组件的实现原理。目录结构上我建议按功能而非按页面切分大致是这样src/ components/ Header/ TopNoticeBar.vue NavBar.vue SearchBar.vue Banner/ HeroSlider.vue Product/ ProductSection.vue ProductCard.vue CountdownSection.vue TabSection.vue Footer/ FooterService.vue FooterLinks.vue views/ Home.vue assets/ hooks/ utils/每个组件文件都承担一个明确职责后期要调整具体模块时能直接定位到对应文件不用在整个页面里翻找数千行代码。这是我从实际项目里总结出的经验仿写官网这种综合性项目真正考验的就是你拆分组件的能力。组件拆分合理整个工程的维护成本会直线下降拆得乱七八糟后面每改一个地方都会牵一发动全身。3. 核心模块逐个击破导航、轮播与吸顶搜索3.1 导航栏静态布局背后的交互细节小米官网的导航栏看起来就是一行白色背景、左侧Logo、中间几个分类入口、右侧搜索框和登录入口但想要做出那种官方感细节全在交互上。先说中间的导航项。小米的导航项在鼠标悬停时会展开一个几乎铺满全屏的下拉面板里面是整整齐齐的商品分类、图片入口、文字入口混排的网格。这个下拉面板的层级和定位问题是最容易踩坑的很多初学者会把下拉面板放在当前导航项的li标签内部结果被父级元素的overflow: hidden裁剪掉或者因为层级不对跑到导航栏下面去。正确的做法是把导航容器设置成 position: relative然后让下拉面板以 position: absolute 且 left: 0; right: 0 的方式定位到导航栏整体下方而不是相对于某个单独的导航项。这样无论鼠标悬停在哪一项下拉面板都能平滑地出现在同一位置.nav-bar { position: relative; z-index: 100; } .nav-dropdown { position: absolute; left: 0; right: 0; top: 100%; visibility: hidden; opacity: 0; transition: opacity 0.2s ease, visibility 0.2s ease; } .nav-item:hover .nav-dropdown { visibility: visible; opacity: 1; }这里我用的是 visibility opacity 配合 transition而不是直接 display: none 切换。display 切换会丢掉过渡动画显示和隐藏都显得很生硬而 visibility 可以保证隐藏状态下不会触发鼠标事件opacity 可以配合过渡实现自然的淡入淡出效果这是官方导航栏顺滑感的核心来源。另外导航项本身还需要一个当前激活态样式。很多人在实际项目里通过路由监听或者手动绑定class来实现但如果是静态仿写最简单的方式是在data里维护一个 currentNav 字段鼠标移入某个导航项时更新它移出整条导航栏时恢复默认值。这里要注意一个细节鼠标从导航项移到下拉面板中间的过程中中间会经历脱离导航项的状态如果直接绑定 mouseleave 会导致下拉面板提前消失。最好把 mouseleave 事件绑定在整个导航容器上而不是每个导航项上这样鼠标在导航项和下拉面板之间移动时就不会触发闪现消失的问题。3.2 轮播图为什么我最终选择了Swiper而不是自己写轮播图是小米官网首页最抓眼球的部分也是最容易被人低估难度的模块。我见过很多人自己写轮播图能实现点击切换、自动播放但一测试就发现两个问题快速点击时切换错乱、拖拽半途松开时动画卡顿。如果你只是为了完成仿写我建议直接用Swiper把精力留到更重要的事情上。Swiper的配置参数很多但仿小米官网时只需要关注这几个核心配置const swiper new Swiper(.hero-slider, { loop: true, speed: 600, autoplay: { delay: 4000, disableOnInteraction: false, }, effect: slide, pagination: { el: .swiper-pagination, clickable: true, }, navigation: { nextEl: .swiper-button-next, prevEl: .swiper-button-prev, }, });代码本身的含义不复杂但有几个参数需要特别理解。disableOnInteraction 的意思是当用户手动切换之后自动播放要不要继续开启。有些轮播组件默认用户点一下之后自动播放就停了而小米官网的体验是用户手动操作完几秒后自动播放照常继续所以必须设为 false。speed 设成600毫秒是为了在顺滑不拖沓之间找平衡太快显得生硬太慢又让人着急。轮播图背后的圆形指示器也要做成可点击跳转的点击某个指示器就直接切换到对应一页。这里建议使用 Swiper 自带的 pagination clickable 配置不要自己写监听避免出现点击指示器后自动播放计时没有重置的问题。还有一个小技巧轮播图下方经常会有左右两侧的切换箭头官方默认是鼠标移入轮播图区域才显示箭头移出就隐藏。这个效果的实现方式是监听轮播图容器上的 mouseenter 和 mouseleave 事件切换一个控制class。用透明度加display配合过渡动画即可不要用display直接切换否则箭头出现和消失会显得很突兀。3.3 吸顶搜索栏position: sticky 远比 fixed 好用小米官网向下滚动时有一条显示搜索框的细长导航条会吸在页面顶部。这个吸顶效果很多人的第一反应是设置 position: fixed然后在滚动事件里判断滚动距离去切换样式。我的建议是优先用 position: sticky。它和 fixed 最大的不同在于sticky 元素仍然占据文档流中的原有位置不会引起页面布局跳动而 fixed 会脱离文档流一旦启用就可能把下方内容顶上去需要额外给高度占位处理起来烦琐得多。.search-sticky-bar { position: sticky; top: 0; z-index: 90; }一个很关键的前提是position: sticky 生效需要父容器没有被 overflow: hidden 之类的属性裁剪。小米官网首页是整个页面滚动所以 sticky 能正常工作。如果你把页面结构嵌套得特别深某个父级容器设置了 overflow-x: hidden很多开发者为了防止横向滚动会这样写sticky 就会失效表现成滑到一半又跑回去了。这种问题排查起来非常隐蔽我当初在这个坑上折腾了大半天最后发现就是某个祖先容器的一行 overflow 样式导致的。如果你确实需要在某些场景下用 fixed 方案那就用滚动监听去动态切换class。但这里每个滚动事件回调里都去操作DOM会造成性能损耗需要做节流或使用requestAnimationFrame控制触发频率简单来说就是不要超过每帧一次的频率去修改样式。4. 容易被忽略的模块骨架屏、图片懒加载与倒计时4.1 骨架屏我们为什么要在页面加载时画一个空壳小米官网在首屏加载时会先展示一个灰色的线框结构等真实内容请求回来后才替换成完整内容。这个东西叫骨架屏作用是告诉用户页面正在加载请稍等减少白屏带来的焦虑感。我们在仿写时可以用CSS再配合简单的JavaScript来模拟这个效果。骨架屏不需要真的从后端拿数据只需要做到先渲染灰色块再替换成真实内容这个流程。我在实际项目里更推荐一个思路先让每一个商品卡片组件都支持一个 loading 状态当 loading 为 true 时卡片内部渲染的是几个灰色圆角矩形模拟图片区和文字行的占位数据加载完成后再渲染真实内容。.skeleton-block { background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 37%, #f0f0f0 63%); background-size: 400% 100%; animation: skeleton-loading 1.4s ease infinite; } keyframes skeleton-loading { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }这里有一块非常容易出现的体验问题骨架屏闪一下就不见了或者真实内容渲染出来之后又发生一次布局跳动导致页面摇晃。布局跳动的根本原因是从骨架屏切换到真实内容时两部分内容的尺寸比例不一致。比如骨架屏的图片区域高度是200px真实图片只有150px切换瞬间整个区域高度会塌掉一块视觉上非常明显。解决方式是在骨架屏阶段就把盒子高度设置成和真实内容一致比如图片区域固定为宽高比 4:3文字区域固定两行这样切换时位置几乎不变体感会顺滑很多。4.2 图片懒加载不要让首屏一次加载几十张高清图小米官网首页商品卡片非常多如果打开页面时一次性把所有图片全部加载进来首屏会非常慢。所以官方采用的方式是图片懒加载也就是图片滚动到可视区域附近时才真正发起加载请求。这个机制的底层逻辑很直白用户没看到的图片没必要浪费流量和带宽提前加载。现代浏览器实现懒加载最简单的方式就是在 img 标签上加一个 loadinglazy 属性。但要注意loadinglazy 只对标准 img 标签生效如果你使用 CSS background-image 来设置背景图这个属性就帮不上忙了。项目里如果有一些区域是用背景图做展示的可以考虑使用 IntersectionObserver 这个API来监听元素是否进入视口进入时才给它设置真正的背景图地址const observer new IntersectionObserver((entries) { entries.forEach(entry { if (entry.isIntersecting) { entry.target.style.backgroundImage url(${entry.target.dataset.src}); observer.unobserve(entry.target); } }); }, { rootMargin: 100px, }); document.querySelectorAll([data-bg-src]).forEach(el observer.observe(el));这里观察器的 rootMargin 设成 100px 是让图片提前一点加载意思是距离可视区域还有100px时就动手这样可以保证用户滚动到该区域时图片已经加载完毕不会出现一片空白等着慢慢填充的体验。懒加载还有一个配套细节为每张图片设置好宽高比。即使在占位阶段图片的外部容器也要按照目标宽高比占好位置。否则在滚动过程中图片逐张加载出来会把页面下方的内容不断顶下去用户滚到哪页面就抖到哪。这也是很多仿站作品看起来飘的直接原因。4.3 倒计时秒杀定时器在组件销毁后一定要清理小米首页有一个秒杀倒计时板块看起来很简单就是你一个大号数字时钟看着时间一分一秒地减少。但这里面的定时器管理是很多人容易写烂的地方。我的做法是把倒计时的目标结束时间存成一个时间戳然后每秒更新一次当前剩余时间。下面这段代码的时间计算没有任何框架依赖关键是new Date(2025-06-18 23:59:59).getTime()拿到的是毫秒时间戳用当前时间戳减它得到剩余毫秒数再通过整除运算拆成时、分、秒const rawTime this.countdownTime - Date.now(); const h Math.floor(rawTime / 3600000); const m Math.floor((rawTime % 3600000) / 60000); const s Math.floor((rawTime % 60000) / 1000);这里最容易被忽视的问题是定时器泄漏。在Vue组件里你在 mounted 里开了 setInterval如果不在 beforeUnmount 里 clearInterval组件销毁后这个定时器仍然在跑还会持续更新已经不存在的DOM变量。严重时页面切换几次之后浏览器里同时有好几个定时器在空转消耗CPU。这个问题的典型特征是页面越用越卡切几次路由后风扇狂转。所以每一处定时器都要打好配对创建它的地方记着销毁它。另一个体验细节是倒计时数字变化时最好用 fixed 宽度的高深数字字体容器避免数字从1变到23时盒子宽度发生变化导致整个板块抖一下。5. 仿写过程中最麻烦的几个坑我把排查思路全说出来5.1 响应式断点失效为什么平板宽度下样式一团乱小米官网是典型的PC优先页面在大屏上非常整齐但缩到平板和手机宽度时就切换成另一套布局。我最早写仿写版时也加了媒体查询但发现某些宽度区间样式会突然错乱比如滚动条出现横向滚动、卡片被拉伸变形。排查过程是这样的先在浏览器里开开发者工具的设备模拟从1440px宽度开始以50px为步长慢慢往窄调。很快发现当页面宽度跌破768px时有一个商品卡片容器的 flex 布局失效了卡片全部挤在一起。再检查CSS才发现原因出在容器设置了 min-width: 1200px屏幕不够宽时容器也不会收缩直接把页面撑爆导致横向滚动。这里的关键知识点是响应式设计必须遵循先定最小宽度再逐级下降的思路。给整体内容区域设置一个合理的最小宽度本身没有错小米官网PC版内容区一般固定为 1226px 左右但问题是你必须在某个断点以下主动改变这个值让布局切换成单列流动模式而不是任由固定宽度把页面撑破。常见的断点可以这样规划≥1200px 使用PC布局992px~1200px 收缩间距768px~992px 转为两列平板布局768px以下 转为单列移动端布局。每个断点都要实际拖拽页面测试确保过渡区间内没有布局闪断。5.2 轮播图Swiper与懒加载冲突首屏图片不显示这个坑特别隐蔽。我一开始在轮播图区域用了Swiper又给首屏的大图加了懒加载属性结果页面打开后第一张主图迟迟不出来反复刷新偶尔又能正常显示。观察网络请求发现第一张图片的请求根本没发出去。后来查了Swiper的文档才恍然Swiper 默认会复制一到两组slide用于loop循环效果复制的幻灯片内容也会复制DOM导致原本应该懒加载的图片因为不在视口内部或者说因为Swiper内部特殊布局被浏览器误判为不需要加载。解决方式有两种一是轮播图作为首屏最高优先级内容完全没必要做懒加载直接使用普通 img 标签加载即可这种大图加快加载速度的收益远大于首屏性能损失二是如果非要懒加载就得把图片放在Swiper的 lazy 配置里去处理用Swiper自己的懒加载机制而不是混用loadinglazy。这个坑给我最大的教训是在做页面性能优化时不要机械地给所有图片都套上懒加载首屏核心内容尤其是轮播图这种关键大图应该优先加载否则优化的收益会被体验问题完全抵消。5.3 z-index 层级混乱下拉面板被商品卡片盖住导航下拉面板和吸顶搜索栏默认都要比其他内容层级高但只给它们设置 z-index 往往不够。我当时遇到的情况是鼠标悬停导航项时下拉面板确实出现了但被下方的商品区域盖住了一半而且悬浮箭头点击不动。检查后发现问题有两层第一下拉面板的父容器没有创建新的层叠上下文导致子元素的 z-index 在和其他兄弟元素比较时没有按照预期生效第二给商品卡片区域的容器设置了 transform 属性来制作悬浮动画而 transform 本身会创建新的层叠上下文把原本应该低人一等的商品区整体抬高到了一个新的层叠层级上。排查和解决思路首先给导航栏整体设置高一点的 z-index比如 z-index: 1000同时确保导航栏自身没有 overflow: hidden其次如果商品卡片的悬浮动画确实需要 transform那就在动画结束后把 transform 还原为 none或者在动画执行期间只改变卡片的 box-shadow 和 translateY避免在包含范围内创建不必要的层叠上下文。这种问题肉眼难看出来唯一可靠的排查手段就是打开开发者工具在 Elements 面板里逐层看元素的计算样式和层叠上下文。5.4 骨架屏导致的白屏闪烁最终用宽度稳定方案解决骨架屏做得不够细致时用户会看到页面先闪现一片灰色然后唰地变成完整内容这种切换非但没缓解焦虑反而更晃眼。我最后用一套方案把这个问题解决了所有需要展示图片的位置在骨架屏阶段就固定好容器高度和宽高比字体区块固定成两行高度不要用 width: 100% 这种会跳变的设置而是使用 padding-top 按比例撑开容器高度确保真实内容替换时盒子尺寸几乎没有变化。这套方案在实际部署后页面加载过程的视觉跳跃感被显著压缩用户感知到的就是内容在转圈后直接出现了而不是界面跳了一下。骨架屏的价值在于过渡而非装饰做得好的骨架屏用户甚至感知不到它的存在做不好就变成另一种闪烁。6. 仿写之后多做这一步才算真正把项目吃到肚子里6.1 从照着抄到主动改把色彩变量和交互全部提取出来我见过太多人仿写完一个官网代码里写满了硬编码的颜色值 #ff6700 散落在一二十个文件中想换一个主题色需要全局搜索对照按钮圆角有的是8px有的是10px卡片间距在不同组件里也各自为政。这种项目的代码质量面试官一眼就能看出是纯照着截图堆出来的。我的建议是仿写完成后花半天时间做一次彻底的重构。把颜色、字号、间距、圆角、阴影这些设计变量全部收敛到一个全局变量文件里比如使用CSS变量时统一写成 --primary-color、--text-color、--radius-md 这类语义化命名通用按钮和卡片做成基础组件通过props传入不同的尺寸和主题色。这样做完之后你会发现整个项目的可读性和可维护性完全上了个档次讲起项目时也更有的说。6.2 用Lighthouse做一次性能体检把分数从60拉到90仿写版写完不是终点性能优化才是拉差距的关键。我建议用Chrome开发者工具自带的Lighthouse跑一次性能检测。第一次跑多半页面只有五六十分问题集中在图片没优化、CSS和JS体积过大、没有做缓存策略等。优化路径基本是这几步把图片压缩并使用webkit格式或转换成WebP给所有静态资源加上hash并开启CDN缓存用路由懒加载把首页初始执行的JS从500KB以上砍到200KB以下去掉页面中不必要的大体积第三方库保证首屏CSS尽量精简。跑第二轮时性能分数一般能上到85分以上这个分数才是一个可以写进作品集里的数字。6.3 面试被问仿写项目有什么难点回答思路要区分普通人仿小米官网这个项目在简历上的含金量高低全看你面试时怎么讲。你说我用了Vue和Swiper没有任何亮点因为用人部门默认这是一个培训机构的标配项目。但你可以这样说这个项目里我处理了轮播图与懒加载的冲突问题梳理了导航栏下拉面板的层叠上下文把首屏从2秒优化到1秒以内拆分了十几个可复用组件。每一条都对应一个真实踩过的坑面试官一听就知道你真做过。我想表达的核心是仿写项目真正的价值不在于像而在于你做了一遍之后对布局、交互、性能、工程化的理解比只看文档深刻了不知多少倍。那些踩过的坑、排查的思路、优化的经验才是这个项目压箱底的收获。按照上面这套思路完整走一遍你手里的仿小米官网模版就不再是一个静态皮囊而是一份能拿出手、经得起问的全链路作品。本文还有配套的精品资源点击获取