4 Punkte von GN⁺ 2023-12-08 | 2 Kommentare | Auf WhatsApp teilen
  • Da sich Web-Illustrationen über flache Vektoren hinaus in Richtung Rauschtexturen sowie Licht- und Schattierungseffekten weiterentwickeln, wird es wichtiger, diese als leichtgewichtige und wiederverwendbare SVGs umzusetzen
  • Das Hauptziel ist, einfachen Formen einen texturierten Schatteneffekt hinzuzufügen und sie so in Svelte- oder React-Komponenten zu übertragen, dass sich Farben und Formen flexibel austauschen lassen
  • Die Grundstruktur definiert eine Form einmal in <defs>, verwendet sie mit <use> wieder und erstellt anschließend mit mask und linearGradient eine Gradientenmaske, die weniger stark an bestimmte Farben gebunden ist
  • Die Körnung wird mit einem auf <feTurbulence> basierenden SVG-Filter erzeugt; <feComposite>, <feColorMatrix> und <feBlend> werden kombiniert, um sie mit der gewählten Füllfarbe zu mischen
  • Das Ergebnis erreicht zwar die gewünschte Textur, es bleiben aber Rendering-Unterschiede in Safari, sodass für browserabhängige Darstellung und komplexere Illustrationen weitere Anpassungen nötig sind

SVGs nur mit Code um eine Rauschtextur erweitern

  • Im aktuellen Webdesign werden Vektorillustrationen weiterhin häufig eingesetzt, gleichzeitig fallen aber Stilrichtungen mit Licht und Schatten samt grober Körnung stärker auf als saubere, flache Formen
  • Solche Stile lassen sich zwar aus Illustrationsprogrammen als SVG exportieren, doch dabei kann die Textur als Raster eingebettet werden oder die Vektordatei stark anwachsen
  • Ziel ist es, einen Schatteneffekt mit texturierter Rauschstruktur allein mit der allgemeinen SVG-Spezifikation zu erzeugen und die Struktur so beizubehalten, dass sie sich leicht in Komponenten überführen lässt
  • Für die Wiederverwendbarkeit ist der Aufbau so gestaltet, dass derselbe Ansatz auch bei anderen Formen und Farben funktioniert

Grundform und Gradient

  • SVG-Grundformen wie Kreise oder Rechtecke lassen sich leicht zeichnen, doch in wiederverwendbaren Komponenten reichen Gradienten mit festgelegten Farben allein nicht aus
  • Um einen Gradient zu erzeugen, der sich an die Grundfarbe anpasst, wird eine Maske (mask) verwendet
    • Eine SVG-Maske steuert mit Schwarz und Weiß, welche Bereiche sichtbar oder verdeckt werden
    • Das Verfahren kann etwas verwirrend wirken, lässt sich aber mit einem einfachen Beispiel beginnen
  • Wenn dieselbe Kreisform mehrfach verwendet wird, wird in <defs> ein <circle id="shape"> definiert und mit <use href="#shape"> referenziert
  • Diese Methode reduziert Wiederholungen und hält die Formdefinitionen als DRY-Struktur an einer Stelle zusammen

Erzeugung der Rauschtextur

  • Um dem Gradient eine Textur zu überlagern, wird ein SVG-Filter (filter) verwendet
  • Die Rauscherzeugung übernimmt <feTurbulence>
    • <feTurbulence> ist ein SVG-Filter-Primitive zur Erzeugung künstlicher Texturen
    • Um die gewünschte Anmutung zu erhalten, müssen mehrere Werte angepasst werden
  • Der finale Filter mischt die Textur in mehreren Schritten mit der Farbe
    • Mit <feTurbulence type="fractalNoise" baseFrequency="19.5" numOctaves="10"> wird das Rauschen erzeugt
    • Mit <feComposite> wird das Turbulence-Ergebnis innerhalb von SourceAlpha komponiert
    • Mit <feColorMatrix type="luminanceToAlpha"> werden Farbvariationen reduziert
    • Mit <feBlend mode="color-burn"> wird es mit der Originalgrafik zusammengesetzt
  • Der Filter wird auf das abschließende <use>-Element mit filter="url('#noise')" angewendet

