喜欢你的五个理由
<!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>
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #0a0e27;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
font-family: "Noto Serif SC", serif;
overflow-x: hidden;
}
.confession-container {
width: 100%;
max-width: 480px;
position: relative;
height: 600px;
}
/* 主显示区域 */
.main-display {
position: relative;
width: 100%;
height: 100%;
perspective: 1000px;
}
/* 星空背景层 */
.starfield-bg {
position: absolute;
width: 100%;
height: 100%;
background: radial-gradient(ellipse at center, #1a1f3a 0%, #0a0e27 70%);
border-radius: 20px;
overflow: hidden;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.05);
transition: filter 0.6s ease;
z-index: 1;
}
.starfield-bg.blurred {
filter: blur(8px) brightness(0.6);
}
/* 背景星点 */
.stars-bg {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.star-dot {
position: absolute;
width: 1px;
height: 1px;
background: #fff;
border-radius: 50%;
opacity: 0.3;
animation: twinkle 3s infinite;
}
@keyframes twinkle {
0%, 100% { opacity: 0.2; }
50% { opacity: 0.8; }
}
/* 可交互的星星 */
.stars-interactive {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 5;
transition: filter 0.6s ease, pointer-events 0.6s ease;
}
.stars-interactive.dimmed {
filter: opacity(0.4);
pointer-events: none;
}
.star {
position: absolute;
cursor: pointer;
width: 40px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.3s ease;
animation: starFloat 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
opacity: 0;
}
.star svg {
width: 100%;
height: 100%;
filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.3));
transition: all 0.3s ease;
}
/* 星星位置分布 */
.star:nth-child(1) {
top: 15%;
left: 20%;
animation-delay: 0.1s;
}
.star:nth-child(2) {
top: 25%;
right: 15%;
animation-delay: 0.2s;
}
.star:nth-child(3) {
top: 50%;
left: 10%;
animation-delay: 0.3s;
}
.star:nth-child(4) {
top: 60%;
right: 20%;
animation-delay: 0.4s;
}
.star:nth-child(5) {
bottom: 20%;
left: 50%;
transform: translateX(-50%);
animation-delay: 0.5s;
}
.star:hover svg {
filter: drop-shadow(0 0 20px rgba(255, 255, 255, 0.8)) drop-shadow(0 0 40px rgba(255, 215, 0, 0.4));
transform: scale(1.3);
}
.star.active svg {
animation: starExplode 0.8s ease forwards;
filter: drop-shadow(0 0 30px rgba(255, 255, 100, 1));
}
/* 星星颜色 */
.star:nth-child(1) svg { --star-color: #FFD700; }
.star:nth-child(2) svg { --star-color: #FFA500; }
.star:nth-child(3) svg { --star-color: #FF69B4; }
.star:nth-child(4) svg { --star-color: #87CEEB; }
.star:nth-child(5) svg { --star-color: #DDA0DD; }
@keyframes starFloat {
from {
opacity: 0;
transform: translateY(20px) scale(0.6);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@keyframes starExplode {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.4);
opacity: 0.8;
}
100% {
transform: scale(0.2);
opacity: 0;
}
}
/* ============ 内容卡片 - 浮于前面 ============ */
.content-card {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 20;
width: 90%;
max-width: 380px;
background: linear-gradient(135deg, rgba(26, 31, 58, 0.98), rgba(10, 14, 39, 0.98));
border-radius: 20px;
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.8), 0 0 60px rgba(255, 215, 0, 0.1);
padding: 40px 30px;
backdrop-filter: blur(20px);
border: 1.5px solid rgba(255, 255, 255, 0.15);
min-height: 220px;
display: flex;
flex-direction: column;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
cursor: pointer;
}
.content-card.show {
opacity: 1;
pointer-events: auto;
animation: cardAppear 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
.content-card.hide {
animation: cardDisappear 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@keyframes cardAppear {
from {
transform: translate(-50%, -50%) scale(0.85) rotateX(20deg);
opacity: 0;
}
to {
transform: translate(-50%, -50%) scale(1) rotateX(0deg);
opacity: 1;
}
}
@keyframes cardDisappear {
from {
transform: translate(-50%, -50%) scale(1) rotateX(0deg);
opacity: 1;
}
to {
transform: translate(-50%, -50%) scale(0.85) rotateX(-20deg);
opacity: 0;
}
}
.content-header {
display: flex;
align-items: center;
margin-bottom: 18px;
}
.reason-number {
display: inline-flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
border-radius: 50%;
font-weight: 700;
font-size: 20px;
color: #fff;
margin-right: 18px;
flex-shrink: 0;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
}
.reason-number.num1 { background: linear-gradient(135deg, #FFD700, #FFA500); }
.reason-number.num2 { background: linear-gradient(135deg, #FFA500, #FF8C00); }
.reason-number.num3 { background: linear-gradient(135deg, #FF69B4, #FF1493); }
.reason-number.num4 { background: linear-gradient(135deg, #87CEEB, #4169E1); }
.reason-number.num5 { background: linear-gradient(135deg, #DDA0DD, #BA55D3); }
.reason-title {
font-size: 18px;
font-weight: 700;
color: #fff;
}
.reason-content {
font-size: 14px;
color: #d0d0d0;
line-height: 1.85;
margin-top: 16px;
}
.progress-info {
margin-top: 20px;
text-align: center;
color: #888;
font-size: 12px;
}
.progress-bar {
width: 100%;
height: 3px;
background: rgba(255, 255, 255, 0.1);
border-radius: 2px;
margin-top: 10px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #FFD700, #FF69B4);
border-radius: 2px;
transition: width 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* 点击提示 */
.click-hint {
text-align: center;
font-size: 11px;
color: #888;
margin-top: 15px;
opacity: 0.7;
}
/* ============ 最终告白 - 浮于前面 ============ */
.final-confession {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 30;
width: 90%;
max-width: 380px;
text-align: center;
opacity: 0;
pointer-events: none;
transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.final-confession.show {
opacity: 1;
pointer-events: auto;
animation: confessionAppear 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@keyframes confessionAppear {
from {
transform: translate(-50%, -50%) scale(0.5) rotateY(90deg);
opacity: 0;
}
to {
transform: translate(-50%, -50%) scale(1) rotateY(0deg);
opacity: 1;
}
}
.heart-glow {
width: 100px;
height: 100px;
margin: 0 auto 20px;
animation: heartAppear 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) forwards,
heartFloat 3s ease-in-out 0.8s infinite;
filter: drop-shadow(0 0 30px rgba(255, 215, 0, 0.6)) drop-shadow(0 0 60px rgba(255, 105, 180, 0.3));
}
@keyframes heartAppear {
from {
transform: scale(0.3);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
@keyframes heartFloat {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-15px);
}
}
.confession-main {
font-size: 32px;
font-weight: 900;
background: linear-gradient(135deg, #FFD700, #FF69B4);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
letter-spacing: 3px;
margin-bottom: 15px;
animation: textGlow 0.8s ease 0.3s forwards;
opacity: 0;
}
@keyframes textGlow {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.confession-sub {
font-size: 16px;
color: #b0b0b0;
letter-spacing: 1.5px;
opacity: 0;
animation: textGlow 0.8s ease 0.6s forwards;
}
/* 交互提示 */
.tap-hint {
position: absolute;
bottom: -60px;
left: 50%;
transform: translateX(-50%);
color: #87ceeb;
font-size: 14px;
opacity: 0;
animation: fadeIn 0.8s ease 1s forwards;
letter-spacing: 1px;
font-weight: 500;
z-index: 10;
transition: opacity 0.3s ease;
}
.tap-hint.hidden {
opacity: 0 !important;
pointer-events: none;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateX(-50%) translateY(-10px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
}
/* 响应式 */
@media (max-width: 480px) {
.confession-container {
height: 500px;
}
.content-card {
padding: 30px 20px;
}
.reason-number {
width: 40px;
height: 40px;
font-size: 16px;
}
.reason-title {
font-size: 16px;
}
.reason-content {
font-size: 13px;
}
.confession-main {
font-size: 26px;
}
}
</style>
</head>
<body>
<div class="confession-container">
<!-- 星空背景 -->
<div class="starfield-bg" id="starfieldBg">
<div class="stars-bg" id="starsBg"></div>
</div>
<!-- 可交互星星 -->
<div class="stars-interactive" id="starsInteractive">
<div class="star" data-index="0">
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="star1" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#FFD700;stop-opacity:1" />
<stop offset="100%" style="stop-color:#FFA500;stop-opacity:1" />
</linearGradient>
</defs>
<polygon points="50,10 61,40 93,40 68,60 79,90 50,70 21,90 32,60 7,40 39,40" fill="url(#star1)"/>
</svg>
</div>
<div class="star" data-index="1">
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="star2" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#FFA500;stop-opacity:1" />
<stop offset="100%" style="stop-color:#FF8C00;stop-opacity:1" />
</linearGradient>
</defs>
<polygon points="50,10 61,40 93,40 68,60 79,90 50,70 21,90 32,60 7,40 39,40" fill="url(#star2)"/>
</svg>
</div>
<div class="star" data-index="2">
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="star3" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#FF69B4;stop-opacity:1" />
<stop offset="100%" style="stop-color:#FF1493;stop-opacity:1" />
</linearGradient>
</defs>
<polygon points="50,10 61,40 93,40 68,60 79,90 50,70 21,90 32,60 7,40 39,40" fill="url(#star3)"/>
</svg>
</div>
<div class="star" data-index="3">
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="star4" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#87CEEB;stop-opacity:1" />
<stop offset="100%" style="stop-color:#4169E1;stop-opacity:1" />
</linearGradient>
</defs>
<polygon points="50,10 61,40 93,40 68,60 79,90 50,70 21,90 32,60 7,40 39,40" fill="url(#star4)"/>
</svg>
</div>
<div class="star" data-index="4">
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="star5" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#DDA0DD;stop-opacity:1" />
<stop offset="100%" style="stop-color:#BA55D3;stop-opacity:1" />
</linearGradient>
</defs>
<polygon points="50,10 61,40 93,40 68,60 79,90 50,70 21,90 32,60 7,40 39,40" fill="url(#star5)"/>
</svg>
</div>
</div>
<!-- 内容卡片 - 浮于前面 -->
<div class="content-card" id="contentCard">
<div class="content-header">
<span class="reason-number" id="reasonNum"></span>
<span class="reason-title" id="reasonTitle"></span>
</div>
<div class="reason-content" id="reasonContent"></div>
<div class="progress-info">
<span id="progressIndicator"></span>
<div class="progress-bar">
<div class="progress-fill" id="progressFill" style="width: 0%;"></div>
</div>
</div>
<div class="click-hint">再次点击收起</div>
</div>
<!-- 最终告白 - 浮于前面 -->
<div class="final-confession" id="finalConfession">
<div class="heart-glow">
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="heartGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#FFD700;stop-opacity:1" />
<stop offset="100%" style="stop-color:#FF69B4;stop-opacity:1" />
</linearGradient>
</defs>
<path d="M50,85 C20,65 5,50 5,35 C5,20 15,10 25,10 C35,10 45,18 50,28 C55,18 65,10 75,10 C85,10 95,20 95,35 C95,50 80,65 50,85 Z" fill="url(#heartGradient)" />
</svg>
</div>
<div class="confession-main">我喜欢你</div>
<div class="confession-sub">永远爱你</div>
</div>
<div class="tap-hint" id="tapHint">✨ 点击星星,看看我喜欢你的理由</div>
</div>
<script>
// 生成背景星点
function generateBackgroundStars() {
const starsBg = document.getElementById('starsBg');
for (let i = 0; i < 80; i++) {
const star = document.createElement('div');
star.className = 'star-dot';
star.style.left = Math.random() * 100 + '%';
star.style.top = Math.random() * 100 + '%';
star.style.animationDelay = Math.random() * 3 + 's';
star.style.width = Math.random() * 2 + 0.5 + 'px';
star.style.height = star.style.width;
starsBg.appendChild(star);
}
}
generateBackgroundStars();
// 理由内容
const reasons = [
{
title: "细心回复",
content: "每次不管我发多少消息,有时间都会认真一句一句回复,甚至会因为回不完难过。这份用心让我感受到自己在你心中的分量。"
},
{
title: "耐心教导",
content: "和我喜欢的游戏都大差不差,也不嫌我是新手操作菜,每次玩游戏都认真教我。你的耐心让我在游戏中也能感受到被珍视的感觉。"
},
{
title: "坦诚相待",
content: "有话就直说,难过不舒服都会第一时间告诉我,方便我们解决问题。直来直往让我能少好多内耗,这是最珍贵的信任。"
},
{
title: "温柔听劝",
content: "很听劝,我说想让你多发语音,多分享日常,你就努力去做。这种温柔的改变让我觉得自己的想法真的很重要。"
},
{
title: "主动化解",
content: "会主动解释可能的误会,不让我多想。你的及时澄清消解了我心中的疑虑,让我们的相处更加坦然。"
}
];
let clickCount = 0;
let currentShownIndex = -1;
let isCardShowing = false;
const stars = document.querySelectorAll('.star');
const contentCard = document.getElementById('contentCard');
const finalConfession = document.getElementById('finalConfession');
const starfieldBg = document.getElementById('starfieldBg');
const starsInteractive = document.getElementById('starsInteractive');
const tapHint = document.getElementById('tapHint');
// 卡片点击收起
contentCard.addEventListener('click', (e) => {
if (isCardShowing && currentShownIndex !== -1) {
// 收起卡片
contentCard.classList.remove('show');
contentCard.classList.add('hide');
setTimeout(() => {
contentCard.classList.remove('hide');
isCardShowing = false;
// 恢复背景
starfieldBg.classList.remove('blurred');
starsInteractive.classList.remove('dimmed');
tapHint.classList.remove('hidden');
}, 600);
}
});
stars.forEach((star, index) => {
star.addEventListener('click', (e) => {
e.stopPropagation();
// 如果卡片正在显示且不是同一个星星
if (isCardShowing && currentShownIndex !== index) {
// 先收起
contentCard.classList.remove('show');
contentCard.classList.add('hide');
setTimeout(() => {
contentCard.classList.remove('hide');
showReason(index, star);
}, 300);
} else if (isCardShowing && currentShownIndex === index) {
// 点击同一个星星,收起卡片
contentCard.classList.remove('show');
contentCard.classList.add('hide');
setTimeout(() => {
contentCard.classList.remove('hide');
isCardShowing = false;
// 恢复背景
starfieldBg.classList.remove('blurred');
starsInteractive.classList.remove('dimmed');
tapHint.classList.remove('hidden');
}, 600);
} else if (!star.classList.contains('active')) {
// 第一次点击
star.classList.add('active');
// 虚化背景
starfieldBg.classList.add('blurred');
starsInteractive.classList.add('dimmed');
tapHint.classList.add('hidden');
setTimeout(() => {
showReason(index, star);
}, 500);
}
});
});
function showReason(index, star) {
const reason = reasons[index];
document.getElementById('reasonNum').textContent = index + 1;
document.getElementById('reasonNum').className = `reason-number num${index + 1}`;
document.getElementById('reasonTitle').textContent = reason.title;
document.getElementById('reasonContent').textContent = reason.content;
document.getElementById('progressIndicator').textContent = `${index + 1} / 5`;
document.getElementById('progressFill').style.width = ((index + 1) / 5 * 100) + '%';
contentCard.classList.add('show');
isCardShowing = true;
currentShownIndex = index;
if (!star.classList.contains('counted')) {
star.classList.add('counted');
clickCount++;
if (clickCount === 5) {
setTimeout(() => {
contentCard.classList.remove('show');
contentCard.classList.add('hide');
setTimeout(() => {
finalConfession.classList.add('show');
}, 600);
}, 2800);
}
}
}
</script>
</body>
</html>