159 lines
4.1 KiB
Plaintext
159 lines
4.1 KiB
Plaintext
---
|
||
// 加载屏组件:首屏/路由切换时遮盖未加载内容,避免 FOUC。
|
||
// - 样式作用域隔离在 #loading-screen 内(is:global,因选择器基于唯一 id,不影响整站黑白调性)。
|
||
// - 隐藏逻辑用 Astro 默认打包的 <script>(module / defer),无需 is:inline;
|
||
// 模块脚本在 window.load 之前执行,故 addEventListener('load') 必然先挂上,无竞态。
|
||
// - Raleway 字体仅加载屏使用,随组件引入(Astro 自动 hoist 到 head)。
|
||
---
|
||
|
||
<div id="loading-screen" aria-hidden="true">
|
||
<div id="wrapper">
|
||
<div id="container">
|
||
<h1>Portfolio Studio</h1>
|
||
<p class="ls-sub">Loading</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
#loading-screen {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 9999;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
background-color: #ffffff;
|
||
color: #0a0a0a;
|
||
font: 16px/1.25 'Raleway', sans-serif;
|
||
text-align: center;
|
||
transition: opacity 0.5s ease;
|
||
}
|
||
#loading-screen.is-hidden {
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
#loading-screen *,
|
||
#loading-screen *:before,
|
||
#loading-screen *:after {
|
||
box-sizing: border-box;
|
||
}
|
||
#loading-screen #wrapper {
|
||
margin-left: auto;
|
||
margin-right: auto;
|
||
max-width: 80em;
|
||
}
|
||
#loading-screen #container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
min-height: 100vh;
|
||
padding: 1em;
|
||
width: 100%;
|
||
}
|
||
#loading-screen h1 {
|
||
animation: ls-text-shadow 1.5s ease-in-out infinite;
|
||
font-size: clamp(2.5rem, 8vw, 5rem);
|
||
font-weight: 900;
|
||
line-height: 1;
|
||
}
|
||
#loading-screen h1:hover {
|
||
animation-play-state: paused;
|
||
}
|
||
#loading-screen a {
|
||
color: #0a0a0a;
|
||
}
|
||
#loading-screen a:hover {
|
||
text-decoration: none;
|
||
}
|
||
#loading-screen .ls-sub {
|
||
margin-top: 1.5em;
|
||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||
font-size: 0.75rem;
|
||
letter-spacing: 0.3em;
|
||
text-transform: uppercase;
|
||
color: #888;
|
||
}
|
||
|
||
/* 关键帧独立命名(ls- 前缀),避免与站点其它 keyframes 冲突 */
|
||
@keyframes ls-text-shadow {
|
||
0% {
|
||
transform: translateY(0);
|
||
text-shadow:
|
||
0 0 0 #000,
|
||
0 0 0 #3a3a3a,
|
||
0 0 0 #777,
|
||
0 0 0 #bbb;
|
||
}
|
||
20% {
|
||
transform: translateY(-1em);
|
||
text-shadow:
|
||
0 0.125em 0 #000,
|
||
0 0.25em 0 #3a3a3a,
|
||
0 -0.125em 0 #777,
|
||
0 -0.25em 0 #bbb;
|
||
}
|
||
40% {
|
||
transform: translateY(0.5em);
|
||
text-shadow:
|
||
0 -0.0625em 0 #000,
|
||
0 -0.125em 0 #3a3a3a,
|
||
0 0.0625em 0 #777,
|
||
0 0.125em 0 #bbb;
|
||
}
|
||
60% {
|
||
transform: translateY(-0.25em);
|
||
text-shadow:
|
||
0 0.03125em 0 #000,
|
||
0 0.0625em 0 #3a3a3a,
|
||
0 -0.03125em 0 #777,
|
||
0 -0.0625em 0 #bbb;
|
||
}
|
||
80% {
|
||
transform: translateY(0);
|
||
text-shadow:
|
||
0 0 0 #000,
|
||
0 0 0 #3a3a3a,
|
||
0 0 0 #777,
|
||
0 0 0 #bbb;
|
||
}
|
||
}
|
||
|
||
/* 尊重系统“减少动画”偏好:仅作用于加载屏,不波及整站 */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
#loading-screen *,
|
||
#loading-screen *:before,
|
||
#loading-screen *:after {
|
||
animation: none !important;
|
||
transition: none !important;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
// 页面 load 后淡出加载屏;最少展示 500ms 防闪烁,最多 3s 兜底。
|
||
// 作为 Astro 默认打包的 module 脚本(defer),在 window.load 前执行,监听必然先挂上。
|
||
(function () {
|
||
var el = document.getElementById('loading-screen');
|
||
if (!el) return;
|
||
var hidden = false;
|
||
function hide() {
|
||
if (hidden) return;
|
||
hidden = true;
|
||
el.classList.add('is-hidden');
|
||
setTimeout(function () {
|
||
el.style.display = 'none';
|
||
}, 600);
|
||
}
|
||
var start = Date.now();
|
||
function tryHide() {
|
||
var waited = Date.now() - start;
|
||
if (waited >= 500) hide();
|
||
else setTimeout(hide, 500 - waited);
|
||
}
|
||
if (document.readyState === 'complete') tryHide();
|
||
else window.addEventListener('load', tryHide);
|
||
setTimeout(hide, 3000);
|
||
})();
|
||
</script>
|