<think>我们将创建一个包含4种天气卡片的页面:风、雨、晴、雪。每个卡片都有相应的动画效果。
由于要求在一个文件中,我们将使用内联CSS和JavaScript。
为了切换天气状态,我们可以通过按钮来切换,但题目要求并排显示,所以我们将同时展示四种天气卡片,每种卡片展示一种天气。
但是,题目要求包含切换不同天气状态的功能,我们可以理解为每个卡片可以独立切换其天气状态?或者整体切换?但题目要求是并排显示,所以这里我们设计为四个卡片分别展示四种天气,同时每个卡片上可以有一个按钮切换该卡片的天气状态(循环切换四种天气),或者我们也可以设计一个全局切换按钮,同时改变所有卡片的天气状态。但题目要求演示每种天气的动画效果,所以同时展示四种天气并分别有切换功能更符合要求。
然而,题目要求是“切换不同天气状态的功能”,我们可以设计为:每个卡片展示一种天气,然后我们有一个按钮组,点击按钮时,所有卡片都切换到同一种天气(比如点击“风”,所有卡片都展示风的动画)。这样也可以同时展示同一种天气的不同动画表现形式(比如风,有的卡片是云,有的卡片是树)。但题目要求并排显示四种天气,所以同时展示四种不同的天气更符合要求。
重新理解需求:所有天气卡片需要并排显示,背景采用深色设计。并且要包含切换不同天气状态的功能。这里有两种理解:
1. 四个卡片分别代表四种天气,每个卡片固定展示一种天气的动画,然后通过切换功能,可以改变每个卡片的天气类型(比如每个卡片都可以独立切换为四种天气之一)。
2. 四个卡片同时展示同一种天气,然后通过切换按钮,让四个卡片同时切换到另一种天气(比如切换到风,四个卡片都展示风的不同动画效果)。
但是题目要求是“直观展示以下天气状况:风力、降雨、晴天、下雪”,并且要并排显示,所以更可能是四个卡片分别展示四种不同的天气。
因此,我们设计:
- 四个卡片,分别固定为:风、雨、晴、雪。
- 每个卡片内部展示对应天气的动画效果。
但是,题目要求“切换不同天气状态的功能”,所以我们可以为每个卡片添加一个切换按钮,点击后循环切换该卡片的天气状态(这样每个卡片就可以独立切换成其他天气)。或者,我们也可以设计一个全局的切换控制,例如一组单选按钮,选择一种天气,然后四个卡片都展示这种天气(但这样四个卡片展示同一种天气,可能通过不同的动画形式表现)。
考虑到题目要求“以不同动画效果直观展示以下天气状况”,并排显示四种天气,所以应该是同时展示四种天气。因此,我们让四个卡片分别代表四种天气,然后每个卡片上有一个按钮,可以切换该卡片到其他天气(这样每个卡片都可以独立切换为四种天气之一),这样就能演示每种天气的动画效果。
但是,这样设计的话,四个卡片一开始分别是风、雨、晴、雪,然后点击任意卡片的切换按钮,该卡片就会变成其他天气,这样四个卡片就可能出现重复的天气。
另一种方案:我们提供四个按钮,分别对应四种天气,点击某个按钮,四个卡片都变成这种天气(但是每个卡片展示这种天气的不同动画表现形式)。例如,点击“风”,第一个卡片展示飘动的云朵,第二个卡片展示摇曳的树木,第三个卡片展示风线,第四个卡片展示另一种风的动画。这样也可以同时展示同一种天气的不同动画。
然而,题目要求并排显示四种天气,所以更倾向于同时展示四种不同的天气。因此,我们选择第一种方案:四个卡片分别固定代表一种天气,然后每个卡片可以独立切换天气。
但是,这样设计的话,四个卡片就不再固定代表一种天气了,而是每个卡片都可以切换成任意天气。那么初始状态,我们让四个卡片分别展示四种不同的天气(风、雨、晴、雪)。然后每个卡片上有一个切换按钮,点击后循环切换到下一种天气(四种天气循环)。
因此,我们设计如下:
- 四个卡片,初始状态分别展示:风、雨、晴、雪。
- 每个卡片内部有一个按钮,点击该按钮,该卡片切换到下一种天气(循环切换)。
这样,用户可以通过点击每个卡片的按钮来单独切换该卡片的天气,从而演示每种天气的动画效果。
接下来,我们设计每种天气的动画效果:
1. 风力:
- 飘动的云朵:使用云朵图片或div,通过CSS动画使其左右移动。
- 摇曳的树木:绘制一个简单的树(用棕色长方形和绿色圆形),然后通过CSS动画使其摇摆。
- 风线:用几条波浪线表示风,从左到右移动。
2. 降雨:
- 下落的雨滴:多个从上到下移动的线条(或水滴形状),有随机延迟。
- 形成的水洼:在卡片底部绘制几个逐渐变大的圆形(表示水洼形成)。
3. 晴天:
- 闪耀的光线:太阳图标,周围有光线旋转或闪烁。
- 明亮的背景:背景颜色渐变,从亮黄色到白色。
4. 下雪:
- 飘落的雪花:多个白色小圆点(或雪花形状)从上到下飘落,有随机延迟和左右飘动效果。
- 积雪效果:在卡片底部逐渐堆积的白色区域。
由于每个卡片需要展示多种天气,我们需要为每个卡片设计四种天气的动画,并根据当前天气状态显示相应的动画。
考虑到代码量,我们简化设计:每个卡片内部,根据当前天气类型,显示对应的动画元素。我们使用CSS类来控制显示和动画。
结构:
- 每个卡片是一个div,包含四个天气动画的子元素(默认隐藏),以及一个按钮。
- 根据当前天气类型,显示对应的子元素。
我们将使用CSS变量来统一主题色,深色背景。
由于在一个文件中,我们将使用内联样式和脚本。
步骤:
1. 创建HTML结构:一个容器包含四个卡片。
2. 每个卡片包含四个天气动画的div(风、雨、晴、雪)和一个切换按钮。
3. 使用CSS设置深色背景,卡片样式,以及每种天气的动画效果。
4. 使用JavaScript为每个按钮添加点击事件,切换卡片的天气类型(循环四种天气)。
注意:为了保持代码简洁,我们将为每种天气设计一个代表性的动画,但每个卡片只展示一种动画(比如风,我们只展示一种动画,如飘动的云朵,而不展示多个)。当然,也可以在一个卡片中同时展示多个元素(比如风:同时有云和树),但为了简化,我们每个天气只设计一个动画。
但是,题目要求“以不同动画效果直观展示”,所以每个天气我们设计一个主要的动画效果,但可以同时包含多个元素(比如风:云和树都放进去,但是它们一起动)。这样也可以。
我们这样设计每个天气的动画:
- 风:云朵从左飘到右,同时树在摇摆。
- 雨:雨滴下落,底部有水洼形成。
- 晴:太阳和光线(光线旋转)。
- 雪:雪花飘落,底部积雪。
这样每个卡片中的动画会稍微复杂一些,但更生动。
由于时间有限,我们尽量简化但保持效果。
开始编写代码:
HTML结构:
<div class="container">
<div class="card" data-weather="wind">
<div class="weather-animation">
<!-- 风的动画:云和树 -->
<div class="cloud"></div>
<div class="tree"></div>
</div>
<button>切换天气</button>
</div>
... 其他三个卡片,初始分别为rain, sun, snow
</div>
但是,每个卡片内的动画元素需要根据天气类型显示,所以我们可以这样:
每个卡片内,包含四个div,分别对应四种天气,通过类名控制显示哪一个。
例如:
<div class="card">
<div class="weather-animation">
<div class="weather wind">...</div>
<div class="weather rain">...</div>
<div class="weather sun">...</div>
<div class="weather snow">...</div>
</div>
<button>切换天气</button>
</div>
初始时,根据卡片的数据属性(data-weather)显示对应的天气div,隐藏其他的。
切换按钮点击时,我们循环切换天气(顺序:wind -> rain -> sun -> snow -> wind...),然后隐藏当前显示的天气div,显示下一个天气div。
接下来,我们设计每种天气的动画元素:
1. 风(wind):
- 云:一个白色的椭圆,水平移动。
- 树:一个树干(长方形)和树冠(圆形),树冠摇摆。
2. 雨(rain):
- 雨滴:多个垂直移动的线条,随机延迟。
- 水洼:底部几个圆形,逐渐变大(从无到有,然后变大一点)。
3. 晴(sun):
- 太阳:一个圆形,放射状的光线(多个三角形旋转)。
4. 雪(snow):
- 雪花:多个白色小圆点,以随机速度和延迟飘落,并左右晃动。
- 积雪:底部一个白色长方形,高度逐渐增加(模拟堆积)。
由于代码较长,我们将分步编写。
注意:为了达到精致流畅的效果,我们将使用CSS3动画,并尽量优化性能。
开始写代码:</think># 国家级精品天气应用卡片设计
我将创建一个精致的动画天气卡片应用,展示风、雨、晴、雪四种天气状态,每种都有独特的动画效果,并实现天气切换功能。
## 实现思路
- 创建响应式深色背景布局
- 设计四种天气卡片(风、雨、晴、雪)
- 为每种天气实现独特的CSS动画效果
- 添加天气切换控制面板
- 优化性能和视觉效果
下面是完整的HTML实现:
```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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
background: linear-gradient(135deg, #0f2027, #203a43, #2c5364);
color: #fff;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 2rem;
overflow-x: hidden;
}
.header {
text-align: center;
margin-bottom: 3rem;
width: 100%;
}
.header h1 {
font-size: 3.5rem;
font-weight: 300;
letter-spacing: 2px;
margin-bottom: 0.5rem;
background: linear-gradient(to right, #00c6ff, #0072ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 20px rgba(0, 114, 255, 0.2);
}
.header p {
font-size: 1.2rem;
opacity: 0.8;
max-width: 800px;
margin: 0 auto;
line-height: 1.6;
}
.container {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 2rem;
max-width: 1600px;
margin: 0 auto;
}
.card {
background: rgba(20, 30, 48, 0.7);
border-radius: 20px;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.5);
width: 350px;
height: 450px;
position: relative;
overflow: hidden;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-10px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.6);
}
.card-title {
position: absolute;
top: 20px;
left: 20px;
font-size: 2rem;
font-weight: 500;
z-index: 10;
text-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}
.card-content {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
/* 风动画效果 */
.wind-card .card-content {
background: linear-gradient(to bottom, #1d2b3a, #0a1929);
}
.wind {
position: relative;
width: 100%;
height: 100%;
}
.cloud {
position: absolute;
top: 20%;
left: -150px;
width: 150px;
height: 60px;
background: rgba(255, 255, 255, 0.9);
border-radius: 50%;
box-shadow:
20px -10px 0 10px rgba(255, 255, 255, 0.9),
40px 0 0 20px rgba(255, 255, 255, 0.9),
80px -10px 0 15px rgba(255, 255, 255, 0.9),
110px 0 0 10px rgba(255, 255, 255, 0.9);
animation: moveCloud 25s linear infinite;
}
.tree {
position: absolute;
bottom: 50px;
left: 50%;
transform: translateX(-50%);
}
.trunk {
width: 15px;
height: 100px;
background: #8B4513;
border-radius: 5px;
margin: 0 auto;
}
.leaves {
width: 100px;
height: 100px;
background: rgba(34, 139, 34, 0.8);
border-radius: 50% 50% 40% 40%;
position: relative;
top: -20px;
animation: sway 5s ease-in-out infinite;
}
.wind-line {
position: absolute;
height: 2px;
background: rgba(255, 255, 255, 0.5);
animation: windFlow 3s linear infinite;
}
/* 雨动画效果 */
.rain-card .card-content {
background: linear-gradient(to bottom, #1a2a3f, #0a1423);
}
.rain {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.rain-drop {
position: absolute;
top: -20px;
width: 2px;
height: 20px;
background: linear-gradient(to bottom, transparent, #00b4ff);
animation: rainFall linear infinite;
}
.puddle {
position: absolute;
bottom: 30px;
width: 80px;
height: 20px;
background: rgba(0, 180, 255, 0.3);
border-radius: 50%;
animation: puddleRipple 4s ease-in-out infinite;
}
.puddle:nth-child(2) {
left: 30%;
animation-delay: 1s;
}
.puddle:nth-child(3) {
right: 30%;
animation-delay: 2s;
}
/* 晴动画效果 */
.sunny-card .card-content {
background: linear-gradient(to bottom, #1a3a5f, #0a1f3a);
}
.sun {
position: absolute;
top: 30%;
left: 50%;
transform: translateX(-50%);
width: 120px;
height: 120px;
background: radial-gradient(circle, #ffd700, #ff8c00);
border-radius: 50%;
box-shadow: 0 0 60px rgba(255, 215, 0, 0.8);
animation: sunPulse 4s ease-in-out infinite;
}
.sun-ray {
position: absolute;
top: 50%;
left: 50%;
width: 200px;
height: 4px;
background: rgba(255, 215, 0, 0.6);
border-radius: 2px;
transform-origin: left center;
animation: rayRotate 20s linear infinite;
}
.sun-ray:nth-child(2) { transform: rotate(45deg); }
.sun-ray:nth-child(3) { transform: rotate(90deg); }
.sun-ray:nth-child(4) { transform: rotate(135deg); }
.sun-ray:nth-child(5) { transform: rotate(180deg); }
.sun-ray:nth-child(6) { transform: rotate(225deg); }
.sun-ray:nth-child(7) { transform: rotate(270deg); }
.sun-ray:nth-child(8) { transform: rotate(315deg); }
/* 雪动画效果 */
.snow-card .card-content {
background: linear-gradient(to bottom, #1a2a40, #0a1420);
}
.snow {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.snowflake {
position: absolute;
top: -20px;
font-size: 24px;
color: rgba(255, 255, 255, 0.9);
animation: snowFall linear infinite;
text-shadow: 0 0 5px rgba(173, 216, 230, 0.7);
}
.snow-ground {
position: absolute;
bottom: 0;
width: 100%;
height: 80px;
background: rgba(255, 255, 255, 0.2);
border-radius: 50% 50% 0 0;
box-shadow: 0 -10px 20px rgba(255, 255, 255, 0.1);
}
.snow-hill {
position: absolute;
bottom: 0;
width: 150px;
height: 60px;
background: rgba(255, 255, 255, 0.3);
border-radius: 50% 50% 0 0;
}
.snow-hill:nth-child(2) {
left: 30%;
height: 50px;
width: 120px;
}
.snow-hill:nth-child(3) {
right: 20%;
height: 40px;
width: 100px;
}
/* 控制面板 */
.controls {
display: flex;
justify-content: center;
gap: 1.5rem;
margin-top: 3rem;
flex-wrap: wrap;
}
.weather-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
padding: 15px 30px;
font-size: 1.2rem;
border-radius: 50px;
cursor: pointer;
transition: all 0.3s ease;
backdrop-filter: blur(5px);
min-width: 150px;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
.weather-btn:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-3px);
}
.weather-btn.active {
background: linear-gradient(45deg, #00c6ff, #0072ff);
box-shadow: 0 0 20px rgba(0, 114, 255, 0.5);
}
/* 动画定义 */
@keyframes moveCloud {
0% { left: -150px; }
100% { left: 110%; }
}
@keyframes sway {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(5deg); }
75% { transform: rotate(-5deg); }
}
@keyframes windFlow {
0% {
width: 0;
left: -100px;
opacity: 0;
}
20% { opacity: 0.5; }
50% {
width: 200px;
opacity: 0.8;
}
80% { opacity: 0.5; }
100% {
width: 0;
left: 100%;
opacity: 0;
}
}
@keyframes rainFall {
0% { transform: translateY(0) translateX(0); opacity: 0; }
10% { opacity: 1; }
100% { transform: translateY(500px) translateX(20px); opacity: 0; }
}
@keyframes puddleRipple {
0%, 100% { transform: scale(1); opacity: 0.6; }
50% { transform: scale(1.2); opacity: 0.3; }
}
@keyframes sunPulse {
0%, 100% { transform: translateX(-50%) scale(1); box-shadow: 0 0 60px rgba(255, 215, 0, 0.8); }
50% { transform: translateX(-50%) scale(1.05); box-shadow: 0 0 80px rgba(255, 215, 0, 0.9); }
}
@keyframes rayRotate {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes snowFall {
0% { transform: translateY(0) translateX(0); opacity: 0; }
10% { opacity: 1; }
100% { transform: translateY(500px) translateX(20px); opacity: 0; }
}
/* 响应式设计 */
@media (max-width: 1200px) {
.container {
gap: 1.5rem;
}
.card {
width: 300px;
height: 400px;
}
}
@media (max-width: 768px) {
.container {
flex-direction: column;
align-items: center;
}
.card {
width: 100%;
max-width: 400px;
}
.controls {
flex-direction: column;
align-items: center;
}
.weather-btn {
width: 100%;
max-width: 300px;
}
}
</style>
</head>
<body>
<div class="header">
<h1>国家级精品天气应用</h1>
<p>采用高级动画效果展示不同天气状况,为您提供沉浸式的天气体验</p>
</div>
<div class="container">
<div class="card wind-card">
<div class="card-title">风力</div>
<div class="card-content">
<div class="wind">
<div class="cloud"></div>
<div class="tree">
<div class="trunk"></div>
<div class="leaves"></div>
</div>
</div>
</div>
</div>
<div class="card rain-card">
<div class="card-title">降雨</div>
<div class="card-content">
<div class="rain"></div>
</div>
</div>
<div class="card sunny-card">
<div class="card-title">晴天</div>
<div class="card-content">
<div class="sun"></div>
<div class="sun-ray"></div>
<div class="sun-ray"></div>
<div class="sun-ray"></div>
<div class="sun-ray"></div>
<div class="sun-ray"></div>
<div class="sun-ray"></div>
<div class="sun-ray"></div>
</div>
</div>
<div class="card snow-card">
<div class="card-title">下雪</div>
<div class="card-content">
<div class="snow">
<div class="snow-ground"></div>
<div class="snow-hill"></div>
<div class="snow-hill"></div>
<div class="snow-hill"></div>
</div>
</div>
</div>
</div>
<div class="controls">
<button class="weather-btn active" data-weather="all">全部天气</button>
<button class="weather-btn" data-weather="wind">风力</button>
<button class="weather-btn" data-weather="rain">降雨</button>
<button class="weather-btn" data-weather="sun">晴天</button>
<button class="weather-btn" data-weather="snow">下雪</button>
</div>
<script>
// 创建动态元素(雨滴、风线、雪花)
function createDynamicElements() {
// 创建风线
const windContainer = document.querySelector('.wind');
for (let i = 0; i < 15; i++) {
const windLine = document.createElement('div');
windLine.className = 'wind-line';
windLine.style.top = `${Math.random() * 100}%`;
windLine.style.animationDelay = `${Math.random() * 3}s`;
windContainer.appendChild(windLine);
}
// 创建雨滴
const rainContainer = document.querySelector('.rain');
for (let i = 0; i < 60; i++) {
const rainDrop = document.createElement('div');
rainDrop.className = 'rain-drop';
rainDrop.style.left = `${Math.random() * 100}%`;
rainDrop.style.animationDuration = `${0.5 + Math.random() * 1}s`;
rainDrop.style.animationDelay = `${Math.random() * 5}s`;
rainContainer.appendChild(rainDrop);
// 每20滴雨创建一个小水洼
if (i % 20 === 0) {
const puddle = document.createElement('div');
puddle.className = 'puddle';
puddle.style.left = `${5 + Math.random() * 90}%`;
rainContainer.appendChild(puddle);
}
}
// 创建雪花
const snowContainer = document.querySelector('.snow');
for (let i = 0; i < 80; i++) {
const snowflake = document.createElement('div');
snowflake.className = 'snowflake';
snowflake.innerHTML = '❄';
snowflake.style.left = `${Math.random() * 100}%`;
snowflake.style.animationDuration = `${5 + Math.random() * 10}s`;
snowflake.style.animationDelay = `${Math.random() * 5}s`;
snowflake.style.fontSize = `${10 + Math.random() * 20}px`;
snowContainer.appendChild(snowflake);
}
}
// 天气切换功能
function setupWeatherControls() {
const buttons = document.querySelectorAll('.weather-btn');
const cards = document.querySelectorAll('.card');
buttons.forEach(button => {
button.addEventListener('click', () => {
const weatherType = button.dataset.weather;
// 更新按钮状态
buttons.forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
// 更新卡片显示状态
cards.forEach(card => {
if (weatherType === 'all') {
card.style.display = 'block';
} else {
card.style.display =
card.classList.contains(`${weatherType}-card`) ? 'block' : 'none';
}
});
});
});
}
// 初始化
document.addEventListener('DOMContentLoaded', () => {
createDynamicElements();
setupWeatherControls();
});
</script>
</body>
</html>
```
## 代码解释
### 设计特点
1. **深色渐变背景**:使用深蓝色渐变背景提升视觉高级感
2. **玻璃拟态卡片**:半透明卡片配合模糊效果和微妙边框
3. **精致动画效果**:
- 风力:飘动的云朵 + 摇曳的树木 + 流动的风线
- 降雨:随机下落的雨滴 + 动态水洼效果
- 晴天:脉动的太阳 + 旋转光线
- 下雪:飘落的雪花 + 积雪效果
4. **流畅交互**:卡片悬停效果和天气切换按钮
5. **响应式设计**:适配各种屏幕尺寸
### JavaScript功能
1. `createDynamicElements()`:动态生成雨滴、风线和雪花元素
2. `setupWeatherControls()`:实现天气切换功能
- 点击按钮可查看特定天气或全部天气
- 按钮状态视觉反馈
- 卡片动态显示/隐藏
### CSS动画技巧
1. 使用关键帧动画实现自然运动效果
2. 随机延迟和持续时间创造更真实的自然现象
3. 渐变和阴影增强深度感
4. 变换和过渡实现平滑交互效果
这个实现完全符合要求,展示了四种天气状态的不同动画效果,所有卡片并排显示在深色背景上,并提供了天气切换功能。视觉效果精致流畅,达到了国家级精品天气应用的水平。