mirror of
https://github.com/ClovertaTheTrilobita/SanYeCao-blog.git
synced 2026-10-25 13:33:53 +00:00
update overal styling
This commit is contained in:
parent
6e4cd96114
commit
566c5fa24a
4 changed files with 156 additions and 82 deletions
|
|
@ -10,23 +10,25 @@ const t = getTranslations(lang);
|
|||
|
||||
<div class="header-slot">
|
||||
<header class="site-header">
|
||||
<div class="theme-icon-wrap">
|
||||
<ThemeIcon />
|
||||
</div>
|
||||
|
||||
<nav class="header-nav">
|
||||
<div class="banner">
|
||||
<a
|
||||
href={`/${lang}/`}
|
||||
data-astro-reload
|
||||
class="banner-link"
|
||||
aria-label="banner"
|
||||
>
|
||||
<span class="banner-logo"></span>
|
||||
</a>
|
||||
<div class="header-content">
|
||||
<div class="theme-icon-wrap">
|
||||
<ThemeIcon />
|
||||
</div>
|
||||
<Navigation />
|
||||
</nav>
|
||||
|
||||
<nav class="header-nav">
|
||||
<div class="banner">
|
||||
<a
|
||||
href={`/${lang}/`}
|
||||
data-astro-reload
|
||||
class="banner-link"
|
||||
aria-label="banner"
|
||||
>
|
||||
<span class="banner-logo"></span>
|
||||
</a>
|
||||
</div>
|
||||
<Navigation />
|
||||
</nav>
|
||||
</div>
|
||||
<div class="divider">
|
||||
<Divider />
|
||||
</div>
|
||||
|
|
@ -40,6 +42,10 @@ const t = getTranslations(lang);
|
|||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.banner-link {
|
||||
display: block;
|
||||
}
|
||||
|
|
@ -103,21 +109,23 @@ const t = getTranslations(lang);
|
|||
|
||||
.site-header {
|
||||
pointer-events: auto;
|
||||
width: var(--header-width, 100%);
|
||||
max-width: none;
|
||||
margin-left: var(--header-offset, 0);
|
||||
margin-right: var(--header-offset, 0);
|
||||
padding: 0.5rem var(--header-inline-padding, 0) 0;
|
||||
width: 100%;
|
||||
max-width: 90ch;
|
||||
margin-inline: auto;
|
||||
padding: 0.5rem 0 0;
|
||||
background-color: color-mix(
|
||||
in srgb,
|
||||
var(--background-color) var(--header-surface-weight, 0%),
|
||||
transparent
|
||||
);
|
||||
backdrop-filter: blur(var(--header-blur, 0));
|
||||
transform: translateY(0);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header-slot.is-scroll-hidden .site-header,
|
||||
.header-slot.is-footer-hidden .site-header {
|
||||
transform: translateY(calc(-100% - 0.5rem));
|
||||
|
|
@ -133,7 +141,7 @@ const t = getTranslations(lang);
|
|||
|
||||
.theme-icon-wrap {
|
||||
top: var(--theme-top, 0);
|
||||
right: var(--theme-right, 0);
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.header-nav {
|
||||
|
|
@ -168,13 +176,11 @@ const t = getTranslations(lang);
|
|||
}
|
||||
|
||||
.site-header :global(.site-nav a) {
|
||||
font-size: var(--site-nav-font-size, 1.2rem);
|
||||
font-size: var(--site-nav-font-size, 1.05rem);
|
||||
}
|
||||
|
||||
.site-header > .divider {
|
||||
width: var(--divider-width, 100%);
|
||||
margin-left: var(--divider-offset, 0);
|
||||
margin-right: var(--divider-offset, 0);
|
||||
width: 100%;
|
||||
margin-top: var(--divider-margin-top, 0.2rem);
|
||||
margin-bottom: var(--divider-margin-bottom, 2rem);
|
||||
transform: translateY(var(--divider-y, 0));
|
||||
|
|
@ -209,13 +215,8 @@ const t = getTranslations(lang);
|
|||
const HEADER_SCROLL_DISTANCE = 120;
|
||||
const DIRECTION_TRIGGER_DISTANCE = 6;
|
||||
const headerStyleProperties = [
|
||||
"--header-width",
|
||||
"--header-offset",
|
||||
"--header-inline-padding",
|
||||
"--header-surface-weight",
|
||||
"--header-blur",
|
||||
"--theme-top",
|
||||
"--theme-right",
|
||||
"--header-gap",
|
||||
"--header-nav-height",
|
||||
"--header-nav-y",
|
||||
|
|
@ -231,8 +232,6 @@ const t = getTranslations(lang);
|
|||
"--divider-margin-top",
|
||||
"--divider-margin-bottom",
|
||||
"--divider-inner-margin-bottom",
|
||||
"--divider-width",
|
||||
"--divider-offset",
|
||||
"--divider-y",
|
||||
];
|
||||
|
||||
|
|
@ -248,6 +247,7 @@ const t = getTranslations(lang);
|
|||
let headerFrame = 0;
|
||||
let headerMetrics: HeaderMetrics | null = null;
|
||||
let footerDividerObserver: IntersectionObserver | null = null;
|
||||
let isFooterDividerVisible = false;
|
||||
let lastScrollY = window.scrollY;
|
||||
let scrollDirection = 0;
|
||||
let directionDistance = 0;
|
||||
|
|
@ -297,6 +297,7 @@ const t = getTranslations(lang);
|
|||
if (!header) return;
|
||||
|
||||
updateScrollVisibility(header.parentElement, window.scrollY);
|
||||
updateFooterVisibility(header.parentElement, window.scrollY);
|
||||
|
||||
if (!desktopHeaderQuery.matches) {
|
||||
clearHeaderStyles(header);
|
||||
|
|
@ -328,12 +329,8 @@ const t = getTranslations(lang);
|
|||
Math.max(9 * rootFontSize, viewportWidth * 0.22),
|
||||
12 * rootFontSize,
|
||||
);
|
||||
const headerWidth = lerp(expandedWidth, viewportWidth, progress);
|
||||
const headerOffset = -(headerWidth - expandedWidth) / 2;
|
||||
const inlinePadding = lerp(0, rootFontSize, progress);
|
||||
const compactSiteNavWidth = Math.max(
|
||||
viewportWidth -
|
||||
2 * rootFontSize -
|
||||
expandedWidth -
|
||||
compactLogoWidth -
|
||||
7.5 * rootFontSize,
|
||||
0,
|
||||
|
|
@ -344,13 +341,8 @@ const t = getTranslations(lang);
|
|||
);
|
||||
|
||||
const values: Record<string, string> = {
|
||||
"--header-width": `${headerWidth}px`,
|
||||
"--header-offset": `${headerOffset}px`,
|
||||
"--header-inline-padding": `${inlinePadding}px`,
|
||||
"--header-surface-weight": `${lerp(0, 94, progress)}%`,
|
||||
"--header-blur": `${lerp(0, 10, progress)}px`,
|
||||
"--header-surface-weight": `${lerp(0, 98, progress)}%`,
|
||||
"--theme-top": `${lerp(0, 0.85 * rootFontSize, progress)}px`,
|
||||
"--theme-right": `${inlinePadding}px`,
|
||||
"--header-gap": `${lerp(rootFontSize, 0, progress)}px`,
|
||||
"--header-nav-height": `${lerp(expandedNavHeight, 3 * rootFontSize, progress)}px`,
|
||||
"--header-nav-y": `${lerp(0, 0.5 * rootFontSize, progress)}px`,
|
||||
|
|
@ -362,12 +354,10 @@ const t = getTranslations(lang);
|
|||
"--site-nav-x": `${lerp(0, compactLogoWidth + 1.5 * rootFontSize, progress)}px`,
|
||||
"--site-nav-y": `${lerp(0, -36, progress)}px`,
|
||||
"--site-nav-gap": `${lerp(1.5 * rootFontSize, compactNavGap, progress)}px`,
|
||||
"--site-nav-font-size": `${lerp(1.2 * rootFontSize, 1.05 * rootFontSize, progress)}px`,
|
||||
"--site-nav-font-size": `${lerp(1.05 * rootFontSize, 0.95 * rootFontSize, progress)}px`,
|
||||
"--divider-margin-top": `${lerp(0.2 * rootFontSize, 0.45 * rootFontSize, progress)}px`,
|
||||
"--divider-margin-bottom": `${lerp(2 * rootFontSize, 0, progress)}px`,
|
||||
"--divider-inner-margin-bottom": `${lerp(rootFontSize, 0, progress)}px`,
|
||||
"--divider-width": `${headerWidth}px`,
|
||||
"--divider-offset": `${-inlinePadding}px`,
|
||||
"--divider-y": `${lerp(0, -0.1 * rootFontSize, progress)}px`,
|
||||
};
|
||||
|
||||
|
|
@ -410,6 +400,23 @@ const t = getTranslations(lang);
|
|||
directionDistance = 0;
|
||||
}
|
||||
|
||||
function updateFooterVisibility(
|
||||
slot: HTMLElement | null,
|
||||
currentScrollY: number,
|
||||
) {
|
||||
if (!slot) return;
|
||||
|
||||
const headerIsFullyExpanded =
|
||||
currentScrollY >= HEADER_SCROLL_DISTANCE;
|
||||
|
||||
slot.classList.toggle(
|
||||
"is-footer-hidden",
|
||||
desktopHeaderQuery.matches &&
|
||||
headerIsFullyExpanded &&
|
||||
isFooterDividerVisible,
|
||||
);
|
||||
}
|
||||
|
||||
function requestHeaderUpdate() {
|
||||
if (headerFrame) return;
|
||||
|
||||
|
|
@ -422,6 +429,7 @@ const t = getTranslations(lang);
|
|||
function bindFooterDividerObserver() {
|
||||
footerDividerObserver?.disconnect();
|
||||
footerDividerObserver = null;
|
||||
isFooterDividerVisible = false;
|
||||
|
||||
const slot = document.querySelector<HTMLElement>(".header-slot");
|
||||
const footerDivider = document.querySelector<HTMLElement>(
|
||||
|
|
@ -435,7 +443,8 @@ const t = getTranslations(lang);
|
|||
if (!desktopHeaderQuery.matches || !footerDivider) return;
|
||||
|
||||
footerDividerObserver = new IntersectionObserver(([entry]) => {
|
||||
slot.classList.toggle("is-footer-hidden", entry.isIntersecting);
|
||||
isFooterDividerVisible = entry.isIntersecting;
|
||||
updateFooterVisibility(slot, window.scrollY);
|
||||
});
|
||||
footerDividerObserver.observe(footerDivider);
|
||||
}
|
||||
|
|
@ -454,6 +463,7 @@ const t = getTranslations(lang);
|
|||
lastScrollY = window.scrollY;
|
||||
scrollDirection = 0;
|
||||
directionDistance = 0;
|
||||
isFooterDividerVisible = false;
|
||||
document
|
||||
.querySelector<HTMLElement>(".header-slot")
|
||||
?.classList.remove("is-scroll-hidden");
|
||||
|
|
|
|||
|
|
@ -3,25 +3,48 @@ import { getLangFromUrl, getTranslations } from "@/i18n";
|
|||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const t = getTranslations(lang);
|
||||
const pathname = Astro.url.pathname;
|
||||
const items = [
|
||||
{ href: `/${lang}/`, label: t.nav.home, exact: true },
|
||||
{ href: `/${lang}/about/`, label: t.nav.about },
|
||||
{ href: `/${lang}/tags/`, label: t.nav.tags },
|
||||
{ href: `/${lang}/timeline/`, label: t.nav.timeline },
|
||||
{ href: `/${lang}/friends/`, label: t.nav.friends },
|
||||
];
|
||||
|
||||
const isCurrent = (href: string, exact = false) =>
|
||||
exact
|
||||
? pathname === href || pathname === href.slice(0, -1)
|
||||
: pathname.startsWith(href);
|
||||
---
|
||||
|
||||
<nav class="site-nav" aria-label="Site navigation">
|
||||
<div class="site-nav-desktop">
|
||||
<a href={`/${lang}/`}>{t.nav.home}</a>
|
||||
<a href={`/${lang}/about/`}>{t.nav.about}</a>
|
||||
<a href={`/${lang}/tags/`}>{t.nav.tags}</a>
|
||||
<a href={`/${lang}/timeline/`}>{t.nav.timeline}</a>
|
||||
<a href={`/${lang}/friends/`}>{t.nav.friends}</a>
|
||||
{
|
||||
items.map(({ href, label, exact }) => (
|
||||
<a
|
||||
href={href}
|
||||
aria-current={isCurrent(href, exact) ? "page" : undefined}
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<details class="site-nav-mobile">
|
||||
<summary>☰ {lang === "zh" ? "导航栏" : "Menu"}</summary>
|
||||
<div class="dropdown-menu">
|
||||
<a href={`/${lang}/`}>{t.nav.home}</a>
|
||||
<a href={`/${lang}/about/`}>{t.nav.about}</a>
|
||||
<a href={`/${lang}/tags/`}>{t.nav.tags}</a>
|
||||
<a href={`/${lang}/timeline/`}>{t.nav.timeline}</a>
|
||||
<a href={`/${lang}/friends/`}>{t.nav.friends}</a>
|
||||
{
|
||||
items.map(({ href, label, exact }) => (
|
||||
<a
|
||||
href={href}
|
||||
aria-current={isCurrent(href, exact) ? "page" : undefined}
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</details>
|
||||
</nav>
|
||||
|
|
@ -54,22 +77,45 @@ const t = getTranslations(lang);
|
|||
}
|
||||
|
||||
.site-nav a {
|
||||
color: black;
|
||||
text-decoration: underline;
|
||||
font-weight: 700;
|
||||
font-size: 1.2rem;
|
||||
position: relative;
|
||||
color: var(--text-color);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
font-size: 1.05rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.site-nav a:hover {
|
||||
text-decoration: underline;
|
||||
.site-nav-desktop a::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: -0.28rem;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: var(--deep-red);
|
||||
transform: translateX(-50%) scaleX(0);
|
||||
transform-origin: center;
|
||||
transition: transform 0.18s ease;
|
||||
}
|
||||
|
||||
.site-nav-desktop a:hover::after,
|
||||
.site-nav-desktop a:focus-visible::after,
|
||||
.site-nav-desktop a[aria-current="page"]::after {
|
||||
transform: translateX(-50%) scaleX(1);
|
||||
}
|
||||
|
||||
.site-nav a:focus-visible {
|
||||
outline: 2px solid var(--url-color);
|
||||
outline-offset: 0.35rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
:global(.dark) .site-nav a {
|
||||
color: white;
|
||||
color: var(--text-color-dark);
|
||||
}
|
||||
|
||||
:global(.dark) .site-nav a:hover {
|
||||
color: #ddd;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.site-nav-mobile {
|
||||
|
|
@ -81,10 +127,10 @@ const t = getTranslations(lang);
|
|||
list-style: none;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
color: black;
|
||||
text-decoration: underline;
|
||||
font-weight: 500;
|
||||
font-size: 1rem;
|
||||
color: var(--text-color);
|
||||
text-decoration: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
|
@ -121,6 +167,11 @@ const t = getTranslations(lang);
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.dropdown-menu a[aria-current="page"] {
|
||||
color: var(--deep-red);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
:global(.dark) .dropdown-menu {
|
||||
background: #1f1b18;
|
||||
border-color: #c8a98a;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import "katex/dist/katex.min.css";
|
|||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const htmlLang = lang === "zh" ? "zh-CN" : "en-US";
|
||||
const isHomePage = new RegExp(`^/${lang}/?$`).test(Astro.url.pathname);
|
||||
import SEO from "@/components/SEO.astro";
|
||||
import FloatingActions from "@/components/FloatingActions.astro";
|
||||
import Spinner from "@/components/Spinner.astro";
|
||||
|
|
@ -115,7 +116,7 @@ const {
|
|||
document.addEventListener("astro:page-load", addCodeCopyButtons);
|
||||
</script>
|
||||
|
||||
<body>
|
||||
<body class:list={{ "is-home": isHomePage }}>
|
||||
<Header />
|
||||
<Spinner />
|
||||
<main
|
||||
|
|
|
|||
|
|
@ -50,18 +50,32 @@ body::after {
|
|||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 400px;
|
||||
/* 按需调整大小 */
|
||||
height: 400px;
|
||||
/* 按需调整大小 */
|
||||
width: clamp(300px, 31vw, 400px);
|
||||
height: clamp(300px, 31vw, 400px);
|
||||
background-image: url("https://files.seeusercontent.com/2026/04/16/1sXb/touhou___kirisame_marisa__2__by_.webp");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right bottom;
|
||||
background-size: contain;
|
||||
opacity: 0.35;
|
||||
opacity: 0;
|
||||
-webkit-mask-image: radial-gradient(
|
||||
ellipse at right bottom,
|
||||
#000 0%,
|
||||
#000 38%,
|
||||
transparent 78%
|
||||
);
|
||||
mask-image: radial-gradient(
|
||||
ellipse at right bottom,
|
||||
#000 0%,
|
||||
#000 38%,
|
||||
transparent 78%
|
||||
);
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
transition: opacity 0.25s ease;
|
||||
}
|
||||
|
||||
body.is-home::after {
|
||||
opacity: 0.16;
|
||||
}
|
||||
|
||||
html.dark body::after {
|
||||
|
|
@ -69,7 +83,7 @@ html.dark body::after {
|
|||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
body::after {
|
||||
body.is-home::after {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -98,7 +112,7 @@ h1 {
|
|||
|
||||
a {
|
||||
color: var(--url-color);
|
||||
font-weight: 700;
|
||||
font-weight: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +133,6 @@ html.dark {
|
|||
|
||||
.dark .nav-links a {
|
||||
color: #9ecbff;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.dark .nav-links a:hover,
|
||||
|
|
@ -129,7 +142,6 @@ html.dark {
|
|||
|
||||
.dark a {
|
||||
color: #9ecbff;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.dark a:hover,
|
||||
|
|
@ -141,4 +153,4 @@ img {
|
|||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue