Drei Wege, um mit CSS und SVG Blobs zu erstellen

Avatar of Akash Mittal
Akash Mittal am

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

Blobs sind die glatten, zufälligen, gallertartigen Formen, die eine skurrile Qualität haben und einfach nur Spaß machen. Sie können als Illustrationselemente und Hintergrundeffekte im Web verwendet werden.

Wie werden sie also erstellt? Einfach eine Illustrations-App öffnen und loslegen, richtig? Klar, das ist cool. Aber wir sind hier in einem Beitrag auf CSS-Tricks, und es wäre viel lustiger, die Möglichkeiten zu betrachten, die wir haben, um dies mit CSS und SVG zu tun – zwei unserer Lieblingszutaten!

Wir haben tatsächlich ein paar Möglichkeiten, an Blobs heranzugehen. Schauen wir sie uns an.

Kreise in SVG zeichnen

Fangen wir einfach an. Wir können SVG in Programmen wie Illustrator, Sketch, Figma oder ähnlichem zeichnen, aber wir werden stattdessen direkt in SVG-Code zeichnen.

Dank des passend benannten <circle>-Elements macht SVG das Zeichnen eines Kreises ziemlich trivial

<circle cx="100" cy="100" r="40" fill="red" />

Diese ausgefallenen Attribute? Sie ergeben Sinn, wenn man sie aufschlüsselt

  • cx definiert die x-Koordinate des Kreismittelpunkts.
  • cy definiert die y-Koordinate.
  • r ist der Radius.
  • fill wird verwendet, um die Form mit Farbe zu füllen.

Dieser Schnipsel erstellt einen Kreis mit einem Radius von 40px, dessen Mittelpunkt bei 100px auf der x-Achse und 100px auf der y-Achse liegt. Die Koordinaten beginnen in der oberen linken Ecke des übergeordneten Containers.

Erstellen wir mehrere überlappende Kreise wie diesen

<svg height="300" width="300">
  <circle cx="80" cy="80" r="40" fill="red" />
  <circle cx="120" cy="80" r="40" fill="red" />
  <circle cx="150" cy="80" r="40" fill="red" />
  <circle cx="150" cy="120" r="40" fill="red" />
  <circle cx="100" cy="100" r="40" fill="red" />
</svg> 

<svg> fungiert als Zeichenfläche, auf der alle verschiedenen Formen und Figuren gezeichnet werden. Seine height und width geben also die Größe an, in die die gesamte Zeichnung eingepasst werden soll. Wenn ein Teil einer Figur außerhalb der Größe des SVG liegt, wird dieser Teil abgeschnitten.

Aber Blobs sind nicht immer so perfekt... rund. Wir können Abwechslung schaffen, indem wir <ellipse> anstelle von <circle> verwenden

<ellipse cx="200" cy="80" rx="100" ry="50" fill="red" />

Dies ist fast identisch mit dem Kreis, außer der Änderung des Tag-Namens und zweier Radienwerte, um den horizontalen (rx) und vertikalen (ry) Radius separat zu definieren. Das Lustige ist, dass wir immer noch einen perfekten Kreis erhalten können, wenn wir wollen, wenn die Radienwerte gleich sind. In diesem Sinne ist <ellipse> etwas vielseitiger.

Und wenn alles, was Sie brauchen, ein Kreis ist, könnten wir uns wahrscheinlich ganz ohne SVG auf CSS verlassen. Jedes Box-Element kann mit border-radius zu einem Kreis oder einer Ellipse werden.

.circle {
  border-radius: 50%;
  height: 50px;
  width: 50px;
}

...aber dazu später mehr.

Freestyling mit SVG-Pfaden

Dank des <path>-Tags von SVG können wir jede Art von Form erstellen. Es ist wie das Zeichnen mit einem Bleistift oder Stift. Sie beginnen an einem Punkt und zeichnen Linien, Kurven, Formen und schließen die Schleife.

Es gibt viele Datenparameter im Pfad für verschiedene Aufgaben, wie zum Beispiel

  • M – Zum Punkt bewegen
  • L – Linie zeichnen
  • C – Kurve zeichnen
  • Q – Bézier-Kurve
  • Z – Pfad schließen

Chris hat eine sehr ausführliche Anleitung, die diese Parameter im Detail erklärt.

Wir benötigen nur den Kurvenparameter (C) für das eigentliche Zeichnen. Aber wir werden auch den Startpunkt bewegen und den Pfad schließen, daher werden wir auch die Parameter M und Z verwenden.

A green blob with four edges that vary in size and shape.
Dies ist eine zufällige, blobige Form, die ich mit dem <path>-Element von SVG erstellt habe.

Bereit, das aufzuschlüsseln? Koordinaten spielen eine große Rolle in <path>, daher wird das, was wir gleich betrachten werden, wie Google Maps-Daten aussehen, die in unseren Code gebrochen sind. Aber es ergibt viel mehr Sinn, wenn wir wissen, was sie tun.

Nehmen Sie dies...

<svg xmlns="http://www.w3.org/2000/svg">
  <path
    fill="#24A148"
    d=""
  />
