CSS filter to SVG filter

조경석·2023년 2월 17일
0

주의사항 : CSS filter는 아직도 초안(Working Draft)으로, 2023년 현재는 일반적으로 사용되어 브라우저에 따라 결과가 유사하다고 말할 수는 있지만 구현과 렌더링 방식에는 차이가 있다.

기초가 되는 SVG filter 요소에 대해 정리해보았으니, HTML 문서 요소에 스타일을 입히기 위한 CSS의 filter 속성에 대해서도 정리해보자.

기초적인 요소들로만 구성되어 있어 구성하려면 여러 요소를 조합해야 하는 SVG filter와 달리, CSS filter는 미리 정의된 효과를 적용하는 함수 위주로 구현되어 있어 일반적인 효과에 대해서는 더 간편하고 직관적이다.

비교적 간단하게 적용할 수 있는 CSS filter 함수를 SVG filter로 유사하게 구현하면서 그 차이를 알아보자.

아래의 내용은 MDN의 CSS filter 문서를 번역한 것으로, 이전 글에서 설명했던 filter primitive를 적용한 방식 위주로 정리할 예정이고, 예시 이미지 역시 해당 페이지에서 제공하는 이미지를 사용했다.

blur()

가장 먼저, CSS filter와 SVG filter의 가장 큰 차이를 한 눈에 확인할 수 있는 blur()와 <feGaussianBlur>를 비교해보자.

/* in css */
filter: blur([amount]px);
/* in svg */
<feGaussianBlur in="SourceGraphic" stdDeviation="[amount]"/>

overflow

위 CODEPEN 예제에서 볼 수 있듯이, CSS blur()를 적용한 첫번째 <img> 예제는 흐림 효과가 적용되어 상위 <td> 요소의 경계선을 넘은 영역까지 그려진다.
반면, <feGaussianBlur>의 경우 상위 SVG 영역을 초과해 그려지지 않아 상위 <td> 요소의 경계선에 맞춰 흐림 효과가 잘려 그려진 것을 볼 수 있다.

이로 인해 SVG 필터를 CSS 필터처럼 상위 요소의 범위에 관계없이 사용하려면 SVG 특성값인 overflow="visible"를 지정해야 한다.

Gaussian Blur

CSS의 blur() 필터는 한 개의 인수로 전달된 길이 값을 반경으로 가지는 가우시안 흐림 효과를 적용한다.

그 반면, SVG의 <feGaussianBlur> 필터 원시형은 stdDeviation으로 지정된 값을 s, t로 하여 그 반경인 d 값을 계산하는 방식이다.
이로 인해 blur()에 사용하는 매개변수 값과 <feGaussianBlur>의 stdDeviation 값은 일치하지 않으며, 상호간에 값을 변환하기도 난해해 근사값으로서 활용한다.

<feGaussianBlur>의 stdDeviation은 최대 2개의 값을 지정할 수 있으며, 이 경우 각각 x축(s), y축(t) 방향의 기준값으로 사용된다.
이 특성을 사용해 위 예제의 stdDeviation="4 0"과 같은 방향이 있는 흐림(Directional/Motion Blur)도 가능하다.

CSS 색상 필터를 설명하기 전에

웹 브라우저에서는 일반적으로 sRGB 색공간을 사용하고,
SVG의 color-interpolation-filters의 기본값은 linearRGB이다.
그렇기 때문에 SVG 요소에 color-interpolation-filters="sRGB"를 지정하지 않으면 계산식에서 유추할 수 있는 결과와 다른 색상으로 그려질 수 있다.
아래에서는 CSS 색상 필터의 계산방식과 SVG 필터의 색상 조정을 비교할 예정이므로, 모든 예제에 color-interpolation-filters="sRGB"를 적용했다.

brightness()

/* in css */
filter: brightness([amount]);
/* in svg */
<feComponentTransfer>
	<feFuncR type="linear" slope="[amount]"/>
	<feFuncG type="linear" slope="[amount]"/>
	<feFuncB type="linear" slope="[amount]"/>
</feComponentTransfer>

brightness()는 각 픽셀 색상의 밝기를 변경하는 필터 함수로, 인수가 0인 경우 검은색, 1인 경우 원래 색상으로 표시되는 백분율 매개변수를 가진다.

