Appearance
HTML+CSS+JS联动实战
19.1 美化个人简介页面
项目目标
使用CSS美化个人简介页面,提升页面的视觉效果。
技术要点
- HTML结构搭建
- CSS样式美化
- 响应式设计
实现代码
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>个人简介</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background-color: #f5f5f5;
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 20px;
}
.card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
overflow: hidden;
margin-top: 50px;
}
.card-header {
text-align: center;
padding: 40px 20px;
color: white;
}
.avatar {
width: 150px;
height: 150px;
border-radius: 50%;
border: 5px solid rgba(255,255,255,0.3);
object-fit: cover;
margin-bottom: 20px;
}
.name {
font-size: 28px;
font-weight: 700;
margin-bottom: 10px;
}
.title {
font-size: 18px;
opacity: 0.9;
margin-bottom: 20px;
}
.social-links {
display: flex;
justify-content: center;
gap: 15px;
}
.social-link {
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 50%;
background-color: rgba(255,255,255,0.2);
color: white;
text-decoration: none;
transition: all 0.3s ease;
}
.social-link:hover {
background-color: rgba(255,255,255,0.3);
transform: translateY(-3px);
}
.card-body {
background-color: white;
padding: 40px;
}
.section {
margin-bottom: 30px;
}
.section-title {
font-size: 20px;
font-weight: 600;
color: #667eea;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 2px solid #f0f0f0;
}
.info-list {
list-style: none;
}
.info-item {
margin-bottom: 10px;
display: flex;
}
.info-label {
font-weight: 600;
width: 100px;
color: #666;
}
.skills {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.skill-item {
background-color: #f0f0f0;
padding: 8px 16px;
border-radius: 20px;
font-size: 14px;
color: #666;
transition: all 0.3s ease;
}
.skill-item:hover {
background-color: #667eea;
color: white;
}
.experience-item {
margin-bottom: 20px;
}
.experience-title {
font-weight: 600;
margin-bottom: 5px;
}
.experience-meta {
font-size: 14px;
color: #666;
margin-bottom: 10px;
}
@media (max-width: 768px) {
.card-body {
padding: 20px;
}
.info-item {
flex-direction: column;
}
.info-label {
width: 100%;
margin-bottom: 5px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="card">
<div class="card-header">
<img src="https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=professional%20profile%20photo&image_size=square" alt="个人头像" class="avatar">
<h1 class="name">张三</h1>
<p class="title">前端开发工程师</p>
<div class="social-links">
<a href="#" class="social-link">🔗</a>
<a href="#" class="social-link">📧</a>
<a href="#" class="social-link">📱</a>
</div>
</div>
<div class="card-body">
<div class="section">
<h2 class="section-title">个人简介</h2>
<p>我是一名前端开发工程师,热爱编程和技术创新。拥有2年前端开发经验,熟悉HTML、CSS、JavaScript等前端技术栈。</p>
</div>
<div class="section">
<h2 class="section-title">联系信息</h2>
<ul class="info-list">
<li class="info-item">
<span class="info-label">邮箱:</span>
<span>zhangsan@example.com</span>
</li>
<li class="info-item">
<span class="info-label">电话:</span>
<span>13800138000</span>
</li>
<li class="info-item">
<span class="info-label">地址:</span>
<span>北京市朝阳区</span>
</li>
</ul>
</div>
<div class="section">
<h2 class="section-title">技能</h2>
<div class="skills">
<span class="skill-item">HTML5</span>
<span class="skill-item">CSS3</span>
<span class="skill-item">JavaScript</span>
<span class="skill-item">React</span>
<span class="skill-item">Vue</span>
<span class="skill-item">Node.js</span>
<span class="skill-item">Git</span>
<span class="skill-item">UI设计</span>
</div>
</div>
<div class="section">
<h2 class="section-title">工作经验</h2>
<div class="experience-item">
<div class="experience-title">前端开发工程师</div>
<div class="experience-meta">2024年至今 | 某某科技有限公司</div>
<p>负责公司官网和内部系统的前端开发,使用React和Vue框架,参与项目的需求分析、设计和开发。</p>
</div>
<div class="experience-item">
<div class="experience-title">前端实习生</div>
<div class="experience-meta">2023年 | 某某互联网公司</div>
<p>参与公司产品的前端开发,学习并掌握了HTML、CSS、JavaScript等前端技术。</p>
</div>
</div>
</div>
</div>
</div>
</body>
</html>19.2 实现表单验证功能
项目目标
使用JavaScript实现表单验证功能,提升用户体验。
技术要点
- HTML表单结构
- JavaScript表单验证
- 实时验证反馈
实现代码
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>表单验证</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background-color: #f5f5f5;
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.form-container {
background-color: white;
border-radius: 10px;
box-shadow: 0 5px 20px rgba(0,0,0,0.1);
padding: 30px;
margin-top: 50px;
}
h1 {
text-align: center;
color: #333;
margin-bottom: 30px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #555;
}
input {
width: 100%;
padding: 12px;
border: 2px solid #ddd;
border-radius: 6px;
font-size: 16px;
transition: all 0.3s ease;
}
input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
input.success {
border-color: #28a745;
}
input.error {
border-color: #dc3545;
}
.error-message {
color: #dc3545;
font-size: 14px;
margin-top: 5px;
min-height: 20px;
}
.btn {
width: 100%;
padding: 15px;
background-color: #667eea;
color: white;
border: none;
border-radius: 6px;
font-size: 18px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.btn:hover {
background-color: #5a6fd8;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.btn:active {
transform: translateY(0);
}
@media (max-width: 768px) {
.form-container {
padding: 20px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="form-container">
<h1>用户注册</h1>
<form id="registration-form">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" id="username" name="username" placeholder="请输入用户名">
<div class="error-message" id="username-error"></div>
</div>
<div class="form-group">
<label for="email">邮箱</label>
<input type="email" id="email" name="email" placeholder="请输入邮箱">
<div class="error-message" id="email-error"></div>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" id="password" name="password" placeholder="请输入密码">
<div class="error-message" id="password-error"></div>
</div>
<div class="form-group">
<label for="confirm-password">确认密码</label>
<input type="password" id="confirm-password" name="confirm-password" placeholder="请确认密码">
<div class="error-message" id="confirm-password-error"></div>
</div>
<button type="submit" class="btn">注册</button>
</form>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('registration-form');
const username = document.getElementById('username');
const email = document.getElementById('email');
const password = document.getElementById('password');
const confirmPassword = document.getElementById('confirm-password');
// 实时验证
username.addEventListener('input', validateUsername);
email.addEventListener('input', validateEmail);
password.addEventListener('input', validatePassword);
confirmPassword.addEventListener('input', validateConfirmPassword);
// 表单提交
form.addEventListener('submit', function(e) {
e.preventDefault();
const isUsernameValid = validateUsername();
const isEmailValid = validateEmail();
const isPasswordValid = validatePassword();
const isConfirmPasswordValid = validateConfirmPassword();
if (isUsernameValid && isEmailValid && isPasswordValid && isConfirmPasswordValid) {
alert('注册成功!');
form.reset();
}
});
function validateUsername() {
const usernameValue = username.value.trim();
const usernameError = document.getElementById('username-error');
if (usernameValue === '') {
setError(username, usernameError, '用户名不能为空');
return false;
} else if (usernameValue.length < 3) {
setError(username, usernameError, '用户名长度不能少于3位');
return false;
} else {
setSuccess(username, usernameError);
return true;
}
}
function validateEmail() {
const emailValue = email.value.trim();
const emailError = document.getElementById('email-error');
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (emailValue === '') {
setError(email, emailError, '邮箱不能为空');
return false;
} else if (!emailRegex.test(emailValue)) {
setError(email, emailError, '请输入有效的邮箱地址');
return false;
} else {
setSuccess(email, emailError);
return true;
}
}
function validatePassword() {
const passwordValue = password.value;
const passwordError = document.getElementById('password-error');
if (passwordValue === '') {
setError(password, passwordError, '密码不能为空');
return false;
} else if (passwordValue.length < 6) {
setError(password, passwordError, '密码长度不能少于6位');
return false;
} else if (!/[A-Z]/.test(passwordValue)) {
setError(password, passwordError, '密码必须包含至少一个大写字母');
return false;
} else if (!/[0-9]/.test(passwordValue)) {
setError(password, passwordError, '密码必须包含至少一个数字');
return false;
} else {
setSuccess(password, passwordError);
return true;
}
}
function validateConfirmPassword() {
const confirmPasswordValue = confirmPassword.value;
const confirmPasswordError = document.getElementById('confirm-password-error');
if (confirmPasswordValue === '') {
setError(confirmPassword, confirmPasswordError, '请确认密码');
return false;
} else if (confirmPasswordValue !== password.value) {
setError(confirmPassword, confirmPasswordError, '两次输入的密码不一致');
return false;
} else {
setSuccess(confirmPassword, confirmPasswordError);
return true;
}
}
function setError(input, errorElement, message) {
input.classList.remove('success');
input.classList.add('error');
errorElement.textContent = message;
}
function setSuccess(input, errorElement) {
input.classList.remove('error');
input.classList.add('success');
errorElement.textContent = '';
}
});
</script>
</body>
</html>19.3 制作图片切换页面
项目目标
使用JavaScript实现图片切换功能,提升用户交互体验。
技术要点
- HTML图片结构
- JavaScript事件处理
- 图片切换逻辑
实现代码
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片切换</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background-color: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.gallery {
background-color: white;
border-radius: 10px;
box-shadow: 0 5px 20px rgba(0,0,0,0.1);
padding: 30px;
margin-top: 50px;
text-align: center;
}
h1 {
margin-bottom: 30px;
color: #333;
}
.image-container {
position: relative;
margin-bottom: 30px;
height: 400px;
overflow: hidden;
border-radius: 10px;
}
.image-container img {
width: 100%;
height: 100%;
object-fit: cover;
transition: all 0.5s ease;
}
.image-container img.fade-in {
animation: fadeIn 0.5s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.controls {
display: flex;
justify-content: center;
gap: 15px;
margin-bottom: 30px;
}
.btn {
padding: 10px 20px;
background-color: #667eea;
color: white;
border: none;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
transition: all 0.3s ease;
}
.btn:hover {
background-color: #5a6fd8;
transform: translateY(-2px);
}
.btn:disabled {
background-color: #ccc;
cursor: not-allowed;
transform: none;
}
.thumbnails {
display: flex;
gap: 10px;
justify-content: center;
flex-wrap: wrap;
}
.thumbnail {
width: 80px;
height: 80px;
border-radius: 6px;
cursor: pointer;
overflow: hidden;
border: 3px solid transparent;
transition: all 0.3s ease;
}
.thumbnail img {
width: 100%;
height: 100%;
object-fit: cover;
}
.thumbnail.active {
border-color: #667eea;
transform: scale(1.1);
}
@media (max-width: 768px) {
.gallery {
padding: 20px;
}
.image-container {
height: 300px;
}
.thumbnail {
width: 60px;
height: 60px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="gallery">
<h1>图片切换展示</h1>
<div class="image-container">
<img id="main-image" src="https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=beautiful%20landscape%201&image_size=landscape_16_9" alt="图片1">
</div>
<div class="controls">
<button id="prev-btn" class="btn">上一张</button>
<button id="next-btn" class="btn">下一张</button>
<button id="play-btn" class="btn">播放</button>
</div>
<div class="thumbnails">
<div class="thumbnail active" data-index="0">
<img src="https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=beautiful%20landscape%201&image_size=square" alt="缩略图1">
</div>
<div class="thumbnail" data-index="1">
<img src="https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=beautiful%20landscape%202&image_size=square" alt="缩略图2">
</div>
<div class="thumbnail" data-index="2">
<img src="https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=beautiful%20landscape%203&image_size=square" alt="缩略图3">
</div>
<div class="thumbnail" data-index="3">
<img src="https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=beautiful%20landscape%204&image_size=square" alt="缩略图4">
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const images = [
"https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=beautiful%20landscape%201&image_size=landscape_16_9",
"https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=beautiful%20landscape%202&image_size=landscape_16_9",
"https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=beautiful%20landscape%203&image_size=landscape_16_9",
"https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image?prompt=beautiful%20landscape%204&image_size=landscape_16_9"
];
let currentIndex = 0;
let slideInterval;
let isPlaying = false;
const mainImage = document.getElementById('main-image');
const prevBtn = document.getElementById('prev-btn');
const nextBtn = document.getElementById('next-btn');
const playBtn = document.getElementById('play-btn');
const thumbnails = document.querySelectorAll('.thumbnail');
// 初始化
updateImage();
// 上一张
prevBtn.addEventListener('click', function() {
currentIndex = (currentIndex - 1 + images.length) % images.length;
updateImage();
});
// 下一张
nextBtn.addEventListener('click', function() {
currentIndex = (currentIndex + 1) % images.length;
updateImage();
});
// 播放/暂停
playBtn.addEventListener('click', function() {
if (isPlaying) {
clearInterval(slideInterval);
playBtn.textContent = '播放';
} else {
slideInterval = setInterval(function() {
currentIndex = (currentIndex + 1) % images.length;
updateImage();
}, 3000);
playBtn.textContent = '暂停';
}
isPlaying = !isPlaying;
});
// 缩略图点击
thumbnails.forEach(function(thumbnail) {
thumbnail.addEventListener('click', function() {
currentIndex = parseInt(this.getAttribute('data-index'));
updateImage();
});
});
function updateImage() {
// 更新主图片
mainImage.src = images[currentIndex];
mainImage.classList.add('fade-in');
setTimeout(function() {
mainImage.classList.remove('fade-in');
}, 500);
// 更新缩略图状态
thumbnails.forEach(function(thumbnail, index) {
if (index === currentIndex) {
thumbnail.classList.add('active');
} else {
thumbnail.classList.remove('active');
}
});
}
});
</script>
</body>
</html>19.4 搭建响应式导航栏
项目目标
使用HTML和CSS搭建响应式导航栏,适配不同设备屏幕。
技术要点
- HTML导航结构
- CSS响应式设计
- JavaScript菜单切换
实现代码
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>响应式导航栏</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background-color: #f5f5f5;
}
header {
background-color: #333;
position: sticky;
top: 0;
z-index: 1000;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.navbar {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
height: 70px;
}
.logo {
color: white;
font-size: 24px;
font-weight: 700;
text-decoration: none;
}
.nav-links {
display: flex;
list-style: none;
gap: 20px;
}
.nav-links li a {
color: white;
text-decoration: none;
font-size: 16px;
font-weight: 500;
transition: all 0.3s ease;
padding: 8px 16px;
border-radius: 4px;
}
.nav-links li a:hover {
background-color: rgba(255,255,255,0.1);
}
.nav-links li a.active {
background-color: #667eea;
}
.menu-toggle {
display: none;
cursor: pointer;
color: white;
font-size: 24px;
}
.hero {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
text-align: center;
padding: 100px 20px;
}
.hero h1 {
font-size: 48px;
margin-bottom: 20px;
}
.hero p {
font-size: 20px;
margin-bottom: 30px;
opacity: 0.9;
}
.btn {
display: inline-block;
padding: 12px 30px;
background-color: white;
color: #667eea;
text-decoration: none;
border-radius: 6px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 50px 20px;
}
.section {
margin-bottom: 50px;
}
.section h2 {
font-size: 32px;
margin-bottom: 20px;
color: #333;
}
@media (max-width: 768px) {
.menu-toggle {
display: block;
}
.nav-links {
position: absolute;
top: 70px;
left: 0;
width: 100%;
background-color: #333;
flex-direction: column;
align-items: center;
padding: 20px 0;
gap: 15px;
box-shadow: 0 5px 10px rgba(0,0,0,0.1);
transform: translateY(-100%);
opacity: 0;
pointer-events: none;
transition: all 0.3s ease;
}
.nav-links.active {
transform: translateY(0);
opacity: 1;
pointer-events: all;
}
.hero h1 {
font-size: 36px;
}
.hero p {
font-size: 18px;
}
}
</style>
</head>
<body>
<header>
<nav class="navbar">
<a href="#" class="logo">Logo</a>
<ul class="nav-links">
<li><a href="#" class="active">首页</a></li>
<li><a href="#">关于我们</a></li>
<li><a href="#">产品中心</a></li>
<li><a href="#">服务项目</a></li>
<li><a href="#">联系我们</a></li>
</ul>
<div class="menu-toggle">☰</div>
</nav>
</header>
<section class="hero">
<h1>欢迎访问我们的网站</h1>
<p>这是一个响应式导航栏示例,适配不同设备屏幕</p>
<a href="#" class="btn">了解更多</a>
</section>
<div class="container">
<section class="section">
<h2>关于我们</h2>
<p>我们是一家专注于前端开发的公司,致力于为客户提供高质量的网站和应用解决方案。我们拥有专业的开发团队,能够满足各种复杂的开发需求。</p>
</section>
<section class="section">
<h2>我们的服务</h2>
<p>我们提供网站开发、应用开发、UI设计等多种服务,能够根据客户的需求提供定制化的解决方案。我们注重用户体验和代码质量,确保每一个项目都能够达到客户的期望。</p>
</section>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const menuToggle = document.querySelector('.menu-toggle');
const navLinks = document.querySelector('.nav-links');
menuToggle.addEventListener('click', function() {
navLinks.classList.toggle('active');
});
// 点击导航链接后关闭菜单
document.querySelectorAll('.nav-links a').forEach(function(link) {
link.addEventListener('click', function() {
navLinks.classList.remove('active');
});
});
});
</script>
</body>
</html>小结
通过本章节的学习,你已经完成了几个HTML+CSS+JS联动的实战项目,包括美化个人简介页面、实现表单验证功能、制作图片切换页面和搭建响应式导航栏。这些项目涵盖了前端开发的核心技能,通过实战练习,你可以巩固所学的HTML、CSS和JavaScript知识,提升实战能力,为将来的前端开发工作打下坚实的基础。
