8. Dezember 2017
Der 'gooey' SVG-Filter unter der Lupe
Seit Lucas Bebber den "gooey effect" in einem Post auf CSS Tricks beschrieben hat, hat er einige Popularität gewonnen. Aber niemand hat nach den zu Grunde liegenden Filter-Primitiven gefragt - wahrscheinlich weil sie so völlig unverständlich aussehen. Aber das hat seinen Preis wenn Browser Bugs aufweisen.
Auf Stackoverflow sind mir zuletzt mehrere Fragen begegnet, die sich damit beschäftigen, dass Browser den Effekt unterschiedlich darstellen. In dieser Antwort habe ich versucht, einige Prinzipien hinter dem Effekt zu erläutern:
🔗 Eingangsgrafiken verwischen
Der Filter startet mit
<feGaussianBlur stdDeviation="20" />
um ein verwischtes Bild zu erzeugen. Während es unterschiedliche Farben "verschmiert", ist seine Hauptaufgabe, ein breites Band von Pixeln entlang des Randes der grafischen Elemente zu erzeugen, bei denen der Alpha-Wert variiert.
🔗 Kontrast des Alpha-Kanals erhöhen
Der Originalansatz nutzt die Möglichkeiten der Filter-Primitiven feColorMatrix
:
<feColorMatrix mode="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9"
result="cutoff" />
Das hat den offensichtlichen Nachteil, dass niemand versteht, was diese Nummern eigentlich
bedeuten. Theoretisch kann die Filter-Primitive feComponentTransfer
genau das gleiche erreichen:
<feComponentTransfer result="cutoff">
<feFuncA type="linear" slope="19" intercept="-9" />
</feComponentTransfer>
Beide transformieren den Alpha-Kanal eines RGBA-Farbwertes nach der Formel
(alpha) => slope * alpha + intercept
und begrenzen den resultierenden Wert auf das Interval [0, 1], so dass
alpha < (0 - intercept) / slope => 0
alpha > (1 - intercept) / slope => 1
Es gibt dann einen kleinenn Bereich, in dem Eingangstransparenzen auf partielle Transparenzen abgebildet werden. (Für die Werte 19 und -9 liegt das zwischen 0.46...0.54.) Der Effekt besteht darin, dass die breiten verwischten Grenzen auf eine sehr dünne Linie reduzuert werden, die alle Ecken "abrundet" und den "gummiartigen" Effekt zwischen Quellobjekten erzeugt, die nahe beieinander liegen.
Aber warum sollte die dünne Linie mit den partiellen Transparenzen im Ausgangsbild verbleiben? Es ist möglich, einen harten Schnitt zwischen opak und voller Transparenz zu erzeugen:
<feComponentTransfer result="cutoff">
<feFuncA type="discrete" tableValues="0 1" />
</feComponentTransfer>
Der Bereich der Eingangswerte wird halbiert:
alpha < 0.5 => 0
alpha >= 0.5 => 1
Das erzeugt jedoch möglicherweise Antialiasing-Artefakte. Es kann von Vorteil sein, einen geringfügigen Blur auf das Ergebnis anzuwenden:
<feComponentTransfer>
<feFuncA type="discrete" tableValues="0 1" />
</feComponentTransfer>
<feGaussianBlur stdDeviation="1" result="cutoff" />
🔗 Überlagern mit der Originalgrafik
Um das "Verschmieren" unterschiedlicher Farben im Innenberreich der Objekte zu vermeiden, kann das Originalbild auf das "Gummi" überlagert werden. Es gibt mehrere Filterprimitive, die das erreichen, einige davon mit Parametern. Die Standardüberlagerung kann so formuliert werden:
<feBlend in="SourceGraphic" in2="cutoff" />
// oder
<feMerge>
<feMergeNode in="cutoff" />
<feMergeNode in="SourceGraphic" />
</feMerge>
// oder
<feComposite operator="over" in="SourceGraphic" in2="cutoff" />
Die Überlagerung kann auch auf den Berreich innerhalb des "Gummis" beschränkt werden:
<feComposite operator="atop" in="SourceGraphic" in2="cutoff" />
🔗 Render-Ergebnisse
Theoretisch sollten, mit Ausname der letzten Unterscheidung, alle Ergebnisse gleich aussehen. Ich habe einen Testfall konstruiert, bei dem Sie mit den verschiedenen Filtervarianten und ihren Einstellungen experimentieren können. Die Filter können auf SVG-Kreise und -Rechtecke sowie HTML-Divs angewendet werden. Sie können den Effekt auf bunte und einfarbige Objekte vergleichen. Das sollte dabei helfen, denjenigen Filter auszuwählen, der die beste Konsistenz zwischen verschiedenen Browsern erreicht.
Ich habe den Verdacht, dass einige Fehldarstellungen an der direkten Verwendung von GPU-Funktionen für einzelne Berechnungen hängt. Da dies nur für bestimmte Hardware-Architekturen anwendbar ist, sollten die Tests auch unterschiedliche Betriebssysteme und Prozessoren beinhalten.
See the Pen goo effect test by ccprog (@ccprog) on CodePen.