CSS マスク入門

CSS マスクを使用すると、1 つ以上のマスク画像を要素に適用して、要素の一部を選択的に表示または非表示にすることができます。これらのマスク画像は、グラデーション、画像、または SVG ソースにすることができます。単一のパスの形状に基づいて要素の領域を完全に表示または非表示にする CSS クリップとは異なり、マスクでは、マスク画像のアルファ透過率およびオプションで輝度に基づいて、微妙な透過率や合成効果を表現することができます。

このガイドでは、マスクの概念、さまざまなマスク画像の型、およびマスクの輝度とアルファ透過率が、マスクされる(表示される)要素の部分とクリップされる(または非表示になる)部分に対してどのように影響するかを紹介します。

CSS でのマスクとは何か

CSS では、マスクを使用して、要素の表示領域と非表示領域を定義することができます。1 つ以上の mask-image ソースによって定義されるマスクレイヤーは、要素の表示領域と不透明度を決定します。

メモ: mask 一括指定プロパティを使用して、複数の CSS マスクプロパティの値を設定することができます。

alpha マスクでは、マスクされた要素の不透明度は、適用されたマスクの不透明度と一致します。 CSS では、マスクとは、不透明な部分が顔を隠す仮面の反対のものです。 CSS では、マスクが完全に不透明な要素の領域は、完全に不透明で表示されます。マスクが完全に透明な部分は、要素が完全に非表示になります。部分的に不透明なマスク領域によってマスクされている要素の領域は、マスクの不透明度に合わせて部分的に不透明になります。

アルファマスクでは、マスクの色は関係ありません。マスクの不透明度だけが重要になります。輝度マスクを使用すると、マスクされた要素の不透明度を決定する際に、マスクの色の明るさが考慮されます。色が明るく不透明であるほど、要素の不透明度が高くなります。色が暗く透明であるほど、マスクの不透明度は低くなります。

マスクは、 CSS グラデーション、ラスター画像 (PNG など)、および SVG <mask> 要素を使用して定義することができます。このガイドでは、不透明度と透過率輝度、およびマスクと CSS クリップについて説明しながら、さまざまなマスク画像の種類を紹介します。

それぞれのマスクレイヤーは、基準ボックスに対して 位置指定された mask-image で構成されます。マスク画像は、サイズを指定したり、反復したり、クリップしたりすることができます。複数のマスク画像が宣言されている場合、マスクレイヤーの合成または結合の方法を設定することができます。これについては、[マスクプロパティガイド] (/ja/docs/Web/CSS/CSS_masking/CSS_mask_properties)で説明しています。

メモ: すべての例では、マスクが適用される基盤要素として次の画像を使用します。

Pride flag

不透明度と透過率

アルファマスクでは、要素の表示領域は、その要素に適用されるマスクのアルファ透過率によって定義されます。マスクが完全に不透明な部分は、要素が表示されます。マスクが完全に透明なピクセルでは、要素も完全に非表示になります。マスクの一部が不透明な領域でマスクされている要素の領域は、そのマスクの不透明度に対応して、部分的に不透明になります。

これを確認するために、conic-gradient()mask-image として使用した例を見ていきましょう。扇形グラデーションを含む CSS グラデーションは、表示領域と非表示領域の間の滑らかなトランジションを作成するために使用することができます。

この場合、マスクの右上隅は完全に不透明、左上隅は完全に透明、そして下半分は不透明から透明へと滑らかに変化しています。

css
.applied-mask {
  mask-image: conic-gradient(rgb(0 0 0 / 1) 90deg, rgba(0 0 0 / 0) 270deg);
}
.mask-source {
  background: conic-gradient(rgb(0 0 0 / 1) 90deg, rgba(0 0 0 / 0) 270deg);
}

マスクが適用されている要素の右上隅が完全に表示され、左上隅が非表示になり、下半分が透明にスムーズに遷移し、適用されたマスク画像の表示状態を反映していることに注意してください。