Aufbau des finalen SVG

  • Das finale Beispiel definiert in <defs> Form, Filter, Maske und Gradient gemeinsam
  • Der Gradient wird mit linearGradient id="fade" aufgebaut
    • An der Position 0% wird Schwarz mit stop-opacity="0.6" verwendet
    • An den Positionen 65% und 75% wird Weiß verwendet, um die Transparenz schrittweise anzupassen
  • Auf die finale Form werden Füllfarbe, Maske und Filter gemeinsam angewendet
    • fill="hsl(337, 92%, 69%)"
    • mask="url(#gradient)"
    • filter="url('#noise')"
  • Durch zusätzliche Farben und feinere Anpassung des Gradients wird ein Ergebnis erzielt, das dem gewünschten visuellen Effekt näherkommt
  • Das Gesamtergebnis ist in der Full Demo zu sehen, und der Implementierungscode ist im repository öffentlich verfügbar

Ergebnis und Grenzen

  • Nach zusätzlichen Experimenten entstand eine zufriedenstellende Illustration, auch wenn das Ergebnis noch nicht perfekt ist
  • Besonders in Safari wird es anders gerendert als in anderen Browsern
  • Im Vergleich zu der als Referenz herangezogenen komplexen Illustration ist der Ansatz noch einfach, hat aber mit weiterer Verfeinerung Potenzial für mehr Einsatzszenarien
  • Laut einem Nachtrag vom 7. Dezember 2023 wurde nach der Einreichung bei Hacker News der CSS-Tricks-Artikel von Jimmy Chion aus dem Jahr 2021 entdeckt: Grainy Gradients
  • Die dort erreichte Technik wirkt ähnlich und kann als ergänzendes Referenzmaterial zusammen herangezogen werden

2 Kommentare

 
ndrgrd 2023-12-09

