DeepSeek V4 Pro 前端表现-天气卡片
- 内容介绍
- 文章标签
- 相关推荐
以 iOS 18 的设计风格做一个带有动画效果的天气卡片,要求是使用 HTML、CSS 和基础 JavaScript,使用横板天气页面(拥有 4 个天气卡片 (晴天,大风,暴雨,暴雪))。应足够美观,实现一定的交互效果。
image1264×533 53.4 KB
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>iOS 18 天气卡片</title>
<style>
:root {
--card-radius: 24px;
--transition-speed: 0.4s;
--bg-gradient-start: #e8eef5;
--bg-gradient-mid: #dce4f0;
--bg-gradient-end: #eef1f7;
--sunny-accent: #f59e4b;
--sunny-bg: #fff8f0;
--sunny-glow: #ffe4c4;
--windy-accent: #7b9eb3;
--windy-bg: #f2f6f9;
--windy-glow: #d4e2ec;
--storm-accent: #5b6e8a;
--storm-bg: #f0f2f7;
--storm-glow: #c8d6e5;
--snow-accent: #a3bfd4;
--snow-bg: #f4f8fb;
--snow-glow: #e2eef7;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', 'PingFang SC', 'Helvetica Neue', sans-serif;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(160deg, #dfe9f3 0%, #e8eef5 20%, #f0f4f8 40%, #eef2f6 60%, #e4ebf3 80%, #dce5ef 100%);
background-attachment: fixed;
position: relative;
overflow-x: hidden;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding: 20px;
}
/* 背景光晕动画 */
.bg-orb {
position: fixed;
border-radius: 50%;
filter: blur(120px);
opacity: 0.35;
pointer-events: none;
z-index: 0;
animation: orbDrift 20s ease-in-out infinite;
}
.bg-orb.orb-1 {
width: 500px;
height: 500px;
background: #ffe4c4;
top: -15%;
left: -10%;
animation-delay: 0s;
}
.bg-orb.orb-2 {
width: 400px;
height: 400px;
background: #c8ddf0;
top: 50%;
right: -8%;
animation-delay: -7s;
animation-duration: 24s;
}
.bg-orb.orb-3 {
width: 350px;
height: 350px;
background: #e8d5f5;
bottom: -12%;
left: 30%;
animation-delay: -14s;
animation-duration: 22s;
}
@keyframes orbDrift {
0%,
100% {
transform: translate(0, 0) scale(1);
}
25% {
transform: translate(60px, -40px) scale(1.08);
}
50% {
transform: translate(-30px, 30px) scale(0.94);
}
75% {
transform: translate(-50px, -20px) scale(1.05);
}
}
/* 主容器 */
.main-container {
position: relative;
z-index: 1;
width: 100%;
max-width: 1350px;
display: flex;
flex-direction: column;
gap: 20px;
}
/* 顶部标题栏 */
.header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 8px 4px;
flex-wrap: wrap;
gap: 12px;
}
.header .location-group {
display: flex;
align-items: center;
gap: 10px;
}
.header .location-icon {
width: 36px;
height: 36px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.55);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
border: 1px solid rgba(255, 255, 255, 0.6);
}
.header .location-name {
font-size: 1.5rem;
font-weight: 600;
color: #1d1d1f;
letter-spacing: -0.02em;
}
.header .date-text {
font-size: 0.95rem;
color: #6e6e73;
font-weight: 500;
padding: 8px 16px;
background: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.55);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
}
/* 卡片网格 */
.cards-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 18px;
width: 100%;
}
/* 单张卡片 */
.weather-card {
position: relative;
background: rgba(255, 255, 255, 0.48);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
border-radius: var(--card-radius);
border: 1px solid rgba(255, 255, 255, 0.65);
box-shadow:
0 4px 20px rgba(0, 0, 0, 0.06),
0 1px 3px rgba(0, 0, 0, 0.04),
inset 0 1px 0 rgba(255, 255, 255, 0.7);
cursor: pointer;
overflow: hidden;
transition:
transform var(--transition-speed) cubic-bezier(0.34, 1.56, 0.64, 1),
box-shadow var(--transition-speed) ease,
border-color var(--transition-speed) ease;
display: flex;
flex-direction: column;
min-height: 420px;
user-select: none;
-webkit-tap-highlight-color: transparent;
z-index: 1;
}
.weather-card:hover {
transform: translateY(-8px);
box-shadow:
0 16px 40px rgba(0, 0, 0, 0.1),
0 4px 12px rgba(0, 0, 0, 0.06),
inset 0 1px 0 rgba(255, 255, 255, 0.8);
border-color: rgba(255, 255, 255, 0.85);
z-index: 5;
}
.weather-card:active {
transform: scale(0.975);
transition: transform 0.15s ease;
}
.weather-card.expanded {
z-index: 10;
box-shadow:
0 24px 55px rgba(0, 0, 0, 0.14),
0 6px 16px rgba(0, 0, 0, 0.07),
inset 0 1px 0 rgba(255, 255, 255, 0.8);
border-color: rgba(255, 255, 255, 0.9);
}
/* 卡片场景区域(天气动画) */
.card-scene {
position: relative;
width: 100%;
height: 220px;
overflow: hidden;
border-radius: var(--card-radius) var(--card-radius) 0 0;
transition: height var(--transition-speed) ease;
}
.weather-card.expanded .card-scene {
height: 200px;
}
/* 场景背景色 */
.card-scene.scene-sunny {
background: linear-gradient(180deg, #ffe8c8 0%, #fff4e4 40%, #fffaf3 100%);
}
.card-scene.scene-windy {
background: linear-gradient(180deg, #dce8f2 0%, #eaf1f7 40%, #f5f8fb 100%);
}
.card-scene.scene-storm {
background: linear-gradient(180deg, #c8d4e2 0%, #dbe3ee 30%, #e8edf5 60%, #f2f4f8 100%);
}
.card-scene.scene-snow {
background: linear-gradient(180deg, #e2eef8 0%, #eef5fa 40%, #f7fafc 100%);
}
/* 场景内的光晕 */
.scene-glow {
position: absolute;
border-radius: 50%;
pointer-events: none;
filter: blur(40px);
opacity: 0.5;
animation: glowPulse 4s ease-in-out infinite;
}
.scene-sunny .scene-glow {
width: 120px;
height: 120px;
background: #fcc870;
top: 30px;
left: 50%;
transform: translateX(-50%);
animation-duration: 3.5s;
}
.scene-windy .scene-glow {
width: 100px;
height: 60px;
background: #b8cfdf;
top: 60px;
left: 30%;
animation-duration: 5s;
}
.scene-storm .scene-glow {
width: 90px;
height: 90px;
background: #8899b5;
top: 50px;
left: 45%;
animation-duration: 2.8s;
opacity: 0.4;
}
.scene-snow .scene-glow {
width: 110px;
height: 110px;
background: #c8dff0;
top: 40px;
left: 50%;
transform: translateX(-50%);
animation-duration: 4.5s;
}
@keyframes glowPulse {
0%,
100% {
opacity: 0.4;
transform: translateX(-50%) scale(1);
}
50% {
opacity: 0.7;
transform: translateX(-50%) scale(1.2);
}
}
/* -------- 太阳 (晴天) -------- */
.sun-container {
position: absolute;
top: 38px;
left: 50%;
transform: translateX(-50%);
width: 80px;
height: 80px;
z-index: 3;
}
.sun-core {
position: absolute;
width: 52px;
height: 52px;
background: radial-gradient(circle at 40% 38%, #fff7c2 0%, #fdb833 55%, #f08c20 100%);
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
box-shadow:
0 0 50px rgba(253, 165, 40, 0.55),
0 0 100px rgba(253, 165, 40, 0.3),
0 0 160px rgba(253, 165, 40, 0.15);
animation: sunPulse 3s ease-in-out infinite;
z-index: 2;
}
@keyframes sunPulse {
0%,
100% {
box-shadow: 0 0 50px rgba(253, 165, 40, 0.55), 0 0 100px rgba(253, 165, 40, 0.3), 0 0 160px rgba(253, 165, 40, 0.15);
}
50% {
box-shadow: 0 0 70px rgba(253, 165, 40, 0.7), 0 0 130px rgba(253, 165, 40, 0.4), 0 0 190px rgba(253, 165, 40, 0.22);
}
}
.sun-ray {
position: absolute;
top: 50%;
left: 50%;
width: 4px;
height: 28px;
background: rgba(253, 180, 50, 0.5);
border-radius: 4px;
transform-origin: center bottom;
animation: rayRotate 12s linear infinite;
}
.sun-ray:nth-child(2) {
transform: rotate(0deg) translateY(-40px);
animation-delay: 0s;
height: 30px;
}
.sun-ray:nth-child(3) {
transform: rotate(45deg) translateY(-40px);
animation-delay: -1.5s;
height: 26px;
}
.sun-ray:nth-child(4) {
transform: rotate(90deg) translateY(-40px);
animation-delay: -3s;
height: 32px;
}
.sun-ray:nth-child(5) {
transform: rotate(135deg) translateY(-40px);
animation-delay: -4.5s;
height: 24px;
}
.sun-ray:nth-child(6) {
transform: rotate(180deg) translateY(-40px);
animation-delay: -6s;
height: 30px;
}
.sun-ray:nth-child(7) {
transform: rotate(225deg) translateY(-40px);
animation-delay: -7.5s;
height: 27px;
}
.sun-ray:nth-child(8) {
transform: rotate(270deg) translateY(-40px);
animation-delay: -9s;
height: 33px;
}
.sun-ray:nth-child(9) {
transform: rotate(315deg) translateY(-40px);
animation-delay: -10.5s;
height: 25px;
}
@keyframes rayRotate {
from {
transform: rotate(var(--r, 0deg)) translateY(-40px) rotate(0deg);
}
to {
transform: rotate(var(--r, 0deg)) translateY(-40px) rotate(360deg);
}
}
/* 为每条光线设置旋转变量 */
.sun-ray:nth-child(2) {
--r: 0deg;
}
.sun-ray:nth-child(3) {
--r: 45deg;
}
.sun-ray:nth-child(4) {
--r: 90deg;
}
.sun-ray:nth-child(5) {
--r: 135deg;
}
.sun-ray:nth-child(6) {
--r: 180deg;
}
.sun-ray:nth-child(7) {
--r: 225deg;
}
.sun-ray:nth-child(8) {
--r: 270deg;
}
.sun-ray:nth-child(9) {
--r: 315deg;
}
/* 晴天小云朵 */
.tiny-cloud-sunny {
position: absolute;
bottom: 35px;
right: 28px;
z-index: 4;
animation: cloudFloat 6s ease-in-out infinite;
}
@keyframes cloudFloat {
0%,
100% {
transform: translateX(0);
}
50% {
transform: translateX(14px);
}
}
/* -------- 云 (CSS绘制) -------- */
.cloud-css {
position: relative;
width: 70px;
height: 32px;
background: rgba(255, 255, 255, 0.85);
border-radius: 32px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
}
.cloud-css::before {
content: '';
position: absolute;
width: 34px;
height: 34px;
background: rgba(255, 255, 255, 0.85);
border-radius: 50%;
top: -18px;
left: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
}
.cloud-css::after {
content: '';
position: absolute;
width: 26px;
height: 26px;
background: rgba(255, 255, 255, 0.8);
border-radius: 50%;
top: -10px;
left: 38px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.03);
}
/* -------- 大风场景 -------- */
.wind-cloud-group {
position: absolute;
top: 40px;
left: 50%;
transform: translateX(-50%);
z-index: 3;
}
.wind-lines {
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 5;
}
.wind-line {
position: absolute;
height: 3px;
background: rgba(140, 170, 195, 0.55);
border-radius: 3px;
animation: windBlow linear infinite;
opacity: 0;
}
.wind-line.wl-1 {
top: 90px;
left: 10%;
width: 50px;
animation-duration: 2.2s;
animation-delay: 0s;
}
.wind-line.wl-2 {
top: 110px;
left: 20%;
width: 70px;
animation-duration: 2.8s;
animation-delay: 0.6s;
}
.wind-line.wl-3 {
top: 130px;
left: 5%;
width: 40px;
animation-duration: 1.9s;
animation-delay: 1.2s;
}
.wind-line.wl-4 {
top: 100px;
left: 30%;
width: 60px;
animation-duration: 2.5s;
animation-delay: 1.8s;
}
.wind-line.wl-5 {
top: 145px;
left: 15%;
width: 35px;
animation-duration: 3.1s;
animation-delay: 0.3s;
}
.wind-line.wl-6 {
top: 120px;
left: 8%;
width: 55px;
animation-duration: 2.4s;
animation-delay: 2s;
}
@keyframes windBlow {
0% {
transform: translateX(-30px);
opacity: 0;
}
15% {
opacity: 0.7;
}
70% {
opacity: 0.6;
}
100% {
transform: translateX(calc(100% + 60px));
opacity: 0;
}
}
/* -------- 暴雨场景 -------- */
.storm-cloud-group {
position: absolute;
top: 28px;
left: 50%;
transform: translateX(-50%);
z-index: 3;
}
.storm-cloud-group .cloud-css {
background: rgba(180, 195, 215, 0.75);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}
.storm-cloud-group .cloud-css::before,
.storm-cloud-group .cloud-css::after {
background: rgba(180, 195, 215, 0.75);
}
.raindrops {
position: absolute;
top: 60px;
left: 0;
width: 100%;
height: calc(100% - 60px);
pointer-events: none;
z-index: 4;
}
.raindrop {
position: absolute;
width: 2px;
height: 16px;
background: linear-gradient(to bottom, rgba(120, 150, 185, 0.3), rgba(100, 140, 180, 0.7));
border-radius: 0 0 4px 4px;
animation: rainFall linear infinite;
opacity: 0;
}
.raindrop.rd-1 {
left: 18%;
animation-duration: .7s;
animation-delay: 0s;
}
.raindrop.rd-2 {
left: 30%;
animation-duration: .85s;
animation-delay: 0.15s;
}
.raindrop.rd-3 {
left: 42%;
animation-duration: .65s;
animation-delay: 0.3s;
}
.raindrop.rd-4 {
left: 54%;
animation-duration: .9s;
animation-delay: 0.45s;
}
.raindrop.rd-5 {
left: 65%;
animation-duration: .75s;
animation-delay: 0.1s;
}
.raindrop.rd-6 {
left: 22%;
animation-duration: .8s;
animation-delay: 0.5s;
}
.raindrop.rd-7 {
left: 48%;
animation-duration: .7s;
animation-delay: 0.35s;
}
.raindrop.rd-8 {
left: 60%;
animation-duration: .95s;
animation-delay: 0.25s;
}
.raindrop.rd-9 {
left: 35%;
animation-duration: .78s;
animation-delay: 0.55s;
}
.raindrop.rd-10 {
left: 70%;
animation-duration: .72s;
animation-delay: 0.4s;
}
@keyframes rainFall {
0% {
transform: translateY(-30px);
opacity: 0;
}
10% {
opacity: 0.8;
}
85% {
opacity: 0.5;
}
100% {
transform: translateY(150px);
opacity: 0;
}
}
/* 闪电 */
.lightning {
position: absolute;
top: 55px;
left: 40%;
width: 3px;
height: 50px;
background: rgba(255, 255, 220, 0.9);
border-radius: 2px;
z-index: 5;
opacity: 0;
animation: lightningFlash 4s ease-in-out infinite;
filter: blur(1px);
box-shadow: 0 0 20px rgba(255, 255, 200, 0.7), 0 0 40px rgba(255, 255, 180, 0.4);
}
.lightning::after {
content: '';
position: absolute;
top: 20px;
left: 6px;
width: 2px;
height: 25px;
background: rgba(255, 255, 210, 0.8);
border-radius: 2px;
transform: rotate(25deg);
}
@keyframes lightningFlash {
0%,
90%,
96%,
100% {
opacity: 0;
}
91% {
opacity: 0.9;
}
92% {
opacity: 0.2;
}
93% {
opacity: 0.85;
}
94% {
opacity: 0.1;
}
95% {
opacity: 0.6;
}
}
/* -------- 暴雪场景 -------- */
.snow-cloud-group {
position: absolute;
top: 30px;
left: 50%;
transform: translateX(-50%);
z-index: 3;
}
.snow-cloud-group .cloud-css {
background: rgba(225, 235, 245, 0.8);
}
.snow-cloud-group .cloud-css::before,
.snow-cloud-group .cloud-css::after {
background: rgba(225, 235, 245, 0.8);
}
.snowflakes {
position: absolute;
top: 55px;
left: 0;
width: 100%;
height: calc(100% - 55px);
pointer-events: none;
z-index: 5;
}
.snowflake {
position: absolute;
background: rgba(255, 255, 255, 0.9);
border-radius: 50%;
animation: snowFall linear infinite;
opacity: 0;
box-shadow: 0 0 6px rgba(255, 255, 255, 0.5);
}
.snowflake.sf-1 {
left: 15%;
width: 6px;
height: 6px;
animation-duration: 3.5s;
animation-delay: 0s;
}
.snowflake.sf-2 {
left: 28%;
width: 4px;
height: 4px;
animation-duration: 4.2s;
animation-delay: 0.8s;
}
.snowflake.sf-3 {
left: 40%;
width: 7px;
height: 7px;
animation-duration: 3.8s;
animation-delay: 1.5s;
}
.snowflake.sf-4 {
left: 55%;
width: 5px;
height: 5px;
animation-duration: 4.6s;
animation-delay: 0.4s;
}
.snowflake.sf-5 {
left: 68%;
width: 6px;
height: 6px;
animation-duration: 3.3s;
animation-delay: 2s;
}
.snowflake.sf-6 {
left: 20%;
width: 3px;
height: 3px;
animation-duration: 5s;
animation-delay: 1.1s;
}
.snowflake.sf-7 {
left: 48%;
width: 5px;
height: 5px;
animation-duration: 3.9s;
animation-delay: 2.5s;
}
.snowflake.sf-8 {
left: 62%;
width: 7px;
height: 7px;
animation-duration: 4.4s;
animation-delay: 0.7s;
}
.snowflake.sf-9 {
left: 33%;
width: 4px;
height: 4px;
animation-duration: 4.8s;
animation-delay: 0.2s;
}
.snowflake.sf-10 {
left: 72%;
width: 5px;
height: 5px;
animation-duration: 3.6s;
animation-delay: 1.8s;
}
@keyframes snowFall {
0% {
transform: translateY(-25px) translateX(0) rotate(0deg);
opacity: 0;
}
10% {
opacity: 0.9;
}
50% {
transform: translateY(60px) translateX(18px) rotate(180deg);
opacity: 0.7;
}
90% {
opacity: 0.3;
}
100% {
transform: translateY(155px) translateX(-10px) rotate(360deg);
opacity: 0;
}
}
/* 地面微光(暴雪) */
.snow-ground {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 30px;
background: linear-gradient(to top, rgba(220, 235, 250, 0.5) 0%, transparent 100%);
z-index: 1;
border-radius: 0 0 var(--card-radius) 0;
}
/* -------- 卡片信息区域 -------- */
.card-info {
padding: 16px 20px 20px;
display: flex;
flex-direction: column;
gap: 6px;
flex: 1;
position: relative;
z-index: 2;
}
.card-temp {
font-size: 3.2rem;
font-weight: 600;
letter-spacing: -0.03em;
line-height: 1;
color: #1d1d1f;
transition: color var(--transition-speed) ease;
}
.card-temp .degree {
font-size: 1.6rem;
font-weight: 500;
vertical-align: super;
margin-left: 2px;
color: #6e6e73;
}
.card-weather-name {
font-size: 1.15rem;
font-weight: 500;
color: #3a3a3c;
letter-spacing: -0.01em;
}
.card-subtitle {
font-size: 0.85rem;
color: #8e8e93;
font-weight: 400;
}
/* 展开详情 */
.card-details {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px 16px;
max-height: 0;
opacity: 0;
overflow: hidden;
transition:
max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.35s ease,
margin-top 0.4s ease;
margin-top: 0;
}
.weather-card.expanded .card-details {
max-height: 120px;
opacity: 1;
margin-top: 12px;
}
.detail-item {
display: flex;
align-items: center;
gap: 7px;
font-size: 0.82rem;
color: #5c5c5e;
font-weight: 500;
}
.detail-item .detail-icon {
width: 22px;
height: 22px;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
background: rgba(0, 0, 0, 0.04);
flex-shrink: 0;
}
.detail-value {
font-weight: 600;
color: #1d1d1f;
}
/* 卡片选中指示器 */
.card-indicator {
position: absolute;
bottom: 16px;
left: 50%;
transform: translateX(-50%);
width: 32px;
height: 4px;
background: rgba(0, 0, 0, 0.15);
border-radius: 4px;
transition: all var(--transition-speed) ease;
opacity: 0;
}
.weather-card.expanded .card-indicator {
opacity: 1;
width: 40px;
background: rgba(0, 0, 0, 0.25);
}
/* -------- 响应式设计 -------- */
@media (max-width: 1100px) {
.cards-grid {
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
.weather-card {
min-height: 380px;
}
.card-scene {
height: 190px;
}
.card-temp {
font-size: 2.8rem;
}
}
@media (max-width: 640px) {
.cards-grid {
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.weather-card {
min-height: 340px;
}
.card-scene {
height: 160px;
}
.card-temp {
font-size: 2.4rem;
}
.card-info {
padding: 12px 14px 16px;
}
.header .location-name {
font-size: 1.2rem;
}
.header .date-text {
font-size: 0.8rem;
padding: 6px 12px;
}
.sun-container {
top: 25px;
width: 60px;
height: 60px;
}
.sun-core {
width: 38px;
height: 38px;
}
.sun-ray {
height: 18px;
width: 3px;
}
.sun-ray:nth-child(2) {
transform: rotate(0deg) translateY(-28px);
}
.sun-ray:nth-child(3) {
transform: rotate(45deg) translateY(-28px);
}
.sun-ray:nth-child(4) {
transform: rotate(90deg) translateY(-28px);
}
.sun-ray:nth-child(5) {
transform: rotate(135deg) translateY(-28px);
}
.sun-ray:nth-child(6) {
transform: rotate(180deg) translateY(-28px);
}
.sun-ray:nth-child(7) {
transform: rotate(225deg) translateY(-28px);
}
.sun-ray:nth-child(8) {
transform: rotate(270deg) translateY(-28px);
}
.sun-ray:nth-child(9) {
transform: rotate(315deg) translateY(-28px);
}
@keyframes rayRotate {
from {
transform: rotate(var(--r, 0deg)) translateY(-28px) rotate(0deg);
}
to {
transform: rotate(var(--r, 0deg)) translateY(-28px) rotate(360deg);
}
}
.cloud-css {
width: 50px;
height: 22px;
border-radius: 22px;
}
.cloud-css::before {
width: 24px;
height: 24px;
top: -13px;
left: 8px;
}
.cloud-css::after {
width: 18px;
height: 18px;
top: -7px;
left: 28px;
}
}
@media (max-width: 420px) {
.cards-grid {
grid-template-columns: 1fr;
gap: 14px;
}
.weather-card {
min-height: 300px;
flex-direction: row;
border-radius: 20px;
}
.card-scene {
width: 140px;
height: auto;
min-height: 140px;
border-radius: 20px 0 0 20px;
flex-shrink: 0;
}
.card-info {
padding: 16px;
justify-content: center;
}
.card-temp {
font-size: 2.2rem;
}
.weather-card.expanded .card-scene {
height: auto;
}
.card-details {
grid-template-columns: 1fr;
gap: 6px;
}
.weather-card.expanded .card-details {
max-height: 200px;
}
.card-indicator {
bottom: 8px;
}
}
</style>
</head>
<body>
<!-- 背景光晕 -->
<div class="bg-orb orb-1"></div>
<div class="bg-orb orb-2"></div>
<div class="bg-orb orb-3"></div>
<!-- 主容器 -->
<div class="main-container">
<!-- 顶部标题 -->
<div class="header">
<div class="location-group">
<div class="location-icon">📍</div>
<span class="location-name">北京 · 中国</span>
</div>
<span class="date-text" id="dateDisplay"></span>
</div>
<!-- 卡片网格 -->
<div class="cards-grid" id="cardsGrid">
<!-- 晴天卡片 -->
<div class="weather-card" data-weather="sunny">
<div class="card-scene scene-sunny">
<div class="scene-glow"></div>
<div class="sun-container">
<div class="sun-core"></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 class="sun-ray"></div>
</div>
<div class="tiny-cloud-sunny">
<div class="cloud-css" style="width:50px;height:22px;border-radius:22px;"></div>
</div>
</div>
<div class="card-info">
<div class="card-temp">28<span class="degree">°C</span></div>
<div class="card-weather-name">☀️ 晴天</div>
<div class="card-subtitle">阳光明媚 · 适合出行</div>
<div class="card-details">
<div class="detail-item">
<span class="detail-icon">🌡️</span>
<span>体感 <span class="detail-value">30°</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">💧</span>
<span>湿度 <span class="detail-value">35%</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">☀️</span>
<span>紫外线 <span class="detail-value">强</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">🍃</span>
<span>风速 <span class="detail-value">2级</span></span>
</div>
</div>
<div class="card-indicator"></div>
</div>
</div>
<!-- 大风卡片 -->
<div class="weather-card" data-weather="windy">
<div class="card-scene scene-windy">
<div class="scene-glow"></div>
<div class="wind-cloud-group">
<div class="cloud-css" style="width:65px;height:28px;border-radius:28px;"></div>
</div>
<div class="wind-lines">
<div class="wind-line wl-1"></div>
<div class="wind-line wl-2"></div>
<div class="wind-line wl-3"></div>
<div class="wind-line wl-4"></div>
<div class="wind-line wl-5"></div>
<div class="wind-line wl-6"></div>
</div>
</div>
<div class="card-info">
<div class="card-temp">15<span class="degree">°C</span></div>
<div class="card-weather-name">💨 大风</div>
<div class="card-subtitle">风力强劲 · 注意保暖</div>
<div class="card-details">
<div class="detail-item">
<span class="detail-icon">🌡️</span>
<span>体感 <span class="detail-value">10°</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">💧</span>
<span>湿度 <span class="detail-value">48%</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">💨</span>
<span>阵风 <span class="detail-value">7级</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">🍃</span>
<span>风速 <span class="detail-value">5级</span></span>
</div>
</div>
<div class="card-indicator"></div>
</div>
</div>
<!-- 暴雨卡片 -->
<div class="weather-card" data-weather="storm">
<div class="card-scene scene-storm">
<div class="scene-glow"></div>
<div class="storm-cloud-group">
<div class="cloud-css" style="width:72px;height:30px;border-radius:30px;"></div>
</div>
<div class="lightning"></div>
<div class="raindrops">
<div class="raindrop rd-1"></div>
<div class="raindrop rd-2"></div>
<div class="raindrop rd-3"></div>
<div class="raindrop rd-4"></div>
<div class="raindrop rd-5"></div>
<div class="raindrop rd-6"></div>
<div class="raindrop rd-7"></div>
<div class="raindrop rd-8"></div>
<div class="raindrop rd-9"></div>
<div class="raindrop rd-10"></div>
</div>
</div>
<div class="card-info">
<div class="card-temp">18<span class="degree">°C</span></div>
<div class="card-weather-name">⛈️ 暴雨</div>
<div class="card-subtitle">雷电交加 · 减少外出</div>
<div class="card-details">
<div class="detail-item">
<span class="detail-icon">🌡️</span>
<span>体感 <span class="detail-value">16°</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">💧</span>
<span>湿度 <span class="detail-value">92%</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">🌧️</span>
<span>降水量 <span class="detail-value">45mm</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">⚡</span>
<span>雷电 <span class="detail-value">频繁</span></span>
</div>
</div>
<div class="card-indicator"></div>
</div>
</div>
<!-- 暴雪卡片 -->
<div class="weather-card" data-weather="snow">
<div class="card-scene scene-snow">
<div class="scene-glow"></div>
<div class="snow-cloud-group">
<div class="cloud-css" style="width:68px;height:29px;border-radius:29px;"></div>
</div>
<div class="snowflakes">
<div class="snowflake sf-1"></div>
<div class="snowflake sf-2"></div>
<div class="snowflake sf-3"></div>
<div class="snowflake sf-4"></div>
<div class="snowflake sf-5"></div>
<div class="snowflake sf-6"></div>
<div class="snowflake sf-7"></div>
<div class="snowflake sf-8"></div>
<div class="snowflake sf-9"></div>
<div class="snowflake sf-10"></div>
</div>
<div class="snow-ground"></div>
</div>
<div class="card-info">
<div class="card-temp">-5<span class="degree">°C</span></div>
<div class="card-weather-name">❄️ 暴雪</div>
<div class="card-subtitle">大雪纷飞 · 注意防寒</div>
<div class="card-details">
<div class="detail-item">
<span class="detail-icon">🌡️</span>
<span>体感 <span class="detail-value">-9°</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">💧</span>
<span>湿度 <span class="detail-value">78%</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">❄️</span>
<span>降雪量 <span class="detail-value">25mm</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">🌬️</span>
<span>能见度 <span class="detail-value">0.5km</span></span>
</div>
</div>
<div class="card-indicator"></div>
</div>
</div>
</div>
</div>
<script>
(function() {
// 日期更新
const dateDisplay = document.getElementById('dateDisplay');
const now = new Date();
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
const weekday = weekdays[now.getDay()];
const month = now.getMonth() + 1;
const day = now.getDate();
dateDisplay.textContent = `${weekday} · ${month}月${day}日`;
// 卡片展开/收起逻辑
const cardsGrid = document.getElementById('cardsGrid');
const cards = cardsGrid.querySelectorAll('.weather-card');
let currentlyExpanded = null;
cards.forEach(card => {
card.addEventListener('click', function(e) {
// 如果点击的是已展开的卡片,则收起
if (this === currentlyExpanded) {
this.classList.remove('expanded');
currentlyExpanded = null;
return;
}
// 收起之前展开的卡片
if (currentlyExpanded) {
currentlyExpanded.classList.remove('expanded');
}
// 展开当前卡片
this.classList.add('expanded');
currentlyExpanded = this;
// 添加涟漪效果
createRipple(e, this);
});
// hover时微调动画速度(通过CSS变量)
card.addEventListener('mouseenter', function() {
this.style.setProperty('--transition-speed', '0.35s');
});
card.addEventListener('mouseleave', function() {
this.style.setProperty('--transition-speed', '0.4s');
});
});
// 点击空白区域收起所有卡片
document.addEventListener('click', function(e) {
if (!e.target.closest('.weather-card') && currentlyExpanded) {
currentlyExpanded.classList.remove('expanded');
currentlyExpanded = null;
}
});
// 涟漪效果
function createRipple(event, card) {
const ripple = document.createElement('span');
ripple.className = 'click-ripple';
const rect = card.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
const x = event.clientX - rect.left - size / 2;
const y = event.clientY - rect.top - size / 2;
ripple.style.cssText = `
position: absolute;
width: ${size}px;
height: ${size}px;
left: ${x}px;
top: ${y}px;
border-radius: 50%;
background: rgba(255,255,255,0.35);
pointer-events: none;
z-index: 20;
animation: rippleOut 0.7s ease-out forwards;
`;
card.appendChild(ripple);
ripple.addEventListener('animationend', function() {
ripple.remove();
});
}
// 动态添加涟漪动画的keyframes
const rippleStyle = document.createElement('style');
rippleStyle.textContent = `
@keyframes rippleOut {
0% { transform: scale(0); opacity: 0.6; }
100% { transform: scale(2.5); opacity: 0; }
}
`;
document.head.appendChild(rippleStyle);
// 触摸设备支持
cards.forEach(card => {
card.addEventListener('touchstart', function() {
this.style.transform = 'scale(0.97)';
this.style.transition = 'transform 0.15s ease';
});
card.addEventListener('touchend', function() {
this.style.transform = '';
this.style.transition = '';
});
});
console.log('🌤️ iOS 18 风格天气卡片已就绪');
console.log(' ☀️ 晴天 | 💨 大风 | ⛈️ 暴雨 | ❄️ 暴雪');
console.log(' 💡 点击卡片查看详细天气信息');
})();
</script>
</body>
</html>
网友解答:
--【壹】--:
感觉不是普通, 是低于目前主流模型的水平, 这太阳,这大风,这暴雨,这暴雪
--【贰】--:
感觉效果一般般,没有啥特别惊艳的感觉,那个太阳也太太阳了
--【叁】--:
在哪里可以进行测试呀,我去huggingface 看到了
以 iOS 18 的设计风格做一个带有动画效果的天气卡片,要求是使用 HTML、CSS 和基础 JavaScript,使用横板天气页面(拥有 4 个天气卡片 (晴天,大风,暴雨,暴雪))。应足够美观,实现一定的交互效果。
image1264×533 53.4 KB
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>iOS 18 天气卡片</title>
<style>
:root {
--card-radius: 24px;
--transition-speed: 0.4s;
--bg-gradient-start: #e8eef5;
--bg-gradient-mid: #dce4f0;
--bg-gradient-end: #eef1f7;
--sunny-accent: #f59e4b;
--sunny-bg: #fff8f0;
--sunny-glow: #ffe4c4;
--windy-accent: #7b9eb3;
--windy-bg: #f2f6f9;
--windy-glow: #d4e2ec;
--storm-accent: #5b6e8a;
--storm-bg: #f0f2f7;
--storm-glow: #c8d6e5;
--snow-accent: #a3bfd4;
--snow-bg: #f4f8fb;
--snow-glow: #e2eef7;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', 'PingFang SC', 'Helvetica Neue', sans-serif;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(160deg, #dfe9f3 0%, #e8eef5 20%, #f0f4f8 40%, #eef2f6 60%, #e4ebf3 80%, #dce5ef 100%);
background-attachment: fixed;
position: relative;
overflow-x: hidden;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding: 20px;
}
/* 背景光晕动画 */
.bg-orb {
position: fixed;
border-radius: 50%;
filter: blur(120px);
opacity: 0.35;
pointer-events: none;
z-index: 0;
animation: orbDrift 20s ease-in-out infinite;
}
.bg-orb.orb-1 {
width: 500px;
height: 500px;
background: #ffe4c4;
top: -15%;
left: -10%;
animation-delay: 0s;
}
.bg-orb.orb-2 {
width: 400px;
height: 400px;
background: #c8ddf0;
top: 50%;
right: -8%;
animation-delay: -7s;
animation-duration: 24s;
}
.bg-orb.orb-3 {
width: 350px;
height: 350px;
background: #e8d5f5;
bottom: -12%;
left: 30%;
animation-delay: -14s;
animation-duration: 22s;
}
@keyframes orbDrift {
0%,
100% {
transform: translate(0, 0) scale(1);
}
25% {
transform: translate(60px, -40px) scale(1.08);
}
50% {
transform: translate(-30px, 30px) scale(0.94);
}
75% {
transform: translate(-50px, -20px) scale(1.05);
}
}
/* 主容器 */
.main-container {
position: relative;
z-index: 1;
width: 100%;
max-width: 1350px;
display: flex;
flex-direction: column;
gap: 20px;
}
/* 顶部标题栏 */
.header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 8px 4px;
flex-wrap: wrap;
gap: 12px;
}
.header .location-group {
display: flex;
align-items: center;
gap: 10px;
}
.header .location-icon {
width: 36px;
height: 36px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.55);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
border: 1px solid rgba(255, 255, 255, 0.6);
}
.header .location-name {
font-size: 1.5rem;
font-weight: 600;
color: #1d1d1f;
letter-spacing: -0.02em;
}
.header .date-text {
font-size: 0.95rem;
color: #6e6e73;
font-weight: 500;
padding: 8px 16px;
background: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.55);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
}
/* 卡片网格 */
.cards-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 18px;
width: 100%;
}
/* 单张卡片 */
.weather-card {
position: relative;
background: rgba(255, 255, 255, 0.48);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
border-radius: var(--card-radius);
border: 1px solid rgba(255, 255, 255, 0.65);
box-shadow:
0 4px 20px rgba(0, 0, 0, 0.06),
0 1px 3px rgba(0, 0, 0, 0.04),
inset 0 1px 0 rgba(255, 255, 255, 0.7);
cursor: pointer;
overflow: hidden;
transition:
transform var(--transition-speed) cubic-bezier(0.34, 1.56, 0.64, 1),
box-shadow var(--transition-speed) ease,
border-color var(--transition-speed) ease;
display: flex;
flex-direction: column;
min-height: 420px;
user-select: none;
-webkit-tap-highlight-color: transparent;
z-index: 1;
}
.weather-card:hover {
transform: translateY(-8px);
box-shadow:
0 16px 40px rgba(0, 0, 0, 0.1),
0 4px 12px rgba(0, 0, 0, 0.06),
inset 0 1px 0 rgba(255, 255, 255, 0.8);
border-color: rgba(255, 255, 255, 0.85);
z-index: 5;
}
.weather-card:active {
transform: scale(0.975);
transition: transform 0.15s ease;
}
.weather-card.expanded {
z-index: 10;
box-shadow:
0 24px 55px rgba(0, 0, 0, 0.14),
0 6px 16px rgba(0, 0, 0, 0.07),
inset 0 1px 0 rgba(255, 255, 255, 0.8);
border-color: rgba(255, 255, 255, 0.9);
}
/* 卡片场景区域(天气动画) */
.card-scene {
position: relative;
width: 100%;
height: 220px;
overflow: hidden;
border-radius: var(--card-radius) var(--card-radius) 0 0;
transition: height var(--transition-speed) ease;
}
.weather-card.expanded .card-scene {
height: 200px;
}
/* 场景背景色 */
.card-scene.scene-sunny {
background: linear-gradient(180deg, #ffe8c8 0%, #fff4e4 40%, #fffaf3 100%);
}
.card-scene.scene-windy {
background: linear-gradient(180deg, #dce8f2 0%, #eaf1f7 40%, #f5f8fb 100%);
}
.card-scene.scene-storm {
background: linear-gradient(180deg, #c8d4e2 0%, #dbe3ee 30%, #e8edf5 60%, #f2f4f8 100%);
}
.card-scene.scene-snow {
background: linear-gradient(180deg, #e2eef8 0%, #eef5fa 40%, #f7fafc 100%);
}
/* 场景内的光晕 */
.scene-glow {
position: absolute;
border-radius: 50%;
pointer-events: none;
filter: blur(40px);
opacity: 0.5;
animation: glowPulse 4s ease-in-out infinite;
}
.scene-sunny .scene-glow {
width: 120px;
height: 120px;
background: #fcc870;
top: 30px;
left: 50%;
transform: translateX(-50%);
animation-duration: 3.5s;
}
.scene-windy .scene-glow {
width: 100px;
height: 60px;
background: #b8cfdf;
top: 60px;
left: 30%;
animation-duration: 5s;
}
.scene-storm .scene-glow {
width: 90px;
height: 90px;
background: #8899b5;
top: 50px;
left: 45%;
animation-duration: 2.8s;
opacity: 0.4;
}
.scene-snow .scene-glow {
width: 110px;
height: 110px;
background: #c8dff0;
top: 40px;
left: 50%;
transform: translateX(-50%);
animation-duration: 4.5s;
}
@keyframes glowPulse {
0%,
100% {
opacity: 0.4;
transform: translateX(-50%) scale(1);
}
50% {
opacity: 0.7;
transform: translateX(-50%) scale(1.2);
}
}
/* -------- 太阳 (晴天) -------- */
.sun-container {
position: absolute;
top: 38px;
left: 50%;
transform: translateX(-50%);
width: 80px;
height: 80px;
z-index: 3;
}
.sun-core {
position: absolute;
width: 52px;
height: 52px;
background: radial-gradient(circle at 40% 38%, #fff7c2 0%, #fdb833 55%, #f08c20 100%);
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
box-shadow:
0 0 50px rgba(253, 165, 40, 0.55),
0 0 100px rgba(253, 165, 40, 0.3),
0 0 160px rgba(253, 165, 40, 0.15);
animation: sunPulse 3s ease-in-out infinite;
z-index: 2;
}
@keyframes sunPulse {
0%,
100% {
box-shadow: 0 0 50px rgba(253, 165, 40, 0.55), 0 0 100px rgba(253, 165, 40, 0.3), 0 0 160px rgba(253, 165, 40, 0.15);
}
50% {
box-shadow: 0 0 70px rgba(253, 165, 40, 0.7), 0 0 130px rgba(253, 165, 40, 0.4), 0 0 190px rgba(253, 165, 40, 0.22);
}
}
.sun-ray {
position: absolute;
top: 50%;
left: 50%;
width: 4px;
height: 28px;
background: rgba(253, 180, 50, 0.5);
border-radius: 4px;
transform-origin: center bottom;
animation: rayRotate 12s linear infinite;
}
.sun-ray:nth-child(2) {
transform: rotate(0deg) translateY(-40px);
animation-delay: 0s;
height: 30px;
}
.sun-ray:nth-child(3) {
transform: rotate(45deg) translateY(-40px);
animation-delay: -1.5s;
height: 26px;
}
.sun-ray:nth-child(4) {
transform: rotate(90deg) translateY(-40px);
animation-delay: -3s;
height: 32px;
}
.sun-ray:nth-child(5) {
transform: rotate(135deg) translateY(-40px);
animation-delay: -4.5s;
height: 24px;
}
.sun-ray:nth-child(6) {
transform: rotate(180deg) translateY(-40px);
animation-delay: -6s;
height: 30px;
}
.sun-ray:nth-child(7) {
transform: rotate(225deg) translateY(-40px);
animation-delay: -7.5s;
height: 27px;
}
.sun-ray:nth-child(8) {
transform: rotate(270deg) translateY(-40px);
animation-delay: -9s;
height: 33px;
}
.sun-ray:nth-child(9) {
transform: rotate(315deg) translateY(-40px);
animation-delay: -10.5s;
height: 25px;
}
@keyframes rayRotate {
from {
transform: rotate(var(--r, 0deg)) translateY(-40px) rotate(0deg);
}
to {
transform: rotate(var(--r, 0deg)) translateY(-40px) rotate(360deg);
}
}
/* 为每条光线设置旋转变量 */
.sun-ray:nth-child(2) {
--r: 0deg;
}
.sun-ray:nth-child(3) {
--r: 45deg;
}
.sun-ray:nth-child(4) {
--r: 90deg;
}
.sun-ray:nth-child(5) {
--r: 135deg;
}
.sun-ray:nth-child(6) {
--r: 180deg;
}
.sun-ray:nth-child(7) {
--r: 225deg;
}
.sun-ray:nth-child(8) {
--r: 270deg;
}
.sun-ray:nth-child(9) {
--r: 315deg;
}
/* 晴天小云朵 */
.tiny-cloud-sunny {
position: absolute;
bottom: 35px;
right: 28px;
z-index: 4;
animation: cloudFloat 6s ease-in-out infinite;
}
@keyframes cloudFloat {
0%,
100% {
transform: translateX(0);
}
50% {
transform: translateX(14px);
}
}
/* -------- 云 (CSS绘制) -------- */
.cloud-css {
position: relative;
width: 70px;
height: 32px;
background: rgba(255, 255, 255, 0.85);
border-radius: 32px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
}
.cloud-css::before {
content: '';
position: absolute;
width: 34px;
height: 34px;
background: rgba(255, 255, 255, 0.85);
border-radius: 50%;
top: -18px;
left: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
}
.cloud-css::after {
content: '';
position: absolute;
width: 26px;
height: 26px;
background: rgba(255, 255, 255, 0.8);
border-radius: 50%;
top: -10px;
left: 38px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.03);
}
/* -------- 大风场景 -------- */
.wind-cloud-group {
position: absolute;
top: 40px;
left: 50%;
transform: translateX(-50%);
z-index: 3;
}
.wind-lines {
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 5;
}
.wind-line {
position: absolute;
height: 3px;
background: rgba(140, 170, 195, 0.55);
border-radius: 3px;
animation: windBlow linear infinite;
opacity: 0;
}
.wind-line.wl-1 {
top: 90px;
left: 10%;
width: 50px;
animation-duration: 2.2s;
animation-delay: 0s;
}
.wind-line.wl-2 {
top: 110px;
left: 20%;
width: 70px;
animation-duration: 2.8s;
animation-delay: 0.6s;
}
.wind-line.wl-3 {
top: 130px;
left: 5%;
width: 40px;
animation-duration: 1.9s;
animation-delay: 1.2s;
}
.wind-line.wl-4 {
top: 100px;
left: 30%;
width: 60px;
animation-duration: 2.5s;
animation-delay: 1.8s;
}
.wind-line.wl-5 {
top: 145px;
left: 15%;
width: 35px;
animation-duration: 3.1s;
animation-delay: 0.3s;
}
.wind-line.wl-6 {
top: 120px;
left: 8%;
width: 55px;
animation-duration: 2.4s;
animation-delay: 2s;
}
@keyframes windBlow {
0% {
transform: translateX(-30px);
opacity: 0;
}
15% {
opacity: 0.7;
}
70% {
opacity: 0.6;
}
100% {
transform: translateX(calc(100% + 60px));
opacity: 0;
}
}
/* -------- 暴雨场景 -------- */
.storm-cloud-group {
position: absolute;
top: 28px;
left: 50%;
transform: translateX(-50%);
z-index: 3;
}
.storm-cloud-group .cloud-css {
background: rgba(180, 195, 215, 0.75);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}
.storm-cloud-group .cloud-css::before,
.storm-cloud-group .cloud-css::after {
background: rgba(180, 195, 215, 0.75);
}
.raindrops {
position: absolute;
top: 60px;
left: 0;
width: 100%;
height: calc(100% - 60px);
pointer-events: none;
z-index: 4;
}
.raindrop {
position: absolute;
width: 2px;
height: 16px;
background: linear-gradient(to bottom, rgba(120, 150, 185, 0.3), rgba(100, 140, 180, 0.7));
border-radius: 0 0 4px 4px;
animation: rainFall linear infinite;
opacity: 0;
}
.raindrop.rd-1 {
left: 18%;
animation-duration: .7s;
animation-delay: 0s;
}
.raindrop.rd-2 {
left: 30%;
animation-duration: .85s;
animation-delay: 0.15s;
}
.raindrop.rd-3 {
left: 42%;
animation-duration: .65s;
animation-delay: 0.3s;
}
.raindrop.rd-4 {
left: 54%;
animation-duration: .9s;
animation-delay: 0.45s;
}
.raindrop.rd-5 {
left: 65%;
animation-duration: .75s;
animation-delay: 0.1s;
}
.raindrop.rd-6 {
left: 22%;
animation-duration: .8s;
animation-delay: 0.5s;
}
.raindrop.rd-7 {
left: 48%;
animation-duration: .7s;
animation-delay: 0.35s;
}
.raindrop.rd-8 {
left: 60%;
animation-duration: .95s;
animation-delay: 0.25s;
}
.raindrop.rd-9 {
left: 35%;
animation-duration: .78s;
animation-delay: 0.55s;
}
.raindrop.rd-10 {
left: 70%;
animation-duration: .72s;
animation-delay: 0.4s;
}
@keyframes rainFall {
0% {
transform: translateY(-30px);
opacity: 0;
}
10% {
opacity: 0.8;
}
85% {
opacity: 0.5;
}
100% {
transform: translateY(150px);
opacity: 0;
}
}
/* 闪电 */
.lightning {
position: absolute;
top: 55px;
left: 40%;
width: 3px;
height: 50px;
background: rgba(255, 255, 220, 0.9);
border-radius: 2px;
z-index: 5;
opacity: 0;
animation: lightningFlash 4s ease-in-out infinite;
filter: blur(1px);
box-shadow: 0 0 20px rgba(255, 255, 200, 0.7), 0 0 40px rgba(255, 255, 180, 0.4);
}
.lightning::after {
content: '';
position: absolute;
top: 20px;
left: 6px;
width: 2px;
height: 25px;
background: rgba(255, 255, 210, 0.8);
border-radius: 2px;
transform: rotate(25deg);
}
@keyframes lightningFlash {
0%,
90%,
96%,
100% {
opacity: 0;
}
91% {
opacity: 0.9;
}
92% {
opacity: 0.2;
}
93% {
opacity: 0.85;
}
94% {
opacity: 0.1;
}
95% {
opacity: 0.6;
}
}
/* -------- 暴雪场景 -------- */
.snow-cloud-group {
position: absolute;
top: 30px;
left: 50%;
transform: translateX(-50%);
z-index: 3;
}
.snow-cloud-group .cloud-css {
background: rgba(225, 235, 245, 0.8);
}
.snow-cloud-group .cloud-css::before,
.snow-cloud-group .cloud-css::after {
background: rgba(225, 235, 245, 0.8);
}
.snowflakes {
position: absolute;
top: 55px;
left: 0;
width: 100%;
height: calc(100% - 55px);
pointer-events: none;
z-index: 5;
}
.snowflake {
position: absolute;
background: rgba(255, 255, 255, 0.9);
border-radius: 50%;
animation: snowFall linear infinite;
opacity: 0;
box-shadow: 0 0 6px rgba(255, 255, 255, 0.5);
}
.snowflake.sf-1 {
left: 15%;
width: 6px;
height: 6px;
animation-duration: 3.5s;
animation-delay: 0s;
}
.snowflake.sf-2 {
left: 28%;
width: 4px;
height: 4px;
animation-duration: 4.2s;
animation-delay: 0.8s;
}
.snowflake.sf-3 {
left: 40%;
width: 7px;
height: 7px;
animation-duration: 3.8s;
animation-delay: 1.5s;
}
.snowflake.sf-4 {
left: 55%;
width: 5px;
height: 5px;
animation-duration: 4.6s;
animation-delay: 0.4s;
}
.snowflake.sf-5 {
left: 68%;
width: 6px;
height: 6px;
animation-duration: 3.3s;
animation-delay: 2s;
}
.snowflake.sf-6 {
left: 20%;
width: 3px;
height: 3px;
animation-duration: 5s;
animation-delay: 1.1s;
}
.snowflake.sf-7 {
left: 48%;
width: 5px;
height: 5px;
animation-duration: 3.9s;
animation-delay: 2.5s;
}
.snowflake.sf-8 {
left: 62%;
width: 7px;
height: 7px;
animation-duration: 4.4s;
animation-delay: 0.7s;
}
.snowflake.sf-9 {
left: 33%;
width: 4px;
height: 4px;
animation-duration: 4.8s;
animation-delay: 0.2s;
}
.snowflake.sf-10 {
left: 72%;
width: 5px;
height: 5px;
animation-duration: 3.6s;
animation-delay: 1.8s;
}
@keyframes snowFall {
0% {
transform: translateY(-25px) translateX(0) rotate(0deg);
opacity: 0;
}
10% {
opacity: 0.9;
}
50% {
transform: translateY(60px) translateX(18px) rotate(180deg);
opacity: 0.7;
}
90% {
opacity: 0.3;
}
100% {
transform: translateY(155px) translateX(-10px) rotate(360deg);
opacity: 0;
}
}
/* 地面微光(暴雪) */
.snow-ground {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 30px;
background: linear-gradient(to top, rgba(220, 235, 250, 0.5) 0%, transparent 100%);
z-index: 1;
border-radius: 0 0 var(--card-radius) 0;
}
/* -------- 卡片信息区域 -------- */
.card-info {
padding: 16px 20px 20px;
display: flex;
flex-direction: column;
gap: 6px;
flex: 1;
position: relative;
z-index: 2;
}
.card-temp {
font-size: 3.2rem;
font-weight: 600;
letter-spacing: -0.03em;
line-height: 1;
color: #1d1d1f;
transition: color var(--transition-speed) ease;
}
.card-temp .degree {
font-size: 1.6rem;
font-weight: 500;
vertical-align: super;
margin-left: 2px;
color: #6e6e73;
}
.card-weather-name {
font-size: 1.15rem;
font-weight: 500;
color: #3a3a3c;
letter-spacing: -0.01em;
}
.card-subtitle {
font-size: 0.85rem;
color: #8e8e93;
font-weight: 400;
}
/* 展开详情 */
.card-details {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px 16px;
max-height: 0;
opacity: 0;
overflow: hidden;
transition:
max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.35s ease,
margin-top 0.4s ease;
margin-top: 0;
}
.weather-card.expanded .card-details {
max-height: 120px;
opacity: 1;
margin-top: 12px;
}
.detail-item {
display: flex;
align-items: center;
gap: 7px;
font-size: 0.82rem;
color: #5c5c5e;
font-weight: 500;
}
.detail-item .detail-icon {
width: 22px;
height: 22px;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
background: rgba(0, 0, 0, 0.04);
flex-shrink: 0;
}
.detail-value {
font-weight: 600;
color: #1d1d1f;
}
/* 卡片选中指示器 */
.card-indicator {
position: absolute;
bottom: 16px;
left: 50%;
transform: translateX(-50%);
width: 32px;
height: 4px;
background: rgba(0, 0, 0, 0.15);
border-radius: 4px;
transition: all var(--transition-speed) ease;
opacity: 0;
}
.weather-card.expanded .card-indicator {
opacity: 1;
width: 40px;
background: rgba(0, 0, 0, 0.25);
}
/* -------- 响应式设计 -------- */
@media (max-width: 1100px) {
.cards-grid {
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
.weather-card {
min-height: 380px;
}
.card-scene {
height: 190px;
}
.card-temp {
font-size: 2.8rem;
}
}
@media (max-width: 640px) {
.cards-grid {
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.weather-card {
min-height: 340px;
}
.card-scene {
height: 160px;
}
.card-temp {
font-size: 2.4rem;
}
.card-info {
padding: 12px 14px 16px;
}
.header .location-name {
font-size: 1.2rem;
}
.header .date-text {
font-size: 0.8rem;
padding: 6px 12px;
}
.sun-container {
top: 25px;
width: 60px;
height: 60px;
}
.sun-core {
width: 38px;
height: 38px;
}
.sun-ray {
height: 18px;
width: 3px;
}
.sun-ray:nth-child(2) {
transform: rotate(0deg) translateY(-28px);
}
.sun-ray:nth-child(3) {
transform: rotate(45deg) translateY(-28px);
}
.sun-ray:nth-child(4) {
transform: rotate(90deg) translateY(-28px);
}
.sun-ray:nth-child(5) {
transform: rotate(135deg) translateY(-28px);
}
.sun-ray:nth-child(6) {
transform: rotate(180deg) translateY(-28px);
}
.sun-ray:nth-child(7) {
transform: rotate(225deg) translateY(-28px);
}
.sun-ray:nth-child(8) {
transform: rotate(270deg) translateY(-28px);
}
.sun-ray:nth-child(9) {
transform: rotate(315deg) translateY(-28px);
}
@keyframes rayRotate {
from {
transform: rotate(var(--r, 0deg)) translateY(-28px) rotate(0deg);
}
to {
transform: rotate(var(--r, 0deg)) translateY(-28px) rotate(360deg);
}
}
.cloud-css {
width: 50px;
height: 22px;
border-radius: 22px;
}
.cloud-css::before {
width: 24px;
height: 24px;
top: -13px;
left: 8px;
}
.cloud-css::after {
width: 18px;
height: 18px;
top: -7px;
left: 28px;
}
}
@media (max-width: 420px) {
.cards-grid {
grid-template-columns: 1fr;
gap: 14px;
}
.weather-card {
min-height: 300px;
flex-direction: row;
border-radius: 20px;
}
.card-scene {
width: 140px;
height: auto;
min-height: 140px;
border-radius: 20px 0 0 20px;
flex-shrink: 0;
}
.card-info {
padding: 16px;
justify-content: center;
}
.card-temp {
font-size: 2.2rem;
}
.weather-card.expanded .card-scene {
height: auto;
}
.card-details {
grid-template-columns: 1fr;
gap: 6px;
}
.weather-card.expanded .card-details {
max-height: 200px;
}
.card-indicator {
bottom: 8px;
}
}
</style>
</head>
<body>
<!-- 背景光晕 -->
<div class="bg-orb orb-1"></div>
<div class="bg-orb orb-2"></div>
<div class="bg-orb orb-3"></div>
<!-- 主容器 -->
<div class="main-container">
<!-- 顶部标题 -->
<div class="header">
<div class="location-group">
<div class="location-icon">📍</div>
<span class="location-name">北京 · 中国</span>
</div>
<span class="date-text" id="dateDisplay"></span>
</div>
<!-- 卡片网格 -->
<div class="cards-grid" id="cardsGrid">
<!-- 晴天卡片 -->
<div class="weather-card" data-weather="sunny">
<div class="card-scene scene-sunny">
<div class="scene-glow"></div>
<div class="sun-container">
<div class="sun-core"></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 class="sun-ray"></div>
</div>
<div class="tiny-cloud-sunny">
<div class="cloud-css" style="width:50px;height:22px;border-radius:22px;"></div>
</div>
</div>
<div class="card-info">
<div class="card-temp">28<span class="degree">°C</span></div>
<div class="card-weather-name">☀️ 晴天</div>
<div class="card-subtitle">阳光明媚 · 适合出行</div>
<div class="card-details">
<div class="detail-item">
<span class="detail-icon">🌡️</span>
<span>体感 <span class="detail-value">30°</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">💧</span>
<span>湿度 <span class="detail-value">35%</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">☀️</span>
<span>紫外线 <span class="detail-value">强</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">🍃</span>
<span>风速 <span class="detail-value">2级</span></span>
</div>
</div>
<div class="card-indicator"></div>
</div>
</div>
<!-- 大风卡片 -->
<div class="weather-card" data-weather="windy">
<div class="card-scene scene-windy">
<div class="scene-glow"></div>
<div class="wind-cloud-group">
<div class="cloud-css" style="width:65px;height:28px;border-radius:28px;"></div>
</div>
<div class="wind-lines">
<div class="wind-line wl-1"></div>
<div class="wind-line wl-2"></div>
<div class="wind-line wl-3"></div>
<div class="wind-line wl-4"></div>
<div class="wind-line wl-5"></div>
<div class="wind-line wl-6"></div>
</div>
</div>
<div class="card-info">
<div class="card-temp">15<span class="degree">°C</span></div>
<div class="card-weather-name">💨 大风</div>
<div class="card-subtitle">风力强劲 · 注意保暖</div>
<div class="card-details">
<div class="detail-item">
<span class="detail-icon">🌡️</span>
<span>体感 <span class="detail-value">10°</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">💧</span>
<span>湿度 <span class="detail-value">48%</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">💨</span>
<span>阵风 <span class="detail-value">7级</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">🍃</span>
<span>风速 <span class="detail-value">5级</span></span>
</div>
</div>
<div class="card-indicator"></div>
</div>
</div>
<!-- 暴雨卡片 -->
<div class="weather-card" data-weather="storm">
<div class="card-scene scene-storm">
<div class="scene-glow"></div>
<div class="storm-cloud-group">
<div class="cloud-css" style="width:72px;height:30px;border-radius:30px;"></div>
</div>
<div class="lightning"></div>
<div class="raindrops">
<div class="raindrop rd-1"></div>
<div class="raindrop rd-2"></div>
<div class="raindrop rd-3"></div>
<div class="raindrop rd-4"></div>
<div class="raindrop rd-5"></div>
<div class="raindrop rd-6"></div>
<div class="raindrop rd-7"></div>
<div class="raindrop rd-8"></div>
<div class="raindrop rd-9"></div>
<div class="raindrop rd-10"></div>
</div>
</div>
<div class="card-info">
<div class="card-temp">18<span class="degree">°C</span></div>
<div class="card-weather-name">⛈️ 暴雨</div>
<div class="card-subtitle">雷电交加 · 减少外出</div>
<div class="card-details">
<div class="detail-item">
<span class="detail-icon">🌡️</span>
<span>体感 <span class="detail-value">16°</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">💧</span>
<span>湿度 <span class="detail-value">92%</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">🌧️</span>
<span>降水量 <span class="detail-value">45mm</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">⚡</span>
<span>雷电 <span class="detail-value">频繁</span></span>
</div>
</div>
<div class="card-indicator"></div>
</div>
</div>
<!-- 暴雪卡片 -->
<div class="weather-card" data-weather="snow">
<div class="card-scene scene-snow">
<div class="scene-glow"></div>
<div class="snow-cloud-group">
<div class="cloud-css" style="width:68px;height:29px;border-radius:29px;"></div>
</div>
<div class="snowflakes">
<div class="snowflake sf-1"></div>
<div class="snowflake sf-2"></div>
<div class="snowflake sf-3"></div>
<div class="snowflake sf-4"></div>
<div class="snowflake sf-5"></div>
<div class="snowflake sf-6"></div>
<div class="snowflake sf-7"></div>
<div class="snowflake sf-8"></div>
<div class="snowflake sf-9"></div>
<div class="snowflake sf-10"></div>
</div>
<div class="snow-ground"></div>
</div>
<div class="card-info">
<div class="card-temp">-5<span class="degree">°C</span></div>
<div class="card-weather-name">❄️ 暴雪</div>
<div class="card-subtitle">大雪纷飞 · 注意防寒</div>
<div class="card-details">
<div class="detail-item">
<span class="detail-icon">🌡️</span>
<span>体感 <span class="detail-value">-9°</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">💧</span>
<span>湿度 <span class="detail-value">78%</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">❄️</span>
<span>降雪量 <span class="detail-value">25mm</span></span>
</div>
<div class="detail-item">
<span class="detail-icon">🌬️</span>
<span>能见度 <span class="detail-value">0.5km</span></span>
</div>
</div>
<div class="card-indicator"></div>
</div>
</div>
</div>
</div>
<script>
(function() {
// 日期更新
const dateDisplay = document.getElementById('dateDisplay');
const now = new Date();
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
const weekday = weekdays[now.getDay()];
const month = now.getMonth() + 1;
const day = now.getDate();
dateDisplay.textContent = `${weekday} · ${month}月${day}日`;
// 卡片展开/收起逻辑
const cardsGrid = document.getElementById('cardsGrid');
const cards = cardsGrid.querySelectorAll('.weather-card');
let currentlyExpanded = null;
cards.forEach(card => {
card.addEventListener('click', function(e) {
// 如果点击的是已展开的卡片,则收起
if (this === currentlyExpanded) {
this.classList.remove('expanded');
currentlyExpanded = null;
return;
}
// 收起之前展开的卡片
if (currentlyExpanded) {
currentlyExpanded.classList.remove('expanded');
}
// 展开当前卡片
this.classList.add('expanded');
currentlyExpanded = this;
// 添加涟漪效果
createRipple(e, this);
});
// hover时微调动画速度(通过CSS变量)
card.addEventListener('mouseenter', function() {
this.style.setProperty('--transition-speed', '0.35s');
});
card.addEventListener('mouseleave', function() {
this.style.setProperty('--transition-speed', '0.4s');
});
});
// 点击空白区域收起所有卡片
document.addEventListener('click', function(e) {
if (!e.target.closest('.weather-card') && currentlyExpanded) {
currentlyExpanded.classList.remove('expanded');
currentlyExpanded = null;
}
});
// 涟漪效果
function createRipple(event, card) {
const ripple = document.createElement('span');
ripple.className = 'click-ripple';
const rect = card.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
const x = event.clientX - rect.left - size / 2;
const y = event.clientY - rect.top - size / 2;
ripple.style.cssText = `
position: absolute;
width: ${size}px;
height: ${size}px;
left: ${x}px;
top: ${y}px;
border-radius: 50%;
background: rgba(255,255,255,0.35);
pointer-events: none;
z-index: 20;
animation: rippleOut 0.7s ease-out forwards;
`;
card.appendChild(ripple);
ripple.addEventListener('animationend', function() {
ripple.remove();
});
}
// 动态添加涟漪动画的keyframes
const rippleStyle = document.createElement('style');
rippleStyle.textContent = `
@keyframes rippleOut {
0% { transform: scale(0); opacity: 0.6; }
100% { transform: scale(2.5); opacity: 0; }
}
`;
document.head.appendChild(rippleStyle);
// 触摸设备支持
cards.forEach(card => {
card.addEventListener('touchstart', function() {
this.style.transform = 'scale(0.97)';
this.style.transition = 'transform 0.15s ease';
});
card.addEventListener('touchend', function() {
this.style.transform = '';
this.style.transition = '';
});
});
console.log('🌤️ iOS 18 风格天气卡片已就绪');
console.log(' ☀️ 晴天 | 💨 大风 | ⛈️ 暴雨 | ❄️ 暴雪');
console.log(' 💡 点击卡片查看详细天气信息');
})();
</script>
</body>
</html>
网友解答:
--【壹】--:
感觉不是普通, 是低于目前主流模型的水平, 这太阳,这大风,这暴雨,这暴雪
--【贰】--:
感觉效果一般般,没有啥特别惊艳的感觉,那个太阳也太太阳了
--【叁】--:
在哪里可以进行测试呀,我去huggingface 看到了

