Die vielen Möglichkeiten, eine SVG-Füllung beim Hovern zu ändern (und wann man sie einsetzt)

Avatar of Cassie Evans
Cassie Evans am

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

SVG ist ein großartiges Format für Icons. Vektorformate sehen gestochen scharf aus, unabhängig von Größe oder Gerät – und wir erhalten tonne von Designkontrolle, wenn wir sie inline verwenden.

SVG bietet uns auch eine weitere mächtige Funktion: die Möglichkeit, ihre Eigenschaften mit CSS zu manipulieren. Dadurch können wir schnelle und einfache Interaktionen realisieren, für die früher ausgeklügelte CSS-Tricks oder das Austauschen ganzer Bilddateien notwendig waren.

Zu diesen Interaktionen gehört das Ändern der Farbe bei Hover-Zuständen. Im Jahr 2019 klingt das nach einer so einfachen Sache, aber es gibt tatsächlich ein paar völlig gültige Wege, dies zu tun – was nur die beeindruckenden Fähigkeiten von SVG weiter unterstreicht.

Beginnen wir zunächst mit etwas abgekürztem SVG-Markup.

<svg class="icon">
  <path .../>
</svg>

Zielen Sie in CSS auf die Klasse .icon und setzen Sie die SVG-Eigenschaft fill im Hover-Zustand, um Farben zu tauschen.

.icon:hover {
  fill: #DA4567;
}

Dies ist bei weitem der einfachste Weg, einen farbigen Hover-Zustand auf eine SVG anzuwenden. Drei Zeilen Code!

SVGs können auch über ein <img>-Tag oder als Hintergrundbild referenziert werden. Dies ermöglicht das Caching der Bilder und vermeidet, dass Ihr HTML mit SVG-Code-Blöcken aufgebläht wird. Aber der Nachteil ist ein großer: Wir haben nicht mehr die Möglichkeit, diese Eigenschaften mit CSS zu manipulieren. Wenn ich auf Nicht-Inline-Icons stoße, ist mein erster Anlaufpunkt, sie inline zu setzen, aber manchmal ist das keine Option.

Ich habe kürzlich an einem Projekt gearbeitet, bei dem die Social-Icons Teil einer Pattern Library waren, mit der alle zufrieden waren. In diesem Fall wurden die Icons über ein <img>-Element referenziert. Meine Aufgabe war es, farbige :focus- und :hover-Stile anzuwenden, ohne das Markup anzupassen.

Wie fügt man also einen farbigen Hover-Effekt zu einem Icon hinzu, wenn es keine Inline-SVG ist?

CSS-Filter

CSS-Filter erlauben es uns, eine ganze Reihe cooler, Photoshop-ähnlicher Effekte direkt im Browser anzuwenden. Filter werden auf das Element angewendet, nachdem der Browser das Layout und den initialen Anstrich gerendert hat, was bedeutet, dass sie sich gut zurückentwickeln lassen. Sie werden auf das gesamte Element angewendet, einschließlich der Kindelemente. Stellen Sie sich einen Filter wie eine Linse vor, die über das Element gelegt wird, auf das er angewendet wird.

Dies sind die uns zur Verfügung stehenden CSS-Filter

  • brightness(<number-percentage>);
  • contrast(<number-percentage>);
  • grayscale(<number-percentage>);
  • invert(<number-percentage>);
  • opacity(<number-percentage>);
  • saturate(<number-percentage>);
  • sepia(<number-percentage>);
  • hue-rotate(<angle>);
  • blur(<length>);
  • drop-shadow(<length><color>);

Alle Filter nehmen einen Wert entgegen, der geändert werden kann, um den Effekt anzupassen. In den meisten Fällen kann dieser Wert entweder als Dezimalzahl oder als Prozentangabe ausgedrückt werden (z. B. brightness(0.5) oder brightness(50%)).

Direkt aus der Box gibt es keinen CSS-Filter, der es uns erlaubt, unsere eigene spezifische Farbe hinzuzufügen.
Wir haben hue-rotate(), aber das *passt* nur eine vorhandene Farbe an; es fügt keine Farbe hinzu, was nicht gut ist, da wir mit einem monochromen Icon beginnen.