アルファマスクでは、マスクの色は関係なく、透過率のみが重要になります。この例では、完全に不透明な赤、半透明の赤、および完全に透明な縞模様のグラデーションが指定されています。

css
.applied-mask {
  mask-image: repeating-linear-gradient(
    to bottom right,
    #f00 0 20px,
    #f005 20px 40px,
    transparent 40px 60px
  );
}
.mask-source {
  background: repeating-linear-gradient(
    to bottom right,
    #f00 0 20px,
    #f005 20px 40px,
    transparent 40px 60px
  );
}

完全に不透明なマスク領域は、要素のピクセルが完全に不透明に表示され、半透明のマスク領域は、半透明の領域が作成され、完全に透明なマスク領域は、対応する領域が完全に非表示になる様子に注意してください。

前の 2 つの例では、グラデーションをマスクおよび背景画像として使用しました。マスク画像は CSS 画像である必要はありません。外部画像や SVG でもかまいません。

この例では、外部の PNG を使用しています。画像には、背景が透明なカラフルなハートが含まれています。

css
.applied-mask {
  mask-image: url(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);
  background-size: 220px 220px;
}

透明なマスク領域が要素をどのように切り取るかに注意してください。要素のうち、表示されているのはマスクが不透明な領域のみです。マスク自体の色は関係ありません。

アルファ透過度と輝度

mask-mode プロパティの既定値である match-source は、その値に応じてモードを alpha または luminance のいずれかに設定します。match-source の値は、SVG <mask> 要素以外のすべてのマスクソースに対して alpha として解決されます。マスクソースが <mask> 要素の場合、 match-source は、設定されている場合は <mask>mask-type プロパティの値として解決されます。それ以外の場合、<mask> 要素に設定されている SVG の mask-type 属性の値に解決されます。それも明示的に設定されていない場合、match-sourceluminance に解決されます。

mask-modeluminance に解決される場合、または明示的に luminance に設定した場合、マスクの色はマスクの不透明度に影響します。前回のデモでは、mask-mode は設定されていなかったため、値は既定の match-source になりました。カラフルなハートの画像は透明な PNG であるため、match-sourcealpha に解決されます。このプロパティを明示的に設定することで、モードを制御することができます。このデモでは、mask-modeluminance に変更します。

css
.applied-mask {
  mask-mode: luminance;
}

前回の例と同じマスクに mask-mode: luminance を適用すると、マスクが最も明るい要素の領域は不透明になり、より暗い領域は不透明度が低くなります。

輝度マスクの不透明度は、次の式を使用して、 RGB 色の RGBA の値によって決定されます。

((0.2125 * R) + (0.7154 * G) + (0.0721 * B)) * A

例えば、最新の <named-color>rebeccapurple で、これは #663399 です。明度は hsl() カラー関数の L と同等であると想定するかもしれませんが、それほど単純ではありません。値 #663399rgb(40% 20% 60% / 1) および hsl(270 50% 40% / 1) と同等ですが、明るさの値は 40% ではなく 27.134% です。

((0.2125 * 0.4) + (0.7154 * 0.2) + (0.0721 * 0.6)) * 1 = 0.27134

白の明るさの値は 100% です。

((0.2125 * 1) + (0.7154 * 1) + (0.0721 * 1)) * 1 = 1

黒の明るさは 0% です。

((0.2125 * 0) + (0.7154 * 0) + (0.0721 * 0)) * 1 = 0

これを、明度 100%、不透明度 27.234% の白色 (rgb(100% 100% 100%)) を、rebeccapurplewhiteblack の線形グラデーションに追加して、画像のマスクに使用して説明します。この白色は、同じ不透明度の値に解決されます。

((0.2125 * 1) + (0.7154 * 1) + (0.0721 * 1)) * 0.27134 = 0.27134

