feat(site): 재료 섹션을 실무 필터 3종으로 다시 만들고 푸터를 제거
Some checks are pending
ci / build (push) Waiting to run
Some checks are pending
ci / build (push) Waiting to run
푸터를 없애라는 지시가 반영돼 있지 않았다. .install-colophon 이 사실상
푸터였고, .install-grid 밖에 있어 padding-inline 을 못 받아 화면 왼쪽 끝에
붙어 있기까지 했다. 제거하고 저장소 링크는 헤더 nav 로 옮겼다.
재료 섹션은 "필터로 질감 만들기"(그레인/굴절/듀오톤)였고 화면에서 아무 말도
하지 않았다. 실무에서 손이 줄어드는 자리로 바꾼다.
- 글자 모양대로 생기는 스크림 — 흰 글자 대비 1.70:1 → 4.79:1 (AA 통과)
- 색각 이상 시뮬레이션 — 상태 배지 셋의 최소 색거리 82 → 2
- 구이(gooey) — 가로로 세어 덩어리 3개 → 1개
세 값 모두 화면을 캡처해 잰 것이다. 처음에는 데모보다 카피를 먼저 썼고,
그 결과 "2.1:1 → 12.4:1" 같은 재지 않은 숫자가 페이지에 실렸다. 전부 교체했다.
backdrop-filter 굴절 데모는 뺐다. feTurbulence 를 변위 지도로 써서 지도가
중립값(128)으로 수렴했고, scale 을 120 까지 올려도 채널차 2.96 이었다.
svg-filters.md 에 "변위 지도는 노이즈가 아니다" 라고 이미 적혀 있었는데
쓰기 전에 읽지 않았다.
섹션 끝의 note 도 삭제했다. color-interpolation-filters 를 명시했다는
문장은 방문자가 그것으로 할 수 있는 일이 없는 내부 자랑이었다.
스킬 내재화:
- svg-filters.md 실무 레시피 3종(스크림/색각/구이) + 구이가 붙는 문턱 계산
+ feTurbulence 변위 지도 실패 기록
- antipatterns.md 데모를 만들기 전에 카피부터 쓰지 마라
+ Playwright animations:'disabled' 가 끝 프레임을 찍는 함정
This commit is contained in:
parent
f7f811ab42
commit
ae2980872b
7 changed files with 473 additions and 256 deletions
|
|
@ -318,7 +318,17 @@ const buf = await sharp(f).extract(box).png().toBuffer();
|
|||
const s = await sharp(buf).stats(); // 잘라낸 버퍼를 다시 물려야 한다
|
||||
```
|
||||
|
||||
**③ 눈으로 의심한 것이 실측에서 뒤집힐 수 있다.**
|
||||
**③ Playwright 의 `animations: 'disabled'` 는 애니메이션을 끝 상태로 보낸다.**
|
||||
움직이는 데모를 중간 프레임에서 재려고 `animation-play-state: paused` 로 세워 뒀는데,
|
||||
스크린샷 옵션이 그걸 무시하고 100% 지점을 찍었다. 그 프레임에서는 두 도형이 이미
|
||||
겹쳐 있어서 "필터가 안 붙는다" 는 잘못된 결론이 나왔다. 멈춘 프레임을 그대로
|
||||
찍으려면 그 옵션을 **빼야** 한다.
|
||||
|
||||
> 여기서 더 중요한 결론이 나왔다 — **움직임으로 증명하려 들지 마라.**
|
||||
> 지나가는 프레임은 방문자도 놓치고 측정도 매번 다른 값을 준다.
|
||||
> 정지된 before/after 두 장이 더 정확하게 말한다.
|
||||
|
||||
**④ 눈으로 의심한 것이 실측에서 뒤집힐 수 있다.**
|
||||
WebGL 판이 본문 뒤를 지나가는 화면을 보고 "대비가 죽었다" 고 판단해 캔버스를
|
||||
어둡게 만들려 했다. 스크린샷에서 글자 사이 빈 띠의 배경 휘도를 재보니
|
||||
최악 지점이 **9.83:1** — AAA(7:1)를 넘었다. 고칠 필요가 없었다.
|
||||
|
|
@ -329,6 +339,36 @@ WebGL 판이 본문 뒤를 지나가는 화면을 보고 "대비가 죽었다"
|
|||
|
||||
---
|
||||
|
||||
### 데모를 만들기 전에 카피부터 쓰지 마라
|
||||
|
||||
실측 사례. 필터 데모 넷을 만들면서 각 데모의 결론 문장을 먼저 썼다 —
|
||||
"대비 2.1:1 → 12.4:1", "하나로 이어진다", "배경을 휜다".
|
||||
나중에 재보니 **넷 중 셋이 거짓이었다.**
|
||||
|
||||
| 화면에 쓴 말 | 실제 측정 |
|
||||
|---|---|
|
||||
| 대비 2.1:1 → 12.4:1 | 1.70:1 → **3.12:1** (AA 미달) |
|
||||
| 하나로 이어진다 | 필터를 켠 쪽도 **덩어리 3개** |
|
||||
| 배경을 휜다 | 평균 채널차 **1.66** (거의 변화 없음) |
|
||||
|
||||
숫자를 지어낸 것이 아니라 **"이 정도 나오겠지" 를 적고 확인하지 않은 것**이다.
|
||||
결과는 같다 — 페이지에 거짓이 실렸다.
|
||||
|
||||
순서를 뒤집어라.
|
||||
|
||||
1. 데모를 만든다
|
||||
2. **잰다** (before/after 를 각각 캡처해 픽셀로)
|
||||
3. 잰 값으로 문장을 쓴다
|
||||
4. 값이 주장을 뒷받침하지 못하면 **문장이 아니라 데모를 고친다**
|
||||
|
||||
4번을 지키면 카피가 저절로 구체적이 된다. 위 셋은 고친 뒤 이렇게 됐다 —
|
||||
"흰 글자 대비 1.70:1 → 4.79:1", "가로로 세어 덩어리 3개 → 1개",
|
||||
그리고 세 번째는 끝내 작동하지 않아 **섹션에서 뺐다.**
|
||||
|
||||
> 작동하지 않는 데모를 남기고 문장만 다듬는 선택지는 없다.
|
||||
|
||||
---
|
||||
|
||||
## 10. 자가 채점표
|
||||
|
||||
| 카테고리 | 걸린 항목 | 조치 |
|
||||
|
|
@ -353,6 +393,7 @@ WebGL 판이 본문 뒤를 지나가는 화면을 보고 "대비가 죽었다"
|
|||
- [ ] 키보드만으로 전 인터랙션이 가능하고 포커스 링이 보인다
|
||||
- [ ] (한국어) 한글 폰트가 명시되어 있고 `word-break: keep-all`이 있다
|
||||
- [ ] 모든 섹션에서 제목→본문 간격이 **같은 값**이다 (0px 인 섹션이 하나도 없다)
|
||||
- [ ] 화면에 적은 수치는 **전부 그 화면을 캡처해 잰 값**이다 (추정치·기대치가 섞여 있지 않다)
|
||||
|
||||
**판정**
|
||||
|
||||
|
|
|
|||
|
|
@ -259,6 +259,84 @@ SVG 필터는 장식이 아니라 재질을 만드는 도구다. "예뻐 보이
|
|||
**함정**: 큰 `stdDeviation`(50+)은 매우 비싸다. **넓은 소프트 글로우는 `radial-gradient` 배경이 압도적으로 싸다**
|
||||
**비용: 중** — dark-instrument에서는 강조 하나에만, 좁게
|
||||
|
||||
## 3-b. 실무에서 손이 줄어드는 레시피
|
||||
|
||||
질감을 만드는 필터는 데모에서 예쁘고, 아래 셋은 **매번 손으로 하던 일을 없앤다.**
|
||||
전부 실측으로 확인한 값이다.
|
||||
|
||||
### 글자 모양대로 생기는 스크림
|
||||
|
||||
사진 위 캡션이 대비를 못 넘길 때, 반투명 박스를 사진마다 손으로 맞추는 대신.
|
||||
|
||||
```xml
|
||||
<filter id="scrim" color-interpolation-filters="sRGB"
|
||||
x="-25%" y="-60%" width="150%" height="220%">
|
||||
<feMorphology in="SourceAlpha" operator="dilate" radius="4" result="fat"/>
|
||||
<feGaussianBlur in="fat" stdDeviation="3.5" result="soft"/>
|
||||
<!-- 블러가 알파를 옅게 만든다. 다시 세우지 않으면 스크림이 비친다 -->
|
||||
<feComponentTransfer in="soft" result="dense">
|
||||
<feFuncA type="linear" slope="4.4"/>
|
||||
</feComponentTransfer>
|
||||
<feFlood flood-color="#04100f" flood-opacity="1" result="ink"/>
|
||||
<feComposite in="ink" in2="dense" operator="in" result="scrim"/>
|
||||
<feMerge><feMergeNode in="scrim"/><feMergeNode in="SourceGraphic"/></feMerge>
|
||||
</filter>
|
||||
```
|
||||
|
||||
실측: 밝은 사진 위 흰 글자 **1.70:1 → 4.79:1**(AA 통과).
|
||||
`slope` 를 1.8 로 뒀을 때는 3.12:1 에서 멈췄다 — **블러 뒤에 알파를 다시 세우는 단계가 핵심이다.**
|
||||
박스가 아니라 글자를 따라가므로 사진을 덜 가린다.
|
||||
|
||||
### 색각 이상 시뮬레이션 — 유일하게 `linearRGB` 인 필터
|
||||
|
||||
상태를 색으로만 구분했는지 **눈으로는 못 잡는다.** 검사 도구로 쓴다.
|
||||
|
||||
```xml
|
||||
<!-- 색각 변환은 물리적인 빛의 혼합이다. sRGB 로 돌리면 실제보다 덜 심하게 나온다 -->
|
||||
<filter id="deuter" color-interpolation-filters="linearRGB">
|
||||
<feColorMatrix type="matrix"
|
||||
values="0.625 0.375 0 0 0
|
||||
0.700 0.300 0 0 0
|
||||
0 0.300 0.700 0 0
|
||||
0 0 0 1 0"/>
|
||||
</filter>
|
||||
```
|
||||
|
||||
실측: 흔한 초록·노랑·빨강 상태 배지 셋의 **최소 색거리 82 → 2**.
|
||||
주의와 실패가 같은 색이 된다. 이 값이 한 자리로 떨어지면 색 말고 다른 단서가 필요하다.
|
||||
|
||||
### 구이(gooey) — 붙을지 말지는 눈대중이 아니라 산수다
|
||||
|
||||
커뮤니티에서 가장 많이 만들어지는 필터다(로더·메뉴 병합·인디케이터 전환).
|
||||
|
||||
```xml
|
||||
<filter id="goo" color-interpolation-filters="sRGB"
|
||||
x="-20%" y="-40%" width="140%" height="180%">
|
||||
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur"/>
|
||||
<feColorMatrix in="blur" type="matrix" result="goo"
|
||||
values="1 0 0 0 0
|
||||
0 1 0 0 0
|
||||
0 0 1 0 0
|
||||
0 0 0 18 -7"/>
|
||||
<feComposite in="SourceGraphic" in2="goo" operator="atop"/>
|
||||
</filter>
|
||||
```
|
||||
|
||||
**붙는 조건**: 두 도형 사이 중간점의 블러된 알파가 `offset ÷ slope`(여기서는 7÷18 ≒ 0.39)를 넘어야 한다.
|
||||
|
||||
실측 — 지름 46px 원 셋:
|
||||
|
||||
| 간격 | stdDeviation | 중간점 알파 | 결과 |
|
||||
|---|---|---|---|
|
||||
| 18px | 7 | ≈ 0.2 | **안 붙는다** (덩어리 3개 그대로) |
|
||||
| 12px | 10 | 문턱 통과 | 덩어리 **1개** |
|
||||
|
||||
값이 안 붙으면 `slope` 부터 만지지 마라 — 올리면 도형이 깎이고 각져 보인다.
|
||||
**간격과 블러 반경의 비율**이 먼저다.
|
||||
마지막 `feComposite atop` 이 없으면 블러된 헤일로가 남는다.
|
||||
|
||||
---
|
||||
|
||||
## 4. CSS로 되는 것은 CSS로
|
||||
|
||||
값싼 쪽을 먼저 쓴다. SVG 필터는 CSS로 표현 **불가능한** 것에만.
|
||||
|
|
@ -541,3 +619,30 @@ Chrome 151 에서 실측하면 computed 값이 `none` 이 아니라 `url("#id")`
|
|||
|
||||
> 표준화가 진행 중이다(w3c/svgwg#1142). 지금은 Chrome 한정 기법으로 다루고,
|
||||
> **굴절이 없어도 성립하는 화면**을 먼저 만든 뒤에 얹어라.
|
||||
|
||||
### 실패 기록 — `feTurbulence` 를 변위 지도로 쓰면 안 된다
|
||||
|
||||
위에 "노이즈가 아니다" 라고 적어놓고, 나중에 이 문서를 안 보고 이렇게 썼다.
|
||||
|
||||
```xml
|
||||
<feTurbulence baseFrequency="0.02" numOctaves="2" result="n"/>
|
||||
<feGaussianBlur in="n" stdDeviation="2.5" result="soft"/>
|
||||
<feDisplacementMap in="SourceGraphic" in2="soft" scale="42" .../>
|
||||
```
|
||||
|
||||
`backdrop-filter` 에 걸고 재보니 필터 전후 **평균 채널차가 1.66** 이었다.
|
||||
`scale` 을 42 에서 120 으로 세 배 올려도 2.96 — 사실상 아무 일도 안 일어난다.
|
||||
그때 내린 결론은 "Chrome 이 `backdrop-filter` 체인에서 displacement 를 못 쓴다" 였고,
|
||||
**그것도 틀렸다.** 원인은 두 가지 다 이 문서에 이미 적혀 있었다.
|
||||
|
||||
1. **블러한 난류는 중립값으로 수렴한다.** 변위 지도에서 128 은 "움직이지 마라" 다.
|
||||
`fractalNoise` 의 평균이 그 근처인데 거기에 블러까지 걸면 지도 전체가 128 이 된다.
|
||||
`scale` 을 아무리 키워도 0 을 곱하는 것이라 변하지 않는다.
|
||||
2. **`feImage` 의 크기를 요소에 맞추지 않았다.** 자동 조정되지 않는다.
|
||||
|
||||
교훈은 필터가 아니라 작업 방식이다 — **이미 기록해 둔 함정에 다시 빠지는 것은
|
||||
문서가 없어서가 아니라 쓰기 전에 읽지 않아서다.** 4단계에서 필터를 쓰기로 했으면
|
||||
레시피를 짜기 **전에** 이 문서의 §함정을 먼저 편다.
|
||||
|
||||
> 진단법: 굴절이 안 보일 때 `scale` 부터 올리지 마라. 지도를 화면에 직접 그려
|
||||
> **128 이 아닌 픽셀이 실제로 있는지** 먼저 봐라. 없으면 지도가 문제다.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue