117 lines
3.1 KiB
Plaintext
117 lines
3.1 KiB
Plaintext
---
|
||
// 加载屏:首屏/整页切换时遮盖未渲染内容,避免 FOUC。
|
||
// 轻量原则(追求朴实流畅):
|
||
// - 只用静态大字 + 小标 + 一条 2px 细线进度(transform/opacity 动画,最便宜);
|
||
// - 去掉昂贵的多层 text-shadow 位移动画与外部字体;最短展示时间压缩到 ~350ms,跟手不拖沓。
|
||
|
||
import { config } from '@/lib/config';
|
||
import { getI18n } from '@/lib/i18n'
|
||
|
||
const { t } = getI18n(Astro)
|
||
---
|
||
|
||
<div id="loading-screen" aria-hidden="true">
|
||
<div id="ls-box">
|
||
<h1>{config.siteName}</h1>
|
||
<p class="ls-sub">{t('loading')}</p>
|
||
<div class="ls-bar" aria-hidden="true"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
#loading-screen {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 9999;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: #ffffff;
|
||
color: #0a0a0a;
|
||
transition: opacity 0.4s ease;
|
||
}
|
||
#loading-screen.is-hidden {
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
#loading-screen h1 {
|
||
margin: 0;
|
||
font-size: clamp(2.2rem, 6vw, 4rem);
|
||
font-weight: 900;
|
||
line-height: 1;
|
||
letter-spacing: -0.02em;
|
||
text-transform: uppercase;
|
||
}
|
||
#loading-screen .ls-sub {
|
||
margin: 1.1em 0 0;
|
||
font-size: 0.72rem;
|
||
letter-spacing: 0.34em;
|
||
text-transform: uppercase;
|
||
color: var(--c-gray-700);
|
||
animation: ls-pulse 1.4s ease-in-out infinite;
|
||
}
|
||
#loading-screen .ls-bar {
|
||
margin-top: 2em;
|
||
width: min(180px, 60vw);
|
||
height: 2px;
|
||
background: var(--c-gray-300);
|
||
overflow: hidden;
|
||
}
|
||
#loading-screen .ls-bar::before {
|
||
content: "";
|
||
display: block;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: #0a0a0a;
|
||
transform-origin: left center;
|
||
animation: ls-bar 1.1s cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
||
}
|
||
|
||
@keyframes ls-pulse {
|
||
0%, 100% { opacity: 0.35; }
|
||
50% { opacity: 1; }
|
||
}
|
||
@keyframes ls-bar {
|
||
0% { transform: scaleX(0.08); }
|
||
45% { transform: scaleX(0.72); }
|
||
100% { transform: scaleX(1); }
|
||
}
|
||
|
||
/* 尊重系统"减少动画"偏好 */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
#loading-screen .ls-sub,
|
||
#loading-screen .ls-bar::before {
|
||
animation: none;
|
||
}
|
||
#loading-screen .ls-bar::before { transform: scaleX(1); }
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
// load 后淡出;最少展示 350ms 防闪烁,最多 2s 兜底。
|
||
(function () {
|
||
const el = document.getElementById('loading-screen');
|
||
if (!el) return;
|
||
const screen = el; // 已收窄为非空;闭包内 TS 不保留对 el 的收窄,故另存一份
|
||
var hidden = false;
|
||
function hide() {
|
||
if (hidden) return;
|
||
hidden = true;
|
||
screen.classList.add('is-hidden');
|
||
setTimeout(function () {
|
||
screen.style.display = 'none';
|
||
}, 500);
|
||
}
|
||
var start = Date.now();
|
||
function tryHide() {
|
||
var waited = Date.now() - start;
|
||
if (waited >= 350) hide();
|
||
else setTimeout(hide, 350 - waited);
|
||
}
|
||
if (document.readyState === 'complete') tryHide();
|
||
else window.addEventListener('load', tryHide);
|
||
setTimeout(hide, 2000);
|
||
})();
|
||
</script>
|