</svg>

Hier speichert das Attribut d die Pfaddaten. Es enthält Informationen darüber, wo die Zeichnung beginnt, in welche Richtung sie sich bewegt, welcher Form sie folgt und wo sie endet. Zum Beispiel

<path d="M 10 10 C 20 20, 40 20, 50 10" stroke="black" fill="transparent"/>

Es zeigt, dass unser Pfad von den Koordinaten 10 10 beginnt, angezeigt durch das M, das ihnen vorangeht. Dann etabliert er eine kubische Bézier-Kurve (C) mit zwei Kontrollpunkten. Bézier-Kurven sind wie Griffe an beiden Enden eines Pfades, die die Krümmung dazwischen steuern. Wir haben zwei Bézier-"Griffe": einen für die Startposition (20 20) der Kurve und einen weiteren für die Endposition (40 20).

Show to end points for a black path line with light red lines extended from each endpoint indicating the amount of curve on each point.

Nutzen wir dieses Wissen, um unseren Blob zu gestalten. Der Blob, den ich gezeichnet habe, ist tatsächlich etwas komplex, mit einer Reihe von Kurven und Kontrollpunkten. Es hilft nicht, dass viele der Koordinaten keine ganzen Zahlen sind. Aber dennoch, jetzt, wo wir wissen, was der d-Parameter von <path> tut und welche Attribute er zum Zeichnen von Punkten entlang des Pfades verwendet, sieht es nicht *ganz* so beängstigend aus.

Aber, hey, ich verstehe es. Das ist viel Code, den man nicht nur von Hand schreiben, sondern auch exakt richtig hinbekommen muss. Ich würde es Ihnen nicht verdenken, wenn Sie ein Werkzeug wie dieses verwenden, um den Code für Sie zu generieren.

Gooey-Effekte mit CSS und SVG-Filtern

SVG-Pfad ist komplex. Richtig? Was wäre, wenn ich Ihnen eine Möglichkeit präsentiere, *viele benutzerdefinierte Formen* (die Sie mit Divs erstellen können) in gooey Blobs zu verwandeln? Hier ist die Idee. Wir erstellen zwei Rechtecke, die sich überschneiden. Sie haben die gleiche Farbe, aber ein wenig Transparenz, um den Bereich, in dem sie sich überschneiden, zu verdunkeln.

Dann nutzen wir die Weichzeichnungsfunktionen von SVG, um die Rechtecke zu verschmieren und einen extra gooey Blob mit weicheren Kanten zu erzeugen. Die beiden sich überschneidenden Rechtecke verwandeln sich in dies –

A bright red blob with four corners of varying shape and size, like in a reverse L shape.

Lassen Sie uns zuerst verstehen, wie Filter in SVG funktionieren. Sie werden mit <filter> auf HTML-Elementen oder anderen SVG-Elementen wie circle deklariert.

circle {
  filter: url("#id_of_filter");
}

<filter> ist im Grunde ein Wrapper für die eigentlichen Filtereffekte, die beinhalten

  • <feGaussianBlur>
  • <feImage>
  • <feMerge>
  • <feColorMatrix>
  • Viele mehr... Die vollständige Liste finden Sie hier.

Unser Blob ist weichgezeichnet und gefärbt, deshalb werden wir <feGaussianBlur> und <feColorMatrix> verwenden.

<feGaussianBlur> nimmt mehrere Attribute entgegen, aber wir interessieren uns nur für zwei davon: Wie viel Weichzeichnung wir wollen und wo wir sie wollen. Die Standardabweichung (stdDeviation) und die in-Eigenschaften entsprechen diesen Anforderungen.

in akzeptiert einen von zwei Werten

  • SourceGraphic – Weichzeichnet die gesamte Form
  • SourceAlpha – Weichzeichnet den Alphawert und wird zur Erstellung von Schatteneffekten verwendet

Nachdem ich ein wenig herumgespielt habe, bin ich beim <feGaussianBlur>-Effekt hier gelandet

<feGaussianBlur in="SourceGraphic" stdDeviation="30" />

Das kommt direkt in das HTML-Markup mit einer ID, die wir auf dem übergeordneten Element unseres Blobs aufrufen

<!-- The SVG filter -->
<svg style="position: absolute; width: 0; height: 0;">
  <filter id="goo">
    <feGaussianBlur in="SourceGraphic" stdDeviation="30" />
  </filter>
</svg>

<!-- The blob -->
<div class="hooks-main">
  <div></div>
  <div></div>
</div>

Der Filter wird tatsächlich nicht gerendert, obwohl er im Markup enthalten ist. Stattdessen referenzieren wir ihn als CSS-Filter auf dem übergeordneten Element des Blobs

/* Blob parent element */
.hooks-main {
  position: absolute;
  width: 100%;
  height: 100%;
  filter: url("#goo&amp");
  overflow: hidden;
}

