🎨 Frontend CSS5. 색·시각 효과04 — Filter & backdrop-filter

04 — Filter & backdrop-filter

한 줄 답: filter요소 자신의 픽셀을, backdrop-filter요소 뒤의 픽셀을 GPU에서 변환한다. 둘 다 합성 단계에 처리되어 빠르지만, backdrop-filter뒤 영역을 매 프레임 다시 raster화하기 때문에 iOS Safari에서 자주 떨어진다. Filter는 stacking context를 만들고 position: fixed 자식을 잘 망가뜨리는 부작용이 있다.


Why — 왜 filter가 별도 도구인가

box-shadow·opacity 같은 시각 효과는 그릴 때 결정된다 (paint 단계). 그런데 다음과 같은 효과는 이미 그려진 픽셀을 변환해야 한다:

  • 사진을 흑백으로
  • 모달 뒤 배경 흐리게 (frosted glass)
  • 비활성 버튼 채도 낮추기
  • SVG 아이콘 색만 바꾸기

이걸 paint 단계에서 처리하면 매번 다시 그려야 한다. filter는 합성 단계에 들어와서 — 그린 결과 위에 GPU 셰이더로 변환을 건다. 그래서 transition·animation이 60fps 유지된다.


How — Filter 파이프라인

도구변환 대상비용
filter요소 + 자식의 합성 결과blur는 비용이 blur² 비례
backdrop-filter요소 뒤의 합성된 픽셀매 프레임 뒤 영역 raster, 상당히 비쌈
<svg><filter>SVG 그래픽가장 복잡, 가장 강력

What — Filter 함수 10가지

CSS filter 함수

/* 단일 */
filter: blur(8px);
filter: brightness(1.5);
filter: contrast(150%);
filter: grayscale(100%);
filter: hue-rotate(90deg);
filter: invert(1);
filter: opacity(0.5);
filter: saturate(2);
filter: sepia(1);
filter: drop-shadow(0 4px 8px rgb(0 0 0 / 0.2));
 
/* 합성 (왼쪽부터 순서대로) */
filter: contrast(120%) saturate(1.2) brightness(0.9);
함수단위효과
blur(r)px가우시안 블러, 반경 r
brightness(p)숫자/%1=원본, >1=밝게, <1=어둡게
contrast(p)숫자/%1=원본
grayscale(p)0~1/%1=완전 흑백
hue-rotate(a)deg색상환 회전
invert(p)0~1/%1=완전 반전
opacity(p)0~1/%CSS opacity와 거의 동일, 합성 단계
saturate(p)숫자/%1=원본, 0=흑백, >1=과채도
sepia(p)0~1/%1=완전 세피아
drop-shadow(...)shadow알파 채널 기준 그림자
url(#filter)SVG ref커스텀 SVG filter

backdrop-filter — Frosted Glass

.glass {
  background: rgb(255 255 255 / 0.2);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);  /* iOS Safari */
}

배경의 영역에 filter를 건다. macOS Big Sur 이후 glassmorphism의 핵심 기법.

SVG Filter — 가장 강력

<svg width="0" height="0" style="position:absolute">
  <filter id="liquid">
    <feTurbulence baseFrequency="0.02" numOctaves="3" />
    <feDisplacementMap in="SourceGraphic" scale="30" />
  </filter>
</svg>
 
<div style="filter: url(#liquid)">왜곡된 텍스트</div>

SVG filter는 primitive 그래프를 직접 짜는 방식. feGaussianBlur·feColorMatrix·feTurbulence·feDisplacementMap 등 30+ primitive 조합으로 Photoshop 수준의 효과가 가능. 단, 성능과 호환성 비용이 크다.


자주 쓰는 패턴

1) Disabled 효과

.btn:disabled {
  filter: grayscale(0.6) opacity(0.6);
  cursor: not-allowed;
}

색을 따로 정의하지 않고 원본을 변환. 디자인 토큰 수가 절반으로 줄어든다.

2) Hover Saturate

.card img {
  filter: saturate(0.8);
  transition: filter 0.3s;
}
.card:hover img {
  filter: saturate(1.1);
}

saturate transition은 합성 단계라 부드럽다.

3) Frosted Glass Modal

.modal-backdrop {
  position: fixed; inset: 0;
  background: rgb(0 0 0 / 0.3);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

4) SVG 아이콘 색을 CSS color로

.icon {
  width: 24px; height: 24px;
  background: currentColor;
  -webkit-mask: url(/icon.svg) center / contain no-repeat;
          mask: url(/icon.svg) center / contain no-repeat;
}

엄밀히는 filter가 아니라 mask지만, SVG의 색을 CSS color로 제어하는 모던 패턴. filter hue-rotate로는 어색하다.

5) drop-shadow for SVG/투명 PNG

.cutout {
  clip-path: polygon(...);
  filter: drop-shadow(0 8px 16px rgb(0 0 0 / 0.2));
}

03-shadows에서 본 알파 채널 기반 그림자.


What-if — 잘못 쓰면

1) Filter는 stacking context를 만든다

.parent { filter: blur(0); }  /* 0이라도 적용되면 stacking context 생성 */
 