Das Entscheidende an CSS-Filtern ist, dass wir sie nicht isoliert verwenden müssen. Mehrere Filter können auf ein Element angewendet werden, indem die Filterfunktionen durch Leerzeichen getrennt werden, so:

.icon:hover {
  filter: grayscale(100%) sepia(100%);
}

Wenn eine der Filterfunktionen nicht existiert oder einen falschen Wert hat, wird die gesamte Liste ignoriert und kein Filter wird auf das Element angewendet.

Bei der Anwendung mehrerer Filterfunktionen auf ein Element ist ihre Reihenfolge wichtig und beeinflusst das Endergebnis. Jede Filterfunktion wird auf das Ergebnis der vorherigen Operation angewendet.

Um unsere Icons zu kolorieren, müssen wir also die richtige Kombination finden.

Um hue-rotate() nutzen zu können, müssen wir mit einem farbigen Icon beginnen. Der sepia()-Filter ist die einzige Filterfunktion, die es uns erlaubt, eine Farbe hinzuzufügen und dem gefilterten Element einen gelb-braunen Stich zu geben, wie bei einem alten Foto.

Die Ausgabefarbe hängt vom anfänglichen Tonwert ab.

Um mit sepia() genug Farbe hinzuzufügen, müssen wir zuerst invert() verwenden, um unser Icon in ein mittleres Grau umzuwandeln.

.icon:hover {
  filter: invert(0.5)
}

Dann können wir den Gelb/Braun-Ton mit sepia() hinzufügen.

.icon:hover {
  filter: invert(0.5) sepia(1);
}

...dann die Farbe mit hue-rotate() ändern.

.icon:hover {
  filter: invert(0.5) sepia(1) hue-rotate(200deg);                                  
}

Sobald wir die grobe Farbe haben, die wir wollen, können wir sie mit saturation() und brightness() anpassen.

.icon:hover {
  filter: 
    invert(0.5)
    sepia(1)
    hue-rotate(200deg)
    saturate(4)
    brightness(1);
}

Ich habe dafür ein kleines Tool erstellt, um Ihnen das Leben zu erleichtern, da dies ein ziemlich verwirrender Prozess zum Raten ist.

Siehe den Pen CSS-Filterbeispiel von Cassie Evans (@cassie-codes)
auf CodePen.

Selbst mit dem Tool ist es immer noch etwas fummelig, wird von Internet Explorer nicht unterstützt und vor allem kann man keine exakte Farbe angeben.

Diese Browser-Supportdaten stammen von Caniuse, das weitere Details enthält. 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*

Was tun wir also, wenn wir einen bestimmten Hex-Code benötigen?

SVG-Filter

Wenn wir mehr präzise Kontrolle (und bessere Browserunterstützung) benötigen, als CSS-Filter bieten können, dann ist es Zeit, zu SVG zu greifen.

Filter stammen ursprünglich aus SVG. Tatsächlich sind CSS-Filter im Grunde nur Abkürzungen für SVG-Filter mit einem bestimmten Satz von voreingestellten Werten.

Im Gegensatz zu CSS ist der Filter nicht für uns vordefiniert, also müssen wir ihn selbst erstellen. Wie machen wir das?

Dies ist die Syntax zum Definieren eines Filters.

<svg xmlns="<http://www.w3.org/2000/svg>" version="1.1">
  <defs>
    <filter id="id-of-your-filter">
      ...          
      
      ...
    </filter>
    ...
  </defs>
</svg>

Filter werden durch ein <filter>-Element definiert, das in den <defs>-Abschnitt einer SVG eingefügt wird.

SVG-Filter können auf SVG-Inhalte innerhalb desselben SVG-Dokuments angewendet werden. Oder der Filter kann referenziert und auf HTML-Inhalte anderswo angewendet werden.

Um einen SVG-Filter auf HTML-Inhalt anzuwenden, referenzieren wir ihn genauso wie einen CSS-Filter: durch die Verwendung der url()-Filterfunktion. Die URL verweist auf die ID des SVG-Filters.

.icon:hover {
  filter: url('#id-of-your-filter');
}

Der SVG-Filter kann inline im Dokument platziert werden oder die Filterfunktion kann eine externe SVG referenzieren. Ich bevorzuge letztere Methode, da sie es mir erlaubt, meine SVG-Filter ordentlich in einem Asset-Ordner aufzubewahren.

