ここを意識したらmaskプロパティの理解が少しだけ深まった話

CSSのmaskプロパティは、グラデーションやSVGを使って要素の表示範囲を自在にコントロールできる便利なプロパティです。しかし実務で扱ってみると、「なぜ画像が消えるの?」「なぜここにマスクが来るの?」と、意図通りに動かず困ることがあります。

この記事ではmaskプロパティの基本的な仕組みをおさらいしつつ、実装中につまずきやすいポイントを具体例を交えて解説します。

maskプロパティの基本的な仕組み

CSSのmaskプロパティは、要素の表示範囲を制御するプロパティの一つです。別の画像やグラデーションを「マスク」として参照し、その透明度(アルファ値)に応じて元の要素の見え方を変化させます。

例えば長方形の画像と、円形の形状をしたSVGがあるとします。

長方形の画像
長方形の画像
円の形状をしたSVG
円の形状をしたSVG

この長方形の画像に対して、円形のSVGをmaskとして参照すると、SVGの形状に応じて表示される範囲が変化します。

長方形の画像に、円形のSVGを適用した例

基本的なプロパティの書き方は次のとおりです。

.img {
mask-image: url(../img/common/circle.svg);
mask-size: contain;
mask-position: center;
mask-repeat: no-repeat;
}

プロパティの構成はbackgroundとよく似ていて、画像の指定・サイズ・位置・繰り返しといった概念で設定します。ただし、maskはあくまで「表示範囲を制御するための画像」として扱われる点が異なります。

上記の例ではmask-imageurl()を使用してSVG画像を指定していますが、そのほかにもlinear-gradientradial-gradientなどのグラデーションを指定することも可能です。

mask-imageにグラデーションを指定した例

これらはいずれも「マスク画像」として扱われ、その透明度(アルファ値)に応じて要素の表示範囲が決まります。

maskで表示される領域

maskで表示される範囲は、mask-imageで指定した形状とその透明度(アルファ値)等によって決まります。上記の例では円形のSVGを指定しているため、不透明の円の部分が表示される領域となります。

マスクの状態α値結果
不透明1表示される
半透明0.5半分だけ表示
透明0完全に非表示(マスクで隠す)

つまり、maskでは不透明な部分が表示され、透明な部分が非表示になります。ここが少し直感的ではなくややこしいポイントで、整理していないと混乱することがあります。

clip-pathとの違い

同じく要素の表示範囲を制御するプロパティにclip-pathがあります。 clip-pathmaskとは異なり、ピクセル単位の透明度を持たず、表示・非表示を明確に切り替える仕組みです。そのため、グラデーションのような滑らかな透過表現は行えません。

両者を表でまとめると次のようになります。

項目clip-pathmask
概念図形で「切り抜く」透明度(アルファ値)で「隠す」
表現方法ベクター形状(circle, polygon など)グラデーション・画像・SVGなど
グラデーション表現不可(連続的な透明度は扱えない)可能(半透明表現ができる)

一見すると、グラデーションが使えるmaskの方が表現力が高いように見えますが、単純に優劣の関係ではありません。

clip-pathはシャープな図形表現や軽量なアニメーションに向いており、maskはフェードやぼかしなど、よりリッチな視覚表現に適しています。このように、両者は似た見た目の効果を実現できる一方で、仕組みと得意分野が異なるプロパティです。

maskを扱う上で注意しておきたいポイント

ここからはmaskプロパティを実務で使用する際に、沼にはまらないために意識しておきたいポイントについて紹介していきます。

mask-imageを指定するとマスクの影響を受ける

次のようにmask-imageを指定しつつ、mask-size: 0% 0%;を設定した場合、どうなるでしょうか?

.img {
mask-image: radial-gradient(closest-side, white 80%, transparent 100%);
mask-size: 0% 0%;
mask-position: center center;
mask-repeat: no-repeat;
}

一見するとマスクのサイズが0%のため、マスクの影響を受けず画像が表示されるように思えます。

しかし実際には、mask-imageを指定した時点で要素はマスクの影響を受けます。mask-size: 0% 0%の場合、マスク画像自体が描画されないため、有効なマスク領域が存在しません。

その結果、多くのブラウザでは要素全体が透明として扱われ、画像は表示されなくなります。

mask-size: 0% 0%; が指定されている場合
mask-size: 0% 0%; が指定されている場合

