글래스모피즘(Glassmorphism) 디자인을 React와 TailwindCSS로 구현하는 방법을 소개합니다. 반투명 카드와 배경 이미지를 활용해 현대적인 UI를 만드는 실전 예제와 코드까지 제공합니다.
이 글에서는 React와 Tailwind CSS로 만든 간단한 글래스모피즘(Glassmorphism) 컴포넌트를 소개합니다. 글래스모피즘은 반투명 유리처럼 보이는 카드와 배경의 블러(blur)를 조합해 깊이와 질감을 만드는 디자인 트렌드입니다.
아래 컴포넌트는 이 블로그에서 사용하는 Glassmorphism 컴포넌트의 전체 코드와 사용 예시, 구현 시 고려할 점들을 정리한 것입니다.
다음은 glassmorphism.tsx 파일의 코드입니다.
import { classNames } from "@/lib/class-names"; // className을 병합하는 유틸 함수
import Image from "next/image";
export default function Glassmorphism({
className,
backgroundAlt,
backgroundImage,
backgroundClassName,
children,
childrenClassName,
copy,
copyClassName,
}: {
className?: string;
backgroundAlt?: string;
backgroundImage: string;
backgroundClassName?: string;
children: React.ReactNode;
childrenClassName?: string;
copy?: React.ReactNode;
copyClassName?: string;
}) {
return (
<div
className={classNames(
"not-prose relative aspect-square overflow-hidden rounded-sm",
className,
)}
>
<div className="absolute inset-0 z-0">
<Image
alt={backgroundAlt ?? ""}
src={backgroundImage}
fill
sizes="(max-width: 640px) 100vw, 50vw"
className={classNames(
"object-cover object-center",
backgroundClassName,
)}
aria-hidden={backgroundAlt ? undefined : true}
priority={false}
/>
</div>
<div
className={classNames(
"absolute z-10 bg-white/20 backdrop-blur-none rounded-md shadow-xl p-4 border border-white/40 sm:backdrop-blur-md",
"transition-transform duration-200 ease-out will-change-transform motion-reduce:transition-none motion-reduce:transform-none",
"hover:scale-105 hover:-translate-y-1 hover:shadow-2xl",
"focus-within:scale-105 focus-within:-translate-y-1 focus-within:shadow-2xl",
"focus-within:ring-2 focus-within:ring-white/40 focus-within:ring-offset-2",
childrenClassName,
)}
tabIndex={-1}
>
{children}
</div>
{copy && (
<div
className={classNames(
"absolute z-10 text-xs bottom-2 left-3",
copyClassName,
)}
>
{copy}
</div>
)}
</div>
);
}relative와 overflow-hidden을 사용해 내부 절대 위치 요소들이 영역을 벗어나지 않게 합니다. 현재는 aspect-square로 기본 비율을 고정합니다(원하면 제거 가능).<Image />(fill)로 렌더링하여 브라우저/프레임워크 차원의 이미지 최적화와 레이지 로딩 혜택을 받습니다. 배경이 장식용이면 aria-hidden을 적용해 스크린 리더에서 무시되도록 하고, 의미 있는 이미지면 backgroundAlt를 전달해 대체 텍스트를 제공합니다.bg-white/20 + backdrop-blur-md로 반투명 유리 효과를 만들고 rounded-md, shadow-xl, border border-white/40 등으로 질감을 더합니다.hover: 유틸로 처리하고, 키보드 접근성은 카드 내부 요소가 포커스될 때(:focus-within) 동일한 리프트(확대/상승/그림자) 효과를 적용합니다. 또한 motion-reduce 유틸로 사용자의 모션 선호에 따른 폴백을 제공합니다.tabIndex={-1}를 둬서 문서의 탭 순서에 들어가지 않도록 하고, 내부의 실제 인터랙티브 요소(예: <a>, <button>)가 탭으로 접근 가능하도록 설계했습니다.backgroundClassName, childrenClassName, copyClassName로 배경, 카드 내부 요소, 카피 텍스트의 스타일을 덮어쓸 수 있습니다.다음은 위 컴포넌트를 사용하는 예시입니다.
<Glassmorphism
backgroundImage="/content/images/yousef-espanioly-hL4JNNkWiwI-unsplash.jpg"
childrenClassName="left-1/10 top-1/5 w-1/2"
copy={
<div>
사진:{" "}
<a
href="https://unsplash.com/ko/%EC%82%AC%EC%A7%84/%EC%9E%94%EC%9E%94%ED%95%9C-%ED%8C%8C%EB%8F%84%EC%99%80-%ED%95%A8%EA%BB%98-%EB%B0%94%EC%9C%84-%ED%95%B4%EB%B3%80-%EC%9C%84%EB%A1%9C-%EC%A7%80%EB%8A%94-%EC%9D%BC%EB%AA%B0-hL4JNNkWiwI?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash"
target="_blank"
rel="noopener noreferrer"
>
Unsplash
</a>
의{" "}
<a
href="https://unsplash.com/ko/@yespanioly?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash"
target="_blank"
rel="noopener noreferrer"
>
Yousef Espanioly
</a>
</div>
}
copyClassName="text-white"
>
<div className="text-white">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</Glassmorphism>성능(Performance)
backdrop-blur를 완화하거나 제거하는 미디어 쿼리 폴백을 적용하세요.이미지 최적화
<Image />를 사용해 자동 최적화와 적절한 크기 선택을 활용하세요.priority나 적절한 sizes를 설정해 LCP를 개선하세요. 덜 중요한 배경이면 lazy-loading(기본)에 맡기면 됩니다.접근성(Accessibility)
aria-hidden을 설정해 스크린 리더에서 무시하게 하세요. 의미가 있다면 backgroundAlt처럼 적절한 대체 텍스트를 제공하세요.tabIndex={-1}), 내부의 실제 인터랙티브 요소(<a>, <button>)에 탭 접근성을 맡기세요. 내부 포커스가 있을 때 카드에 시각적 변화를 주려면 :focus-within을 사용하세요.:focus-visible 스타일을 명확히 해서 포커스 이동이 눈에 띄게 하세요(예: outline 또는 ring).반응형(Responsive)
aspect-square는 간편하지만 모든 레이아웃에 적합하지 않을 수 있습니다. 카드 크기와 패딩은 뷰포트에 맞춰 미디어 쿼리로 조절하세요. 내부 텍스트가 넘치지 않도록 max-w 또는 text-sm 같은 유틸도 고려합니다.글래스모피즘은 적절히 쓰면 세련된 느낌을 줄 수 있지만, 남용하면 가독성과 성능 문제를 일으킬 수 있습니다. 위 컴포넌트는 간단한 시작점이므로 필요에 따라 확장해서 사용해 보세요.