.icon:hover {
  filter: url('assets/your-SVG.svg#id-of-your-filter');
}

Zurück zum <filter>-Element selbst.

<filter id="id-of-your-filter">
  ...          
  
  ...
</filter>

Im Moment ist dieser Filter leer und tut nichts, da wir keine Filter-Primitive definiert haben. Filter-Primitive sind das, was die Filtereffekte erzeugt. Es gibt eine Reihe von Filter-Primitiven, die uns zur Verfügung stehen, darunter:

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

Genau wie bei CSS-Filtern können wir sie einzeln verwenden oder mehrere Filter-Primitive im <filter>-Tag für interessantere Effekte einbeziehen. Wenn mehr als eine Filter-Primitive verwendet wird, baut jede Operation auf der vorherigen auf.

Für unsere Zwecke verwenden wir nur feColorMatrix, aber wenn Sie mehr über SVG-Filter erfahren möchten, können Sie die Spezifikationen auf MDN oder diese (zum Zeitpunkt des Schreibens im Entstehen befindliche) Artikelreihe von Sara Soueidan durchsehen.

feColourMatrix erlaubt es uns, Farbwerte kanalweise zu ändern, ähnlich wie beim Kanal-Mixing in Photoshop.

Dies ist die Syntax.

<svg xmlns="<http://www.w3.org/2000/svg>" version="1.1">
  <defs>
    <filter id="id-of-your-filter">
      <feColorMatrix
        color-interpolation-filters="sRGB"
        type="matrix"
        values="1 0 0 0 0
                0 1 0 0 0
                0 0 1 0 0
                0 0 0 1 0 "/>
    </filter>
    ...
  </defs>
</svg>

Das Attribut color-interpolation-filters legt unseren Farbraum fest. Der Standardfarbraum für Filtereffekte ist linearRGB, während in CSS RGB-Farben im sRGB-Farbraum angegeben werden. Es ist wichtig, den Wert auf sRGB zu setzen, damit unsere Farben übereinstimmen.

Werfen wir einen genaueren Blick auf die Farbmatrixwerte.

Die ersten vier Spalten repräsentieren die Rot-, Grün- und Blaukanäle der Farbe und den Alpha-Wert (Deckkraft). Die Zeilen enthalten die Rot-, Grün-, Blau- und Alpha-Werte in diesen Kanälen.

Die M-Spalte ist ein Multiplikator – wir müssen keine dieser Werte für unsere Zwecke ändern. Die Werte für jeden Farbkanal werden als Gleitkommazahlen im Bereich von 0 bis 1 dargestellt.

Wir könnten diese Werte als CSS RGBA-Farbdeklaration schreiben, so:

rgba(255, 255, 255, 1)

Die Werte für jeden Farbkanal (Rot, Grün und Blau) werden als Ganzzahlen im Bereich von 0 bis 255 gespeichert. Im Computer ist dies der Bereich, den ein 8-Bit-Byte bieten kann.

Indem wir diese Farbkanalwerte durch 255 teilen, können die Werte als Gleitkommazahl dargestellt werden, die wir in feColorMatrix verwenden können.

Und dadurch können wir einen Farbfilter für jede Farbe mit einem RGB-Wert erstellen!

Wie zum Beispiel Türkis.

rgba(0, 128, 128, 1). 128%255=0.50

Siehe den Pen
SVG-Filter – Türkis-Hover
von Cassie Evans (@cassie-codes)
auf CodePen.

Dieser SVG-Filter färbt nur Icons mit weißer Füllung ein. Wenn wir also ein Icon mit schwarzer Füllung haben, können wir invert() verwenden, um es vor dem Anwenden des SVG-Filters in Weiß umzuwandeln.

.icon:hover {
  filter: invert(100%) url('assets/your-SVG.svg#id-of-your-filter');
}

Wenn wir nur einen Hex-Code haben, ist die Mathematik etwas kniffliger, obwohl es viele Hex-zu-RGBA-Konverter gibt. Zur Hilfe habe ich einen HEX-zu-feColorMatrix-Konverter erstellt.

Siehe den Pen
HEX zu feColorMatrix Konverter
von Cassie Evans (@cassie-codes)
auf CodePen.

Spielen Sie damit herum und viel Spaß beim Filtern!