Hinzufügen von Schatten zu SVG-Icons mit CSS und SVG-Filtern

Avatar of Joel Olawanle
Joel Olawanle am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Warum sollten wir Schatten auf SVG anwenden müssen?

  1. Schatten sind ein gängiges Designmerkmal, das Elementen wie Icons helfen kann, hervorzustechen. Sie können dauerhaft sein oder in verschiedenen Zuständen (z. B. :hover, :focus oder :active) angewendet werden, um dem Benutzer Interaktion anzuzeigen.
  2. Schatten gibt es im wirklichen Leben, daher können sie auf Bildschirmen verwendet werden, um Ihren Elementen Leben einzuhauchen und einen Hauch von Realismus zu einem Design zu verleihen.

Da wir Listen erstellen, gibt es zwei Hauptmethoden, mit denen wir Schatten auf ein SVG anwenden können

  1. Verwenden der CSS-Eigenschaft filter()
  2. Verwenden eines SVG <filter>

Ja, beides beinhaltet Filter! Und ja, sowohl CSS als auch SVG haben ihre eigenen Arten von Filtern. Aber es gibt auch einige Überschneidungen zwischen ihnen. Zum Beispiel kann ein CSS filter sich auf ein SVG <filter> beziehen; das heißt, wenn wir mit einem Inline-SVG statt z. B. einem als Hintergrundbild in CSS verwendeten SVG arbeiten.

Was Sie nicht verwenden können: die CSS-Eigenschaft box-shadow. Diese wird häufig für Schatten verwendet, folgt aber dem rechteckigen Außenrand von Elementen, nicht den Kanten von SVG-Elementen, wie wir es möchten. Hier hat Michelle Barker eine klare Erklärung

Two flat kitten faces in bright pink showing ears eyes and whiskers. The first kitten has a drop shadow around its box and the second kitten has a drop shadow around its path edges.

Wenn Sie jedoch ein SVG-Icon-Font verwenden, gibt es immer text-shadow. Das funktioniert tatsächlich. Aber konzentrieren wir uns auf die ersten beiden, da sie mit der Mehrheit der Anwendungsfälle übereinstimmen.

Schatten mit CSS-Filtern

Der Trick beim direkten Anwenden eines Schattens auf SVG über CSS-Filter ist die Funktion drop-shadow()

svg {
  filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));
}

Dies wendet einen Schatten an, der bei 3px horizontal, 5px nach unten, mit 2px Unschärfe beginnt und 40% schwarz ist. Hier sind einige Beispiele dafür

Diese Daten zur Browserunterstützung stammen von Caniuse, wo weitere Details zu finden sind. Eine Zahl gibt an, dass der Browser die Funktion ab dieser Version unterstützt.

Desktop

ChromeFirefoxIEEdgeSafari
18*35Nein796*

Mobil / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
1271274.4*6.0-6.1*

Aufrufen eines SVG-Filters innerhalb eines CSS-Filters

Nehmen wir an, wir haben einen SVG-Filter im HTML

<svg height="0" width="0">
  
  <filter id='shadow' color-interpolation-filters="sRGB">
    <feDropShadow dx="2" dy="2" stdDeviation="3" flood-opacity="0.5"/>
  </filter>
  
</svg>

Wir können einen CSS-Filter verwenden, um diesen SVG-Filter anhand der ID aufzurufen, anstatt der zuvor gezeigten Werte

svg {
  filter: url(#shadow);
}

Nun wird dieser Filter aus dem HTML übernommen und im CSS referenziert, was ihn anwendet.

Verwenden von SVG-Filter-Primitiven

Sie fragen sich vielleicht, wie wir diesen SVG-<filter> zum Laufen gebracht haben. Um einen Drop-Schatten mit einem SVG-Filter zu erstellen, verwenden wir ein Filter-Primitiv. Ein Filter-Primitiv in SVG ist ein Element, das eine Art Bild oder Grafik als Eingabe nimmt und dieses Bild oder diese Grafik ausgibt, wenn es aufgerufen wird. Sie funktionieren so ähnlich wie Filter in einer Grafikbearbeitungsanwendung, aber im Code und können nur innerhalb eines SVG-<filter>-Elements verwendet werden.

Es gibt viele verschiedene Filter-Primitive in SVG. Das, was wir verwenden, ist <feDropShadow>. Ich überlasse es Ihnen zu erraten, was es tut, nur anhand des Namens.

Also, ähnlich wie wir etwas hatten, das dies mit einem CSS-Filter getan hat

svg {
  filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));
}