Safari enttäuscht die Erwartungen mal wieder nicht! Der Name des IE der 2020er ist wirklich nicht unverdient.

 
GN⁺ 2023-12-08
Hacker-News-Kommentare
  • Ich habe kürzlich wieder mit SVG herumgespielt und wollte einen Drop Shadow hinzufügen, den ich mit Canvas nur schwer umsetzen konnte. In Safari funktionieren jedoch CSS-Drop-Shadows innerhalb von SVG nicht, sodass ich den nativen SVG-Drop-Shadow-Filter verwenden musste, und selbst dann sah das Ergebnis anders aus als in anderen Browsern
    Ein konkretes Beispiel gibt es unter https://www.einarmagnus.net/pages/logo; dort wird Safari per JavaScript erkannt, damit die SVG-Version aktiviert und die CSS-Version deaktiviert wird
    Der Hintergrund „rekursives Yin und Yang“ ist hier zu sehen: https://einarmagnus.net/blog/2020/01/22/finding-the-logo
    Ich würde auch gern noch mehr mit Texturen experimentieren, aber es ist frustrierend, wie anders es in Safari aussieht. Ich frage mich, ob sich die Interpretation von SVG irgendwann angleichen wird

    • Wahrscheinlich vorerst nicht. Leider gibt es keine Implementierung, die die gesamte SVG-Spezifikation umsetzt, und bei SVG 2 ist man davon noch viel weiter entfernt
      Zu diesem Thema ist https://razrfalcon.github.io/notes-on-svg-parsing/ lesenswert
      In Bugreports für SVG-Bibliotheken liest man oft „mein SVG wird nicht korrekt gerendert“, aber der Punkt ist eigentlich, dass es so etwas wie ein korrekt gerendertes SVG gar nicht gibt. Sobald man fortgeschrittene Funktionen wie Text, Filter oder Animationen verwendet, bricht es je nach Renderer leicht auseinander
    • Wer auf der „logo“-Seite nur die Standardwellenform anschaut und wieder geht, sollte ein paar der Presets im Dropdown unten rechts ausprobieren
      Es ist beeindruckend, wie schon kleine Parameteränderungen zu ziemlich unterschiedlichen Designs wie scorpion, balance oder spruce führen
  • Der Begriff, nach dem der Autor gesucht hat, liegt näher an Dithering. Auch CSS-Tricks erklärt in „Grainy Gradients“ dieselbe Technik
    https://css-tricks.com/grainy-gradients/
    Es gibt auch eine Alternative, die etwas Ähnliches mit CSS macht, allerdings auf das gesamte Bild angewendet
    https://github.com/tomren1/dither-with-css

    • Eigentlich ist das eher einfach Rauschen, genauer gesagt etwas aus der Perlin-Noise-Familie, kombiniert mit dem Blend-Modus „color burn“. Es wird nur über einen Farbverlauf gelegt und wirkt dadurch wie Dithering, ist aber keines
      Dithering ist eine Technik, bei der ein glattes Bild mit hoher Farbtiefe auf eine begrenzte Anzahl von Farben quantisiert wird, um Banding zu reduzieren, indem jeder Pixel probabilistisch auf einen oberen oder unteren Wert gesetzt wird. An Stellen, die dem Zielwert genau entsprechen, muss es dabei nicht einmal wie Rauschen aussehen
      Hier entsteht lediglich eine gleichmäßige Rauschtextur, und tatsächliches Banding wird dadurch nicht reduziert. Für ästhetische Zwecke sieht das aber vermutlich besser aus als echtes Dithering
      Es kann allerdings ähnlich wie Dithering Mängel kaschieren und die wahrgenommene Schärfe erhöhen, sodass die Bildqualität besser wirkt
    • Dithering ist zwar eine echte technische Methode mit einem ähnlichen Endeffekt, bedeutet aber nicht einfach Körnung hinzufügen, und auch dieses Beispiel wurde nicht durch Dithering erzeugt
      Der Autor scheint eher nach einem Designbegriff für einen visuellen Stil zu suchen, so wie „flat“, „skeuomorphic“ oder „italian style“
      Bei der Kombination aus geometrischen Formen und Körnung muss ich an den Memphis style denken
    • Wenn damit nicht eine größere Farbspanne mit einer begrenzten Palette simuliert wird, weiß ich nicht, ob man das wirklich Dithering nennen kann
      Es erinnert mich eher an Vintage-Reiseposter-Kunst. Zum Beispiel: https://www.graphicart-news.com/wp-content/uploads/2012/09/2...
    • Es hat zwar mit Dithering zu tun, aber für mich wirkt es eher wie Pointillismus [0]
      [0] https://en.wikipedia.org/wiki/Stippling
    • Ist mir ein bisschen peinlich. Ich sollte den Beitrag aktualisieren und auf den Artikel verlinken
      Als ich das gemacht habe, hatte ich ihn wirklich nicht gesehen, und ich bin beim eigenen Herumprobieren unabhängig zum selben Ergebnis gekommen
  • Das erinnert mich daran, wie Filmfotografen und Filmemacher versucht haben, Filmkorn loszuwerden, während Digitalfotografen es nun wieder hinzufügen wollen. Das Gras ist auf der anderen Seite eben immer grüner
    Zwischen all den digital steril wirkenden Dingen wirkt das Beispiel auf dieser Seite ziemlich attraktiv

    • Man sollte das nicht zu sehr verallgemeinern. Seit es digitales Video und später digitale Fotografie gibt, gab es immer gleichzeitig Leute, die Rauschen reduzieren wollten, es entfernen wollten, es nachahmen wollten oder es bewusst einsetzen wollten
      Das Problem war nie das Rauschen an sich, sondern immer nur, wenn es zu viel davon gab
    • Hat Foveon X3 das nicht bis zu einem gewissen Grad gelöst? Auf eine Art, die wie Film wirkt, aber digital ist
  • Gibt es irgendwo eine Übersicht dazu, welche Funktionen in welcher Implementierung kaputtgehen? Ich würde gern wissen, wie man mit SVG seine geistige Gesundheit bewahrt
    Ich habe kürzlich den Fehler gemacht, ein komplexes Konferenzposter als SVG zu erstellen, und jetzt wird es je nach Browser und Programm unterschiedlich gerendert
    https://kxygk.github.io/imergination/
    Was ich beim Erstellen erlebt habe: Man kann SVG einbetten oder verlinken, aber wenn darin wiederum andere SVG stecken, funktioniert es nicht. Wenn man also eine Struktur wie Poster → Diagramm → mehrere Plots/Karten hat, sind SVGs, die sich bei Änderungen der Unterbilder dynamisch aktualisieren, praktisch unmöglich
    Webbrowser zeigen eingebettete/verlinkte Bilder aus „Sicherheitsgründen“ teils nach Belieben nicht an. Öffnet man das SVG unter dem obigen Link in einem separaten Tab, wird es nicht korrekt dargestellt: https://raw.githubusercontent.com/wiki/kxygk/imergination/ag...
    Auch komplexe SVG konsistent in PDF umzuwandeln ist schwierig, und mitunter geht dabei der Speicher aus. Je nach SVG-to-PDF-Konverter fällt das Ergebnis anders aus
    Mehrere Implementierungen wie Inkscape behandelten eingebettete SVG teils willkürlich als Rastergrafik, und ich konnte letztlich nie eingrenzen, wann genau das passiert. Beim Rendern nach PNG gab es außerdem das Problem, dass Inkscape die DPI-Einstellung nicht an Unterbilder weitergab

  • Sieht gut aus. Inkscape scheint diese Art von Rauschen hinzufügen über mehrere Effekte im Menü Filters zu unterstützen. Ich habe als Plain SVG exportiert und im Code nachgesehen; dort wird tatsächlich feTurbulence verwendet
    Zum Vergleich habe ich auch die Rauschfüllung von Affinity Designer 2 getestet, und im exportierten SVG war das Rauschen als base64-JPEG-Bild eingebettet

    • Ich sitze gerade nicht am PC und kann es nicht direkt prüfen, aber mich würde interessieren, ob ein einzelnes Rauschtextur-Bild eingebettet und mehrfach verwendet wird oder ob bei jeder Nutzung von Rauschen eine neue Textur erzeugt wird
      Da sich eine Adobe-Lizenz schwer rechtfertigen lässt und mir Inkscape auch nicht so recht liegt, war Designer abgesehen von solchen Merkwürdigkeiten eine perfekte Alternative
    • Affinity Designer 2 war als Alternative ohne Adobe Creative Cloud ziemlich gut, aber ich musste SVG wirklich sehr oft manuell nachbearbeiten
  • Auf der Website von „ApeFest“[1] gibt es ebenfalls dynamisches Rauschen, also habe ich mir das CSS angesehen. Das ist die Event-Seite jener Veranstaltung, die den Teilnehmern die Netzhaut mit UV verbrannt hat
    Tatsächlich wird ein gekacheltes PNG-Overlay[2] verwendet, das per CSS-Animation „zufällig“ hin- und hergeschüttelt wird. Korrektur: Offenbar wird es in Wirklichkeit per JS bewegt. Ziemlich Low-Tech, aber es funktioniert
    [1] https://apefest.com/
    [2] https://framerusercontent.com/images/rR6HYXBrMmX4cRpXfXUOvpv...

    • Der apefest-Effekt braucht viel CPU und verbraucht entsprechend auch viel Energie
  • Ich wollte solche SVG-Filter mehrfach verwenden, aber das Problem ist, dass die Darstellung je nach Engine und Zoomstufe stark variiert
    Deshalb taugen sie nur für subtile Effekte, bei denen Ungenauigkeit nicht so wichtig ist, und am Ende kehre ich leider immer wieder zu Rastergrafiken zurück
    Außerdem arbeiten sie auf Pixelebene, weshalb Dinge wie feDisplacementMap das Antialiasing ruinieren, was ungefähr die Hälfte der Situationen zerstört, in denen man sie eigentlich gern einsetzen würde

  • Perlin-Rauschen und sein Nachfolger, Fraktalrauschen, haben ein enorm gutes Kosten-Nutzen-Verhältnis, wenn man Realismus oder ein organisches Gefühl hinzufügen will
    Man sieht das zum Beispiel sehr wirkungsvoll in Aladdin (1992) in der Szene, in der sie aus der Cave of Wonders entkommen

  • Ich weiß nicht, wie das eigentlich aussehen soll, aber auf meinem Handy sehe ich nur einen glatten Verlauf ohne Rauschen

    • Hier genauso. Ich nutze Android Chrome
    • Android Chrome unterstützt anscheinend irgendeine Funktion im Code nicht
  • Der Effekt gefällt mir, aber gibt es eine Möglichkeit, ihn unabhängig von der Zoomstufe zu machen?
    Außerdem scheint das hier ebenfalls etwas Zufälligkeit hinzuzufügen, daher würde mich interessieren, ob man auch einen Seed setzen kann. Es wäre zum Beispiel gut, wenn man für eine bestimmte Größe ein einziges korrektes Rendering-Ergebnis definieren könnte

    • Ich bin der Autor. Ja, das geht. Der zugrunde liegende SVG-Algorithmus und seine Implementierung akzeptieren einen Seed-Wert: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/s...
    • Wie in der anderen Antwort erwähnt, gibt es das Attribut seed, und auch der Algorithmus der Zufallsfunktion ist in der Spezifikation in 186 Zeilen C-Code definiert[0], sodass Implementierungen theoretisch zum gleichen Ergebnis kommen sollten
      Wenn man sich den Code allerdings ansieht, werden Gleitkommaoperationen verwendet, und soweit ich weiß, ist deren Verhalten implementierungsabhängig, daher scheint es möglich, dass es je nach Plattform unterschiedlich läuft
      [0]: https://drafts.fxtf.org/filter-effects/#elementdef-feturbule...