.parent .modal {
  position: fixed;  /* 의도: 뷰포트 기준 */
  top: 0;
  /* 실제: parent 기준으로 잡힘 → 모달이 부모 안에 갇힘 */
}

filter·backdrop-filter·transform·will-change·isolation: isolate는 모두 stacking context + containing block을 만든다. position: fixed 자식이 부모 기준으로 contain되는 함정이 있다 → 자세히는 05-blend-modes, 00-foundations/05-position-context.

2) backdrop-filter의 iOS Safari 떨림

  • GPU 비용: 매 프레임 뒤 영역을 다시 raster해야 한다.
  • iOS Safari: 스크롤 중 backdrop-filter가 떨어졌다 돌아오는 현상이 빈번. 작은 영역 + blur 반경 작게 + 스크롤 위 고정은 상대적으로 안정.
  • prefix: iOS Safari는 -webkit-backdrop-filter도 같이 적어야 한다.
  • isolation: isolate 우회: 부모에 isolation: isolate를 주면 일부 Safari 버그 회피 가능.
.glass {
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
@supports not (backdrop-filter: blur(20px)) {
  .glass { background: rgb(255 255 255 / 0.85); }  /* 불투명 fallback */
}

3) Filter blur의 페인트 비용

/* 전체 화면 blur — 비쌈 */
.bg { width: 100vw; height: 100vh; filter: blur(40px); }
 
/* 트릭: 작게 그리고 scale */
.bg {
  width: 200px; height: 200px;
  background: url(...) 0 0 / cover;
  filter: blur(20px);
  transform: scale(10);
  transform-origin: top left;
}

blur 비용은 raster 크기 × blur²에 비례. 작게 그리고 transform scale로 키우는 게 사실상 표준.

4) drop-shadow 다중 적용 시 차이

/* 같은 모양에 두 개 그림자 — filter는 chain */
filter: drop-shadow(0 2px 4px rgb(0 0 0 / 0.1))
        drop-shadow(0 8px 16px rgb(0 0 0 / 0.05));

box-shadow는 쉼표로 합성하지만, filter함수 chain. 순서가 의미 있다 (다음 함수의 입력이 이전 함수의 출력).

5) forced-colors 모드와 filter

Windows 고대비 모드에서는 대부분의 filter가 무시된다. 의미 전달을 filter에만 의존하면 접근성 실패. @media (forced-colors: active)에서 대체 시각 단서를 준비해야 한다.

6) filter: contrast + filter: brightness 트릭 — Gooey

.gooey {
  filter: contrast(20) blur(5px);
}
.gooey > * {
  background: black;
  filter: blur(10px);
}

대비를 극도로 높이고 blur를 합치면 물방울이 합쳐지는 듯한 gooey 효과. SVG feGaussianBlur + feColorMatrix로도 같은 효과 — 모던 사이트의 인터랙티브 텍스트 트랜지션에 종종.


Insight — Filter의 GPU 시대

“CSS Filter는 SVG Filter의 후예다”

filter 명세는 2014년 SVG Filter Effects를 CSS에 들이는 작업으로 시작됐다. 그래서 filter: url(#svgFilter)로 SVG primitive를 그대로 쓸 수 있는 것이다 — CSS는 그 위에 흔히 쓰는 10개를 단축 함수로 노출한 셈.

backdrop-filter는 더 최근(2017 ED) 표준이다. 흥미로운 점은 Apple이 가장 먼저 구현하고 가장 먼저 망쳤다는 것 — macOS의 모든 메뉴바·Dock·Notification Center가 backdrop-filter를 OS 수준에서 쓰는데, 브라우저 구현은 그것의 1/10 성능. iOS Safari의 떨림은 batter life 절약을 위해 GPU 합성 우선순위가 낮은 게 원인이라는 설.

2024년 분기점은 color() 함수 + filter의 P3 호환이다. 이전엔 filter가 sRGB로 강제 변환되어 광역색이 손실됐다. 이제 P3 입력 → P3 합성 → P3 출력이 가능해져, 광역색 사진의 채도가 filter를 통과해도 살아남는다.

또 하나의 반전: filter: opacity(0.5)opacity: 0.5는 거의 동일하다. 명세도 효과는 동일하다고 명시. 차이는 어디서 합성되느냐filterfilter chain의 일부로, opacity별도 합성 속성으로. 모바일 GPU에서는 opacity 단독이 약간 더 빠르다는 측정도 있다.


요약 + Mermaid

  • filter는 요소 자신, backdrop-filter는 요소 뒤를 변환.
  • 합성 단계 처리 — paint 단계 효과보다 빠름.
  • iOS Safari backdrop-filter 는 스크롤 떨림·성능 저하 — prefix + @supports fallback 필수.
  • Filter는 stacking context를 만든다 → position: fixed 자식 함정.
  • Blur 비용은 blur² 비례 — 작게 그리고 scale로 키우는 트릭.
  • SVG filter는 Photoshop 수준 가능, 성능·호환성 비용 큼.

다음: 05-blend-modes — filter가 요소 안의 변환이라면 blend는 요소들 사이의 합성이다.