SVG mask – Masken mit weichem Übergang

SVG maskieren

Eine Maske zeigt Teile eines Bildes oder einer Grafik und verbringt den Rest auf dem Monitor, wobei das ursprüngliche Bild oder die Grafik erhalten bleibt. Vor allem bei Bitmap-Bildern erspart das Maskieren mit SVG mask den Gang in die Bildbearbeitungssoftware und die Verwaltung von Originalbild und freigestellten Bildmotiven.

In der Bildbearbeitung ist das Maskieren mit weichen Konturen mittels Alphakanal eine alte Technik, die seit vielen Jahren im Druck angewendet wird.

SVG mask

Da SVG seine Ursprünge in Illustrationsprogrammen wie Illustrator und Corel hat, ist das Maskieren von Bildern mit SVG zuverlässiger als das gleichnamige CSS mask, das zwar inzwischen in Chrome, Firefox und Safari zuhause ist, aber in IE11 noch nicht unterstützt wird und in MS EDGE noch hinter about:flags aktiviert werden muss.

Masken bestehen aus einer oder mehreren Formen wie circle, rect, text oder path und in ein mask-Element gelegt werden.

<mask id="circle">
	<circle cx="490" cy="327" r="300" fill="black" />
</mask>
<image mask="url(#circle)" xlink:href="rosen-980.jpg" x="1" y="1" width="980" height="653" />

Das maskierte Element setzt die Maske durch das mask-Attribut und den Verweis auf das mask-Element ein. Dabei spielt es keine Rolle, auf welcher Position die Maske im Markup sitzt: vor oder nach dem maskierten Element. I.d.R. wird die Maske gleich an den Anfang der SVG-Datei gesetzt, oft auch zusätzlich in defs-Tags.

Das funktioniert problemlos, wenn das SVG-Bild inline im HTML sitzt. Wird die SVG-Grafik aus einer externen Datei mit einem HTML-img-Tag eingebunden, zeigen die meisten Browser das Bild nicht an. Statt das Bild über xlink:href aus einer externen Datei einzubinden kann es auch als Data URL eingebettet werden.

Die maskierte Form oder das Bild wird an allen Stellen außerhalb der Maske durchsichtig. Wie durchsichtig der offene Bereich der Maske wird, hängt von der Helligkeit der Füllfarbe der Maske ab.

<path d="m 690,168 …" fill="white" filter="url(#blur)" />

Je dunkler die Füllfarbe der Maske, desto matter wird das darunter liegende Bild angezeigt.

Masken mit weichen Übergängen

Masken wirken entsprechend ihrer Helligkeit: Ein reines Weiß wird vollständig durchsichtig, Grau semitransparent, Schwarz transparent. Eine Farbe wirkt entsprechend ihrer Helligkeit.

Wenn die Maske einen weichen Rand hat, überträgt sich der Übergang auf die maskierte Form. Die einfachste Technik für einen weichen Übergang von Transparent zu gedeckt bietet der SVG Blur-Filter.

<svg viewBox="0 0 980 653" width="100%" height="100%">
    <filter id="blur">
        <feGaussianBlur stdDeviation="20"/>
    </filter>
    <mask id="circlemask">
        <circle cx="490" cy="326" r="290" fill="#fff" filter="url(#blur)" />
    </mask>
    <image width="980" height="653" mask="url(#circlemask)" xlink:href="rosen.jpg" />
</svg>

Mehr ist nicht nötig, um ein Bild mit einem weichen Übergang freizustellen. Der SVG-Blur-Filter braucht nur die Angabe einer Stärke (stdDeviation). SVG-Masken reagieren auf die Helligkeit der Maskenfüllung, während bei einem clipPath nur die Kontur des Freistellpads eine Rolle spielt.

Unterschiede: SVG mask vs clipPath

In Hinsicht auf die weiche oder harte Kontur ist mask genereller als clipPath, denn mask ohne Blur-Filter liefert genauso einen harten Rand wie ein clipPath.

Allerdings sollte mask trotzdem i.d.R. dem Freistellen mit einem weichen Übergang zur Transparenz vorbehalten bleiben, denn Maskieren ist eine Raster-Operation mit einem großen Speicherbedarf und langsamer als clipPath.

