HTML5 敲击乐:前端项目入门实战指南
在本教程中,我们将使用现代前端开发的核心技术(HTML5 + CSS3 + JavaScript)构建一个响应式的 HTML5 敲击乐 Web 应用。整个过程将严格遵循前端工程化最佳实践,并融合关键知识点:CSS Reset、选择器规范、背景处理、相对单位(rem/vh)、弹性布局(Flexbox) 。
一、项目目标
- 用户点击或按键盘按键时,播放对应音效。
- 页面结构清晰、样式统一、交互流畅。
- 适配不同屏幕尺寸(尤其是移动端)。
- 代码模块化、可维护、可扩展。
- 最终界面样式
二、HTML 结构设计
我们使用语义化标签构建页面骨架,每个“鼓键”用 <div class="key"> 表示,并通过 data-key 属性绑定键盘码,便于 JS 控制。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HTML5 敲击乐</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="keys">
<!-- dom 上添加一个数据属性 -->
<div class="key" data-key="65">
<h3>A</h3>
<span class="sound">clap</span>
</div>
<div class="key" data-key="83">
<h3>S</h3>
<span class="sound">hihat</span>
</div>
<div class="key">
<h3>D</h3>
<span class="sound">kick</span>
</div>
<div class="key">
<h3>F</h3>
<span class="sound">openhat</span>
</div>
<div class="key">
<h3>G</h3>
<span class="sound">boom</span>
</div>
<div class="key">
<h3>H</h3>
<span class="sound">ride</span>
</div>
<div class="key">
<h3>J</h3>
<span class="sound">snare</span>
</div>
<div class="key">
<h3>K</h3>
<span class="sound">tom</span>
</div>
<div class="key">
<h3>L</h3>
<span class="sound">tink</span>
</div>
</div>
<script src="./script.js"></script>
</body>
</html>
- 模块运行结构 `-
A
clapS
hihatD
kickF
openhatG
boomH
rideJ
snareK
tomL
tink✅ 说明:
- 使用 类选择器
.key而非标签选择器,提高可维护性。- 每个按键包含字母提示和音效名称,结构清晰。
- 其中编码使用emet简化编码提高开发效率
- css的导入要在head处,script导入在body前一行使得不会阻塞流程运行
三、CSS 样式:专业、响应、高性能
1. 使用业界推荐的 CSS Reset(避免 *)
/*
Eric Meyer's Reset CSS v3.0.0 (https://meyerweb.com/eric/tools/css/reset/)
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, i, u, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/* 建议补充:现代开发常用的全局设置 */
*, *::before, *::after {
box-sizing: border-box;
}
img {
max-width: 100%;
height: auto;
display: block; /* 避免图片下方出现间隙 */
}
a {
text-decoration: none;
color: inherit;
}
/* 业务样式 */
html, body {
height: 100%;
}
html {
font-size: 10px;
background: url('./background.jpg') bottom center;
background-size: cover;
}
.keys {
display:flex; /*弹性布局*/
min-height: 100vh;/*现代的相对单位,不同手机,高度不一样,100vh 占满整个
不同设备间的兼容
*/
/* background: green; 背景颜色调试法*/
align-items: center;
justify-content: center;
}
.key {
/* background: red; */
border: .4rem solid black;
border-radius: 0.5rem;
margin: 1rem;
font-size: 1.5rem;
padding: 1rem 0.5rem;
width: 10rem;
text-align: center;
color: white;
background: rgba(0,0,0, 0.4);
text-shadow: 0 0 .5rem black;
}
.key h3 {
display: block;
font-size: 4rem;
}
.key .sound {
font-size: 1.2rem;
text-transform: uppercase;
letter-spacing: 0.1rem;
color: #ffc600;
}
.playing {
transform: scale(1.1);/*变基属性 放大1.5倍*/
border-color: #ffc600;
box-shadow: 0 0 1rem #ffc600;
}
✅ 为什么不用
*?
*会匹配所有元素,包括不需要重置的(如<svg>、<canvas>),影响渲染性能。
2. 设置根字体大小,启用 rem 单位
html {
font-size: 10px; /* 1rem = 10px */
}
body {
background: #2c3e50;
min-height: 100vh;
}
3. 使用 Flex 布局实现居中 & 自适应
html {
font-size: 10px;
background: url('./background.jpg') bottom center;
background-size: cover;
}
✅ 优势:
display: flex解决多端布局兼容问题。min-height: 100vh确保容器占满视口高度。- 使用
rem和vh替代px,实现真正响应式。
4. 按键样式 + 背景图处理(可选)
如果你想为每个按键添加背景图(如鼓面纹理):
.key {
width: 12rem;
height: 12rem;
background-image: url('drum-bg.jpg');
background-size: cover; /* 覆盖整个按键,可能裁剪 */
background-position: bottom center;
background-repeat: no-repeat;
border-radius: 1rem;
box-shadow: 0 0.5rem 1.5rem rgba(0,0,0,0.3);
color: white;
text-align: center;
padding: 2rem 1rem;
cursor: pointer;
transition: transform 0.1s ease;
}
.key:active {
transform: scale(0.95);
}
✅ 背景属性说明:
cover:以容器为主,图片等比缩放覆盖全部区域(适合装饰性背景)。contain:以图片为主,完整显示图片(适合图标类)。no-repeat+bottom center:精准控制位置。
四、JavaScript 交互:延迟执行,不阻塞渲染
将脚本放在 </body> 前,确保静态内容优先加载。
// 页面的最底部,在静态页面出现之后再执行
// document 整个文档 添加了一个事件监听
// 首要渲染界面, html + css, 不需要js 参与
// DOMContentLoaded html 文档加载完后在执行
// DOM 文档结构
// script阻塞html 的下载
document.addEventListener('DOMContentLoaded', function () {
// 页面加载完成后执行的代码
// 可以获取页面元素、添加事件监听器等
function playSound(event) {
// 事件对象, 在事件发生的时候会给回调函数
// keyCode 按下的键的编码
console.log(event.keyCode, '/////////');
let keyCode = event.keyCode;
let element = document.querySelector('.key[data-key="'+ keyCode +'"]');
//
console.log(element);
// 动态DOM编程 增加类
element.classList.add('playing');
}
// 事件监听
window.addEventListener('keydown', playSound);
});
✅ 关键点:
- 使用
DOMContentLoaded确保 DOM 就绪后再操作。- 支持 键盘 + 鼠标 双交互。
- 添加
.playing类实现点击动画反馈(可在 CSS 中定义)。
五、总结:核心知识点回顾
| 技术点 | 应用方式 | 目的 |
|---|---|---|
| CSS Reset | 列出具体标签重置 | 统一浏览器默认样式,提升性能 |
| 类选择器 | .key, .letter | 提高可维护性与复用性 |
| 背景处理 | background-size: cover + no-repeat | 美观且不失真的背景展示 |
| 相对单位 | rem(基于 html { font-size: 10px }),vh | 适配移动端多尺寸屏幕 |
| Flex 布局 | display: flex + justify-content/align-items | 实现完美居中与自适应排列 |
| JS 引入位置 | <script> 放在 </body> 前 | 不阻塞 HTML 渲染,提升首屏速度 |
六、下一步建议
- 添加真实的
<audio>元素(隐藏)用于播放音效。 - 使用 CSS 动画增强
.playing状态反馈。 - 打包工具(如 Vite)优化资源加载。
- PWA 支持,实现离线使用。
通过这个小项目,你不仅掌握了敲击乐应用的开发,更深入理解了现代前端开发的核心理念:结构、样式、行为分离 + 响应式 + 性能优先。现在,去敲出属于你的节奏吧!🥁
五、源代码
- HTML代码板块
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HTML5 敲击乐</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="keys">
<!-- dom 上添加一个数据属性 -->
<div class="key" data-key="65">
<h3>A</h3>
<span class="sound">clap</span>
</div>
<div class="key" data-key="83">
<h3>S</h3>
<span class="sound">hihat</span>
</div>
<div class="key">
<h3>D</h3>
<span class="sound">kick</span>
</div>
<div class="key">
<h3>F</h3>
<span class="sound">openhat</span>
</div>
<div class="key">
<h3>G</h3>
<span class="sound">boom</span>
</div>
<div class="key">
<h3>H</h3>
<span class="sound">ride</span>
</div>
<div class="key">
<h3>J</h3>
<span class="sound">snare</span>
</div>
<div class="key">
<h3>K</h3>
<span class="sound">tom</span>
</div>
<div class="key">
<h3>L</h3>
<span class="sound">tink</span>
</div>
</div>
<script src="./script.js"></script>
</body>
</html>
- CSS板块
/*
Eric Meyer's Reset CSS v3.0.0 (https://meyerweb.com/eric/tools/css/reset/)
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, i, u, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/* 建议补充:现代开发常用的全局设置 */
*, *::before, *::after {
box-sizing: border-box;
}
img {
max-width: 100%;
height: auto;
display: block; /* 避免图片下方出现间隙 */
}
a {
text-decoration: none;
color: inherit;
}
/* 业务样式 */
html, body {
height: 100%;
}
html {
font-size: 10px;
background: url('./background.jpg') bottom center;
background-size: cover;
}
.keys {
display:flex; /*弹性布局*/
min-height: 100vh;/*现代的相对单位,不同手机,高度不一样,100vh 占满整个
不同设备间的兼容
*/
/* background: green; 背景颜色调试法*/
align-items: center;
justify-content: center;
}
.key {
/* background: red; */
border: .4rem solid black;
border-radius: 0.5rem;
margin: 1rem;
font-size: 1.5rem;
padding: 1rem 0.5rem;
width: 10rem;
text-align: center;
color: white;
background: rgba(0,0,0, 0.4);
text-shadow: 0 0 .5rem black;
}
.key h3 {
display: block;
font-size: 4rem;
}
.key .sound {
font-size: 1.2rem;
text-transform: uppercase;
letter-spacing: 0.1rem;
color: #ffc600;
}
.playing {
transform: scale(1.1);/*变基属性 放大1.5倍*/
border-color: #ffc600;
box-shadow: 0 0 1rem #ffc600;
}
- JavaScript 板块
// 页面的最底部,在静态页面出现之后再执行
// document 整个文档 添加了一个事件监听
// 首要渲染界面, html + css, 不需要js 参与
// DOMContentLoaded html 文档加载完后在执行
// DOM 文档结构
// script阻塞html 的下载
document.addEventListener('DOMContentLoaded', function () {
// 页面加载完成后执行的代码
// 可以获取页面元素、添加事件监听器等
function playSound(event) {
// 事件对象, 在事件发生的时候会给回调函数
// keyCode 按下的键的编码
console.log(event.keyCode, '/////////');
let keyCode = event.keyCode;
let element = document.querySelector('.key[data-key="'+ keyCode +'"]');
//
console.log(element);
// 动态DOM编程 增加类
element.classList.add('playing');
}
// 事件监听
window.addEventListener('keydown', playSound);
});