01Thẻ đăng nhập kiểu kính mờ (glassmorphism)
Một thẻ kính mờ trong suốt làm nhòe gradient phía sau, trong khi một vệt sáng mềm trôi chậm qua bề mặt để tôn lên chất liệu kính.
Dùng choModal đăng nhập trên trang landing sản phẩm, màn hình đầu tiên của SaaS theme tối
backdrop-filter: blur반투명 테두리@keyframes drift-a

<main class="stage">
<div class="glass-scene is-demo">
<span class="glass-scene__blob glass-scene__blob--a" aria-hidden="true"></span>
<span class="glass-scene__blob glass-scene__blob--b" aria-hidden="true"></span>
<form class="glass-card" autocomplete="off">
<h2 class="glass-card__title">Welcome back</h2>
<input class="glass-card__input" type="email" placeholder="Email">
<input class="glass-card__input" type="password" placeholder="Password">
<button class="glass-card__btn" type="button">Log in</button>
</form>
</div>
</main>@use "../../../../site/static/demo-tokens" as *;
$duration: $dur-base; // 카드 진입·호버 전환 시간
$easing: $ease-out;
$color: $subject-blue; // 블롭 색 1
@include stage($stage-ink);
.glass-scene {
position: relative;
width: min(240px, 80vw);
height: 168px;
display: grid;
place-items: center;
overflow: hidden;
border-radius: $r-card;
}
.glass-scene__blob {
position: absolute;
width: 140px;
height: 140px;
border-radius: 50%;
filter: blur(2px);
opacity: 1;
transform: translate(-30px, -20px);
}
.glass-scene__blob--a { background: radial-gradient(circle, #c5dfe2, transparent 68%); top: 8%; left: 8%; }
.glass-scene__blob--b { background: radial-gradient(circle, #eddae1, transparent 68%); bottom: 3%; right: 3%; }
.glass-card {
position: relative;
z-index: 1;
width: min(185px, 66vw);
padding: $sp-3;
display: flex;
flex-direction: column;
gap: $sp-1;
background: rgba(255, 255, 255, .14);
border: 1px solid rgba(255, 255, 255, .35);
border-radius: $r-card;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
box-shadow: $shadow-raised;
}
.glass-card__title { margin: 0 0 $sp-1; color: $stage-paper; font-size: 15px; font-weight: 700; font-family: inherit; }
.glass-card__input {
width: 100%;
box-sizing: border-box;
padding: $sp-2 $sp-3;
border-radius: $r-sm;
border: 1px solid rgba(255, 255, 255, .3);
background: rgba(255, 255, 255, .12);
color: $stage-paper;
font-size: 12px;
font-family: inherit;
&::placeholder { color: rgba(255, 255, 255, .65); }
&:focus-visible { outline: 2px solid $stage-paper; outline-offset: 1px; }
}
.glass-card__btn {
margin-top: $sp-1;
padding: $sp-2;
border: none;
border-radius: $r-sm;
background: $color;
color: $stage-paper;
font-weight: 700;
font-size: 12px;
font-family: inherit;
cursor: pointer;
transition: transform $dur-instant $easing, box-shadow $dur-instant $easing;
&:hover, &:focus-visible { transform: translateY(-1px); box-shadow: $shadow-press; }
&:active { transform: translateY(0); }
}
.glass-scene.is-demo .glass-scene__blob--a { animation: drift-a $dur-loop $easing infinite; }
.glass-scene.is-demo .glass-scene__blob--b { animation: drift-b $dur-loop $easing infinite; }
@keyframes drift-a {
0%, 100% { transform: translate(-30px, -20px) scale(1); }
50% { transform: translate(40px, 30px) scale(1.15); }
}
@keyframes drift-b {
0%, 100% { transform: translate(20px, 10px) scale(1); }
50% { transform: translate(-40px, -25px) scale(1.2); }
}
@media (prefers-reduced-motion: reduce) {
.glass-scene.is-demo .glass-scene__blob--a,
.glass-scene.is-demo .glass-scene__blob--b { animation: none; }
.glass-card__btn { transition: none; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #17141a;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.glass-scene {
position: relative;
width: min(240px, 80vw);
height: 168px;
display: grid;
place-items: center;
overflow: hidden;
border-radius: 16px;
}
.glass-scene__blob {
position: absolute;
width: 140px;
height: 140px;
border-radius: 50%;
filter: blur(2px);
opacity: 1;
transform: translate(-30px, -20px);
}
.glass-scene__blob--a {
background: radial-gradient(circle, #c5dfe2, transparent 68%);
top: 8%;
left: 8%;
}
.glass-scene__blob--b {
background: radial-gradient(circle, #eddae1, transparent 68%);
bottom: 3%;
right: 3%;
}
.glass-card {
position: relative;
z-index: 1;
width: min(185px, 66vw);
padding: 12px;
display: flex;
flex-direction: column;
gap: 4px;
background: rgba(255, 255, 255, 0.14);
border: 1px solid rgba(255, 255, 255, 0.35);
border-radius: 16px;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
box-shadow: 0 14px 24px rgba(23, 20, 26, 0.32);
}
.glass-card__title {
margin: 0 0 4px;
color: #ffffff;
font-size: 15px;
font-weight: 700;
font-family: inherit;
}
.glass-card__input {
width: 100%;
box-sizing: border-box;
padding: 8px 12px;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.3);
background: rgba(255, 255, 255, 0.12);
color: #ffffff;
font-size: 12px;
font-family: inherit;
}
.glass-card__input::placeholder {
color: rgba(255, 255, 255, 0.65);
}
.glass-card__input:focus-visible {
outline: 2px solid #ffffff;
outline-offset: 1px;
}
.glass-card__btn {
margin-top: 4px;
padding: 8px;
border: none;
border-radius: 8px;
background: #2f6df6;
color: #ffffff;
font-weight: 700;
font-size: 12px;
font-family: inherit;
cursor: pointer;
transition: transform 140ms ease-out, box-shadow 140ms ease-out;
}
.glass-card__btn:hover, .glass-card__btn:focus-visible {
transform: translateY(-1px);
box-shadow: 0 6px 12px rgba(23, 20, 26, 0.32);
}
.glass-card__btn:active {
transform: translateY(0);
}
.glass-scene.is-demo .glass-scene__blob--a {
animation: drift-a 2s ease-out infinite;
}
.glass-scene.is-demo .glass-scene__blob--b {
animation: drift-b 2s ease-out infinite;
}
@keyframes drift-a {
0%, 100% {
transform: translate(-30px, -20px) scale(1);
}
50% {
transform: translate(40px, 30px) scale(1.15);
}
}
@keyframes drift-b {
0%, 100% {
transform: translate(20px, 10px) scale(1);
}
50% {
transform: translate(-40px, -25px) scale(1.2);
}
}
@media (prefers-reduced-motion: reduce) {
.glass-scene.is-demo .glass-scene__blob--a,
.glass-scene.is-demo .glass-scene__blob--b {
animation: none;
}
.glass-card__btn {
transition: none;
}
}import type { CSSProperties } from "react";
import styles from "./GlassLoginCard.module.scss";
export type GlassLoginCardProps = {
/** 카드 등장 전환 시간 (기본 300ms) */
duration?: number;
easing?: string;
/** 카드 뒤 블롭 색 1 */
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
/** 반투명 카드가 backdrop-filter 로 뒤 블롭을 흐리게 비춘다. 블롭은 항상 천천히 움직인다 */
export default function GlassLoginCard({
duration = 300,
easing = "ease-out",
color = "#2f6df6",
}: GlassLoginCardProps) {
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
return (
<div className={styles.scene} style={vars}>
<span className={`${styles.blob} ${styles.blobA}`} aria-hidden="true" />
<span className={`${styles.blob} ${styles.blobB}`} aria-hidden="true" />
<form className={styles.card} onSubmit={(e: { preventDefault(): void }) => e.preventDefault()}>
<h2 className={styles.title}>Welcome back</h2>
<input className={styles.input} type="email" placeholder="Email" />
<input className={styles.input} type="password" placeholder="Password" />
<button className={styles.btn} type="submit">Log in</button>
</form>
</div>
);
}01 Thẻ đăng nhập kiểu kính mờ (glassmorphism) — Diện tích đo được 19.275% · khung hình chuyển động 18/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · 9 mẫu form đăng ký & đăng nhập copy-paste được
Bài viết chứa demo này
9 mẫu form đăng ký & đăng nhập copy-paste đượcMột mẫu form đăng ký tưởng chỉ có ô email, mật khẩu — nhưng là chín quyết định nhỏ: chất liệu thẻ, layout, tiến trình từ Xem tất cả demo trong bài này