…können wir dasselbe mit dem <feDropShadow> SVG-Filter-Primitiv erreichen. Es gibt drei Schlüsselattribute, die es wert sind, erwähnt zu werden, da sie das Aussehen des Drop-Schattens definieren helfen

  • dx — Dies verschiebt die Position des Schattens entlang der x-Achse.
  • dy — Dies verschiebt die Position des Schattens entlang der y-Achse.
  • stdDeviation — Dies definiert die Standardabweichung für den Unschärfevorgang des Drop-Schattens. Es gibt andere Attribute, die wir verwenden können, wie z. B. flood-color zum Festlegen der Farbe des Drop-Schattens und flood-opacity zum Festlegen der Opazität des Drop-Schattens.

Dieses Beispiel enthält drei <filter>-Elemente, jedes mit seinem eigenen <feDropShadow>-Filter-Primitiv.

Verwenden von SVG-Filtern

SVG-Filter sind sehr mächtig. Wir haben gerade <feDropShadow> behandelt, was natürlich sehr nützlich ist, aber es gibt noch viel mehr, was sie können (einschließlich Photoshop-ähnlicher Effekte), und die Teilmenge dessen, was wir nur für Schatten bekommen, ist umfangreich. Schauen wir uns einige an, wie farbige Schatten und Innen-Schatten.

Nehmen wir den SVG-Markup für das Twitter-Logo als Beispiel

<svg class="svg-icon" viewBox="0 0 20 20">
  <path fill="#4691f6" d="M18.258,3.266c-0.693,0.405-1.46,0.698-2.277,0.857c-0.653-0.686-1.586-1.115-2.618-1.115c-1.98,0-3.586,1.581-3.586,3.53c0,0.276,0.031,0.545,0.092,0.805C6.888,7.195,4.245,5.79,2.476,3.654C2.167,4.176,1.99,4.781,1.99,5.429c0,1.224,0.633,2.305,1.596,2.938C2.999,8.349,2.445,8.19,1.961,7.925C1.96,7.94,1.96,7.954,1.96,7.97c0,1.71,1.237,3.138,2.877,3.462c-0.301,0.08-0.617,0.123-0.945,0.123c-0.23,0-0.456-0.021-0.674-0.062c0.456,1.402,1.781,2.422,3.35,2.451c-1.228,0.947-2.773,1.512-4.454,1.512c-0.291,0-0.575-0.016-0.855-0.049c1.588,1,3.473,1.586,5.498,1.586c6.598,0,10.205-5.379,10.205-10.045c0-0.153-0.003-0.305-0.01-0.456c0.7-0.499,1.308-1.12,1.789-1.827c-0.644,0.28-1.334,0.469-2.06,0.555C17.422,4.782,17.99,4.091,18.258,3.266" ></path>
</svg>

Wir benötigen ein <filter>-Element, um diese Effekte zu erzielen. Dies muss sich innerhalb eines <svg>-Elements im HTML befinden. Ein <filter>-Element wird niemals direkt im Browser gerendert — es dient nur als etwas, auf das über das filter-Attribut in SVG oder die url()-Funktion in CSS verwiesen werden kann.

Hier ist die Syntax, die einen SVG-Filter zeigt und ihn auf ein Quellbild anwendet

<svg width="300" height="300" viewBox="0 0 300 300">

  <filter id="myfilters">
    <!-- All filter effects/primitives go in here -->
  </filter>

  <g filter="url(#myfilters)">
    <!-- Filter applies to everything in this group -->
    <path fill="..." d="..." ></path>
  </g>

</svg>

Das filter-Element soll Filter-Primitive als Kinder enthalten. Es ist ein Container für eine Reihe von Filteroperationen, die kombiniert werden, um einen Filtereffekt zu erzeugen.

