backdrop-filter 오판을 정정하고 리퀴드 글래스 기법을 기록한다
All checks were successful
ci / build (push) Successful in 25s

'backdrop-filter 에 SVG 를 얹으면 Chrome 이 선언 전체를 버린다' 고
적어두고 페이지 프리플라이트 로그에까지 실었다. 사실이 아니었다.

Chrome 151 에서 재측정
  computed 값이 none 이 아니라 url(#id) 로 유지된다
  대비 높은 배경 위에서 실제로 굴절된다(줄무늬가 가장자리에서 압축됨)

진짜 원인은 feImage 의 width/height 를 요소 크기와 맞추지 않은 것이었다.
backdrop-filter 는 필터 이미지를 자동으로 조정하지 않는다.

검색도 다시 했다. feTurbulence grain 에 갇혀 2019년 글만 보고 있었다.
liquid glass 계열 최신 자료를 보니 변위 지도는 노이즈가 아니라
물리 기반 사전계산 이미지였다 — R=X변위, G=Y변위, 128 이 중립,
감쇠는 Squircle 곡선. 캔버스로 즉석 생성하면 240x160 이 2.7KB 다.

스킬 svg-filters.md 에 '리퀴드 글래스' 절을 넣었다.
구조 · 변위 지도 만드는 법 · 함정 넷 · @supports 폴백.
오판 정정도 문서 첫 줄에 남겼다.

한 번 실패한 것을 '안 되는 것' 으로 적으면 그 문장이 다음 사람의
상한선이 된다. 페이지 로그 항목도 그 내용으로 바꿨다.
This commit is contained in:
Yun Chan 2026-08-20 22:09:22 +09:00
parent 31c0690d4b
commit e1e6002bee
4 changed files with 84 additions and 7 deletions

View file

@ -481,3 +481,63 @@ if (reduceEffects()) document.documentElement.classList.add('reduce-effects');
1. `in`/`in2` 순서가 뒤집혔는가
2. `baseFrequency` 가 너무 높은가
3. 필터 영역(`x`/`y`/`width`/`height`)이 좁아 결과가 잘렸는가
---
## 리퀴드 글래스 — `backdrop-filter: url()` 은 살아 있다
**정정부터.** 이 문서는 한때 "Chrome 은 `CSS.supports` 로 true 를 주면서 렌더에서
`backdrop-filter` 선언 전체를 버린다" 고 적고 있었다. **틀렸다.**
Chrome 151 에서 실측하면 computed 값이 `none` 이 아니라 `url("#id")` 로 유지되고,
배경이 실제로 굴절된다. 우리가 겪은 실패는 다른 원인이었다(아래 §함정).
### 구조
```html
<svg style="position:absolute;width:0;height:0">
<filter id="lg" color-interpolation-filters="sRGB"
x="0" y="0" width="100%" height="100%">
<!-- 변위 지도. feTurbulence 가 아니라 사전계산 이미지다 -->
<feImage href="data:image/png;base64,…" x="0" y="0" width="240" height="160" result="map"/>
<feDisplacementMap in="SourceGraphic" in2="map" scale="34"
xChannelSelector="R" yChannelSelector="G"/>
</filter>
</svg>
```
```css
.glass { backdrop-filter: url(#lg); }
```
### 변위 지도를 어떻게 만드나
**노이즈가 아니다.** 유리는 무작위로 휘지 않는다 — 가장자리에서 **경계 법선 방향**으로 휜다.
- `R` 채널 = X 변위, `G` 채널 = Y 변위, **128 이 중립**(변위 없음)
- 값 인코딩: `r = 128 + x * 127`, `g = 128 + y * 127`
- 가장자리에서 거리 `d` 를 구해 그 함수로 변위 크기를 정한다
- 감쇠 곡선은 **Squircle** `y = ⁴√(1 - (1-x)⁴)` 이 원보다 자연스럽다(Apple 이 쓰는 곡선)
캔버스로 즉석 생성해 `toDataURL()` 로 넘기면 이미지 파일이 필요 없다.
실측: 240×160 맵이 **2.7KB** data URI.
### 함정 — 여기서 실패한다
1. **`feImage``width`/`height` 를 요소 크기와 맞춰라.**
`backdrop-filter` 는 요소 크기에 맞춰 필터 이미지를 자동 조정하지 **않는다.**
크기가 어긋나면 굴절이 엉뚱한 곳에 걸리거나 아예 안 보인다.
요소가 리사이즈되면 맵을 다시 만들어야 한다
2. **Chrome 전용이다.** Safari·Firefox 는 `backdrop-filter` 에 SVG 필터를 받지 않는다.
`@supports` 로 감싸고 `blur()` 폴백을 둬라
3. **모양·크기를 애니메이션하지 마라.** 변위 맵 전체가 다시 계산된다.
`<feDisplacementMap scale>` 만 애니메이션해라 — 그건 재계산이 없다
4. `color-interpolation-filters="sRGB"` 를 빼면 색이 어둡게 뜬다
```css
.glass { backdrop-filter: blur(18px) saturate(150%); } /* 기본 */
@supports (backdrop-filter: url(#lg)) {
.glass { backdrop-filter: url(#lg); } /* 굴절 */
}
```
> 표준화가 진행 중이다(w3c/svgwg#1142). 지금은 Chrome 한정 기법으로 다루고,
> **굴절이 없어도 성립하는 화면**을 먼저 만든 뒤에 얹어라.