ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

HTML5+CSS3+JS实战:6页面静态电影网站开发全解析

2026/9/11 23:21:15 拓冰建站 浏览量
HTML5+CSS3+JS实战:6页面静态电影网站开发全解析 简介面向大学生HTML5期末作业与Web前端入门实践的猫眼电影网页设计成品共6个页面综合运用HTML5结构、CSS3样式与JavaScript交互可帮助从零搭建风格统一、具备动态效果的电影信息展示站点。压缩包共36个文件、约693KB其中包含6个html页面、8个css样式表、2个js脚本以及png、jpg图片和ico图标素材目录按页面与公共样式划分便于定位和二次修改。目前已有76人学习下载。资源覆盖首页、电影详情、搜索结果、登录注册、影评与排行榜等模块轮播图、搜索展示、用户信息交互等均由原生JavaScript实现并针对不同屏幕做了响应式布局页面间导航清晰代码结构规范适合作为期末作业提交、课程设计参考或前端综合练兵项目。1. 从 6 个静态页面看 html5css3js 期末作业的真实边界我最初拿到这套猫眼电影 6 页面资源时以为最大的看点是轮播图和渐变背景。真正把所有 HTML 文件在本地跑起来之后才发现这个项目最值钱的地方在于拆得很清楚index.html 负责聚合入口cinema.html 和 list.html 承担列表与搜索move.html 是详情落地Beihai.html 补一个内容专题样式按通用、页面、动画拆成 8 个 CSS 文件交互集中在 JS.js 和 index.js 两个脚本里。对于做大学生 HTML5 期末作业的读者来说它示范了一套不依赖框架的 web 前端项目该如何组织对已经有两年工作经验的工程师也能从命名、兼容性和交互拆分里找到可以复盘的问题。整包没有后端任何静态服务器都能打开适合拿来练手和改造成自己的作品。2. HTML5 语义化与 6 页面信息架构有了整体印象之后第一件事不是写代码而是把 6 个 HTML 页面之间的关系先画出来。这个项目只有 6 个页面但如果页面职责不清晰后期改样式时就会陷入「改一个页面要同步改三个文件」的境地。2.1 六个页面先对号入座从资源包的文件清单可以直接反推出每个页面的职责。index.html 是首页hotspot.html 做热门影片排行cinema.html 是影院信息和排片list.html 承接列表与搜索move.html 是电影详情页拼写应是 movie.htmlBeihai.html 是一个以「北海」为主题的影评或专题落地页。下面这张表是这些页面在项目里的实际分工页面文件页面职责配套样式/脚本index.html首页轮播、热映推荐、排行榜入口common.css、index.css、lunbo.css、JS.js、index.jshotspot.html热门影片排行按热度/评分排序common.css、hotspot.css、JS.jscinema.html影院列表与排片时间表common.css、cinema.css、JS.jslist.html电影列表与搜索结果页common.css、list.css、JS.jsmove.html电影详情海报、简介、评分、影评common.css、move.css、JS.jsBeihai.html影评专题落地页common.css、Normal flow.css、JS.js从这个表能看出两个问题。第一页面数量和样式文件不是一一对应有些页面复用 common.css 和 Normal flow.css只有专属模块才单独建 CSS这个思路是对的。第二Beihai.html 和 move.html 的命名都不够语义化。Beihai 是专题内容名不是通用页面类型下次再做一个专题得再建一个 Jiaozhou.htmlmove.html 更是 movie.html 的误拼。期末作业我一般建议直接用 review.html、movie.html让文件名反映页面类型而不是业务位置这样导航和 CSS 命名都会顺很多。2.2 公共 header 用语义化标签搭出来六个页面都需要的公共部分是顶部导航、搜索框、登录入口和底部信息。用 HTML5 语义化标签去写比满屏 div 更容易被老师挑出亮点。常见的做法是 header 包裹 brand 和 nav搜索用 form 而不是 div登录入口放在 header 右侧。下面这段结构可以原样套到所有页面里header classfilm-header a classbrand hrefindex.html img srcimg/logo.png alt猫眼电影 width120 height40 /a nav classfilm-nav aria-label主导航 a hrefindex.html aria-currentpage首页/a a hrefhotspot.html热映/a a hrefcinema.html影院/a a hreflist.html榜单/a a hrefmove.html详情/a a hrefBeihai.html影评/a /nav form classsearch-form actionlist.html methodget input typesearch namekeyword placeholder找电影 / 找影院 button typesubmit搜索/button /form a classuser-entry hreflist.html#login img srcimg/yonghu.png alt登录 /a /header这里有几个细节值得注意。aria-currentpage用来标记当前页CSS 可以用[aria-currentpage]选中它做高亮比手动加 class 更符合语义。搜索框为什么用 form 包起来因为用户在输入框按回车时form 默认会提交页面自动跳到 list.html 并通过 URL 携带 keyword 参数这样 list.html 不需要额外 JS 就能拿到搜索词。img标签上的 width 和 height 是宽高占位避免图片加载过程中页面布局跳动这在期末作业里很少见但确实是加分项。登录入口直接指向项目里没有单独登录页而是锚点到 list.html 的登录模块这个做法节省页面数量也说明页面跳转不一定非要新建 HTML。2.3 main 内部用 section/article 组织首页内容头部之后是首页主体。轮播区、正在热映、即将上映、排行榜这些模块建议用 section 划分每张电影卡用 article。section 表示一个独立主题区块article 表示可以被单独引用的内容单元这样的结构读起来比一层层 div 清晰得多。main classhome-main section classcarousel aria-label推荐影片 div classcarousel-track div classcarousel-slideimg srcimg/1.jpg alt热映影片 A/div div classcarousel-slideimg srcimg/2.jpg alt新片推荐 B/div div classcarousel-slideimg srcimg/3.jpg alt会员专享 C/div /div /section section classhot-movies h2正在热映/h2 div classmovie-grid article classmovie-card img srcimg/4.png alt示例影片海报 h3a hrefmove.html?id1示例影片/a/h3 p classscore9.2 分/p /article /div /section /main轮播区域用 section 带上 aria-label因为首页可能只有一个轮播但为了读屏用户能识别它的用途最好给出可访问名称。hot-movies 区域里我加了一个 h2这是很多作业容易漏掉的地方section 通常需要一个标题否则读屏用户无法感知这个区块的主题。电影卡片用 article 包起来里面再放链接到 move.html?id1这里使用 query string 传递电影 id详情页的 JS 可以通过 location.search 解析出要展示哪部电影这种传参方式不依赖服务端静态页面也能实现。页脚部分和头部同理六个页面共用一个 footer 结构不要每个页面复制不同版本。常见做法是把版权信息、二维码图片资源包里的二维码.jpg 和 shouji.png 就是用来做移动端入口的和备案号放在一起底部背景用深色。由于是期末作业footer 不需要写得太重但每个页面的 footer 文案必须一致否则在页面间跳转时会被一眼看出是拼凑的。3. CSS3 布局体系从 Normal flow.css 到 lunbo.css 的动画参数HTML 结构明确了接下来是样式。这套项目的 CSS 文件有 8 个初看会觉得琐碎拆开看其实分三类全局基础common.css、Normal flow.css、页面专属index.css、hotspot.css、cinema.css、list.css、move.css、动画lunbo.css。这种拆法最大的好处是页面之间不互相污染坏处是文件多了以后命名必须更克制。3.1 样式文件先分类再决定怎么写下表把每个 CSS 文件的职责列出来。这个清单是判断一个 CSS 文件是否被塞进多余样式的检查表如果一个页面专属 CSS 里出现了 reset 或全局字体设置说明职责分界已经模糊了。样式文件覆盖范围典型内容common.css全局公共盒模型重置、body 字体、按钮、输入框Normal flow.css文档流基础排版标题、段落、列表的默认间距index.css首页轮播容器、热映榜单布局lunbo.css轮播动画keyframes、animation 属性hotspot.css热映排行页排行数字、hover 状态cinema.css影院页影院卡片、排片表格list.css列表与搜索列表项、分页器、空状态move.css详情页海报栏、演职员列表这里要特别点出两个命名问题。第一个是 Normal flow.css文件名里带空格和首字母大写浏览器和构建工具可以处理但部署到 Nginx 或 Linux 服务器时大小写敏感的文件系统会导致 404空格在 URL 里也会被编码成 %20。第二个是 move.css 对应 move.html业务上没问题但容易和 move 动画的含义混淆建议统一改成 movie.html/movie.css。命名问题不影响这次作业演示但本科阶段就建立「机器可读」的命名习惯工作后会少踩很多坑。3.2 Flex 搭头部Grid 搭卡片网格电影类站点首页的视觉重点在头部导航和卡片网格。CSS3 的 Flexbox 处理水平分布比 float 省事Grid 处理卡片自动换行更直观。先看头部/* common.css 片段 */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font: 14px/1.6 PingFang SC, Microsoft YaHei, sans-serif; background: #f5f5f5; } .film-header { position: sticky; top: 0; z-index: 100; display: flex; justify-content: space-between; align-items: center; height: 56px; padding: 0 24px; background: #e54847; } .film-nav { display: flex; gap: 8px; } .film-nav a { padding: 6px 14px; border-radius: 4px; color: #fff; text-decoration: none; } .film-nav a[aria-currentpage] { background: rgba(255, 255, 255, 0.25); }参数解释justify-content: space-between使 logo、导航、搜索、用户入口在水平方向两端分布即使中间导航链接数量变了也不会因为手写 margin 而错位。position: sticky加top: 0让 header 在滚动时吸顶注意 sticky 是相对最近滚动容器生效如果它的父级设置了 overflow 非 visible吸顶会失效。gap: 8px替代逐个设置 margin是 Flexbox 布局里更省心的间距方案。接下来是首页卡片网格和卡片 hover 效果/* index.css 片段 */ .movie-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 16px; padding: 16px; } .movie-card { overflow: hidden; border-radius: 6px; background: #fff; transition: transform 0.3s ease, box-shadow 0.3s ease; } .movie-card:hover { transform: translateY(-4px); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12); }这里最值得写进注释的是repeat(auto-fill, minmax(150px, 1fr))每一列至少 150px视口宽度足够就自动增加一列比写死三列更抗缩放。.movie-card:hover的translateY(-4px)做卡片浮起效果transition只写了发生变化的属性而不是 all避免鼠标经过时无关属性也做无意义过渡这是性能习惯不是放大镜级别的细节。3.3 lunbo.css 中 CSS3 动画关键参数轮播是首页交互核心。纯 CSS 方案适合期末演示不依赖 JS 也能运行。实现方式是 track 宽度 300%三张 slide 各占 1/3通过 keyframes 改变 transform 位移/* lunbo.css */ .carousel { overflow: hidden; } .carousel-track { display: flex; width: 300%; animation: carousel-slide 12s ease-in-out infinite; } .carousel-slide { width: 33.3333%; flex-shrink: 0; } .carousel-slide img { display: block; width: 100%; height: 200px; object-fit: cover; } keyframes carousel-slide { 0%, 30% { transform: translateX(0); } 34%, 63% { transform: translateX(-33.3333%); } 66%, 95% { transform: translateX(-66.6666%); } 100% { transform: translateX(0); } }参数含义先说清楚12s是整个动画周期ease-in-out控制变速曲线infinite让动画无限重复播放。动画执行次数由animation-iteration-count控制值为 2 就正向播两次值为 infinite 才适合轮播这种首尾相接场景。关键帧里 0%-30% 让第一屏停留34%-63% 切到第二屏66%-95% 切到第三屏最后 100% 瞬移回起点三屏各停留约 3 秒循环没有画面断档感。33.3333%对应三张 slide 各占 1/3如果改成 5 屏这个百分比要同步调整。object-fit: cover让图片按容器比例裁剪而不是拉伸变形。这里需要补两个容易被忽略的参数。第一想让动画延迟 1 秒再启动写animation-delay: 1s但要配合animation-fill-mode: backwards否则延迟期间元素处于未定义状态会出现闪动。动画完成后要保持最后一帧用animation-fill-mode: forwards兼顾延迟阶段和结束阶段则直接写both。第二animation-direction: alternate会让动画正向播完再反向播放适合跑马灯、影评渐变这类往复场景配合 infinite 时方向会来回切换轮播这种首尾相接的场景最好别用因为正反方向在首尾处的跳变会露出破绽。把这些参数的取值背景写在注释里页面一看就是自己调过的。3.4 媒体查询兜底最后给一段移动端媒体查询media (max-width: 768px) { .film-header { height: auto; flex-wrap: wrap; padding: 8px 12px; } .film-nav { order: 3; width: 100%; overflow-x: auto; } .movie-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; } }说明flex-wrap: wrap让头部在手机端换行order: 3把导航挪到最后一行overflow-x: auto让导航在窄屏上横向滑动。网格从 auto-fill 改成固定两列手机端卡片不会太小。这三个兜底基本能保证 375px 宽度下不出现明显布局错乱。4. JavaScript 交互轮播、搜索过滤与 fetch 数据替换HTML 负责结构、CSS 负责视觉JS 在这个项目里负责三件事轮播自动播放、搜索过滤、表单交互。资源包里有 JS.js 和 index.js 两个脚本从分工上看JS.js 更像工具函数和数据集合index.js 更像首页初始化脚本。把数据、工具函数和页面逻辑分开组织比把所有代码堆在一个文件里更容易扩展。4.1 轮播的 JS 控制setInterval 与悬停暂停第 3 章已经给了纯 CSS 轮播。如果作业要求「鼠标悬停暂停」纯 CSS 做不到需要改用 JS 控制。二者只能选一种不要在一个元素上同时挂 animation 和 JS 改 transform否则动画帧会覆盖 JS 写入的位移值出现抽搐。JS 版常见做法是去掉 track 的 animation改用 setInterval 定时切换配合 transition 产生滑动动画。// index.js —— JS 控制的轮播 (function () { use strict; const track document.querySelector(.carousel-track); const slides track.children; const total slides.length; const interval 4000; let current 0; let timer null; function moveTo(index) { const width track.clientWidth; track.style.transition transform .45s ease; track.style.transform translateX(- index * width px); } function next() { current (current 1) % total; moveTo(current); } timer setInterval(next, interval); track.addEventListener(mouseenter, function () { clearInterval(timer); }); track.addEventListener(mouseleave, function () { clearInterval(timer); timer setInterval(next, interval); }); })();逻辑拆解track.clientWidth每次调用时读取容器实时宽度窗口缩放后位移依然正确不需要写死 1200px。(current 1) % total取余实现「到最后一张回到第一张」的循环比手动 if 判断越界更简洁。mouseenter 和 mouseleave 配对使用进入时清掉计时器离开时重新创建悬停暂停与离开恢复是真实可用的。transition: transform .45s ease在每次 moveTo 都会重新赋值和 transform 同时作用实现滑动。两个参数最值得调interval 控制停留时长4000ms 是常规值transition 时长控制在 0.4s 到 0.6s 之间太长拖沓太短像硬切。4.2 list 页搜索filter 追加 includes再用 map 渲染搜索是信息类网站的常见交互。list.html 作为搜索目标页需要从 URL 读取 keyword同时也要响应用户在页面里再次输入的过滤。先把本地电影数据组织成数组再在 input 事件里做过滤和渲染。// JS.js —— 数据定义与通用渲染 const movieList [ { id: 1, name: 示例影片, genre: 剧情, score: 9.2 }, { id: 2, name: 动画示例, genre: 动画, score: 8.8 }, { id: 3, name: 科幻示例, genre: 科幻, score: 7.9 } ]; function renderMovies(list, container) { if (!container) return; if (list.length 0) { container.innerHTML p classempty没有找到相关电影/p; return; } container.innerHTML list .map(function (item) { return ( article classmovie-card h3a hrefmove.html?id item.id item.name /a/h3 span classgenre item.genre /span span classscore item.score.toFixed(1) /span /article ); }) .join(); }这段代码的关键在 filter 和 map 的配合。filter 不会修改原数组每次输入都基于 movieList 重新筛选避免连续输入时把上一次的结果再过滤一遍。map 把对象数组转换成 HTML 字符串数组最后用 join 拼接成一整段 innerHTML比在循环里反复 innerHTML 要高效也避免每次都触发浏览器重排。toFixed(1) 把 9.2 显示成一位小数更整齐。接着是输入监听// list.html 中初始化搜索 searchInput.addEventListener(input, function () { const keyword searchInput.value.trim().toLowerCase(); const matched movieList.filter(function (item) { return ( item.name.toLowerCase().includes(keyword) || item.genre.toLowerCase().includes(keyword) ); }); renderMovies(matched, movieListContainer); });includes 是 ES6 字符串方法用来判断字符串是否包含关键字但它大小写敏感所以输入和源数据都先 toLowerCase 再比较。trim 去掉首尾空格避免用户多敲一个空格就搜不到结果。如果页面是从搜索框 GET 跳转过来的还要把 URL 里的 keyword 回填到输入框const params new URLSearchParams(location.search); const keyword params.get(keyword) || ; if (keyword) { searchInput.value keyword; searchInput.dispatchEvent(new Event(input)); }URLSearchParams 是专门的查询参数解析接口比手动 split 安全也不需要手动 decodeURIComponent。最后一行 dispatchEvent 是为了让页面在打开时自动执行一次过滤初始渲染时不用再把过滤逻辑写一遍。这个手法在期末作业里不容易被注意到但面试时可以讲一整段。4.3 从写死数组切换到 fetch 加载 JSON当电影数量超过 30 条数据写在 JS 里很难维护。常见做法是把数据抽成 data/movies.json用 fetch 请求。静态页面用 fetch 时必须注意直接双击打开 HTML 时 fetch 会被 CORS 拦截必须通过本地静态服务器访问。fetch(data/movies.json) .then(function (res) { if (!res.ok) throw new Error(请求失败状态码 res.status); return res.json(); }) .then(function (data) { renderMovies(data, movieListContainer); }) .catch(function (err) { console.error(err); renderMovies(movieList, movieListContainer); // 本地数据兜底 });这里为什么先检查 res.okfetch 只有网络层失败才会 rejectHTTP 404 或 500 时 Promise 状态仍然是 resolved不检查的话后续解析会拿到错误数据页面崩溃只在控制台里有痕迹。catch 里回落到 JS.js 中写死的 movieList这个「先用本地数据兜底再尝试请求远端」的渐进增强思路比严格的前后端分离更适合作业场景还能让评委断网时也能打开页面。4.4 表单校验与交互点汇总六个页面里的登录、注册、影评提交这类表单不需要复杂框架。用 HTML5 原生属性加少量 JS 即可input typetext nameusername required pattern[A-Za-z0-9_]{4,16} title4-16位字母、数字或下划线form 提交时调用 checkValidity返回 false 时用 reportValidity 显示浏览器默认提示。验证码倒计时用 setInterval 每 1 秒把剩余秒数减 1到 0 时 clearInterval 并恢复按钮文案倒计时的第一行就button.disabled true避免用户重复点击。交互点数据来源实现方式涉及文件轮播自动播放页面图片setInterval transformindex.js电影列表渲染本地数组map joinJS.js搜索过滤URL 参数 / input 输入filter includesJS.js、list.html表单校验HTML5 pattern checkValidity原生校验JS.js验证码倒计时本地倒数setIntervalJS.js5. 本地静态服务器、兼容性修复与期末验收清单5.1 先跑起来再谈优化用本地静态服务器启动在项目根目录执行python3 -m http.server 8080然后在浏览器打开http://localhost:8080/index.html。8080 是端口号可以换成 8000 或 8081只要不和其他进程冲突。没有 Python 就改用npx serve只需临时安装一个依赖。注意不要直接双击 HTML 文件file:// 协议下 fetch、ES6 module、部分字体文件都会被拦截还会因为相对路径解析问题出现图片 404。资源包里Normal flow.css的文件名含空格在 Windows 上双击可能没问题但放在 Linux 服务器上就要留心大小写和空格最好提前改成 normal-flow.css。5.2 兼容性三处要修第一处是 transform 和 transition 的前缀讲师演示机如果浏览器内核偏老动画可能不生效可以在轮播和 hover 效果的属性行前补-webkit-transform和-webkit-transition。第二处是 CSS Grid 的 auto-fill 在旧 Edge 下行为异常保险做法是给 .movie-grid 加一层display: flex; flex-wrap: wrap兜底再用supports (display: grid)覆盖成 Grid。第三处是 JS 的 includes 和 URLSearchParams 在 IE11 不存在必须兼容 IE 就改成 indexOf 和手写解析期末作业一般只保证 Chrome 和 Edge 即可。5.3 验收清单检查项通过标准导航连通6 个 HTML 页面之间互相跳转无 404当前导航有高亮轮播自动播放悬停暂停离开恢复无跳帧抽搐搜索list.html 能读取 keyword 并过滤无结果有空状态表单空值、格式错误有提示不产生无意义提交图片所有 img 均显示Network 面板无 404JS 报错切换所有页面后 Console 无报错移动端375px 宽度下不出现横向滚动条5.4 最后动手调一遍资源跑通以后真正提升完成度的是资源质量而不是再写一轮功能。第一把 img 目录下超过 200KB 的 jpg/png 压缩到 80KB 左右首屏加载速度会明显变快第二给非首屏图片加上loadinglazy让浏览器只在接近视口时才发起请求第三把 JS.js、index.js 里的 console.log 全部清掉避免老师打开控制台时看到调试残留。验证时不要只点页面看效果打开 DevTools 的 Network 面板确认每个资源返回 200再切到 Lighthouse 跑一遍 Performance分数低于 90 就从图片压缩和懒加载两条路开始改。本文还有配套的精品资源点击获取