Das ist noch nicht alles. Die Weichzeichnung ist verstreut und die Form des Elements hat ihre Grenzen und Farbe verloren. Wir brauchen einen aufwölbenden Effekt mit Weichzeichnung an den Rändern und einer soliden Farbe, um die Form zu füllen. Hier kommt unser nächster SVG-Filter, <feColorMatrix>, ins Spiel.

Es gibt zwei <feColorMatrix>-Attribute, die wir wollen

  • in – Gibt an, wo der Effekt angewendet wird, genau wie bei <feGaussianBlur>.
  • values – Eine Matrix aus vier Zeilen und fünf Spalten.

Das values-Attribut ist etwas nuancierter. Es enthält eine Matrix, die mit den Farb- und Alpha-Werten **jedes Pixels** multipliziert wird und einen neuen Farbwert für dieses Pixel erzeugt. Mathematisch gesprochen

new pixel color value = ( values matrix ) × ( current pixel color value )

Werden wir hier ein bisschen zahlenmäßig nerdy. In dieser Gleichung ist Werte-Matrix gleich

[F-red1 F-green1 F-blue1 F-alpha1 F-constant1
 F-red2 F-green2 F-blue2 F-alpha2 F-constant2
 F-red3 F-green3 F-blue3 F-alpha3 F-constant3
 F-red4 F-green4 F-blue4 F-alpha4 F-constant4]

Hier bedeutet F-rot ein Bruchteil von Rot in Pixeln, mit einem Wert von 0 bis 1. F-konstant ist ein bestimmter konstanter Wert, der zum Farbwert addiert (oder subtrahiert) wird.

Um das weiter aufzuschlüsseln... Wir haben ein Farb-Pixel mit einem RGBA-Wert von rgba(214, 232, 250, 1). Um es in eine neue Farbe umzuwandeln, multiplizieren wir es mit unserer Werte-Matrix.

Werte-MatrixFarb-Pixel (RGBA)Neue Farbe (RGBA)
[1 0 0 0 0
 0 1 0 0 0
 0 0 1 0 0
 0 0 0 1 0
 0 0 0 0 1]
×[214
 232
 250
 1
 1]
= [ 214x1 + 232x0 + 250x0 + 1x0 + 1x1
      214x0 + 232x1 + 250x0 + 1x0 + 1x1
      214x0 + 232x0 + 250x1 + 1x0 + 1x1
      214x0 + 232x0 + 250x0 + 1x1 + 1x1
      214x0 + 232x0 + 250x0 + 1x0 + 1x1 ]
= [214
  232
  250
 1
  1]

Der Pixelwert hat sich nicht geändert, da wir ihn mit der Einheitsmatrix multipliziert haben, aber wenn Sie die Werte der Matrix ändern, ändert sich auch ihr Pixelwert. Erfahren Sie mehr über die Werte-Matrix in der MDN-Dokumentation.

In unserem Fall scheinen diese Werte ziemlich gut zu funktionieren

<filter id="goo">
  <feGaussianBlur in="SourceGraphic" stdDeviation="30" />
  <feColorMatrix
    in="blur"
    values="1 0 0 0 0 
            0 1 0 0 0 
            0 0 1 0 0 
            0 0 0 30 -7"
  />
</filter>

Ich habe dem Blob noch ein paar zusätzliche Stile hinzugefügt, um ihn von der Ecke aus zu dehnen.

Versuchen Sie, diese Filterwerte für andere Formen zu verwenden, und lassen Sie mich in den Kommentaren wissen, wie sie für Sie funktionieren.

Verwendung von CSS border-radius

Wir haben dies bereits angedeutet, aber jetzt kommen wir zur CSS-Eigenschaft border-radius. Dank ihrer Fähigkeit, die Ecken eines Elements zu glätten, kann sie auch blob-ähnliche Formen erzeugen. Dies ist möglich, da jeder Eckradius in zwei Radien unterteilt ist, einen für jede Kante. Deshalb können wir Formen außer Kreis und Ellipse haben.

Each corner has two radii, one for each edge. For example, the top-left corder of a box has two radii, one for its left edge and one for its top edge.

Sie sind es vielleicht gewohnt, border-radius als Kurzschreibweise für alle vier Ecken eines Elements zu verwenden

.rounded {
  border-radius: 25%;
}

Das ist eine schöne Möglichkeit, Einheitlichkeit für alle Ecken zu erreichen. Aber Blobs sind nicht so einheitlich. Wir wollen, dass einige Ecken runder sind als andere, um einige zu erhalten, die gooey aussehen. Deshalb greifen wir zu den Bestandteilen von border-radius, wie

.element {
  border-top-left-radius: 70% 60%;
  border-top-right-radius: 30% 40%;
  border-bottom-right-radius: 30% 60%;
  border-bottom-left-radius: 70% 40%;
}

Und sehen Sie, wie jede Eigenschaft zwei Werte annimmt? Das ist einer für jede Kante der Ecke, was uns viel Flexibilität gibt, ein Element in interessante Formen zu krümmen. Dann können wir eine Hintergrundfarbe einfügen, es mit einem Farbverlauf füllen oder sogar einen box-shadow darauf setzen, um einen schönen Effekt zu erzielen.