안녕하세요! 프론트엔드 개발자 양성 과정 강사입니다. 이번에 살펴볼 내용은 CSS의 시각적 효과 중에서도 아주 세련된 기술인 마스킹(Masking)입니다.
이미지의 특정 부분만 보여주거나, 부드럽게 페이드 아웃 시키는 등의 효과를 줄 때 아주 요긴하게 쓰이죠. 단순히 자르는 것(Clipping)과는 또 다른 매력이 있답니다. MDN 문서를 바탕으로 개념부터 실습까지 하나하나 짚어드릴게요!
CSS 마스킹을 사용하면 하나 이상의 마스크 이미지(mask images)를 적용하여 요소의 특정 부분을 선택적으로 보여주거나 숨길 수 있습니다. 이 마스크 이미지는 그라데이션(gradients), 일반 이미지, 또는 SVG 소스가 될 수 있죠.
단순히 하나의 경로를 기준으로 영역을 완전히 보여주거나 숨기는 CSS 클리핑(clipping)과는 다릅니다. 마스킹은 마스크 이미지의 알파 투명도(alpha transparency)나 루미넌스(luminance, 휘도)를 기반으로 미세한 투명도 조절과 블렌딩 효과를 낼 수 있다는 게 아주 큰 장점이에요.
이 가이드에서는 마스킹의 개념과 다양한 마스크 이미지 유형을 소개합니다. 또한 마스크의 휘도와 알파 투명도가 요소의 가시 영역(마스킹된 부분)과 숨겨진 영역(클리핑된 부분)에 어떤 영향을 미치는지 알아보겠습니다.
CSS에서 마스크는 요소의 어느 부분이 보이고 어느 부분이 숨겨질지를 정의하는 데 사용됩니다. 하나 이상의 mask-image 소스로 정의되는 마스크 레이어는 요소의 가시 영역과 그 불투명도(opacity)를 결정하죠.
참고:
mask단축 속성을 사용하면 여러 개의 마스킹 관련 속성값을 한 번에 설정할 수 있습니다.
alpha 마스크를 사용하면, 마스킹된 요소의 불투명도는 적용된 마스크의 불투명도와 일치하게 됩니다. 흔히 쓰는 '가면'을 생각하면 가면이 얼굴을 가리지만, CSS 마스킹은 그 반대라고 생각하면 쉬워요. 마스크가 불투명한 곳에서 요소가 보이고, 마스크가 투명한 곳에서 요소가 숨겨집니다. 즉, 마스크가 완전히 불투명한 영역은 요소도 완전히 보이고, 마스크가 완전히 투명한 영역은 요소도 완전히 숨겨집니다. 마스크가 반투명하다면 요소도 그만큼만 반투명하게 보이겠죠.
알파 마스크를 쓸 때는 마스크 이미지의 '색상'은 전혀 중요하지 않습니다. 오직 '투명도'만 따지죠. 반면에 휘도 마스크(luminance masks)는 마스크 색상의 밝기를 기준으로 요소의 투명도를 결정합니다. 색상이 밝고 불투명할수록 요소가 더 진하게 보이고, 색상이 어둡고 투명할수록 요소가 흐릿하게 보입니다.
마스크는 CSS 그라데이션, 비트맵 이미지(PNG 등), 그리고 SVG <maskbox> 요소를 사용해 정의할 수 있습니다.
각 마스크 레이어는 기준 박스를 기준으로 위치가 잡히는 mask-image로 구성됩니다. 마스크 이미지는 크기 조절, 반복, 클리핑이 가능합니다. 여러 개의 마스크 이미지를 선언한 경우, 마스크 레이어를 합성하거나 결합하는 방식도 설정할 수 있습니다.
참고: 모든 예제는 아래의 무지개 깃발 이미지를 배경 요소로 사용하여 마스크를 적용할 것입니다.
알파 마스크에서 요소의 가시 영역은 적용된 마스크의 알파 투명도에 의해 정의됩니다.
conic-gradient()를 mask-image로 사용한 예제를 보며 이해해 봅시다. CSS 그라데이션은 보이는 영역과 숨겨진 영역 사이를 부드럽게 연결할 때 아주 좋습니다.
이 예제에서 마스크의 오른쪽 상단은 완전히 불투명하고, 왼쪽 상단 사분면은 완전히 투명하며, 하단 절반은 불투명에서 투명으로 부드럽게 변화합니다.
.applied-mask {
mask-image: conic-gradient(black 90deg, transparent 270deg);
}
.mask-source {
background: conic-gradient(black 90deg, transparent 270deg);
}
결과를 보면, 마스크가 적용된 요소의 오른쪽 상단은 뚜렷하게 보이고, 왼쪽 상단은 사라졌으며, 아래쪽은 서서히 투명해지는 것을 확인할 수 있습니다. 적용된 마스크 이미지의 투명도 상태가 그대로 요소에 반영된 것이죠.
알파 마스크에서는 색상이 중요하지 않다는 걸 보여주기 위해, 이번에는 불투명한 빨간색, 반투명한 빨간색, 그리고 투명한 색이 섞인 스트라이프 그라데이션을 써볼게요.
.applied-mask {
mask-image: repeating-linear-gradient(
to bottom right,
red 0 20px,
#ff000055 20px 40px,
transparent 40px 60px
);
}
.mask-source {
background: repeating-linear-gradient(
to bottom right,
red 0 20px,
#ff000055 20px 40px,
transparent 40px 60px
);
}
빨간색 그라데이션을 썼지만, 실제 결과물은 빨간색과 상관없이 마스크의 불투명도에 따라 요소가 보이거나 숨겨집니다.
마스크 이미지는 꼭 CSS 그라데이션일 필요는 없습니다. 외부 이미지 파일이나 SVG도 가능하죠. 이번에는 투명한 배경에 알록달록한 하트가 그려진 PNG 파일을 마스크로 써보겠습니다.
.applied-mask {
mask-image: url("[https://mdn.github.io/shared-assets/images/examples/colorful-heart.png](https://mdn.github.io/shared-assets/images/examples/colorful-heart.png)");
mask-size: 220px 220px;
}
.mask-source {
background: url("[https://mdn.github.io/shared-assets/images/examples/colorful-heart.png](https://mdn.github.io/shared-assets/images/examples/colorful-heart.png)");
background-size: 220px 220px;
}
투명한 마스크 영역이 요소를 잘라내는 것을 확인해 보세요. 하트 모양(불투명한 부분) 안쪽의 요소만 화면에 보일 것입니다. 역시 마스크 하트의 원래 색상은 결과에 영향을 주지 않습니다.
mask-mode 속성의 기본값인 match-source는 값에 따라 모드를 alpha 혹은 luminance로 설정합니다.
alpha 모드로 작동합니다.<maskbox> 요소: 명시적인 설정이 없다면 기본적으로 luminance 모드로 작동합니다.만약 mask-mode가 luminance(휘도)라면, 마스크 이미지의 색상 밝기가 투명도에 영향을 줍니다. 방금 본 하트 예제에 mask-mode: luminance를 강제로 적용해 볼까요?
.applied-mask {
mask-mode: luminance;
}
이렇게 하면 마스크에서 가장 밝은 영역은 더 선명하게(불투명하게) 보이고, 어두운 영역은 흐릿하게(투명하게) 보이게 됩니다.
💡 강사의 팁:
휘도 마스크의 불투명도를 결정하는 공식은 다음과 같아요:
((0.2125 * R) + (0.7154 * G) + (0.0721 * B)) * A
복잡해 보이지만 핵심은 이겁니다: 흰색(밝음)은 보여주고, 검은색(어두움)은 가린다!
예를 들어, 검은 밤하늘에 떠 있는 흰 달 이미지를 마스크로 쓴다고 해봅시다.
.applied-mask {
mask-image: url("[https://mdn.github.io/shared-assets/images/examples/moon.jpg](https://mdn.github.io/shared-assets/images/examples/moon.jpg)");
mask-mode: luminance;
mask-size: 220px;
}
.mask-source {
background: url("[https://mdn.github.io/shared-assets/images/examples/moon.jpg](https://mdn.github.io/shared-assets/images/examples/moon.jpg)");
background-size: 220px;
}
밤하늘이 검은색(휘도 0)인 부분은 요소가 완전히 가려지고, 달이 밝은 흰색인 부분에서만 요소가 선명하게 나타납니다. 만약 여기서 mask-mode를 다시 alpha로 바꾸면 어떻게 될까요? JPG 이미지는 투명도 정보가 없으므로 전체가 불투명한 것으로 간주되어 요소 전체가 다 보이게 됩니다.
<mask>를 마스크 소스로 사용하기 (SVG as mask source)마스크는 모든 유형의 CSS 이미지나 <mask-source>가 될 수 있습니다. <mask-source>는 SVG <mask> 요소를 가리키는 url() 참조입니다.
이는 CSS clip-path와 비슷하지만, clip-path는 SVG <clipPath> 요소를 사용하며 휘도(밝기)를 따지지 않는다는 차이가 있습니다.
<svg class="mask-source">
<mask id="mask-heart">
<path
d="M20,70 A40,40,0,0,1,100,70 A40,40,0,0,1,180,70 Q180,130,100,190 Q20,130,20,70 Z"
fill="rgb(255 0 0 / 0.5)"
stroke="rgb(255 255 255 / 1)"
stroke-width="20" />
</mask>
</svg>
.applied-mask {
mask-image: url("#mask-heart");
}
SVG 마스크를 사용하면 mask-mode 설정을 통해 알파 투명도를 쓸지, 휘도를 쓸지 자유롭게 결정할 수 있습니다.
이 예제는 CSS 마스킹과 클리핑의 차이를 잘 보여줍니다.
1. 마스킹(Masking): 휘도와 알파 투명도를 따집니다. 요소의 불투명도를 미세하게 조절할 수 있습니다. (반투명 가능)
2. 클리핑(Clipping): 경로 안쪽은 다 보여주고 바깥쪽은 무조건 가립니다. 중간 단계가 없이 '보이거나 안 보이거나' 둘 중 하나입니다.
만약 단순히 특정 모양(도형)으로 자르기만 하면 된다면 클리핑이 충분합니다. 하지만 안개처럼 서서히 사라지는 효과나, 밝기에 따른 투명도 조절이 필요하다면 마스킹이 정답입니다.
mask 속성들 (CSS mask properties)MDN 문서 개선에 참여하기 (Help improve MDN)
강사로서 한마디 덧붙이자면, 마스킹은 실무에서 고급스러운 UI 디자인을 구현할 때 정말 자주 쓰입니다. 예를 들어, 배경 이미지 위에 텍스트를 쓸 때 이미지를 특정 방향으로 은은하게 마스킹 처리하면 훨씬 가독성이 좋아지죠.
혹시 mask-composite를 이용해 여러 마스크 이미지를 겹치고 빼는 복잡한 합성 방법도 궁금하신가요? 아니면 실무에서 자주 쓰는 '텍스트에 이미지 마스킹하기' 기법을 같이 연습해 볼까요? 언제든 말씀해 주세요!