beautiful-ui
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBeautiful UI
精美UI
Build premium glassmorphism interfaces — dark-mode-first, with luminous glass surfaces, fluid animations, and meticulous visual polish using Next.js + Tailwind CSS v4.
使用Next.js + Tailwind CSS v4构建高级玻璃态界面——以暗黑模式为优先,搭配发光玻璃表面、流畅动画和细致的视觉打磨效果。
Design DNA
设计准则
Every interface follows these non-negotiable principles:
- Dark mode is the default — design for dark first, light is optional
- Glass is the primary surface — translucent layers with backdrop-blur over rich backgrounds
- Light is a material — use glows, gradients, and luminance to create depth
- Motion is intentional — every animation serves hierarchy, feedback, or delight
- Typography is bold — distinctive fonts, never generic (no Inter, Roboto, Arial)
每个界面都遵循这些不可妥协的原则:
- 暗黑模式为默认 —— 优先为暗黑模式设计,浅色模式为可选
- 玻璃为主要载体 —— 在丰富背景上使用带有 backdrop-blur 的半透明图层
- 光影为材质 —— 使用光晕、渐变和亮度来营造层次感
- 动效有目的性 —— 每个动画都服务于层级结构、反馈或视觉愉悦
- 排版风格鲜明 —— 使用有特色的字体,绝不使用通用字体(如Inter、Roboto、Arial)
Tailwind v4 Dark Glass Theme
Tailwind v4 暗黑玻璃主题
css
@import "tailwindcss";
@theme {
/* Dark-first color system using OKLCH */
--color-background: oklch(10% 0.015 270);
--color-surface: oklch(14% 0.01 270);
--color-elevated: oklch(18% 0.012 270);
--color-foreground: oklch(95% 0.005 270);
--color-foreground-muted: oklch(65% 0.01 270);
--color-foreground-subtle: oklch(45% 0.01 270);
/* Glass surface tokens */
--color-glass: oklch(100% 0 0 / 0.06);
--color-glass-hover: oklch(100% 0 0 / 0.1);
--color-glass-active: oklch(100% 0 0 / 0.14);
--color-glass-border: oklch(100% 0 0 / 0.12);
--color-glass-border-hover: oklch(100% 0 0 / 0.2);
/* Accent — a vibrant hue that glows on dark surfaces */
--color-accent: oklch(72% 0.19 250);
--color-accent-hover: oklch(78% 0.17 250);
--color-accent-muted: oklch(72% 0.19 250 / 0.15);
--color-accent-foreground: oklch(98% 0.005 270);
/* Status colors (muted to match dark glass aesthetic) */
--color-success: oklch(72% 0.17 155);
--color-warning: oklch(78% 0.15 75);
--color-destructive: oklch(65% 0.2 25);
--color-border: oklch(100% 0 0 / 0.08);
--color-ring: oklch(72% 0.19 250 / 0.5);
/* Radius — generous for glass surfaces */
--radius-sm: 0.5rem;
--radius-md: 0.75rem;
--radius-lg: 1rem;
--radius-xl: 1.25rem;
--radius-2xl: 1.5rem;
/* Glass-specific animations */
--animate-glass-in: glass-in 0.4s cubic-bezier(0.16, 1, 0.3, 1);
--animate-glow-pulse: glow-pulse 3s ease-in-out infinite;
--animate-fade-up: fade-up 0.5s cubic-bezier(0.16, 1, 0.3, 1);
--animate-scale-in: scale-in 0.3s cubic-bezier(0.16, 1, 0.3, 1);
--animate-shimmer: shimmer 2.5s linear infinite;
--animate-float: float 6s ease-in-out infinite;
@keyframes glass-in {
from { opacity: 0; backdrop-filter: blur(0px); transform: translateY(8px) scale(0.98); }
to { opacity: 1; backdrop-filter: blur(16px); transform: translateY(0) scale(1); }
}
@keyframes glow-pulse {
0%, 100% { box-shadow: 0 0 20px oklch(72% 0.19 250 / 0.15); }
50% { box-shadow: 0 0 40px oklch(72% 0.19 250 / 0.3); }
}
@keyframes fade-up {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes scale-in {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-8px); }
}
}
/* Base layer */
@layer base {
* { @apply border-border; }
body {
@apply bg-background text-foreground antialiased;
font-feature-settings: "cv02", "cv03", "cv04", "cv11";
}
}
/* Glass utility classes */
@utility glass {
@apply bg-glass backdrop-blur-xl border border-glass-border;
}
@utility glass-hover {
@apply hover:bg-glass-hover hover:border-glass-border-hover transition-all duration-200;
}
@utility glass-strong {
@apply bg-glass backdrop-blur-2xl backdrop-saturate-150 border border-glass-border;
}
@utility glow {
box-shadow: 0 0 20px oklch(72% 0.19 250 / 0.15),
0 0 60px oklch(72% 0.19 250 / 0.05);
}
@utility glow-border {
box-shadow: inset 0 0.5px 0 0 oklch(100% 0 0 / 0.15),
0 0 20px oklch(72% 0.19 250 / 0.1);
}
@utility text-glow {
text-shadow: 0 0 30px oklch(72% 0.19 250 / 0.5);
}
@utility noise {
position: relative;
}
/* Apply noise::after with a tiny noise SVG for texture */css
@import "tailwindcss";
@theme {
/* Dark-first color system using OKLCH */
--color-background: oklch(10% 0.015 270);
--color-surface: oklch(14% 0.01 270);
--color-elevated: oklch(18% 0.012 270);
--color-foreground: oklch(95% 0.005 270);
--color-foreground-muted: oklch(65% 0.01 270);
--color-foreground-subtle: oklch(45% 0.01 270);
/* Glass surface tokens */
--color-glass: oklch(100% 0 0 / 0.06);
--color-glass-hover: oklch(100% 0 0 / 0.1);
--color-glass-active: oklch(100% 0 0 / 0.14);
--color-glass-border: oklch(100% 0 0 / 0.12);
--color-glass-border-hover: oklch(100% 0 0 / 0.2);
/* Accent — a vibrant hue that glows on dark surfaces */
--color-accent: oklch(72% 0.19 250);
--color-accent-hover: oklch(78% 0.17 250);
--color-accent-muted: oklch(72% 0.19 250 / 0.15);
--color-accent-foreground: oklch(98% 0.005 270);
/* Status colors (muted to match dark glass aesthetic) */
--color-success: oklch(72% 0.17 155);
--color-warning: oklch(78% 0.15 75);
--color-destructive: oklch(65% 0.2 25);
--color-border: oklch(100% 0 0 / 0.08);
--color-ring: oklch(72% 0.19 250 / 0.5);
/* Radius — generous for glass surfaces */
--radius-sm: 0.5rem;
--radius-md: 0.75rem;
--radius-lg: 1rem;
--radius-xl: 1.25rem;
--radius-2xl: 1.5rem;
/* Glass-specific animations */
--animate-glass-in: glass-in 0.4s cubic-bezier(0.16, 1, 0.3, 1);
--animate-glow-pulse: glow-pulse 3s ease-in-out infinite;
--animate-fade-up: fade-up 0.5s cubic-bezier(0.16, 1, 0.3, 1);
--animate-scale-in: scale-in 0.3s cubic-bezier(0.16, 1, 0.3, 1);
--animate-shimmer: shimmer 2.5s linear infinite;
--animate-float: float 6s ease-in-out infinite;
@keyframes glass-in {
from { opacity: 0; backdrop-filter: blur(0px); transform: translateY(8px) scale(0.98); }
to { opacity: 1; backdrop-filter: blur(16px); transform: translateY(0) scale(1); }
}
@keyframes glow-pulse {
0%, 100% { box-shadow: 0 0 20px oklch(72% 0.19 250 / 0.15); }
50% { box-shadow: 0 0 40px oklch(72% 0.19 250 / 0.3); }
}
@keyframes fade-up {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes scale-in {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-8px); }
}
}
/* Base layer */
@layer base {
* { @apply border-border; }
body {
@apply bg-background text-foreground antialiased;
font-feature-settings: "cv02", "cv03", "cv04", "cv11";
}
}
/* Glass utility classes */
@utility glass {
@apply bg-glass backdrop-blur-xl border border-glass-border;
}
@utility glass-hover {
@apply hover:bg-glass-hover hover:border-glass-border-hover transition-all duration-200;
}
@utility glass-strong {
@apply bg-glass backdrop-blur-2xl backdrop-saturate-150 border border-glass-border;
}
@utility glow {
box-shadow: 0 0 20px oklch(72% 0.19 250 / 0.15),
0 0 60px oklch(72% 0.19 250 / 0.05);
}
@utility glow-border {
box-shadow: inset 0 0.5px 0 0 oklch(100% 0 0 / 0.15),
0 0 20px oklch(72% 0.19 250 / 0.1);
}
@utility text-glow {
text-shadow: 0 0 30px oklch(72% 0.19 250 / 0.5);
}
@utility noise {
position: relative;
}
/* Apply noise::after with a tiny noise SVG for texture */Glass Component Patterns
玻璃态组件模式
Glass Card (Primary Surface)
玻璃态卡片(主要载体)
tsx
import { cn } from "@/lib/utils";
export function GlassCard({
children,
className,
glow = false,
...props
}: React.HTMLAttributes<HTMLDivElement> & { glow?: boolean }) {
return (
<div
className={cn(
"relative overflow-hidden rounded-2xl",
"bg-white/[0.06] backdrop-blur-xl backdrop-saturate-150",
"border border-white/[0.12]",
"shadow-[0_8px_32px_rgba(0,0,0,0.4)]",
glow && "shadow-[0_0_30px_oklch(72%_0.19_250/0.12)]",
className
)}
{...props}
>
{/* Top highlight — simulates light hitting glass edge */}
<div className="absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-white/25 to-transparent" />
<div className="relative z-10">{children}</div>
</div>
);
}tsx
import { cn } from "@/lib/utils";
export function GlassCard({
children,
className,
glow = false,
...props
}: React.HTMLAttributes<HTMLDivElement> & { glow?: boolean }) {
return (
<div
className={cn(
"relative overflow-hidden rounded-2xl",
"bg-white/[0.06] backdrop-blur-xl backdrop-saturate-150",
"border border-white/[0.12]",
"shadow-[0_8px_32px_rgba(0,0,0,0.4)]",
glow && "shadow-[0_0_30px_oklch(72%_0.19_250/0.12)]",
className
)}
{...props}
>
{/* Top highlight — simulates light hitting glass edge */}
<div className="absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-white/25 to-transparent" />
<div className="relative z-10">{children}</div>
</div>
);
}Glass Button
玻璃态按钮
tsx
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const glassButtonVariants = cva(
"inline-flex items-center justify-center gap-2 rounded-xl font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-40",
{
variants: {
variant: {
default:
"bg-white/[0.08] backdrop-blur-lg border border-white/[0.12] text-foreground hover:bg-white/[0.14] hover:border-white/[0.2] active:bg-white/[0.18]",
accent:
"bg-accent text-accent-foreground hover:bg-accent-hover shadow-[0_0_20px_oklch(72%_0.19_250/0.25)] hover:shadow-[0_0_30px_oklch(72%_0.19_250/0.35)]",
ghost:
"text-foreground-muted hover:text-foreground hover:bg-white/[0.06]",
outline:
"border border-white/[0.15] text-foreground hover:bg-white/[0.06] hover:border-white/[0.25]",
},
size: {
sm: "h-9 px-3.5 text-sm",
default: "h-11 px-5 text-sm",
lg: "h-12 px-8 text-base",
icon: "size-10",
},
},
defaultVariants: { variant: "default", size: "default" },
}
);
export function GlassButton({
className,
variant,
size,
...props
}: React.ButtonHTMLAttributes<HTMLButtonElement> &
VariantProps<typeof glassButtonVariants>) {
return (
<button
className={cn(glassButtonVariants({ variant, size, className }))}
{...props}
/>
);
}tsx
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const glassButtonVariants = cva(
"inline-flex items-center justify-center gap-2 rounded-xl font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-40",
{
variants: {
variant: {
default:
"bg-white/[0.08] backdrop-blur-lg border border-white/[0.12] text-foreground hover:bg-white/[0.14] hover:border-white/[0.2] active:bg-white/[0.18]",
accent:
"bg-accent text-accent-foreground hover:bg-accent-hover shadow-[0_0_20px_oklch(72%_0.19_250/0.25)] hover:shadow-[0_0_30px_oklch(72%_0.19_250/0.35)]",
ghost:
"text-foreground-muted hover:text-foreground hover:bg-white/[0.06]",
outline:
"border border-white/[0.15] text-foreground hover:bg-white/[0.06] hover:border-white/[0.25]",
},
size: {
sm: "h-9 px-3.5 text-sm",
default: "h-11 px-5 text-sm",
lg: "h-12 px-8 text-base",
icon: "size-10",
},
},
defaultVariants: { variant: "default", size: "default" },
}
);
export function GlassButton({
className,
variant,
size,
...props
}: React.ButtonHTMLAttributes<HTMLButtonElement> &
VariantProps<typeof glassButtonVariants>) {
return (
<button
className={cn(glassButtonVariants({ variant, size, className }))}
{...props}
/>
);
}Glass Input
玻璃态输入框
tsx
export function GlassInput({
className,
...props
}: React.InputHTMLAttributes<HTMLInputElement>) {
return (
<input
className={cn(
"flex h-11 w-full rounded-xl px-4 text-sm",
"bg-white/[0.06] backdrop-blur-lg",
"border border-white/[0.1]",
"text-foreground placeholder:text-foreground-subtle",
"focus:outline-none focus:border-white/[0.25] focus:bg-white/[0.1]",
"focus:ring-2 focus:ring-accent/30",
"transition-all duration-200",
className
)}
{...props}
/>
);
}tsx
export function GlassInput({
className,
...props
}: React.InputHTMLAttributes<HTMLInputElement>) {
return (
<input
className={cn(
"flex h-11 w-full rounded-xl px-4 text-sm",
"bg-white/[0.06] backdrop-blur-lg",
"border border-white/[0.1]",
"text-foreground placeholder:text-foreground-subtle",
"focus:outline-none focus:border-white/[0.25] focus:bg-white/[0.1]",
"focus:ring-2 focus:ring-accent/30",
"transition-all duration-200",
className
)}
{...props}
/>
);
}Background Patterns
背景模式
Every glassmorphism UI needs a rich background. Use one per page:
每个玻璃态UI都需要丰富的背景,每页使用一种:
Mesh Gradient Background
网格渐变背景
tsx
export function MeshBackground() {
return (
<div className="fixed inset-0 -z-10 bg-background">
{/* Primary gradient orb */}
<div className="absolute top-[-20%] left-[-10%] h-[600px] w-[600px] rounded-full bg-[oklch(45%_0.15_270)] opacity-30 blur-[120px]" />
{/* Secondary orb */}
<div className="absolute bottom-[-10%] right-[-5%] h-[500px] w-[500px] rounded-full bg-[oklch(50%_0.18_200)] opacity-20 blur-[100px]" />
{/* Accent orb */}
<div className="absolute top-[40%] right-[20%] h-[300px] w-[300px] rounded-full bg-[oklch(60%_0.2_320)] opacity-15 blur-[80px]" />
{/* Subtle noise texture */}
<div className="absolute inset-0 opacity-[0.03]" style={{ backgroundImage: "url(\"data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\")" }} />
</div>
);
}tsx
export function MeshBackground() {
return (
<div className="fixed inset-0 -z-10 bg-background">
{/* Primary gradient orb */}
<div className="absolute top-[-20%] left-[-10%] h-[600px] w-[600px] rounded-full bg-[oklch(45%_0.15_270)] opacity-30 blur-[120px]" />
{/* Secondary orb */}
<div className="absolute bottom-[-10%] right-[-5%] h-[500px] w-[500px] rounded-full bg-[oklch(50%_0.18_200)] opacity-20 blur-[100px]" />
{/* Accent orb */}
<div className="absolute top-[40%] right-[20%] h-[300px] w-[300px] rounded-full bg-[oklch(60%_0.2_320)] opacity-15 blur-[80px]" />
{/* Subtle noise texture */}
<div className="absolute inset-0 opacity-[0.03]" style={{ backgroundImage: "url(\"data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\")" }} />
</div>
);
}Dot Grid Background
点阵网格背景
tsx
export function DotGridBackground() {
return (
<div className="fixed inset-0 -z-10 bg-background">
<div
className="absolute inset-0 opacity-[0.15]"
style={{
backgroundImage: "radial-gradient(oklch(100% 0 0 / 0.3) 1px, transparent 1px)",
backgroundSize: "24px 24px",
}}
/>
{/* Radial fade so dots don't tile harshly */}
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,transparent_0%,var(--color-background)_70%)]" />
</div>
);
}tsx
export function DotGridBackground() {
return (
<div className="fixed inset-0 -z-10 bg-background">
<div
className="absolute inset-0 opacity-[0.15]"
style={{
backgroundImage: "radial-gradient(oklch(100% 0 0 / 0.3) 1px, transparent 1px)",
backgroundSize: "24px 24px",
}}
/>
{/* Radial fade so dots don't tile harshly */}
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,transparent_0%,var(--color-background)_70%)]" />
</div>
);
}Animation Patterns
动效模式
Use Framer Motion for orchestrated animations. CSS for simple hover/transitions.
使用Framer Motion实现协调的动画效果,简单的悬停/过渡效果使用CSS实现。
Staggered Glass Cards
交错入场的玻璃态卡片
tsx
import { motion } from "framer-motion";
const container = {
hidden: {},
show: { transition: { staggerChildren: 0.08 } },
};
const item = {
hidden: { opacity: 0, y: 20, filter: "blur(4px)" },
show: {
opacity: 1, y: 0, filter: "blur(0px)",
transition: { duration: 0.5, ease: [0.16, 1, 0.3, 1] },
},
};
export function CardGrid({ cards }: { cards: CardData[] }) {
return (
<motion.div
variants={container}
initial="hidden"
animate="show"
className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"
>
{cards.map((card) => (
<motion.div key={card.id} variants={item}>
<GlassCard className="p-6">
{/* card content */}
</GlassCard>
</motion.div>
))}
</motion.div>
);
}tsx
import { motion } from "framer-motion";
const container = {
hidden: {},
show: { transition: { staggerChildren: 0.08 } },
};
const item = {
hidden: { opacity: 0, y: 20, filter: "blur(4px)" },
show: {
opacity: 1, y: 0, filter: "blur(0px)",
transition: { duration: 0.5, ease: [0.16, 1, 0.3, 1] },
},
};
export function CardGrid({ cards }: { cards: CardData[] }) {
return (
<motion.div
variants={container}
initial="hidden"
animate="show"
className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"
>
{cards.map((card) => (
<motion.div key={card.id} variants={item}>
<GlassCard className="p-6">
{/* card content */}
</GlassCard>
</motion.div>
))}
</motion.div>
);
}Interactive Glass Hover
交互式玻璃态悬停效果
tsx
<motion.div
whileHover={{
scale: 1.02,
boxShadow: "0 0 30px oklch(72% 0.19 250 / 0.2)",
}}
whileTap={{ scale: 0.98 }}
transition={{ type: "spring", stiffness: 400, damping: 25 }}
className="glass rounded-2xl p-6 cursor-pointer"
>
{children}
</motion.div>tsx
<motion.div
whileHover={{
scale: 1.02,
boxShadow: "0 0 30px oklch(72% 0.19 250 / 0.2)",
}}
whileTap={{ scale: 0.98 }}
transition={{ type: "spring", stiffness: 400, damping: 25 }}
className="glass rounded-2xl p-6 cursor-pointer"
>
{children}
</motion.div>Motion Spec
动效规范
| Interaction | Duration | Easing |
|---|---|---|
| Hover state | 150ms | |
| Button press | 100ms | |
| Card entrance | 400-500ms | |
| Modal open | 300ms | |
| Page transition | 400ms | |
| Stagger delay | 60-100ms | — |
| Glow pulse | 3s | |
| Float | 6s | |
Spring config for interactive elements:
{ stiffness: 400, damping: 25, mass: 0.8 }Performance rules:
- Only animate ,
transform,opacity,filter(GPU-accelerated)box-shadow - Respect — disable all non-essential motion
prefers-reduced-motion - Keep UI interaction durations under 500ms
| 交互类型 | 时长 | 缓动函数 |
|---|---|---|
| 悬停状态 | 150ms | |
| 按钮按压 | 100ms | |
| 卡片入场 | 400-500ms | |
| 模态框打开 | 300ms | |
| 页面过渡 | 400ms | |
| 交错延迟 | 60-100ms | — |
| 光晕脉冲 | 3s | |
| 浮动效果 | 6s | |
交互式元素的弹簧配置:
{ stiffness: 400, damping: 25, mass: 0.8 }性能规则:
- 仅对、
transform、opacity、filter进行动画(GPU加速属性)box-shadow - 尊重设置 —— 禁用所有非必要动效
prefers-reduced-motion - 保持UI交互时长在500ms以内
Typography
排版规范
Choose distinctive, characterful fonts. Pair a display font with a refined body font.
Strong pairings for dark glass aesthetics:
- Space Age: Orbitron (display) + DM Sans (body)
- Editorial Glow: Playfair Display (display) + Outfit (body)
- Neo-Geometric: Sora (display) + Plus Jakarta Sans (body)
- Monospace Hacker: JetBrains Mono (display) + Geist Sans (body)
- Elegant Precision: Cormorant Garamond (display) + Geist Sans (body)
Next.js font loading:
tsx
import { Sora, Plus_Jakarta_Sans } from "next/font/google";
const display = Sora({ subsets: ["latin"], variable: "--font-display" });
const body = Plus_Jakarta_Sans({ subsets: ["latin"], variable: "--font-body" });
// In layout.tsx body:
<body className={`${display.variable} ${body.variable} font-body`}>css
@theme inline {
--font-display: var(--font-display), system-ui;
--font-body: var(--font-body), system-ui;
}Scale (1.25 ratio):
- : 0.64rem — captions, badges
text-xs - : 0.8rem — labels, metadata
text-sm - : 1rem — body text
text-base - : 1.25rem — subheadings
text-lg - : 1.563rem — section titles
text-xl - : 1.953rem — page titles
text-2xl - : 2.441rem — hero (mobile)
text-3xl - : 3.052rem — hero (desktop)
text-4xl - : 3.815rem — display
text-5xl
Headlines: tight tracking ( to ), bold weight.
Body: default tracking, regular weight, .
-0.02em-0.04emleading-relaxed选择有特色、有个性的字体,将显示字体与精致的正文字体搭配使用。
适合暗黑玻璃美学的优质字体组合:
- 太空时代风格:Orbitron(显示字体) + DM Sans(正文字体)
- 编辑光晕风格:Playfair Display(显示字体) + Outfit(正文字体)
- 新几何风格:Sora(显示字体) + Plus Jakarta Sans(正文字体)
- ** monospace黑客风格**:JetBrains Mono(显示字体) + Geist Sans(正文字体)
- 优雅精准风格:Cormorant Garamond(显示字体) + Geist Sans(正文字体)
Next.js字体加载:
tsx
import { Sora, Plus_Jakarta_Sans } from "next/font/google";
const display = Sora({ subsets: ["latin"], variable: "--font-display" });
const body = Plus_Jakarta_Sans({ subsets: ["latin"], variable: "--font-body" });
// In layout.tsx body:
<body className={`${display.variable} ${body.variable} font-body`}>css
@theme inline {
--font-display: var(--font-display), system-ui;
--font-body: var(--font-body), system-ui;
}字号比例(1.25倍):
- : 0.64rem —— 说明文字、徽章
text-xs - : 0.8rem —— 标签、元数据
text-sm - : 1rem —— 正文内容
text-base - : 1.25rem —— 子标题
text-lg - : 1.563rem —— 章节标题
text-xl - : 1.953rem —— 页面标题
text-2xl - : 2.441rem —— 英雄区(移动端)
text-3xl - : 3.052rem —— 英雄区(桌面端)
text-4xl - : 3.815rem —— 展示用大标题
text-5xl
标题:字距收紧(至),加粗字重。
正文:默认字距,常规字重,。
-0.02em-0.04emleading-relaxedColor Strategy
色彩策略
Dark glassmorphism thrives on contrast between deep backgrounds and luminous accents.
Accent palette options (swap in the theme):
--color-accent- Electric Blue: — tech, modern, trustworthy
oklch(72% 0.19 250) - Violet Glow: — creative, premium
oklch(68% 0.2 290) - Cyan Neon: — futuristic, sharp
oklch(80% 0.16 195) - Emerald: — fresh, organic
oklch(72% 0.17 160) - Rose Gold: — warm, luxurious
oklch(72% 0.14 15) - Amber: — warm, energetic
oklch(80% 0.15 75)
Rules:
- One dominant accent per interface — secondary accents are desaturated or opacity-reduced
- Glass surfaces pick up ambient color from background gradient orbs
- Text on glass must pass WCAG AA (4.5:1) — use not
text-foregroundfor primary contenttext-foreground-subtle - Status colors (success/warning/destructive) are muted to not compete with accent
暗黑玻璃态美学的核心是深色背景与发光强调色之间的对比。
强调色选项(在主题中替换):
--color-accent- 电光蓝:—— 科技感、现代、可信
oklch(72% 0.19 250) - 紫罗兰光晕:—— 创意、高级
oklch(68% 0.2 290) - 霓虹青:—— 未来感、锐利
oklch(80% 0.16 195) - 祖母绿:—— 清新、自然
oklch(72% 0.17 160) - 玫瑰金:—— 温暖、奢华
oklch(72% 0.14 15) - 琥珀色:—— 温暖、有活力
oklch(80% 0.15 75)
规则:
- 每个界面仅使用一种主强调色 —— 次要强调色需降低饱和度或透明度
- 玻璃表面会从背景渐变球体中获取环境色
- 玻璃上的文字必须符合WCAG AA标准(4.5:1对比度)—— 主要内容使用而非
text-foregroundtext-foreground-subtle - 状态色(成功/警告/危险)需降低饱和度,避免与强调色冲突
Next.js Specifics
Next.js 专属配置
Layout with Glass Shell
带玻璃态外壳的布局
tsx
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className="dark">
<body className={`${display.variable} ${body.variable} font-body antialiased`}>
<MeshBackground />
<div className="relative z-10 min-h-screen">
<GlassNavbar />
<main className="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
{children}
</main>
</div>
</body>
</html>
);
}tsx
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className="dark">
<body className={`${display.variable} ${body.variable} font-body antialiased`}>
<MeshBackground />
<div className="relative z-10 min-h-screen">
<GlassNavbar />
<main className="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
{children}
</main>
</div>
</body>
</html>
);
}Glass Navbar
玻璃态导航栏
tsx
export function GlassNavbar() {
return (
<nav className="sticky top-0 z-50 border-b border-white/[0.08] bg-background/60 backdrop-blur-xl backdrop-saturate-150">
<div className="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6 lg:px-8">
{/* Logo + nav items */}
</div>
</nav>
);
}tsx
export function GlassNavbar() {
return (
<nav className="sticky top-0 z-50 border-b border-white/[0.08] bg-background/60 backdrop-blur-xl backdrop-saturate-150">
<div className="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6 lg:px-8">
{/* Logo + nav items */}
</div>
</nav>
);
}Page Transitions
页面过渡效果
tsx
// components/page-transition.tsx
"use client";
import { motion, AnimatePresence } from "framer-motion";
import { usePathname } from "next/navigation";
export function PageTransition({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
return (
<AnimatePresence mode="wait">
<motion.div
key={pathname}
initial={{ opacity: 0, y: 12, filter: "blur(4px)" }}
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
exit={{ opacity: 0, y: -8, filter: "blur(4px)" }}
transition={{ duration: 0.35, ease: [0.16, 1, 0.3, 1] }}
>
{children}
</motion.div>
</AnimatePresence>
);
}tsx
// components/page-transition.tsx
"use client";
import { motion, AnimatePresence } from "framer-motion";
import { usePathname } from "next/navigation";
export function PageTransition({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
return (
<AnimatePresence mode="wait">
<motion.div
key={pathname}
initial={{ opacity: 0, y: 12, filter: "blur(4px)" }}
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
exit={{ opacity: 0, y: -8, filter: "blur(4px)" }}
transition={{ duration: 0.35, ease: [0.16, 1, 0.3, 1] }}
>
{children}
</motion.div>
</AnimatePresence>
);
}Quality Checklist
质量检查清单
Glass & Visual
玻璃态与视觉效果
- Background has gradient orbs or mesh — never flat solid
- Glass surfaces have + border + top highlight
backdrop-blur-xl - Accent color has a visible glow on hover/focus
- Noise/grain texture overlay at low opacity for depth
- No pure white or pure black surfaces — always tinted
- 背景使用渐变球体或网格,而非纯色
- 玻璃表面带有、边框和顶部高光
backdrop-blur-xl - 强调色在悬停/聚焦时有可见的光晕效果
- 低透明度的噪点/颗粒纹理叠加,增强层次感
- 无纯白或纯黑表面,始终带有色调
Animation
动效
- Page load has staggered entrance animations
- Interactive elements have hover + active states with spring physics
- Modals/overlays animate in with scale + fade
- respected
prefers-reduced-motion
- 页面加载时有交错入场动画
- 交互式元素带有悬停+激活状态,使用弹簧物理效果
- 模态框/覆盖层使用缩放+淡入动画
- 尊重设置
prefers-reduced-motion
Typography
排版
- Display font is distinctive (not Inter/Roboto/Arial)
- Headings have tight tracking, body has relaxed leading
- Font loaded via with variable CSS
next/font
- 显示字体有特色(非Inter/Roboto/Arial)
- 标题字距收紧,正文字距宽松
- 使用加载字体,并配合CSS变量
next/font
Accessibility
可访问性
- Text contrast >= 4.5:1 on glass surfaces (test with backdrop)
- Focus rings visible (use )
ring-accent/50 - Touch targets >= 44px
- Keyboard navigation for all interactive elements
- Alt text on images, aria-labels on icon buttons
- 玻璃表面上的文字对比度≥4.5:1(需结合背景测试)
- 聚焦环可见(使用)
ring-accent/50 - 触摸目标尺寸≥44px
- 所有交互式元素支持键盘导航
- 图片带有替代文本,图标按钮带有aria标签
Performance
性能
- Animations use GPU properties only (transform, opacity, filter)
- Images use with proper sizing
next/image - Fonts preloaded, no layout shift
- limited to visible elements (avoid stacking)
backdrop-blur
- 仅对GPU加速属性(transform、opacity、filter)进行动画
- 图片使用并设置正确尺寸
next/image - 字体预加载,无布局偏移
- 仅应用于可见元素(避免多层叠加)
backdrop-blur
References
参考资料
For additional patterns, see:
- references/glass-patterns.md — Advanced glassmorphism component recipes
- references/animation-recipes.md — Framer Motion orchestration patterns
如需更多模式,请查看:
- references/glass-patterns.md —— 高级玻璃态组件实现方案
- references/animation-recipes.md —— Framer Motion协调动效模式