Diese Filter-Primitive führen eine einzelne grundlegende grafische Operation (z. B. Weichzeichnen, Verschieben, Füllen, Kombinieren oder Verzerren) auf einer oder mehreren Eingaben aus. Sie sind wie Bausteine, wobei jeder SVG-Filter in Verbindung mit anderen verwendet werden kann, um einen Effekt zu erzeugen. <feGaussianBlur> ist ein beliebtes Filter-Primitiv, das verwendet wird, um einen Weichzeichnungseffekt hinzuzufügen.

Nehmen wir an, wir definieren den folgenden SVG-Filter mit <feGaussianBlur>

<svg version="1.1" width="0" height="0">
  <filter id="gaussian-blur">
    <feGaussianBlur stdDeviation="1 0" />
  </filter>
</svg>

Wenn dieser Filter auf ein Element angewendet wird, erzeugt er einen Gaußschen Weichzeichner, der das Element mit einem Radius von 1px auf der x-Achse weichzeichnet, aber keine Weichzeichnung auf der y-Achse. Hier ist das Ergebnis, mit und ohne den Effekt

Es ist möglich, mehrere Primitive innerhalb eines einzigen Filters zu verwenden. Dies erzeugt interessante Effekte, aber Sie müssen die verschiedenen Primitive voneinander abhängig machen. Bence Szabó hat eine verdammt coole Sammlung von Mustern, die er auf diese Weise erstellt hat.

Beim Kombinieren mehrerer Filter-Primitive verwendet das erste Primitiv die Originalgrafik (SourceGraphic) als seine grafische Eingabe. Jedes nachfolgende Primitiv verwendet das Ergebnis des vorherigen Filtereffekts als seine Eingabe. Und so weiter. Aber wir können mit den Attributen in, in2 und result auf den Primitiv-Elementen etwas Flexibilität erzielen. Steven Bradley hat eine ausgezeichnete Abhandlung über Filter-Primitive, die aus dem Jahr 2016 stammt, aber heute noch Gültigkeit hat.

Es gibt 17 Primitive, die wir heute verwenden können

  • <feGaussianBlur>
  • <feDropShadow>
  • <feMorphology>
  • <feDisplacementMap>
  • <feBlend>
  • <feColorMatrix>
  • <feConvolveMatrix>
  • <feComponentTransfer>
  • <feSpecularLighting>
  • <feDiffuseLighting>
  • <feFlood>
  • <feTurbulence>
  • <feImage>
  • <feTile>
  • <feOffset>
  • <feComposite>
  • <feMerge>

Beachten Sie das fe-Präfix bei allen. Das steht für *filter effect*. Das Verstehen von SVG-Filtern ist herausfordernd. Ein Effekt wie ein Innen-Schatten erfordert eine ausführliche Syntax, die ohne ein tiefes Verständnis von Mathematik und Farbtheorie schwer zu erfassen ist. (Rob O’Learys „Getting Deep Into Shadows“ ist ein guter Ausgangspunkt.)

Anstatt uns in dieses Kaninchenloch zu begeben, werden wir mit einigen vorgefertigten Filtern arbeiten. Glücklicherweise gibt es viele gebrauchsfertige SVG-Filter.

Innen-Schatten

Um einen Filtereffekt auf das Twitter-Logo anzuwenden, müssen wir ihn in unserem „SVG-Quellendokument“ mit einer eindeutigen ID deklarieren, auf die in unserem <filter>-Tag verwiesen werden kann.

<filter id='inset-shadow'>
  <!-- Shadow offset -->
  <feOffset
    dx='0'
    dy='0'
  />

  <!-- Shadow blur -->
  <feGaussianBlur
    stdDeviation='1'
    result='offset-blur'
  />

  <!-- Invert drop shadow to make an inset shadow -->
  <feComposite
    operator='out'
    in='SourceGraphic'
    in2='offset-blur'
    result='inverse'
  />
  
  <!-- Cut color inside shadow -->
  <feFlood
    flood-color='black'
    flood-opacity='.95'
    result='color'
  />
  <feComposite
    operator='in'
    in='color'
    in2='inverse'
    result='shadow'
  />

  <!-- Placing shadow over element -->
  <feComposite
    operator='over'
    in='shadow'
    in2='SourceGraphic'
  />
