# 브라우저에서 Liquid Glass 구현: CSS와 SVG를 활용한 빛의 굴절

> Clean Markdown view of GeekNews topic #22989. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=22989](https://news.hada.io/topic?id=22989)
- GeekNews Markdown: [https://news.hada.io/topic/22989.md](https://news.hada.io/topic/22989.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-09-09T21:33:52+09:00
- Updated: 2025-09-09T21:33:52+09:00
- Original source: [kube.io](https://kube.io/blog/liquid-glass-css-svg/)
- Points: 5
- Comments: 2

## Summary

애플이 WWDC 2025에서 공개한 **Liquid Glass** 시각 효과를 웹에서 **CSS, SVG, 그리고 물리 기반 굴절 계산**으로 구현하는 기법을 소개합니다. 핵심은 **Snell의 법칙** 등 광학 원리를 기반으로 실제 유리 표면처럼 **빛의 변형(굴절)**을 정확히 시뮬레이션하고, 이를 **SVG displacement map**을 이용해 브라우저 UI 컴포넌트에 적용하는 점입니다. **Chrome** 우선으로 **SVG filter와 backdrop-filter**를 결합해 다양한 UI 요소(돋보기, 스위치 등)에 실시간 효과를 구현하였고, Open Source 공개 가능성까지 언급합니다. 실제 프로덕션 도입 전 고려할 브라우저 호환성과 퍼포먼스 이슈를 짚으면서도, **차세대 유리 효과 인터페이스** 구현에 관심 있는 개발자라면 살펴볼 만한 내용입니다.

## Topic Body

- **Apple**이 2025년 WWDC에서 공개한 **Liquid Glass 효과**를 웹에서 **CSS와 SVG, 물리 기반 굴절 계산**으로 재현하는 방법 소개임
- **굴절 현상**의 원리와 **Snell의 법칙**을 활용한 **유리 표면 묘사**와 굴절 시뮬레이션 과정을 설명함
- **SVG displacement map** 이용해 렌더링에 적합한 **변위 벡터 필드**를 생성하고, 실제 UI 컴포넌트에 적용 가능함을 시연함
- Chrome에 한해 **SVG filter를 backdrop-filter로 활용** 가능하며, 다양한 **UI 요소(돋보기, 스위치, 플레이어 등)** 에 적용하는 예시를 제시함
- 실시간 효과 구현이 가능하지만 크로스 브라우저 문제 및 퍼포먼스 제한이 있고, 향후 오픈소스 계획이 있음을 언급함

---

### 소개

Apple은 2025년 6월 WWDC에서 **Liquid Glass 효과**를 최초로 선보였음. 이 효과는 인터페이스 요소가 곡선의 **굴절 유리**처럼 보이도록 해 실제 유리 표면과 유사한 시각적 경험을 제공함. 이 글에서는 웹 환경에서 **CSS, SVG displacement map, 물리 기반 굴절 계산**을 통해 유사한 효과를 만드는 실습을 다룸. 완전한 구현은 목표가 아니고, 굴절과 반사 하이라이트 등 주요 특징을 재현한 **확장 가능한 개념 증명**을 목표로 함. 빛이 서로 다른 재질을 통과할 때 어떻게 **굴절**되는지 기초 원리로부터 시작해 단계별로 효과를 구축함. 마지막에 제공되는 인터랙티브 데모는 현재 Chrome에서만 정상 동작함.

### 굴절 현상의 이해

**굴절**이란 빛이 한 재질에서 다른 재질로 이동할 때 진행 방향이 바뀌는 현상임. 각 재질마다 **빛의 속도**가 다르기 때문에 발생하며, **Snell의 법칙**으로 입사각과 굴절각의 관계가 수식으로 표현됨:
- n1 * sin(θ1) = n2 * sin(θ2)
  - n1: 첫 번째 매질의 굴절률
  - θ1: 입사각
  - n2: 두 번째 매질의 굴절률
  - θ2: 굴절각

인터랙티브 다이어그램에서 확인할 수 있는 것:
- 두 매질의 굴절률이 같으면 빛은 굴절 없이 직진함
- 두 번째 매질이 더 높은 굴절률일 때 빛은 법선 방향으로 굴절함
- 두 번째 매질이 더 낮은 굴절률이면 빛이 멀어지며, 경우에 따라 내부 전반사가 발생할 수 있음
- 입사광이 표면에 수직이면 굴절률과 무관하게 직진함

#### 이 프로젝트의 한계

복잡도를 제한하고 알고리듬을 단순화하기 위해 다음과 같은 조건을 설정함:
- 외부 매질 굴절률은 1 (공기)
- 내부 유리 재질은 1.5 사용 (일반적인 유리)
- 굴절 이벤트는 한 번만 고려 (출구에서의 굴절 무시)
- 입사광은 항상 배경면에 수직
- 모든 오브젝트는 2D 도형, 원 형태만 사용 (직사각형 등 확장 가능하지만 계산 필요)
- 오브젝트와 배경면 사이에 틈이 없음
- 이 조건을 통하면 Snell의 법칙으로 모든 광선을 단순 계산 가능

### 유리 표면 만들기

Liquid Glass 효과 구현을 위해선 가상 유리의 단면(렌즈 또는 곡면 판넬)을 수학적 함수로 정의해야 함.

#### 표면 함수

유리 표면은 **surface function**으로 정의되며, 가장자리에서 평평한 내부까지의 두께를 나타냄
- 함수 입력값 0: 외곽, 1: 베젤 끝 (평면 시작)
- 각 점의 두께에서 도함수를 통해 표면의 **법선 벡터** 구함

```js
const height = f(distanceFromSide);
const delta = 0.001;
const y1 = f(distanceFromSide - delta);
const y2 = f(distanceFromSide + delta);
const derivative = (y2 - y1) / (2 * delta);
const normal = { x: -derivative, y: 1 };
```

#### 주요 표면 함수 유형

- **Convex Circle**: y = sqrt((1 - (1 - x))^2)  
  - 간단한 원호 형태, 내부로 갈수록 급격하게 평평해져 굴절 가장자리가 뚜렷함
- **Convex Squircle**: y = ((1 - (1 - x))^4)^(1/4)
  - Apple에서 즐겨 사용하는 형태, 곡선과 평면의 경계가 부드러워 확장 시에도 효과가 자연스러움
- **Concave**: y = 1 - Convex(x)
  - 오목(볼록 반대) 형태, 빛이 오브젝트 경계 바깥으로 굴절되어 바깥 샘플링이 필요함
- **Lip**: y = mix(Convex(x), Concave(x), Smootherstep(x))
  - 가장자리에 돌출된 립, 중앙에 얕은 굴곡이 있는 복합 구조

이 네 가지 함수만으로도 표면 형상에 따른 굴절 차이를 효과적으로 비교 가능함

#### 시뮬레이션

각 표면 함수에 따라 **광선의 굴절 경로**를 시뮬레이션하여 실제 효과 차이를 시각화함.  
- 볼록(Convex)은 빛의 경로를 내부로 묶고, 오목(Concave)은 외부로 밀어냄
- Apple의 Liquid Glass는 대부분 볼록 형태를 선호 (Switch 등 예외)
- 배경 화살표는 굴절량(변위)을 마그니튜드로 색을 입혀 표시함  
- 좌우 경계에서 같은 거리에선 동일한 변위를 가져 효율적 재사용 가능

### 변위 벡터 필드 생성

유리 표면 전체에서 각 위치별로 **빛의 변위 방향과 크기**를 나타내는 벡터 필드를 구축함
- 원형에선 경계 기준으로 항상 법선 방향으로 이동

#### 변위 크기 미리 계산하기

- 변위 크기는 경계로부터의 거리마다 대칭이므로 반지름 단위로 미리 값들을 계산해 배열로 저장
- 2D에서 한 번만(127개 레이 시뮬레이션) 계산 후, z축을 중심으로 회전해 전체 필드 생성

#### 벡터 정규화

벡터를 displacement map에 쓰기 위해 **정규화(최대 1.0 스케일)** 수행
- 최대 변위값을 기준으로 나머지 벡터 크기를 나눠 정규화

```js
const maximumDisplacement = Math.max(...displacementMagnitudes);
displacementVector_normalized = {
  angle: normalAtBorder,
  magnitude: magnitude / maximumDisplacement,
};
```

SVG displacement map에서 실제 픽셀 단위 변환 시 scale로 다시 최대 변위값을 곱해 원래 크기 복구

### SVG Displacement Map

수학적 굴절 계산 결과를 실질적으로 **브라우저 렌더링에 적용**하기 위해 **SVG displacement map**을 사용함

- `&lt;feDisplacementMap /&gt;`의 각 채널(RGBA, 8비트)은 각각 변위의 X, Y축을 담당할 수 있음
- 각 채널이 0~255의 값을 갖고, 128이 중성(변위 없음)을 의미함
- displacement map은 반드시 이미지로 변환 필요

```jsx
&lt;svg colorInterpolationFilters="sRGB"&gt;
  &lt;filter id={id}&gt;
    <feImage
      href={displacementMapDataUrl}
      x={0}
      y={0}
      width={width}
      height={height}
      result="displacement_map"
    />
    <feDisplacementMap
      in="SourceGraphic"
      in2="displacement_map"
      scale={scale}
      xChannelSelector="R"
      yChannelSelector="G"
    />
  &lt;/filter&gt;
&lt;/svg&gt;
```

#### Scale

Red(X)와 Green(Y) 채널의 값을 [−1, 1] 범위로 맵핑
- scale 속성으로 픽셀 단위 변위 최대치 곱해 실제 렌더링 구현  
- scale을 애니메이션해 효과 강도 조정 가능

#### 벡터 → Red/Green 값 변환

- 변위 벡터(각도, 크기)를 x, y 직교좌표로 변환 후, 128(중성) 기준으로 0~255로 맵핑

```js
const x = Math.cos(angle) * magnitude;
const y = Math.sin(angle) * magnitude;
const result = {
  r: 128 + x * 127,
  g: 128 + y * 127,
  b: 128,
  a: 255,
};
```

완성된 이미지는 SVG filter displacement map으로 활용 가능

#### Playground

인터렉티브 Playground에서는 표면 형태, 베젤 두께, 유리 두께, effect scale 등을 실시간 변경하며 굴절 필드, displacement map, 최종 렌더링 변화를 체험할 수 있음

### Specular Highlight

마지막으로 **specular highlight**(유리 표면의 밝은 엣지 하이라이트)를 추가함
- Apple의 구현은 rim light(가장자리 라이트) 방식으로, 표면 법선과 광원 각도에 따라 밝기 강도가 달라짐

### 굴절과 Specular Highlight 결합

최종 SVG filter에선 **displacement map**과 **specular highlight** 이미지를 각각 `&lt;feImage /&gt;`로 불러오고 `&lt;feBlend /&gt;`로 합쳐 최종 효과를 생성함  
- filter 파라미터를 조정해 다양한 비주얼을 연출할 수 있음

#### SVG filter를 `backdrop-filter`로 사용

- 실질적으로 UI 컴포넌트에 Liquid Glass 효과를 입히려면, Chrome의 `backdrop-filter: url(#...)` 지원이 필요함
- `backdrop-filter` 이미지 크기가 자동으로 맞춰지지 않으니, element 크기에 맞는 displacement map 준비 필수

```css
.glass-panel {
  backdrop-filter: url(#liquidGlassFilterId);
}
```

### 실제 UI 컴포넌트 적용

계산한 refraction과 displacement map을 바탕으로 현실적인 UI 컴포넌트에 적용 예시 구현

- Chrome만 SVG filter를 `backdrop-filter`로 처리할 수 있음
- 예시들은 진짜 프로덕션 컴포넌트가 아니라, 다양한 UI에 Liquid Glass 효과가 적용되는 모습을 시연하는 목적

#### Magnifying Glass

- 양쪽에 refraction 및 zoom, 두 개의 displacement map을 사용
- 그림자, 스케일 조정으로 인터렉티브한 효과 부여
- 드래그로 렌즈 변형, 굴절 경로를 관찰 가능
- 부드러운 specular highlight 추가

#### Searchbox

- 표준 입력창 형태에 Liquid Glass 효과 적용

#### Switch

- lip bezel 사용해 외부는 볼록, 내부는 오목
- 중앙 슬라이더만 확대/축소된 상태, 가장자리는 내부 이미지 굴절

#### Slider

- convex bezel을 사용, 현재값을 유리를 통해 그대로 보여주고, 양쪽은 배경 굴절 적용

#### Music Player

- Apple Music의 Liquid Glass panel 스타일을 모방
- convex bezel, subtle specular highlight로 입체감 부여
- iTunes Search API를 활용해 앨범 아트와 곡명 등 정보를 로드

- (리스트 형태의 곡명 및 앨범 정보 제공)

### 결론

이 프로토타입은 Apple의 Liquid Glass 개념을 **실시간 굴절 효과**와 간단한 하이라이트로 단순화해 표현함. **Chromium 기반 브라우저**(또는 Electron)에서만 실질적으로 동작 가능하며, 타 브라우저에서는 blur 레이어로 대체가 가능함.  
이는 실험적인 구현이며, shape/size 변화마다 displacement map 재생성이 매우 비효율적임(필터 `scale` 등 일부 파라미터 만 애니메이션 가능).  
추후 오픈소스 공개를 검토 중이며, 최적화 및 코드 정리에 관심이 있음을 밝힘.

## Comments



### Comment 43897

- Author: bobross0
- Created: 2025-09-16T11:17:17+09:00
- Points: 1

웹에서 봤던 리퀴드 글라스 중 가장 비슷하네요

### Comment 43558

- Author: neo
- Created: 2025-09-09T21:33:54+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=45174297) 
* WebGL 셰이더로 비슷한 기능을 만든 경험이 있음, 여러 브라우저에서 동작하는 장점이 있음, https://real-glass.vercel.app 공유함, 어려웠던 점은 실제 HTML 요소 뒤에서 굴절 효과를 제대로 재현하는 부분이었음
  * 유리 효과를 텍스트 위에 올려서 움직일 때 생기는 고스트 현상/딜레이는 무엇이 원인인지 궁금함
  * 너무 멋지다고 생각함, 가장자리에서 색이 분리되는 분산 효과까지 구현된 것처럼 보임
  * 비주얼은 멋진데, 실제로 사용하기엔 반응 속도가 너무 느림, 원 게시자의 것이 훨씬 부드럽게 동작함
  * 인상적임
* 스크롤을 내릴 때마다 M4-Max Macbook Pro에서도 버벅임이 생기는 점이 인상적임, 만약 전체 UI에 이런 기술이 적용된다면 성능면에서 걱정이 앞섬, Apple에서 가능한 이유는 극도로 최적화했기 때문일 것임
  * 본문 작성자로서 성능 이슈는 미리 고치려 했으나 누군가가 예상보다 먼저 HN에 게시해버림, 지적한 내용이 맞아서 지금은 다소 느리고 추가적인 최적화가 필요함, 굴절/변위 맵 뿐만 아니라 시각화 등 다른 부분도 아직 최적화가 안 되어 있음
  * 크롬에서 성능 개선을 빠르게 진행했기 때문에 약간 더 좋아졌을 것임, 사파리에서는 SVG 렌더링이 여전히 느림, 예상치 못하게 게시되어 더 개선할 부분이 남아 있음
  * 이 사이트는 스크롤이 부드럽게 되지 않음, 대부분의 경우 CSS는 GPU를 잘 활용하지 못함, Apple은 UI 처리를 위해 실리콘에 특수한 처리를 추가한 것으로 보임
  * 내 컴퓨터에서도 같은 현상, 테두리 효과도 제대로 보이지 않았음
* 내용도 좋지만, 전체 기사 구성과 퀄리티 또한 훌륭했음, Liquid glass라는 개념 자체가 실질적인 UX에는 특별히 추가적인 이점을 주진 않음(오히려 과하게 쓰면 UX를 해칠 수도 있음), 하지만 신선하고 즐거운 경험임
* chrome 전용 데모임을 강조하며, 마지막 인터랙티브 데모는 Chrome에서만 동작함(SVG filter로 인한 backdrop-filter 제약 때문), 타 브라우저에서도 본문 읽기나 간단한 시뮬레이션은 가능함이라고 작성함. 이에 대해 "네 가족 모두에게 불명예를!"이라는 유머러스한 반응이 있음
  * 이런 방식이 허용되는 건 불가피함, 해당 기능은 특정 브라우저에서만 지원되는 것을 보여주기 위한 목적임
  * 재미있게도, 내 경우에는 Chrome에서 페이지가 더 느리고 스크롤도 더 버벅거리는 반면, Firefox에서는 지원되지 않는 효과임에도 불구하고 오히려 더 부드러웠음, 그래도 기사 자체에는 매우 감탄했음
  * 나 역시 비슷한 반응이었지만, 특이하게도 FireFox에서도 꽤 괜찮게 보였음
  * 레퍼런스를 궁금해 한다면, https://youtu.be/GamP4chXJ2I?t=17 을 참고할 수 있음
* liquid glass 디자인 언어가 웹에 적용될 것임은 예상된 일이었음, 하지만 텍스트 왜곡 때문에 웹사이트가 내 배터리를 축낼 경우에는 오래 머무르지 않을 예정임, 이미 많은 이가 버벅임을 지적했기에 추가 언급은 하지 않겠음
* 멋지고 정성이 느껴지는 작업임, 하지만 liquid glass라는 것은 서로 가까운 요소가 메타볼처럼 합쳐지거나, 다양한 틴팅/클리어 모드, 컨트롤이 콘텐츠와 분리된 레이어에 있는 등 디자인 언어 전체를 의미함, 이번 구현은 말하자면 단순 '글래스 셰이더'에 가까움
  * 요소 합치기는 훨씬 단순한 필터인 'Goo' 필터로 해결할 수 있음, 예전부터 사용하던 방식임, 참고용 구현: https://codepen.io/lenymo/pen/pJzWVy
* liquid-glass용 JS 라이브러리를 포크해서 위치 수정 패치를 추가함, 프레젠테이션할 때 사용하면 재밌음, 소스코드: https://github.com/nkzw-tech/liquid-glass
  * 멋짐, 오히려 이쪽이 더 마음에 듦
* Firefox에서 일부 효과만 동작하지만(대신 성능 확보!), 지금까지 본 중에서 최고의 구현임, 최근 며칠간 관련 리서치를 많이 했기에 더 인상적임, 가장 마음에 들었던 건 웹사이트의 디자인과 정성 들인 인터랙티브 시각화였음, Bartosz Ciechanowski와 Josh Comeau의 작품과 동급이라고 느낌, 소스코드가 공개되길 바람
* 브라우저 지원 제약에도 불구하고 훌륭한 시도라고 생각함, 인라인 인터랙티브 예시가 추가적 가치를 더했음, 어느 순간엔가 Ciechanowski의 글을 읽는 느낌이었음(참고: https://ciechanow.ski/)
* 새로 나온 ray-traced 스크롤바와 버튼이 실제로 더 기능적이며, 예전의 텍스트 모드 터보 비전이나 Windows 3의 버튼보다 생산성이 향상되는지 궁금함