Masken mit Aussparung – Löchern

Das Loch in der Donut-förmigen Maske wird von einem weiteren circle-Element gebildet und ist mit Schwarz gefüllt.

<mask id="mask5" >
    <circle cx="340" cy="340" r="290" fill="#fff" filter="url(#blur2)"/>
    <circle cx="340" cy="340" r="140" fill="#000" filter="url(#blur2)"/>
</mask>

<image mask="url(#mask5)" xlink:href="little-planet.jpg" x="100" y="30" width="680" height="679" />

Text-Masken

STOFF muster
<mask id="myMask">
    <rect width="100%" height="100%" fill="#fff" />
    <text x="300" y="200" text-anchor="middle" font-size="100" font-family="Arial Black">STOFF</text>
    <text x="300" y="260" text-anchor="middle" font-size="80" font-family="Arial Black">muster</text>
</mask>
<image xlink:href="stoff.jpg" width="680" height="416" />
<ellipse mask="url(#myMask)" cx="300" cy="200" rx="240" ry="150" fill="hsla(0,0%,100%,0.8)" />

maskUnits objectBoundingBox | userSpaceOnUse

In gleiche Weise wie clipPathUnits und gradientUnits definiert maskUnits das Koordinatensystem mit dem Attributen x, y, width und height.

  • Die Vorgabe ist objectBoundingBox: Die Strecke, über die sich die Maske erstreckt, ist relativ zum maskierten Element.
  • userSpaceOnUse ist die Strecke relativ zum Dokument.

Mit relativen Werten und der Voreinstellung objectBoundingBox anstelle absoluter Werte lassen sich Masken direkt auf andere Elemente übertragen.

<mask id="rect">
    <rect x="0" y="0" width="50%" height="50%" fill="#444"/>
    <rect x="50%" y="0" width="50%" height="50%" fill="#888"/>
    <rect x="0" y="50%" width="50%" height="50%" fill="#aaa"/>
    <rect x="50%" y="50%" width="50%" height="50%" fill="#ddd"/>
</mask>
<circle mask="url(#rect)" cx="120" cy="120" r="120" fill="blue"/>
<image mask="url(#rect)" xlink:href="rosen.jpg" width="980" height="653" />

SVG-Formen konstruieren und animieren

Masken werden in SVG nicht nur zum Beschneiden von Bitmap-Bildern verwendet, sondern auch für die Konstruktion komplexer Formen und insbesondere auch für Animationen.

Das mask-Element beschneidet sämtliche Elemente in kompletten Gruppen.

<g id="beach" mask="url(#growingcircle)">
    …
</g>

Masken können aus einfachen Formen wie circle, rect oder text bestehen, die sich einfach animieren lassen (einfacher als ein Pfad in einem clip-path).

<mask id="growingcircle">
    <circle id="showcircle" cx="267" cy="165" r="1" fill="#fff" />
</mask>

Die Animation übernimmt ein kleines Javascript mit wenigen Zeilen (Download Quelltext).

Pattern (Muster) für Masken

Während bei einem clipPath Farbe und Füllung keine Wirkung haben, kann die Form einer Maske gefüllt sein. Darum kann eine Maske auf SVG-Pattern aufsetzen, ein clipPath nicht.

<filter id="sw" style="color-interpolation-filters:sRGB">
<feColorMatrix 
  values="0.21  0.72  0.072  0   0
          0.21  0.72  0.072  0   0
          0.21  0.72  0.072  0   0 
          0     0     0      1   0 "/>
</filter>

<pattern id="pattern" x="0" y="0" width="12" height="12" patternUnits="userSpaceOnUse">  
    <circle cx="6" cy="6" r="6" fill="#eee"/>  
</pattern>

<mask id="pattern-mask" x="0" y="0" width="1" height="1" >  
    <rect x="0" y="0" width="100%" height="100%" fill="url(#pattern)"/>  
</mask> 

<image filter="url(#sw)" mask="url(#pattern-mask)" preserveAspectRatio="xMidYMid slice" … />

preserveAspectRatio="xMidYMid slice" füllt das SVG mit dem Bild, ähnlich wie CSS background-size: cover.