css
.applied-mask {
  mask-image: repeating-linear-gradient(
    to bottom left,
    rebeccapurple 0 20px,
    rgb(100% 100% 100% / 0.27134) 20px 40px,
    black 40px 45px,
    white 45px 50px
  );
  mask-mode: luminance;
}
.mask-source {
  background: repeating-linear-gradient(
    to bottom left,
    rebeccapurple 0 20px,
    rgb(100% 100% 100% / 0.27134) 20px 40px,
    black 40px 45px,
    white 45px 50px
  );
}

white マスクが設定されている領域は完全に不透明です。 black マスクが設定されている領域は完全に透明です。 rebeccapurple マスクが設定されている領域と、不透明度の 27.1234% の白いマスクが設定されている領域は、どちらも不透明度 27.1234% です。

mask-modealpha に切り替えると、グラデーションの色は関係なくなります。半透明の白で覆われた部分以外は、要素全体が不透明になります。

mask-mode プロパティを使用すると、 JPEG などのアルファ透過率のないラスター画像をマスク画像として使用することができます。 JPEG は不透明なピクセルで構成されています。既定の alpha マスクモードで JPEG をマスクとして使用すると、要素全体が非表示になります。一方、mask-modeluminance 値は、マスクが黒(明度がない)の部分をクリップし、マスクが不透明な白(明度 100%)の部分は完全に不透明にし、それ以外の部分は、それを覆っているマスク領域の明度に応じて半透明にします。

この例では、黒い夜空に白い月が指定されています。

css
.applied-mask {
  mask-image: url(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);
  background-size: 220px;
}

要素はクリップされ、空が黒い部分では表示されません。画像は、月が最も明るい部分で最もよく見えます。

この場合、mask-modealpha に切り替えると、マスク全体が不透明になるため、要素全体が表示されます。

SVG の <mask> をマスクソースとする

マスクは、CSS の <image> または <mask-source> であれば何でも構いません。 <mask-source> は、 <url> であり、SVG の <mask> 要素への参照です。これは、 CSS の clip-path プロパティによるクリップと似ていますが、この場合は「マスク」は SVG <clipPath> 要素になります(clip-path を使用する場合、パスの輝度は関係ありません)。

この例では、<mask> 要素、同一の <clipPath> 要素、および同一の <path> 要素を持つ SVG を定義して、マスクとクリップパスのソースを表示できるようにしています。

html
<img
  src="https://mdn.github.io/shared-assets/images/examples/progress-pride-flag.jpg"
  alt="Pride flag"
  class="applied-mask" />
<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>
  <clippath id="clip-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" />
  </clippath>
  <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" />
</svg>
<img
  src="https://mdn.github.io/shared-assets/images/examples/progress-pride-flag.jpg"
  alt="Pride flag"
  class="applied-clip" />
css
.applied-mask {
  mask-image: url(#mask-heart);
}
.applied-clip {
  clip-path: url(#clip-heart);
}

画像ソースは <mask> であり、マスクには mask-type CSS プロパティも mask-type SVG 属性も設定されていないため、mask-type は既定で alpha となり、mask-mode: match-source の既定は luminance に解決されます。これは、SVG <mask> 要素であるマスクソースの場合、mask-type 属性が明示的に alpha に設定されていない限り、mask-type は既定で luminance になるからです。

マスクに mask-type 属性または CSS プロパティを設定していないため、mask-mode プロパティの既定値である match-sourceluminance に解決されます。チェックボックスをオンまたはオフにして、mask-mode の値を alpha に設定するか、既定値の match-source のままにします。

この例では、 CSS におけるマスクとクリップの相違点も示しました。輝度とアルファ透過度はマスクには関係がありますが、クリップには関係がないことに注意してください。マスクは要素の不透明度を制御するために使用できますが、クリップはクリップパス内のすべてを表示し、クリップパス外の要素の部分を完全に非表示にします。クリップされた領域は完全に非表示になりますが、マスクされた領域は部分的にまたは完全に表示することができます。

必要なのが形状だけなら、クリップで十分です。しかし、フェード、不透明度の変化、あるいは位置やサイズの制御(これについては別のガイドで説明します)が必要な場合は、マスキングの方が適しています。

関連情報