이를 SVG 필터를 사용해 유사한 결과를 표시하려면, 지난 글에서 정리했던 <feComponentTransfer>를 사용한다.
type이 linear인 경우 원래 색상값에 곱하는 slope 특성값을 백분율 값으로,
type이 gamma인 경우 원래 색상값에 곱하는 amplitude 특성값을 백분율 값으로 지정하면 같은 결과가 나온다.

contrast()

/* in css */
filter: contrast([amount]);
/* in svg */
<feComponentTransfer>
	<feFuncR type="linear" slope="[amount]" intercept="-(0.5 * [amount]) + 0.5"/>
	<feFuncG type="linear" slope="[amount]" intercept="-(0.5 * [amount]) + 0.5"/>
	<feFuncB type="linear" slope="[amount]" intercept="-(0.5 * [amount]) + 0.5"/>
</feComponentTransfer>

contrast()는 채도가 가장 높은 픽셀(명부) 색상과 가장 낮은 픽셀(암부) 색상의 차이를 조정하는 필터 함수로, 인수가 0인 경우 모든 픽셀의 채도가 동일한 grayscale 이미지, 1인 경우 원래 색상으로 표시되는 백분율 매개변수를 가진다.

<feComponentTransfer>를 통해 유사한 결과를 내는 위 예제의 경우 명부와 암부의 밝기값을 기준으로 하는 방식이 아닌, 근사값을 계산하는 방식으로 대비가 너무 크면 contrast()와 다른 결과가 나타난다.
(예제 이미지 연필 아래의 그림자 영역을 비교해보자.)

invert()

/* in css */
filter: invert([amount]);
/* in svg */
<feComponentTransfer>
	<feFuncR type="table" tableValues="[amount] (1 - [amount])"/>
	<feFuncG type="table" tableValues="[amount] (1 - [amount])"/>
	<feFuncB type="table" tableValues="[amount] (1 - [amount])"/>
</feComponentTransfer>

invert()는 단순하게 색상값을 뒤집는다. 인수가 0인 경우 원래 색상, 0.5인 경우 모든 픽셀이 회색 단색으로 칠해진 이미지, 1인 경우 모두 반전된 색상으로 표시되는 0부터 1 사이의 백분율 매개변수를 가진다.

계산방식이 단순한만큼 <feComponentTransfer>의 type="table"을 통해서도 간단하게 동일한 결과를 낼 수 있다.

opacity()

/* in css */
filter: opacity([amount]);
/* in svg */
<feComponentTransfer>
	<feFuncA type="table" tableValues="0 [amount]"/>
</feComponentTransfer>

opacity()는 더욱 단순하게도 대상에 opacity를 다시 한번 적용한다.
당연히 매개변수로는 0부터 1 사이의 값을 가지며, 1은 원래 이미지의 투명도를 그대로 유지한다.
CSS의 기존 opacity와 동일하고, 유일한 장점은 CSS 필터이므로 일부 브라우저에서는 하드웨어 가속을 사용한다는 것 뿐이다.

SVG에서도 opacity 특성을 사용하는 것과 차이가 없지만,
SVG 필터를 사용하여 외부 요소에 적용하려는 경우 <feFuncA>를 통해 투명도 채널의 최대값만 다시 지정해 리매핑하는 방식으로 <feComponentTransfer>를 사용할 수 있다.

이를 응용해, 역으로 <feFuncA>를 사용해 기존의 opacity 속성에서는 불가능한 알파 채널값을 증가시키는 필터를 사용할 수 있다.

위는 기존 예시 이미지의 중앙 사각형 영역만 투명도를 50%로 설정한 이미지이다.
CSS로는 어떤 방법으로도 위 이미지를 완전히 불투명하게 만들 방법이 없지만, <feFuncA>와 type="table" tableValues="1"를 사용하면 아래와 같이 가능하다.

의도적으로 td의 배경색을 빨간색으로 지정해두었고,
개발자 도구를 통해 두 이미지가 동일하다는 것을 확인 가능하다.

쉬어가기

색상을 조절하기 위해 사용하는 SVG filter primitive는 <feComponentTransfer> 외에도 <feColorMatrix>가 있다.
나머지 CSS 필터를 설명하기 전에, 함수와 동일한 색상 계산을 수행하는 <feColorMatrix>의 일부 특성에 대해서 먼저 정리하고 다시 돌아오겠다.

0개의 댓글