GODRICH
#css애니메이션#버튼#로딩#전환효과#스크롤#대시보드#실전ui#디자인트렌드

CSS 글래스모피즘 리퀴드 글래스 효과 9종

화면 위에 반투명한 유리판을 얹어 놓은 것처럼, 뒤 배경이 흐릿하게 비치면서 내용은 또렷하게 보이는 디자인을 CSS 글래스모피즘(리퀴드 글래스)이라고 부릅니다. 카드부터 내비게이션, 버튼, 토글까지 아홉 가지 유리 효과를 전부 한 줄 복붙으로 붙일 수 있게 모았습니다.

자동 재생 · 눌러서 해당 항목으로 · 전부 한 zip

아홉 개는 인기 순이 아니라 화면에서 유리 재질을 마주치는 순서를 따라갑니다. 정지해 있어도 유리로 보이는 것(01 카드·02 내비게이션)에서 시작해, 누르거나 지나가야 반응하는 것(03 버튼·04 움직이는 배경)을 지나, 클릭으로 여닫는 것(05 모달)과 마우스를 얹어야 살아나는 것(06 커서 추적)을 거쳐, 마지막은 고르고 켜고 입력하는 컨트롤(07 탭·08 토글·09 인풋)로 끝납니다. 유리판 안에 사진을 넘겨 보여 준다면 CSS 이미지 슬라이드 애니메이션이 그 짝이고, 성공을 축하하는 파티를 열 거라면 컨페티 축하 애니메이션이 그 뒤를 따릅니다.

01프로스티드 카드

유리 느낌 디자인은 어디에 쓰나

포트폴리오나 랜딩 페이지의 소개 카드에 backdrop-filter: blur()와 반투명 배경을 올리면, 뒤에 있는 색이 흐릿하게 비치면서 카드가 유리판처럼 떠 보입니다.

프로스티드 카드
새 창에서 열기

01 · 프로스티드 카드 — 측정 누적면적 4.222% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

backdrop-filterscale300ms

무엇이 핵심인가

마우스를 올리면 카드가 살짝 커지고 그림자가 깊어집니다.

.fc-card {
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .35);
  backdrop-filter: blur(16px) saturate(160%);
  box-shadow: $shadow-press;
  transition: transform $duration $easing, box-shadow $duration $easing;
}
.fc-focal:hover {
  transform: scale(1.03);
  box-shadow: $shadow-raised;
}

02유리 내비게이션

언제 쓰나

반투명 유리 재질 내비게이션 바 안에서 지금 선택된 메뉴 뒤로 흐릿한 유리 알약이 translateX로 옮겨 다닙니다.

유리 내비게이션
새 창에서 열기

02 · 유리 내비게이션 — 측정 누적면적 6.783% · 움직인 프레임 14/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

backdrop-filtertranslateX220ms

짚어 둘 점

탭 폭을 고정값으로 둬서 어떤 메뉴를 눌러도 알약이 정확한 자리에 멈춥니다.

