![图片[1]-HTML源码 – 人生倒计时单页源码-林儿の博客](https://liner.love/wp-content/uploads/2025/09/屏幕截图-2025-09-10-215125-1024x526.png)
AI写的人生倒计时单页源码 可视化您的人生旅程,珍惜每一刻时光
<!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>
/* 插件容器样式 - 添加lpd前缀避免与主题样式冲突 */
.lpd-container {
max-width: 1200px; /* 设置最大宽度 */
margin: 30px auto; /* 居中显示 */
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
box-sizing: border-box;
border-radius: 12px;
background: #f6f8fa;
color: #111;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
}
.lpd-container {
--lpd-bg:#f6f8fa;
--lpd-card:#ffffff;
--lpd-muted:#666;
--lpd-text:#111;
--lpd-accent:#7c6cff;
--lpd-accept-weak:#a79cff;
--lpd-danger:#ff6b6b;
--lpd-ok:#22c55e;
--lpd-shadow:0 8px 25px rgba(0,0,0,.1), inset 0 1px 0 rgba(255,255,255,.6);
--lpd-radius:16px;
background: var(--lpd-bg);
color: var(--lpd-text);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
transition: all .3s ease;
}
.lpd-container[data-theme="dark"]{
--lpd-bg:#0b1220;
--lpd-card:#121b2d;
--lpd-muted:#94a3b8;
--lpd-text:#e5e7eb;
--lpd-accent:#7c6cff;
--lpd-accept-weak:#a79cff;
--lpd-danger:#ff6b6b;
--lpd-ok:#22c55e;
--lpd-shadow:0 8px 25px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.02);
}
.lpd-head{
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px; /* 减小底部间距 */
flex-wrap: wrap;
gap: 15px;
}
.lpd-title{
font-size: 22px;
font-weight: 700;
letter-spacing: .5px;
margin: 0;
color: var(--lpd-text);
flex: 1;
min-width: 200px;
}
/* 添加二级标题样式 */
.lpd-subtitle {
text-align: center;
font-size: 16px;
color: var(--lpd-muted);
margin-top: 8px;
margin-bottom: 20px;
width: 100%;
}
.lpd-theme-toggle{
cursor: pointer;
font-size: 18px;
padding: 10px 15px;
border-radius: 8px;
user-select: none;
background: var(--lpd-card);
box-shadow: var(--lpd-shadow);
border: none;
display: flex;
align-items: center;
justify-content: center;
min-width: 60px;
transition: transform 0.2s;
}
.lpd-theme-toggle:active {
transform: scale(0.95);
}
.lpd-grid{
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 18px;
}
.lpd-card{
grid-column: span 12;
background: var(--lpd-card);
border-radius: var(--lpd-radius);
box-shadow: var(--lpd-shadow);
padding: 20px;
position: relative;
overflow: hidden;
transition: all .3s ease;
box-sizing: border-box;
}
.lpd-card h3{
margin: 0 0 14px 0;
font-size: 18px;
opacity: .95;
color: var(--lpd-text);
}
.lpd-countdown-large{
font-size: 80px;
line-height: 1;
font-weight: 800;
color: var(--lpd-accent);
text-shadow: 0 4px 15px rgba(124,108,255,.25);
}
.lpd-unit{
opacity: .9;
font-size: 16px;
margin-left: 8px;
color: var(--lpd-text);
}
.lpd-mini-grid{
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px;
margin-top: 20px;
}
.lpd-mini{
background: var(--lpd-card);
border-radius: 14px;
padding: 12px 8px;
text-align: center;
box-shadow: var(--lpd-shadow);
transition: all .3s ease;
}
.lpd-mini .lpd-num{
font-size: 26px;
font-weight: 800;
color: var(--lpd-text);
}
.lpd-mini .lpd-lab{
font-size: 11px;
color: var(--lpd-muted);
letter-spacing: .15em;
opacity: .9;
margin-top: 4px;
}
.lpd-kpi-grid{
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.lpd-kpi{
background: var(--lpd-card);
border-radius: 14px;
padding: 18px;
box-shadow: var(--lpd-shadow);
transition: all .3s ease;
}
.lpd-kpi .lpd-big{
font-size: 28px;
font-weight: 800;
margin-bottom: 6px;
color: var(--lpd-text);
}
.lpd-kpi .lpd-sub{
color: var(--lpd-muted);
font-size: 12px;
letter-spacing: .1em;
}
/* 顶部横向进度条样式 */
.lpd-top-progress {
width: 100%;
height: 24px;
background: rgba(0,0,0,0.06);
border-radius: 12px;
margin: 15px 0 25px;
overflow: hidden;
position: relative;
box-shadow: var(--lpd-shadow);
}
.lpd-container[data-theme="dark"] .lpd-top-progress {
background: rgba(255,255,255,0.06);
}
.lpd-top-progress-fill {
height: 100%;
background: linear-gradient(90deg, #7c6cff, #8fb1ff);
border-radius: 12px;
transition: width 0.8s cubic-bezier(.2,.9,.25,1);
position: relative;
}
.lpd-top-progress-text {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: 700;
color: white;
text-shadow: 0 1px 2px rgba(0,0,0,0.3);
}
.lpd-muted{
color: var(--lpd-muted);
}
.lpd-num-inline{
font-variant-numeric: tabular-nums;
}
/* 配置显示区域 */
.lpd-config-display {
background: var(--lpd-card);
border-radius: var(--lpd-radius);
padding: 18px;
margin-bottom: 20px;
box-shadow: var(--lpd-shadow);
display: flex;
justify-content: space-between;
align-items: center;
}
.lpd-config-item {
display: flex;
flex-direction: column;
align-items: center;
}
.lpd-config-label {
font-size: 13px;
color: var(--lpd-muted);
margin-bottom: 5px;
}
.lpd-config-value {
font-size: 16px;
font-weight: 600;
color: var(--lpd-accent);
}
/* 移动端优化 */
@media (max-width: 768px){
.lpd-container {
padding: 15px;
margin: 20px 0;
max-width: 100%; /* 移动端全宽 */
}
.lpd-head {
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.lpd-theme-toggle {
position: static;
margin: 0;
order: 2;
flex-shrink: 0;
}
.lpd-title {
order: 1;
min-width: unset;
margin-right: 15px;
font-size: 20px;
}
.lpd-countdown-large {
font-size: 60px;
}
/* 移动端活了多久显示两列 */
.lpd-kpi-grid {
grid-template-columns: repeat(2, 1fr);
}
.lpd-kpi .lpd-big {
font-size: 24px;
}
.lpd-config-display {
flex-direction: column;
gap: 12px;
align-items: flex-start;
}
.lpd-card {
padding: 16px;
}
.lpd-top-progress {
height: 20px;
margin: 10px 0 20px;
}
.lpd-top-progress-text {
font-size: 12px;
}
/* 移动端网格布局调整 */
.lpd-grid {
grid-template-columns: 1fr;
gap: 15px;
}
.lpd-card.lpd-span-5,
.lpd-card.lpd-span-4,
.lpd-card.lpd-span-3 {
grid-column: span 1;
}
.lpd-mini-grid {
grid-template-columns: repeat(2, 1fr);
}
.lpd-mini .lpd-num {
font-size: 22px;
}
}
@media (min-width: 769px) and (max-width: 1024px){
.lpd-card.lpd-span-5{
grid-column: span 6;
}
.lpd-card.lpd-span-4{
grid-column: span 6;
}
.lpd-card.lpd-span-3{
grid-column: span 4;
}
}
@media (min-width:1025px){
.lpd-card.lpd-span-5{
grid-column: span 5;
}
.lpd-card.lpd-span-4{
grid-column: span 4;
}
.lpd-card.lpd-span-3{
grid-column: span 3;
}
.lpd-countdown-large{
font-size: 90px;
}
}
.lpd-footer{
margin-top: 15px;
display: flex;
justify-content: space-between;
align-items: center;
color: var(--lpd-muted);
font-size: 11px;
padding-top: 15px;
border-top: 1px solid rgba(0,0,0,0.05);
}
.lpd-container[data-theme="dark"] .lpd-footer {
border-top: 1px solid rgba(255,255,255,0.05);
}
</style>
</head>
<body>
<div class="lpd-container">
<div class="lpd-head">
<div>
<h2 class="lpd-title">人生时间进度仪表盘</h2>
<!-- 添加二级标题 -->
<div class="lpd-subtitle">可视化您的人生旅程,珍惜每一刻时光</div>
</div>
<div id="lpdThemeToggle" class="lpd-theme-toggle">🌙</div>
</div>
<!-- 顶部横向进度条 -->
<div class="lpd-top-progress">
<div class="lpd-top-progress-fill" id="lpdTopProgressFill">
<div class="lpd-top-progress-text" id="lpdTopProgressText">44.0%</div>
</div>
</div>
<!-- 配置显示区域 -->
<div class="lpd-config-display">
<div class="lpd-config-item">
<div class="lpd-config-label">出生日期</div>
<div id="lpdBirthDateDisplay" class="lpd-config-value">2025年1月1日</div>
</div>
<div class="lpd-config-item">
<div class="lpd-config-label">预期寿命</div>
<div id="lpdLifeExpectancyDisplay" class="lpd-config-value">80 岁</div>
</div>
</div>
<div class="lpd-grid">
<section class="lpd-card lpd-span-5">
<h3>距离生日还有</h3>
<div><span id="lpdDLeft" class="lpd-countdown-large lpd-num-inline">296</span><span class="lpd-unit">天</span></div>
<div class="lpd-mini-grid">
<div class="lpd-mini"><div id="lpdDLeft_d" class="lpd-num lpd-num-inline">296</div><div class="lpd-lab">天</div></div>
<div class="lpd-mini"><div id="lpdDLeft_h" class="lpd-num lpd-num-inline">02</div><div class="lpd-lab">时</div></div>
<div class="lpd-mini"><div id="lpdDLeft_m" class="lpd-num lpd-num-inline">57</div><div class="lpd-lab">分</div></div>
<div class="lpd-mini"><div id="lpdDLeft_s" class="lpd-num lpd-num-inline">41</div><div class="lpd-lab">秒</div></div>
</div>
</section>
<section class="lpd-card lpd-span-4">
<h3>活了多久</h3>
<div class="lpd-kpi-grid">
<div class="lpd-kpi"><div id="lpdLived_days" class="lpd-big lpd-num-inline">12,853</div><div class="lpd-sub">天</div></div>
<div class="lpd-kpi"><div id="lpdLived_hours" class="lpd-big lpd-num-inline">308,493</div><div class="lpd-sub">小时</div></div>
<div class="lpd-kpi"><div id="lpdAge_years" class="lpd-big lpd-num-inline">35</div><div class="lpd-sub">岁</div></div>
<div class="lpd-kpi"><div id="lpdBirthdays" class="lpd-big lpd-num-inline">35</div><div class="lpd-sub">个生日</div></div>
</div>
</section>
<section class="lpd-card lpd-span-3">
<h3>人生进度</h3>
<div class="lpd-muted" style="margin-bottom:8px;text-align:center">预期 <span id="lpdExpect_years" class="lpd-num-inline">80</span> 岁</div>
<div style="text-align: center; font-size: 24px; font-weight: 800; color: var(--lpd-accent); margin: 15px 0;" id="lpdProgress">44.0%</div>
<div style="margin-top:10px;font-size:14px;text-align:center">
<div class="lpd-muted">剩余大约 <span id="lpdRemain_years" class="lpd-num-inline">44.8</span> 年</div>
<div class="lpd-muted" style="margin-top:6px"><span id="lpdRemain_days" class="lpd-num-inline">16,366</span> 天</div>
</div>
</section>
</div>
<div class="lpd-footer">
<div>⏱️ 实时刷新中</div>
<div id="lpdLastUpdated">上次更新:2025/9/10 21:02:19</div>
</div>
</div>
<script>
// ===== 配置区 =====
// 在这里直接修改出生日期和预期寿命
const LPD_CONFIG = {
birthDate: "2025-01-01", // 出生日期 (格式: YYYY-MM-DD)
lifeExpectancy: 80 // 预期寿命(年)
};
// =================
// 确保DOM完全加载后再执行
document.addEventListener('DOMContentLoaded', function() {
const LPD_DAY = 24 * 60 * 60 * 1000, LPD_HOUR = 60 * 60 * 1000, LPD_MIN = 60 * 1000;
const LPD_avgYear = 365.2425;
function lpdPad(n){return n.toString().padStart(2,'0')}
function lpdFmtTime(dt){return new Date(dt).toLocaleString(undefined,{hour12:false})}
function lpdIsLeap(y){return (y%4===0 && y%100!==0) || (y%400===0)}
function lpdSafeBirthdayThisYear(birth, year){
const m=birth.getMonth(),d=birth.getDate();
if(m===1 && d===29 && !lpdIsLeap(year)) return new Date(year,1,28,0,0,0);
return new Date(year,m,d,0,0,0);
}
function lpdNextBirthdayFrom(now,birth){
const thisYear=lpdSafeBirthdayThisYear(birth,now.getFullYear());
if(thisYear.getTime()>now.getTime()) return thisYear;
return lpdSafeBirthdayThisYear(birth,now.getFullYear()+1);
}
function lpdCalcAgeYears(now,birth){
let age=now.getFullYear()-birth.getFullYear();
const bdThis=lpdSafeBirthdayThisYear(birth,now.getFullYear());
if(now<bdThis) age-=1;
return Math.max(age,0);
}
function lpdClamp(v,a,b){return Math.min(Math.max(v,a),b)}
// 主题切换
const lpdThemeToggle=document.getElementById('lpdThemeToggle');
function lpdApplyTheme(auto=false){
let h=new Date().getHours();
if(auto){
if(h>=19||h<7){
document.querySelector('.lpd-container').setAttribute('data-theme','dark');
if(lpdThemeToggle) lpdThemeToggle.textContent='☀️';
}else{
document.querySelector('.lpd-container').setAttribute('data-theme','light');
if(lpdThemeToggle) lpdThemeToggle.textContent='🌙';
}
}else{
let cur=document.querySelector('.lpd-container').getAttribute('data-theme')||'light';
if(cur==='light'){
document.querySelector('.lpd-container').setAttribute('data-theme','dark');
if(lpdThemeToggle) lpdThemeToggle.textContent='☀️';
}else{
document.querySelector('.lpd-container').setAttribute('data-theme','light');
if(lpdThemeToggle) lpdThemeToggle.textContent='🌙';
}
}
}
if(lpdThemeToggle) {
lpdThemeToggle.addEventListener('click',()=>lpdApplyTheme(false));
}
lpdApplyTheme(true);
// 显示配置信息
const lpdBirthDateDisplay = document.getElementById('lpdBirthDateDisplay');
const lpdLifeExpectancyDisplay = document.getElementById('lpdLifeExpectancyDisplay');
// 格式化日期显示
function lpdFormatDateDisplay(dateStr) {
const date = new Date(dateStr);
return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`;
}
if(lpdBirthDateDisplay) {
lpdBirthDateDisplay.textContent = lpdFormatDateDisplay(LPD_CONFIG.birthDate);
}
if(lpdLifeExpectancyDisplay) {
lpdLifeExpectancyDisplay.textContent = `${LPD_CONFIG.lifeExpectancy} 岁`;
}
const lpdDLeft=document.getElementById('lpdDLeft');
const lpdDLeft_d=document.getElementById('lpdDLeft_d');
const lpdDLeft_h=document.getElementById('lpdDLeft_h');
const lpdDLeft_m=document.getElementById('lpdDLeft_m');
const lpdDLeft_s=document.getElementById('lpdDLeft_s');
const lpdLived_days=document.getElementById('lpdLived_days');
const lpdLived_hours=document.getElementById('lpdLived_hours');
const lpdAge_years=document.getElementById('lpdAge_years');
const lpdBirthdays=document.getElementById('lpdBirthdays');
const lpdProgressEl=document.getElementById('lpdProgress');
const lpdExpect_years=document.getElementById('lpdExpect_years');
const lpdRemain_years=document.getElementById('lpdRemain_years');
const lpdRemain_days=document.getElementById('lpdRemain_days');
const lpdLastUpdated=document.getElementById('lpdLastUpdated');
const lpdTopProgressFill = document.getElementById('lpdTopProgressFill');
const lpdTopProgressText = document.getElementById('lpdTopProgressText');
function lpdTick(){
const now=new Date();
const birth=new Date(LPD_CONFIG.birthDate+"T00:00:00");
const livedMs=now-birth;
const days=Math.floor(livedMs/LPD_DAY);
const hours=Math.floor(livedMs/LPD_HOUR);
const age=lpdCalcAgeYears(now,birth);
const bdays=age;
if(lpdLived_days) lpdLived_days.textContent=days.toLocaleString();
if(lpdLived_hours) lpdLived_hours.textContent=hours.toLocaleString();
if(lpdAge_years) lpdAge_years.textContent=age.toString();
if(lpdBirthdays) lpdBirthdays.textContent=bdays.toString();
const nextBd=lpdNextBirthdayFrom(now,birth);
const diff=nextBd-now;
const d=Math.floor(diff/LPD_DAY);
const h=Math.floor((diff%LPD_DAY)/LPD_HOUR);
const m=Math.floor((diff%LPD_HOUR)/LPD_MIN);
const s=Math.floor((diff%LPD_MIN)/1000);
if(lpdDLeft) lpdDLeft.textContent=d;
if(lpdDLeft_d) lpdDLeft_d.textContent=d;
if(lpdDLeft_h) lpdDLeft_h.textContent=lpdPad(h);
if(lpdDLeft_m) lpdDLeft_m.textContent=lpdPad(m);
if(lpdDLeft_s) lpdDLeft_s.textContent=lpdPad(s);
if(lpdExpect_years) lpdExpect_years.textContent=LPD_CONFIG.lifeExpectancy;
const totalDays=LPD_CONFIG.lifeExpectancy*LPD_avgYear;
const prog=lpdClamp(days/totalDays,0,1);
const percent=(prog*100).toFixed(1)+'%';
// 更新顶部横向进度条
if(lpdTopProgressFill) {
lpdTopProgressFill.style.width = (prog*100)+'%';
}
if(lpdTopProgressText) {
lpdTopProgressText.textContent = percent;
}
if(lpdProgressEl) lpdProgressEl.textContent=percent;
const remainD=Math.max(Math.round(totalDays-days),0);
const remainY=(remainD/LPD_avgYear).toFixed(1);
if(lpdRemain_days) lpdRemain_days.textContent=remainD.toLocaleString();
if(lpdRemain_years) lpdRemain_years.textContent=remainY;
if(lpdLastUpdated) lpdLastUpdated.textContent='上次更新:'+lpdFmtTime(now);
requestAnimationFrame(lpdTick);
}
// 确保所有元素都存在再开始计时
if(lpdTopProgressFill && lpdDLeft && lpdLived_days) {
requestAnimationFrame(lpdTick);
} else {
console.error('人生进度仪表盘初始化失败:某些必要元素未找到');
}
});
</script>
</body>
</html>
© 版权声明
THE END
暂无评论内容