この挙動は次のように整理できます。

  • マスク自体は定義されている
  • しかしマスク画像のサイズが 0% 0%
  • マスクとして参照できる領域が存在しない
  • 結果として、表示されるピクセルが存在しない(= 透明になる)

maskは要素単位で適用される

maskは要素ごとに適用されるプロパティであり、他の要素に効果が伝播することはありません。

例えば次のようなコードを考えます。

.img {
position: relative;
}
.img::before {
content: "";
width: 100%;
height: 100%;
mask-image: url("../img/common/circle.svg");
mask-size: 100% 100%;
mask-position: center center;
mask-repeat: no-repeat;
position: absolute;
inset: 0;
}

この例では、ラッパー要素に::before擬似要素を生成し、その擬似要素にmaskを適用しています。しかし、maskはその擬似要素自身の描画にのみ適用されるため、背面にある画像には影響しません。

擬似要素にmaskを適用しても画像には影響しない
擬似要素にmaskを適用しても画像には影響しない

この挙動は次のように整理できます。

  • ::before.imgは別の描画レイヤーとして扱われる
  • maskは適用された要素の描画結果に対してのみ作用する
  • そのため、重なっていても他の要素には影響しない

また、この例では::before自体には背景が設定されていないため、マスクが適用されても視覚的な変化が現れていません。つまり、

  • 擬似要素自体にはマスクが適用されている
  • しかしその要素に描画内容がないため、結果として何も見えない
  • 下にある画像をマスクする効果は発生しない

という状態になります。擬似要素と親要素は別レイヤーとして扱われるため、擬似要素のmaskの効果は親要素に及ばない、と覚えておくと良いでしょう。

mask-position-xが100%でも中心より左側に配置されることがある

次のようにmask-position: 100% 0%;を指定するとどうなるでしょうか?

.img {
mask-image: url("../img/common/circle.svg");
mask-size: 200% 100%;
mask-position: 100% 0%;
mask-repeat: no-repeat;
}

mask-position-x: 100%のため、直感的にはマスクが要素の右端に揃うように思えます。しかし実際には、マスクは要素の中心よりも左側に配置されます。

mask-position-x: 100% でも中心より左側に配置される例
mask-position-x: 100% でも中心より左側に配置される例

これは誤りではなく、mask-positionの仕様通りの挙動です。100%を指定しているのに、なぜ左側に配置されるのでしょうか?その答えは、mask-positionの%指定の仕組みにあります。

mask-positionを%で指定した場合、マスク画像の位置は次の計算式で決定します。

マスクの位置(x) = (要素の幅 - マスク画像の幅) × パーセント値

今回のケースを具体的な数値で見てみます。

  • 要素の幅:500px
  • マスク画像の幅:500px × 200% = 1000px
  • 差分:500px - 1000px = -500px
  • パーセント値:100%
マスクの位置(X) = (500px - 1000px) × 1 = -500px

この計算結果は、マスク画像の左端が要素の左端より500px外側に配置されることを意味します。つまり、要素の中にはマスク画像の右半分だけが重なった状態になり、直感と異なる見え方になります。

このmask-positionの仕様は、background-positionの仕様と同じです。

さらに詳しく知りたい場合、下記の記事もあわせてご覧ください。
なぜbackground-position-xが300%なのに背景画像が左に配置されるのか?

まとめ

この記事では、CSSのmaskプロパティの基本的な仕組みと、実務で意識しておきたいポイントを紹介しました。改めて整理すると次のようになります。

  • mask-imageを指定した時点でマスクの影響を受けるため、mask-size: 0%にすると要素全体が非表示になる
  • maskは要素単位で適用されるプロパティであり、擬似要素のマスクが親要素に影響することはない
  • mask-positionを%で指定する場合、マスク画像が要素より大きいと計算値がマイナスになり、直感と逆の挙動になる

いずれも一度仕組みを理解してしまえば、原因の見当がつきやすくなります。maskプロパティは扱いこなすと表現の幅が大きく広がるので、ぜひ実装に活用してみてください。

この記事を書いた人

写真:ブール 代表 西川雅人

Masato Nishikawa

ウェブ制作会社・デザイナー様向けに、コーディングやWordPress実装を承っているフリーランスです。繁忙期のサポートや、継続的な外注先をお探しでしたら、お気軽にお声がけください。

コーディングや
WordPress実装の
ご相談を承っています。

新規制作から運用フェーズの修正まで柔軟に対応します。
お見積りや実装可否の確認など、お気軽にご連絡ください。