.gn-link { flex: 0 0 auto; width: $w; }
.gn-pill {
  position: absolute;
  width: $w;
  background: rgba(255, 255, 255, .6);
  transform: translateX(0);
  transition: transform $duration $easing;
}
.gn-nav:has(.gn-link:nth-child(3):hover) .gn-pill {
  transform: translateX(calc(#{$w} + #{$sp-2}));
}

03굴절 하이라이트 버튼

어떤 화면인가

버튼 표면에 좁은 빛줄기 레이어를 올려 두고, 마우스를 올리면 그 빛줄기가 버튼을 가로질러 한 번 지나가 액체 유리가 굴절되듯 반짝입니다.

굴절 하이라이트 버튼
새 창에서 열기

03 · 굴절 하이라이트 버튼 — 측정 누적면적 3.422% · 움직인 프레임 10/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

backdrop-filtertranslateX600ms

어떻게 만들었나

.lb-btn::before {
  content: "";
  position: absolute;
  width: 40%; height: 140%;
  background: linear-gradient(100deg, transparent, $color, transparent);
  transform: translateX(-40%) skewX(-18deg);
  transition: transform $duration $easing;
}
.lb-focal:hover::before {
  transform: translateX(340%) skewX(-18deg);
}

04움직이는 블롭 배경

무엇이 움직이나

유리 패널 뒤에서 색이 다른 흐린 블롭 두 개가 transform으로 천천히 자리를 바꾸며 떠다니고, 패널의 backdrop-filter가 그 움직임을 흐릿하게 비춥니다.

움직이는 블롭 배경
새 창에서 열기

04 · 움직이는 블롭 배경 — 측정 누적면적 41.944% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

transformblur(40px)2s loop

코드 읽는 법

.bb-blob { border-radius: 50%; filter: blur(26px); }
.bb-blob--a { animation: bb-drift-a $duration $easing infinite; }
@keyframes bb-drift-a {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(110px, 70px); }
}

05유리 모달

어디에 쓰나

확인 버튼을 누르면 유리 재질 모달 패널이 opacity와 scale로 작게 접혀 있다가 커지며 나타나고, 뒤 화면은 흐릿하게 비칩니다.

유리 모달
새 창에서 열기

05 · 유리 모달 — 측정 누적면적 14.35% · 움직인 프레임 10/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

opacityscale600ms

코드의 요점

.gm-modal {
  opacity: 0;
  transform: scale(.85);
  transition: opacity $duration $easing, transform $duration $easing;
}
.gm-check:checked ~ .gm-modal {
  opacity: 1;
  transform: scale(1);
}

06마우스 따라 광택

눈에 보이는 것

커다란 유리 패널 위에서 마우스를 움직이면 좌표를 저장한 --mx·--my 커스텀 속성을 따라 타원형 광택이 실시간으로 따라다녀, 유리 표면을 문지르는 듯한 반사가 생깁니다.

마우스 따라 광택
새 창에서 열기

06 · 마우스 따라 광택 — 측정 누적면적 37.717% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

custom propertyradial-gradientJS 8줄

동작 원리

panel.addEventListener('pointermove', function (e) {
  var r = panel.getBoundingClientRect();
  var x = ((e.clientX - r.left) / r.width * 100) + '%';
  var y = ((e.clientY - r.top) / r.height * 100) + '%';
  panel.style.setProperty('--mx', x);
  panel.style.setProperty('--my', y);
});
.rh-panel::before {
  background: radial-gradient(120px 80px at var(--mx) var(--my), $color 0%, transparent 70%);
}

07유리 탭

어떤 상황인가

유리 재질 탭 그룹 안에서 탭을 고르면 반투명 유리 인디케이터가 고정 폭 그대로 translateX로 그 탭 아래로 옮겨 갑니다.

유리 탭
새 창에서 열기

07 · 유리 탭 — 측정 누적면적 6.422% · 움직인 프레임 14/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

backdrop-filtertranslateX220ms

만드는 방식

.gt__tab { flex: 0 0 auto; width: $w; }
.gt__pill {
  position: absolute;
  width: $w;
  transform: translateX(0);
  transition: transform $duration $easing;
}
#gt-2:checked ~ .gt__nav .gt__pill {
  transform: translateX(calc(#{$w} + #{$sp-2}));
}

08유리 토글

무슨 일이 일어나나

유리 재질 트랙 안에서 손잡이가 켜짐·꺼짐 사이를 translateX로 미끄러지듯 오가고, 트랙 배경색도 함께 옅게 바뀝니다.

유리 토글
새 창에서 열기

08 · 유리 토글 — 측정 누적면적 1.328% · 움직인 프레임 12/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

backdrop-filtertranslateX300ms

왜 이렇게 만들었나

.sw__knob {
  transform: translateX(0);
  transition: transform $duration $easing, box-shadow $duration $easing;
}
.sw__input:checked ~ .sw__track .sw__knob {
  transform: translateX(22px);
  box-shadow: $shadow-raised;
}
.sw__input:checked ~ .sw__track { background: rgba($color, .55); }

09유리 인풋

화면에서 벌어지는 일

유리 재질 입력창에 초점이 가면 테두리 빛이 밝아지고 위쪽 라벨이 translateY로 살짝 떠오르며 자리를 잡습니다.

유리 인풋
새 창에서 열기

09 · 유리 인풋 — 측정 누적면적 2.953% · 움직인 프레임 15/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

box-shadowtranslateY220ms

구현의 핵심

.gi-field__label {
  transform: translateY(-50%) scale(1);
  transition: transform $duration $easing, color $duration $easing;
}
.gi-field:focus-within .gi-field__label {
  transform: translateY(-14px) scale(.82);
}
.gi-field:focus-within .gi-focal {
  border-color: rgba($color, .9);
  box-shadow: 0 0 0 3px rgba($color, .35), $shadow-raised;
}

글래스모피즘은 어디서 깨지는가

무엇이 문제인가

아이폰 리퀴드 글래스 효과를 흉내 낼 때도 마찬가지로, 아홉 개 중 가장 자주 걸려 넘어지는 지점은 backdrop-filter 자체입니다. 이 속성은 자기 뒤에 있는 실제 콘텐츠를 흐릿하게 비추는 방식이라, 뒤에 아무것도 없거나 배경이 통짜 단색이면 아무리 값을 키워도 "그냥 반투명한 상자"로만 보입니다. 04번처럼 흐린 블롭을 따로 깔아 두거나, 실제 페이지에서는 이미지·그라디언트·다른 콘텐츠가 카드 뒤로 지나가야 유리 느낌이 삽니다. 블러 값도 과하면 문제입니다 — 04번을 처음 만들 때 blur(40px)를 썼더니 인접한 두 프레임 사이의 색 차이가 너무 작아져 애니메이션 측정 도구가 "정지 화면"으로 오판했습니다.

어떻게 피하나

배경과 부품의 명도 차가 사라지면 형태가 녹아 없어지는데, 그림자 두 겹만으로 형태를 세우는 뉴모피즘 랜딩 UI에서는 이 대비 계산이 디자인 전부입니다.

08번처럼 무대 배경과 유리 색이 둘 다 밝으면(흰 바탕에 흰 유리) 테두리와 그림자를 더 진하게 줘야 윤곽이 살아남고, 그렇지 않으면 아예 안 보이는 상자가 됩니다. 이 아홉 개를 담은 압축 파일을 열려면 열쇠글이 하나 필요한데, vn8q8tgw 이 문단 뒷부분을 눈여겨보면 그 안에 그대로 섞여 있습니다. backdrop-filter는 Safari·Chrome·Edge·Firefox 최신 버전에서 널리 지원되지만, 오래된 브라우저에서는 그냥 반투명 배경만 보이므로 필수 정보를 블러 효과 하나에만 의존해서는 안 됩니다.

접근성 — 아홉 개가 reduced-motion에서 남기는 것

reduced-motion 에서 남는 것

시스템에서 동작 줄이기를 켜면 아홉 개 전부 prefers-reduced-motion: reduce에서 animation과 transition을 꺼서 움직임을 멈춥니다. 01·02·03·07·08·09처럼 호버·클릭에 반응하는 장식은 마지막 상태로 바로 전환되면 충분하지만, 04의 떠다니는 블롭과 06의 커서 추적 광택은 움직임 자체가 콘텐츠는 아니므로 정지해도 화면 정보가 전혀 줄지 않습니다. backdrop-filter는 저사양 기기에서 그리기 비용이 커서 항목 수가 많은 실제 페이지라면 동시에 적용되는 유리 패널 개수를 제한하는 것도 함께 고려할 만합니다.

이어서 볼 글

같은 CSS 유리 질감을 카드형 배경 대신 그리드 레이아웃에서 보고 싶다면 CSS 벤토 그리드 레이아웃 호버 애니메이션 9종 글도 참고할 만하고, 전체 목록은 CSS 애니메이션 카테고리에서 모아 볼 수 있습니다.

FAQ — 자주 묻는 질문

글래스모피즘에 꼭 backdrop-filter가 필요한가요?

네, 뒤 배경을 흐릿하게 비추는 핵심은 backdrop-filter: blur()입니다. background: rgba(255,255,255,.14)만으로는 반투명한 판만 될 뿐 뒤가 흐려지지 않아 유리 느낌이 나지 않습니다. 두 속성을 항상 같이 씁니다.

리퀴드 글라스 효과는 오래된 브라우저에서 어떻게 보이나요?

backdrop-filter를 지원하지 않으면 블러 없이 반투명 배경(rgba(255,255,255,.14) 같은 값)만 그대로 남습니다. 내용을 읽는 데는 지장이 없지만 유리 질감은 사라지므로, 대비가 너무 낮은 글자색은 피하는 게 안전합니다.

zip 안의 vanilla와 react 코드가 다른가요?

동작은 같습니다. vanilla는 체크박스·라디오처럼 순수 HTML 상태로 열림·선택을 표현하고, React 판은 같은 상태를 useState로 옮겼습니다. 05·07·08번이 이 차이가 가장 뚜렷한 항목입니다. 유리 카드에 커서를 얹었을 때의 반응까지 설계하고 싶으면 CSS 카드 호버 효과에 그 문법이 있습니다.

압축 비밀번호를 입력하세요

비밀번호는 이 글 본문 안에 있습니다. 읽다 보면 나옵니다.