</filter>

Es gibt vier verschiedene Primitive darin, und jedes führt eine andere Funktion aus. Aber zusammen erreichen sie einen Innen-Schatten.

Nachdem wir diesen Innen-Schatten-Filter erstellt haben, können wir ihn auf unser SVG anwenden. Wir haben bereits gesehen, wie wir ihn über CSS anwenden. Etwas wie

.filtered {
  filter: url(#myfilters);
}

/* Or apply only in certain states, like: */
svg:hover, svg:focus {
  filter: url(#myfilters);
} 

Wir können auch einen SVG-<filter> direkt innerhalb der SVG-Syntax mit dem filter-Attribut anwenden. Das ist wie

<svg>

  <!-- Apply a single filter -->
  <path d="..." filter="url(#myfilters)" />

  <!-- Or apply to a whole group of elements -->
  <g filter="url(#myfilters)">
    <path d="..." />
    <path d="..." />
  </g>
</svg>

Weitere Beispiele

Hier sind weitere Schattenbeispiele von Oleg Solomka

Beachten Sie, dass die einfachen Schatten hier wahrscheinlich komplizierter sind als nötig. Zum Beispiel kann ein farbiger Schatten immer noch mit <feDropShadow> wie folgt erstellt werden

<feDropShadow dx="-0.8" dy="-0.8" stdDeviation="0"
  flood-color="pink" flood-opacity="0.5"/>

Aber dieser geprägte Effekt ist als Filter ziemlich großartig!

Beachten Sie auch, dass Sie SVG-Filter möglicherweise in SVG-Syntax wie folgt sehen

<svg height="0" width="0" style="position: absolute; margin-left: -100%;">
  <defs>
    <filter id="my-filters">
      <!-- ... -->
    </filter>

    <symbol id="my-icon">
      <!-- ... -->
    </symbol>
  </defs>
</svg>

In der ersten Zeile dort heißt es: Dieses SVG soll überhaupt nicht gerendert werden – es sind nur Dinge, die wir später verwenden wollen. Das <defs>-Tag sagt etwas Ähnliches: Wir definieren diese Dinge nur zur späteren Verwendung. Auf diese Weise müssen wir uns nicht wiederholen, indem wir Dinge immer und immer wieder schreiben. Wir werden auf den Filter anhand der ID verweisen, und die Symbole ebenfalls, vielleicht so

<svg>
  <use xlink:href="#my-icon" />
</svg>

SVG-Filter haben eine breite Unterstützung (sogar in Internet Explorer und Edge!) mit sehr schneller Leistung.

Diese Daten zur Browserunterstützung stammen von Caniuse, wo weitere Details zu finden sind. Eine Zahl gibt an, dass der Browser die Funktion ab dieser Version unterstützt.

Desktop

ChromeFirefoxIEEdgeSafari
8310126

Mobil / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
1271274.46.0-6.1

Zusammenfassung

Ein abschließender Vergleich

  • CSS-Filter sind einfacher zu verwenden, aber viel eingeschränkter. Ich glaube nicht, dass es möglich ist, mit der Funktion drop-shadow() einen Innen-Schatten hinzuzufügen, zum Beispiel.
  • SVG-Filter sind viel robuster, aber auch viel komplizierter und erfordern, dass das <filter> irgendwo im HTML vorhanden ist.
  • Beide haben eine großartige Browserunterstützung und funktionieren gut in allen modernen Browsern, obwohl SVG-Filter (überraschenderweise) die tiefste Browserunterstützung haben.

In diesem Artikel haben wir gesehen, warum und wie man Schatten auf SVG-Icons anwendet, mit Beispielen für jeden. Haben Sie das getan, aber es auf eine andere Weise als die hier gezeigten getan? Haben Sie versucht, einen Schatteneffekt zu erzielen, der sich als unmöglich herausstellte? Bitte teilen Sie es mit!