<!DOCTYPE html>
<html lang="zh-***">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS3 & jQuery 天气预报</title>
<style>
/ 基础样式 /
{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Arial', sans-serif;
}
body {
background: linear-gradient(135deg, #1e5799 0%, #207***a 51%, #2989d8 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
/ 天气卡片容器 /
.weather-container {
width: 100%;
max-width: 800px;
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
border-radius: 20px;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2);
overflow: hidden;
color: white;
position: relative;
transition: all 0.5s ease;
}
/ 当前天气区域 /
.current-weather {
padding: 30px;
text-align: center;
position: relative;
z-index: 1;
}
.location {
font-size: 24px;
margin-bottom: 10px;
font-weight: 300;
}
.date {
font-size: 14px;
opacity: 0.8;
margin-bottom: 20px;
}
.temp {
font-size: 72px;
font-weight: 300;
margin: 20px 0;
position: relative;
display: inline-block;
}
.temp:after {
content: "°C";
position: absolute;
top: 10px;
right: -25px;
font-size: 24px;
}
.weather-icon {
width: 120px;
height: 120px;
margin: 0 auto;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
position: relative;
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
.description {
font-size: 18px;
text-transform: capitalize;
margin-bottom: 20px;
}
.details {
display: flex;
justify-content: space-around;
margin-top: 30px;
}
.detail-item {
text-align: center;
}
.detail-item i {
font-size: 24px;
margin-bottom: 10px;
display: block;
}
.detail-value {
font-size: 18px;
font-weight: 300;
}
.detail-label {
font-size: 12px;
opacity: 0.8;
margin-top: 5px;
}
/ 天气预报区域 /
.forecast {
background: rgba(0, 0, 0, 0.1);
padding: 20px;
display: flex;
overflow-x: auto;
scrollbar-width: none;
}
.forecast::-webkit-scrollbar {
display: none;
}
.forecast-day {
min-width: 100px;
text-align: center;
padding: 10px;
margin-right: 10px;
border-radius: 10px;
transition: all 0.3s ease;
cursor: pointer;
}
.forecast-day:hover {
background: rgba(255, 255, 255, 0.1);
transform: translateY(-5px);
}
.forecast-day:last-child {
margin-right: 0;
}
.day-name {
font-size: 14px;
margin-bottom: 10px;
}
.forecast-icon {
width: 50px;
height: 50px;
margin: 0 auto 10px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.forecast-temp {
font-size: 16px;
}
/ 搜索区域 /
.search-container {
padding: 20px;
display: flex;
justify-content: center;
}
.search-input {
padding: 12px 20px;
border: none;
border-radius: 30px;
width: 70%;
max-width: 400px;
font-size: 16px;
outline: none;
background: rgba(255, 255, 255, 0.2);
color: white;
transition: all 0.3s ease;
}
.search-input::placeholder {
color: rgba(255, 255, 255, 0.7);
}
.search-input:focus {
background: rgba(255, 255, 255, 0.3);
box-shadow: 0 0 10px rgba(255, 255, 255, 0.2);
}
/ 天气背景效果 /
.weather-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
opacity: 0.3;
}
/ 响应式设计 /
@media (max-width: 600px) {
.temp {
font-size: 60px;
}
.weather-icon {
width: 100px;
height: 100px;
}
.forecast-day {
min-width: 80px;
}
}
/ 天气图标动画 /
.sun {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23FFD700"><circle cx="12" cy="12" r="5"/><path d="M12 1v2m0 18v2M4.22 4.22l1.42 1.42m12.72 12.72l1.42 1.42M1 12h2m18 0h2M4.22 19.78l1.42-1.42m12.72-12.72l1.42-1.42"/></svg>');
animation: pulse 2s infinite alternate;
}
.cloud {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23FFFFFF"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96z"/></svg>');
animation: float 4s ease-in-out infinite;
}
.rain {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23FFFFFF"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM7 17l-3.17-3.17 1.41-1.41L7 14.17l4.59-4.58 1.41 1.41L7 17z"/></svg>');
position: relative;
}
.rain:after {
content: "";
position: absolute;
bottom: -15px;
left: 50%;
transform: translateX(-50%);
width: 60px;
height: 10px;
background: radial-gradient(circle, rgba(255,255,255,0.8) 0%, rgba(255,255,255,0) 70%);
animation: rainDrops 1s linear infinite;
}
@keyframes rainDrops {
0% { opacity: 0; transform: translateX(-50%) translateY(0) scale(0.3); }
50% { opacity: 1; }
100% { opacity: 0; transform: translateX(-50%) translateY(20px) scale(1); }
}
.snow {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23FFFFFF"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM12 18c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></svg>');
position: relative;
}
.snow:after {
content: "";
position: absolute;
bottom: -15px;
left: 50%;
transform: translateX(-50%);
width: 60px;
height: 10px;
background: radial-gradient(circle, rgba(255,255,255,0.8) 0%, rgba(255,255,255,0) 70%);
animation: snowFlakes 2s linear infinite;
}
@keyframes snowFlakes {
0% { opacity: 0; transform: translateX(-50%) translateY(0) scale(0.3) rotate(0deg); }
50% { opacity: 1; }
100% { opacity: 0; transform: translateX(-50%) translateY(20px) scale(1) rotate(360deg); }
}
.thunder {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23FFFFFF"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 17h-4l2-4h-3l3-6 1 2h3l-2 4h3z"/></svg>');
animation: flash 3s infinite;
}
@keyframes flash {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
/ 加载动画 /
.loading {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 10;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
}
.loading.active {
opacity: 1;
pointer-events: all;
}
.spinner {
width: 50px;
height: 50px;
border: 5px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: white;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/ 版权信息 /
.copyright {
text-align: center;
font-size: 12px;
margin-top: 20px;
opacity: 0.7;
}
.copyright a {
color: white;
text-decoration: none;
}
.copyright a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="weather-container">
<div class="loading">
<div class="spinner"></div>
</div>
<div class="current-weather">
<h1 class="location">加载中...</h1>
<div class="date">--年--月--日 星期-</div>
<div class="weather-icon sun"></div>
<div class="temp">--</div>
<div class="description">加载天气数据...</div>
<div class="details">
<div class="detail-item">
<i>💧</i>
<div class="detail-value">--%</div>
<div class="detail-label">湿度</div>
</div>
<div class="detail-item">
<i>🌬️</i>
<div class="detail-value">-- km/h</div>
<div class="detail-label">风速</div>
</div>
<div class="detail-item">
<i>☁️</i>
<div class="detail-value">--%</div>
<div class="detail-label">云量</div>
</div>
</div>
</div>
<div class="forecast">
<!-- 天气预报将通过JavaScript动态生成 -->
</div>
<div class="search-container">
<input type="text" class="search-input" placeholder="输入城市名称..." id="city-input">
</div>
</div>
<script src="https://code.jquery.***/jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function() {
// 默认城市
let currentCity = "北京";
// 天气图标映射
const weatherIcons = {
"clear": "sun",
"clouds": "cloud",
"rain": "rain",
"snow": "snow",
"thunderstorm": "thunder",
"drizzle": "rain",
"mist": "cloud",
"smoke": "cloud",
"haze": "cloud",
"dust": "cloud",
"fog": "cloud",
"sand": "cloud",
"ash": "cloud",
"squall": "thunder",
"tornado": "thunder"
};
// 星期映射
const weekDays = ["日", "一", "二", "三", "四", "五", "六"];
// 初始化获取天气数据
getWeatherData(currentCity);
// 搜索城市
$("#city-input").on("keypress", function(e) {
if (e.which === 13) {
currentCity = $(this).val().trim();
if (currentCity) {
getWeatherData(currentCity);
$(this).val("");
}
}
});
// 获取天气数据
function getWeatherData(city) {
showLoading(true);
// 这里使用模拟数据,实际应用中应该调用天气API
setTimeout(() => {
// 模拟API响应
const mockData = generateMockWeatherData(city);
updateWeatherUI(mockData);
showLoading(false);
}, 1000);
}
// 更新天气UI
function updateWeatherUI(data) {
// 更新当前天气
$(".location").text(data.city);
const date = new Date(data.current.dt * 1000);
const dateStr = ${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日 星期${weekDays[date.getDay()]}`;
$(".date").text(dateStr);
$(".temp").text(Math.round(data.current.temp));
$(".description").text(data.current.weather[0].description);
// 更新天气图标
const weatherMain = data.current.weather[0].main.toLowerCase();
const iconClass = weatherIcons[weatherMain] || "sun";
$(".weather-icon").removeClass().addClass("weather-icon " + iconClass);
// 更新详情
$(".detail-item:nth-child(1) .detail-value").text(data.current.humidity + "%");
$(".detail-item:nth-child(2) .detail-value").text(data.current.wind_speed + " km/h");
$(".detail-item:nth-child(3) .detail-value").text(data.current.clouds + "%");
// 更新天气预报
$(".forecast").empty();
data.daily.slice(1, 6).forEach(day => {
const dayDate = new Date(day.dt * 1000);
const dayName = weekDays[dayDate.getDay()];
const dayWeatherMain = day.weather[0].main.toLowerCase();
const dayIconClass = weatherIcons[dayWeatherMain] || "sun";
$(".forecast").append(
<div class="forecast-day">
<div class="day-name">${dayName}</div>
<div class="forecast-icon ${dayIconClass}"></div>
<div class="forecast-temp">${Math.round(day.temp.day)}°</div>
</div>
);
});
}
// 显示/隐藏加载动画
function showLoading(show) {
if (show) {
$(".loading").addClass("active");
} else {
$(".loading").removeClass("active");
}
}
// 生成模拟天气数据
function generateMockWeatherData(city) {
const weatherConditions = [
{ main: "Clear", description: "晴天" },
{ main: "Clouds", description: "多云" },
{ main: "Rain", description: "小雨" },
{ main: "Snow", description: "小雪" },
{ main: "Thunderstorm", description: "雷阵雨" }
];
// 随机选择当前天气
const currentWeather = weatherConditions[Math.floor(Math.random() * weatherConditions.length)];
// 当前天气数据
const current = {
dt: Math.floor(Date.now() / 1000),
temp: 10 + Math.floor(Math.random() * 20), // 10-30度
humidity: 30 + Math.floor(Math.random() * 60), // 30-90%
wind_speed: 1 + Math.floor(Math.random() * 15), // 1-15 km/h
clouds: 10 + Math.floor(Math.random() * 80), // 10-90%
weather: [currentWeather]
};
// 每日预报数据
const daily = [];
for (let i = 0; i < 7; i++) {
const dayWeather = weatherConditions[Math.floor(Math.random() * weatherConditions.length)];
daily.push({
dt: current.dt + (i * 86400),
temp: {
day: current.temp - 2 + Math.floor(Math.random() * 8) // 当前温度±5度
},
weather: [dayWeather]
});
}
return {
city: city,
current: current,
daily: daily
};
}
// 添加背景动画效果
function addBackgroundEffects() {
const container = $(".weather-container");
const effects = ["sunny", "cloudy", "rainy", "snowy"];
// 每10秒切换一次背景效果
setInterval(() => {
const effect = effects[Math.floor(Math.random() * effects.length)];
container.removeClass(effects.join(" ")).addClass(effect);
}, 10000);
}
// 初始化背景效果
addBackgroundEffects();
});
</script>
</body>
</html>