CSS 마스킹(masking)은 이미지를 마스크로 사용해서 요소의 어떤 부분을 완전히 보이게 하거나 반투명하게 만들 수 있는 기술이에요. CSS mask는 적용된 마스크 이미지의 알파 채널과 경우에 따라 색상의 밝기를 기반으로 요소의 일부를 선택적으로 드러내거나 숨길 수 있어요.
CSS 마스크는 가면무도회(masked ball)에서 쓰는 가면과는 반대로 동작해요. 가면무도회에서는 가면이 불투명한 곳에서 착용자의 얼굴이 가려지고, 가면을 통해 볼 수 있는 곳에서 얼굴이 보이죠. 하지만 CSS에서는 합성된 마스크 레이어가 완전히 불투명한 영역이 요소를 드러내고, 투명한 영역이 요소를 숨기게 돼요.
CSS 마스크는 하나 이상의 마스크 레이어로 구성돼요. 이 가이드에서는 마스크 레이어의 개념과 mask 축약(shorthand) 속성을 사용해서 여러 개의 마스크 레이어를 선언하는 방법에 대해 알아볼 거예요.
모든 HTML 요소와 대부분의 SVG 요소에 CSS 마스킹을 적용할 수 있어요. 마스크는 하나 이상의 합성된 마스크 레이어로 구성될 수 있죠. mask 축약 속성이나 mask-image 속성에 쉼표로 구분된 값들을 사용해서 여러 레이어를 정의할 수 있어요—none으로 설정된 값도 하나의 레이어로 카운트된다는 점을 기억하세요.
각 마스크 레이어는 마스크 이미지를 포함할 수 있는데, 이 이미지는 마스크의 원점 박스(origin box)를 기준으로 위치가 정해져요. 이미지의 크기를 조정하고, 반복하고, 잘라낼 수 있죠. 만약 여러 개의 마스크 이미지를 포함한다면, 마스크 레이어들이 합성되거나 결합되는 방식을 정의할 수 있어요. (이러한 기능들은 이 가이드에서 간략하게 소개할게요. 더 자세한 내용과 예제는 마스킹 속성 가이드를 참고하세요.)
mask 축약 속성은 쉼표로 구분된 마스크 레이어 목록을 받아들여요. 각 레이어의 문법은 다음 값들을 포함할 수 있어요:
<image> <position> / <size> <repeat> <origin> <clip> <composite> <mode>
마스크 레이어의 모든 구성요소는 선택사항이에요. 하지만 mask-image 값을 생략하면 기본값이 투명한 검은색 이미지가 되는데, 이는 해당 레이어에서 요소를 완전히 숨기게 돼요.
mask 축약 선언은 모든 mask-* 속성들의 값을 설정해요. 레이어 내에서 선언되지 않은 구성요소는 초기값으로 기본 설정돼요. mask 속성은 또한 모든 mask-border-* 속성들을 초기값으로 재설정해요. mask-image 값만 포함하는 mask 선언은 암묵적으로 다음과 같이 설정돼요:
mask-mode: match-source;
mask-position: 0% 0%;
mask-size: auto;
mask-repeat: repeat;
mask-origin: border-box;
mask-clip: border-box;
mask-composite: add;
mask-border-source: none;
mask-border-mode: alpha;
mask-border-outset: 0;
mask-border-repeat: stretch;
mask-border-slice: 0;
mask-border-width: auto;
mask-image로 마스크 레이어 정의하기쉼표로 구분된 mask-image 속성 선언에 none이 아닌 값이 최소 하나 이상 포함되어 있다면, 선언의 모든 값에 대해 마스크 레이어가 생성돼요—심지어 none 값도 마찬가지예요. 이 동작은 mask-image 속성을 사용하든 mask 축약을 사용하든 동일하게 적용돼요. 이러한 마스크 이미지는 그레이디언트, 이미지, 또는 SVG 소스가 될 수 있어요. CSS 그레이디언트, 래스터 이미지(PNG 같은), 또는 SVG <mask> 요소를 사용해서 정의할 수 있죠.
.gradient-mask {
mask-image: linear-gradient(to right, black, transparent);
}
.raster-mask {
mask-image: url("alphaImage.png");
}
.mask-element-mask {
mask-image: url("#svg-mask");
}
마스킹 입문 가이드에서 다양한 타입의 마스크 이미지와 그 모드를 소개하고 있어요.
mask-image 속성은 background-image 속성과 유사해요. background-image 속성처럼, 여러 개의 마스크 이미지를 포함하려면 이미지 값들을 쉼표로 구분하면 돼요.
.multiple-gradient-mask {
mask-image:
linear-gradient(to right, black, transparent),
radial-gradient(circle, white 50%, transparent 75%);
}
각 마스크 이미지가 여러 이미지 선언에서 하나의 마스크 레이어를 생성해요. 이 섹션의 모든 예제는 하나의 마스크 레이어를 생성하는데, multiple-gradient-mask 선언만 두 개를 생성해요.
💡 강사 팁: 실무에서 여러 마스크 레이어를 사용할 때는 각 레이어가 어떤 역할을 하는지 주석으로 잘 정리해두는 게 좋아요. 나중에 유지보수할 때 훨씬 편하거든요!
none 키워드만약 none이 mask-image 속성의 유일한 값이라면, 마스크 레이어가 생성되지 않고 마스킹도 발생하지 않아요.
.no-masks {
mask-image: none;
}
마찬가지로, mask 축약을 사용할 때 none 외에 다른 mask-image 값이 없으면 마스킹이 발생하지 않아요. 다음 중 하나라도 선언되면, 마스크 레이어가 생성되지 않고 아무것도 숨겨지지 않아요:
mask: none;
mask: none 100px 100px no-repeat;
mask: 100px 100px no-repeat;
그렇지 않고, none으로 설정되지 않은 mask-image가 선언되어 있다면, 쉼표로 구분된 값 목록의 모든 값에 대해 마스크 레이어가 생성돼요—심지어 쉼표로 구분된 목록의 값에서 mask-image 값이 생략되거나 명시적으로 none으로 설정된 경우에도 마찬가지예요. 다시 말해서, 전체 속성이 none으로 해석되지 않는 한, 각각의 유효한 쉼표로 구분된 값에 대해 레이어가 생성돼요.
.masked-element {
mask-image:
url("alphaImage.png"), linear-gradient(to right, black, transparent),
radial-gradient(circle, white 50%, transparent 75%), none, url("#svg-mask");
}
쉼표로 구분된 마스크 소스 목록 내의 none 키워드는 마스크 레이어를 생성하는데, 투명한 검은색 이미지 레이어가 되는 거예요. masked-element 클래스가 있는 모든 요소는 5개의 마스크 레이어를 가지게 돼요.
mask 축약을 사용해서도 레이어를 생성할 수 있어요:
.masked-element {
mask:
url("alphaImage.png"), linear-gradient(to right, black, transparent),
radial-gradient(circle, white 50%, transparent 75%), none, url("#svg-mask");
}
쉼표로 구분된 값 목록의 값이 빈 이미지이거나, 다운로드에 실패하거나, 존재하지 않는 <mask> 요소를 참조하거나, 그 외의 이유로 표시될 수 없는 경우(또는 none으로 설정된 경우)에도, 여전히 마스크 이미지 레이어로 카운트되어 시각적 효과가 없는 투명한 검은색 마스크 이미지를 렌더링해요. 모든 값이 이렇게 되면, 요소가 완전히 숨겨지게 돼요.
전체 속성이 none으로 해석되면 마스킹이 발생하지 않아서 요소가 완전히 보이게 돼요. 반면에 값이 여러 레이어를 포함하고 있고 최소 하나가 none이 아니라면, none 레이어는 요소의 어떤 부분도 드러내지 않아요(또는 요소의 어떤 부분도 보이게 만들지 않아요). 이 예제에서는 값이 none으로 해석되지 않지만, 모든 non-none 이미지가 유효하지 않기 때문에 마스킹이 발생하고, 요소가 완전히 숨겨지게 돼요.
none이 아닌 계산된 값은 CSS 쌓임 맥락(stacking context)을 생성해요.
💡 강사 팁: 마스크 이미지 로딩 실패를 방지하려면, 항상 이미지 경로를 정확히 확인하고, 가능하면 fallback 전략을 고려하세요. 프로덕션 환경에서는 이미지가 제대로 로드되는지 꼭 테스트해보는 게 중요해요!
mask-* 속성에 미치는 영향마스크 레이어의 개수는 mask 선언 이후에 또는 더 높은 특정도(specificity)로 개별 mask-* 속성을 사용할 때 중요해요.
mask-* 속성들은 다음을 포함해요:
mask-mode: 각 마스크 레이어의 모드를 alpha 또는 luminance로 설정하거나, 값을 match-source로 설정하여 소스의 모드를 기본값으로 사용할 수 있어요. 기본값은 match-source예요.
mask-position: background-position 속성과 유사하며, background-position의 <position> 문법을 따라요. 마스크 레이어의 원점 박스를 기준으로 마스크 이미지의 초기 위치를 설정하며, 원점 박스는 mask-origin 속성으로 정의돼요. 1개, 2개, 또는 4개의 <position> 값을 지정할 수 있어요. 기본값 0% 0%는 마스크의 왼쪽 위 모서리를 마스크 원점 박스의 왼쪽 위 모서리에 위치시켜요.
mask-origin: background-origin 속성과 유사하며, 마스크 위치 지정 영역을 지정해요. 이는 마스크 이미지가 위치할 마스크 원점 박스 영역이에요. 예를 들어, mask-position이 top left라면, 이 속성은 그것이 테두리(border)의 바깥쪽 가장자리, 패딩(padding)의 바깥쪽 가장자리, 또는 콘텐츠의 바깥쪽 가장자리를 기준으로 하는지를 정의해요.
mask-clip: background-clip 속성과 유사하며, 마스크의 영향을 받는 요소의 영역을 결정해요. 마스크 페인팅 영역이 border, padding, 또는 content 박스인지를 정의하여, 요소의 그려진 콘텐츠를 이 영역으로 제한해요. 마스크 레이어의 mask-image 소스가 SVG <mask> 요소라면, mask-clip 속성은 효과가 없어요.
mask-size: background-size 속성과 유사하며, 마스크 레이어의 크기를 조정하는 데 사용돼요. 값은 단일 키워드(cover, contain, 또는 auto), 단일 길이나 백분율, 또는 공백으로 구분된 두 값이 될 수 있는데—각각은 길이, 백분율, 또는 auto가 될 수 있어요. 기본값은 auto예요.
mask-repeat: background-repeat 속성과 유사하며, 마스크 레이어 이미지의 크기와 위치가 정해진 후 어떻게 타일링될지를 정의해요.
mask-composite: 마스크가 아래에 있는 마스크 레이어들과 어떻게 결합되는지를 정의해요. 각 마스크 레이어는 이전에 합성된 아래의 마스크 레이어들에 추가되거나, 빼지거나, 포함되거나, 제외될 수 있어요. mask-mode와 마찬가지로, 유사한 background-* 속성이 없어요.
쉼표로 구분된 mask 구성요소 속성 목록의 각 mask-* 값은 별도의 마스크 레이어에 적용돼요. 앞서 언급했듯이, 요소는 여러 개의 마스크 레이어를 가질 수 있는데—레이어의 수는 mask-image 또는 mask 속성의 쉼표로 구분된 값의 개수로 결정돼요. 각 mask-* 값은 순서대로 마스크 레이어와 매칭돼요. mask-* 속성의 값 개수가 마스크 레이어 수보다 많으면, 초과된 값들은 무시돼요. 마스크 구성요소 속성의 값이 마스크 레이어 수보다 적으면, mask-* 값들이 반복돼요.
이러한 개별 속성들에 대해 더 알아보려면, CSS mask 속성을 참고하세요.
💡 강사 팁: 마스크 레이어가 많아질수록 성능에 영향을 줄 수 있어요. 실무에서는 꼭 필요한 만큼만 레이어를 사용하고, 브라우저 개발자 도구로 렌더링 성능을 체크해보는 습관을 들이세요!
대부분의 경우 속성의 순서는 유연하지만, 몇 가지 특이사항과 예외가 있어요.
mask-origin과 mask-clip의 순서 규칙mask-origin 값은 문법에서 <origin>으로 나열되며, mask-clip 값(<clip>)보다 앞에 와요.
<image> <position> / <size> <repeat> <origin> <clip> <composite> <mode>
둘 다 <geometry-box> 키워드를 받아요. 추가로, mask-clip은 no-clip도 받을 수 있어요. 이 때문에 mask-clip을 no-clip 이외의 값으로 설정하고 싶을 때 이 두 속성의 순서가 중요해요.
<geometry-box> 값 하나가 no-clip 키워드와 함께 있으면, <geometry-box>가 mask-origin 값을 설정하고, mask-clip은 no-clip으로 설정돼요. 이 경우에는 순서가 중요하지 않아요.
<geometry-box> 값 하나만 있고 no-clip 키워드가 없으면, mask-origin과 mask-clip 구성요소 둘 다 그 값으로 설정돼요. 값이 하나뿐이므로, 역시 순서가 중요하지 않아요.
<geometry-box> 값 두 개가 있으면, 첫 번째가 mask-origin 구성요소를 설정하고 두 번째가 mask-clip 구성요소를 설정해요. 이 경우, 순서가 매우 중요해요.
mask-origin과 mask-clip 값의 잘못된 순서는 외관에 영향을 줄 수 있지만, 선언을 실패하게 만들지는 않아요.
💡 강사 팁: 헷갈릴 수 있으니까, 저는 실무에서 항상 mask-origin과 mask-clip을 명시적으로 쓰는 걸 추천해요. 축약 속성이 편하긴 하지만, 순서를 잘못 쓰면 디버깅이 정말 어려워질 수 있거든요!
mask-size와 mask-position의 순서 규칙mask-position과 mask-size 사이에 슬래시가 있다는 걸 눈치채셨을 거예요. 문법에서 <position>과 <size>로 나열되죠. 두 속성 모두 비슷한 값을 받아요.
<image> <position> / <size> <repeat> <origin> <clip> <composite> <mode>
이 경우, 순서가 매우 중요해요. <length-percentage> 값 하나 또는 한 쌍만 있으면, 크기가 아니라 이미지의 위치를 정의하게 돼요. 두 값 사이에 슬래시를 포함하지 않고 마스크 레이어에 위치와 크기를 모두 포함하면 전체 선언이 무효가 돼요.
mask:
url("star.svg") bottom 2em right 4em / auto 2vw no-repeat padding-box
content-box luminance,
url("circle.svg") 100px 100px / 50% repeat-x border-box padding-box alpha;
<length-percentage> 값 한 쌍만 있으면, mask-position 속성을 설정하고 mask-size는 auto가 돼요. 레이어에 mask-size와 mask-position이 모두 포함되어 있다면, mask-size 속성 값은 mask-position 속성 값 뒤에 와야 하고, 값들은 슬래시(/)로 구분되어야 해요. mask-size가 유효한 mask-position 값이 아닌 값으로 설정되어 있어도 슬래시가 필요해요.
mask: url("star.svg") contain;
mask: url("star.svg") 10px 10px cover;
mask: url("star.svg") top right 100px 100px;
mask: url("star.svg") 10px 10px / cover;
mask: url("star.svg") top 100px right 100px;
mask: url("star.svg") top right / 100px 100px;
mask 축약을 사용해서 마스크 레이어에 mask-size를 포함하려면, 바로 앞에 슬래시와 함께 mask-position 값을 포함해야 해요.
⚠️ 경고:
레이어에 크기를 포함했는데 위치 뒤의 슬래시를 잊어버리면, 전체 선언이 무효가 돼요.
💡 강사 팁: 실수를 방지하기 위해, mask-position과 mask-size를 함께 쓸 때는 항상 이렇게 기억하세요: "위치 / 크기" 순서로, 반드시 슬래시 포함! 린터(linter)나 코드 포맷터를 사용하면 이런 실수를 많이 줄일 수 있어요.
💡 마지막 팁: CSS 마스킹은 처음에는 복잡해 보일 수 있지만, 차근차근 연습하면서 익히면 정말 강력한 도구가 돼요. 작은 예제부터 시작해서 점차 복잡한 효과를 만들어보세요. 그리고 브라우저 호환성도 꼭 체크하는 걸 잊지 마세요! 특히 프로덕션에 적용할 때는 Can I Use 같은 사이트에서 지원 브라우저를 확인하는 게 필수예요.