Wellenförmige Form mit CSS

80

Ich versuche, dieses Bild mit CSS neu zu erstellen:

Wayvy Form

Ich würde es nicht brauchen, um es zu wiederholen. Das habe ich angefangen, aber es hat nur eine gerade Linie:

#wave {
  position: absolute;
  height: 70px;
  width: 600px;
  background: #e0efe3;
}
<div id="wave"></div>

Stevenspiel
quelle
2
Wenn Sie dies mit CSS nur für die Größe neu erstellen möchten, verwenden Sie stattdessen SVG
iKamy
Hattest du irgendwelche Gedanken? Hast du was versucht?
David Fritsch
1
Warum nicht einfach ein Hintergrundbild verwenden? Manchmal ist es am besten, die Leistung von CSS nicht zu missbrauchen oder zu "nutzen", wenn ein einfaches PNG-Image Sie vielleicht 20 Bytes kosten würde.
ProfileTwist
1
Für doppelt gekrümmte Formen können Sie diese Frage überprüfen: Doppelt gekrümmte Form
Web-Tiki
Ich fand diese bootsnipp.com/snippets/yN3Zo
core114

Antworten:

80

Ich bin nicht sicher, ob es deine Form ist, aber es ist nah - du kannst mit den Werten spielen:

https://jsfiddle.net/7fjSc/9/

#wave {
  position: relative;
  height: 70px;
  width: 600px;
  background: #e0efe3;
}
#wave:before {
  content: "";
  display: block;
  position: absolute;
  border-radius: 100% 50%;
  width: 340px;
  height: 80px;
  background-color: white;
  right: -5px;
  top: 40px;
}
#wave:after {
  content: "";
  display: block;
  position: absolute;
  border-radius: 100% 50%;
  width: 300px;
  height: 70px;
  background-color: #e0efe3;
  left: 0;
  top: 27px;
}
<div id="wave"></div>

iKamy
quelle
1
Dies fällt ohne festgelegte Breite auseinander. Ich brauche immer Breite = 100%. Gute Arbeit.
MH
4
Es gibt eine unschöne Lücke, in der sich beide Pseudoelemente treffen.
Fabien Snauwaert
85

Ich denke, dies ist der richtige Weg, um eine Form zu erstellen, wie Sie es möchten. Durch die Verwendung der SVG-Möglichkeiten und eines Containers, um die Form ansprechend zu halten.

svg {
  display: inline-block;
  position: absolute;
  top: 0;
  left: 0;
}
.container {
  display: inline-block;
  position: relative;
  width: 100%;
  padding-bottom: 100%;
  vertical-align: middle;
  overflow: hidden;
}
<div class="container">
  <svg viewBox="0 0 500 500" preserveAspectRatio="xMinYMin meet">
    <path d="M0,100 C150,200 350,0 500,100 L500,00 L0,0 Z" style="stroke: none; fill:red;"></path>
  </svg>
</div>

ThomasA
quelle
1
Obwohl es möglich ist, Formen mit SVG zu zeichnen und zu animieren, exportieren die meisten Benutzer ihre SVG-Dateien aus Vektor-basierter Software wie Corel oder Illustrator und fügen sie in die HTML-Datei ein. Dann können Sie mehr mit CSS formatieren oder sogar die Knoten mit JS oder SVG bearbeiten Bibliotheken. und das ist der Fall für SVG, weil es die Schwierigkeiten beim Zeichnen in CSS lösen soll
iKamy
Darauf habe ich in meiner Antwort aufgebaut, indem ich zwei Divs hinzugefügt habe, um das Beispiel realistischer zu gestalten, das SVG beschnitten habe, um unerwünschte Ränder zu beseitigen, und das Inline-SVG zugunsten einer CSS-Lösung entfernt habe.
Fabien Snauwaert
40

Meine Implementierung verwendet das svg-Element in HTML und ich habe auch einen Generator erstellt, um die gewünschte Welle zu erzeugen:

https://smooth.ie/blogs/news/svg-wavey-transitions-between-sections

<div style="height: 150px; overflow: hidden;">
  <svg viewBox="0 0 500 150" preserveAspectRatio="none" style="height: 100%; width: 100%;">
    <path d="M0.00,92.27 C216.83,192.92 304.30,8.39 500.00,109.03 L500.00,0.00 L0.00,0.00 Z" style="stroke: none;fill: #e1efe3;"></path>
  </svg>
</div>

https://jsfiddle.net/1b8L7nax/5/

Patch92
quelle
7
Das ist noch nie passiert, aber ich habe mich tatsächlich angemeldet, um diese Antwort für den Wellengenerator zu verbessern. Ich hasse SVGs und du hast mir so viel Zeit gespart!
GoreDefex
20

Meine reine CSS-Implementierung basiert auf oben mit 100% Breite. Ich hoffe es hilft!

PVermeer
quelle
1
Ohne den Code zu gründlich zu untersuchen, scheint dies besser zu sein als die derzeit akzeptierte Antwort, die für mich (Firefox 61.0a1) einige gerade horizontale Pixel in der Mitte anzeigt.
user4642212
Ändern Sie die Farben und Sie werden sehen :)
PVermeer
17

Ich mag die Antwort von ThomasA, wollte aber einen realistischeren Kontext mit der Welle, mit der zwei Divs getrennt werden. Also habe ich eine vollständigere Demo erstellt, in der das Trennzeichen SVG perfekt zwischen den beiden Divs positioniert wird.

CSS-Wellenteiler in CSS

Jetzt dachte ich, es wäre cool, weiter zu gehen. Was wäre, wenn wir dies alles in CSS tun könnten , ohne die Inline-SVG zu benötigen ? Der Punkt ist, zusätzliche Aufschläge zu vermeiden. So habe ich es gemacht:

Zwei einfache <div>:

/** CSS using pseudo-elements: **/

#A {
  background: #0074D9;
}

#B {
  background: #7FDBFF;
}

#A::after {
  content: "";
  position: relative;
  left: -3rem;
  /* padding * -1 */
  top: calc( 3rem - 4rem / 2);
  /* padding - height/2 */
  float: left;
  display: block;
  height: 4rem;
  width: 100vw;
  background: hsla(0, 0%, 100%, 0.5);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 70 500 60' preserveAspectRatio='none'%3E%3Crect x='0' y='0' width='500' height='500' style='stroke: none; fill: %237FDBFF;' /%3E%3Cpath d='M0,100 C150,200 350,0 500,100 L500,00 L0,0 Z' style='stroke: none; fill: %230074D9;'%3E%3C/path%3E%3C/svg%3E");
  background-size: 100% 100%;
}


/** Cosmetics **/

* {
  margin: 0;
}

#A,
#B {
  padding: 3rem;
}

div {
  font-family: monospace;
  font-size: 1.2rem;
  line-height: 1.2;
}

#A {
  color: white;
}
<div id="A">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus nec quam tincidunt, iaculis mi non, hendrerit felis. Nulla pretium lectus et arcu tempus, quis luctus ex imperdiet. In facilisis nulla suscipit ornare finibus. …
</div>

<div id="B" class="wavy">… In iaculis fermentum lacus vel porttitor. Vestibulum congue elementum neque eget feugiat. Donec suscipit diam ligula, aliquam consequat tellus sagittis porttitor. Sed sodales leo nisl, ut consequat est ornare eleifend. Cras et semper mi, in porta nunc.</div>

Demo Welliger Teiler (mit CSS-Pseudoelementen, um zusätzliches Markup zu vermeiden)

Die Positionierung war etwas schwieriger als bei einem Inline-SVG, funktioniert aber genauso gut. (Kann benutzerdefinierte CSS-Eigenschaften oder Präprozessorvariablen verwenden, um die Höhe und den Abstand gut lesbar zu halten.)

Um die Farben zu bearbeiten, müssen Sie die URL-codierte SVG selbst bearbeiten.

Achten Sie (wie in der ersten Demo) auf eine Änderung inviewBox , um unerwünschte Leerzeichen in der SVG zu entfernen. (Eine andere Möglichkeit wäre, eine andere SVG zu zeichnen.)

Eine andere Sache, auf die Sie hier achten sollten, ist das background-sizeSet 100% 100%, um es in beide Richtungen zu dehnen.

Fabien Snauwaert
quelle
17

Kürzlich wurde ein großartiges Tool namens Get Waves eingeführt, mit dem Sie einfach über die Benutzeroberfläche Ihre eigenen Wellen erstellen und diese dann in das SVG-Format exportieren können. Dies ist so einfach wie das Aufrufen der Website https://getwaves.io/ und das Genießen!

Bearbeiten:

Kürzlich habe ich auch ein neues Tool entdeckt - https://shapedivider.app/

Daniel Danielecki
quelle
1
Dies ersparte mir viel CSS-Ärger. Vielen Dank!
Liz
Gerne helfen :)
Daniel Danielecki
3

Hier ist eine andere Möglichkeit :) Das Konzept besteht darin, ein Clip-Path-Polygon mit der Welle als einer Seite zu erstellen.

Dieser Ansatz ist ziemlich flexibel. Sie können die Position (links, rechts, oben oder unten) ändern, an der die Welle erscheint. Ändern Sie die Wellenfunktion in eine beliebige Funktion (t), die [0,1] zugeordnet ist. Das Polygon kann auch für die Form außerhalb verwendet werden, wodurch Text in der Ausrichtung "links" oder "rechts" um die Welle fließen kann.

Am Ende können Sie ein Beispiel auskommentieren, das die Animation der Welle demonstriert.

 

function PolyCalc(f /*a function(t)  from [0, infinity) => [0, 1]*/, 
                  s, /*a slice function(y, i) from y [0,1] => [0, 1], with slice index, i, in [0, n]*/
									w /*window size in seconds*/,
                  n /*sample size*/,
                  o /*orientation => left/right/top/bottom - the 'flat edge' of the polygon*/ 
                  ) 
{
	this.polyStart = "polygon(";
  this.polyLeft = this.polyStart + "0% 0%, "; //starts in the top left corner
  this.polyRight = this.polyStart + "100% 0%, "; //starts in the top right corner
  this.polyTop = this.polyStart + "0% 0%, "; // starts in the top left corner
  this.polyBottom = this.polyStart + "0% 100%, ";//starts in the bottom left corner
  
  var self = this;
  self.mapFunc = s;
  this.func = f;
  this.window = w;
  this.count = n;
  var dt = w/n;  

  switch(o) {
    case "top":
      this.poly = this.polyTop; break;
    case "bottom":
      this.poly = this.polyBottom; break;
  	case "right":
    	this.poly = this.polyRight; break;
  	case "left":
  	default:
  		this.poly = this.polyLeft; break;
    }
    
  this.CalcPolygon = function(t) {
  	var p = this.poly;
    for (i = 0; i < this.count; i++) {
      x = 100 * i/(this.count-1.0);
      y = this.func(t + i*dt);
      if (typeof self.mapFunc !== 'undefined')
      	y=self.mapFunc(y, i);
      y*=100;
      switch(o) {
        case "top": 
          p += x + "% " + y + "%, "; break;
        case "bottom":
          p += x + "% " + (100-y) + "%, "; break;
      	case "right":
        	p += (100-y) + "% " + x + "%, "; break;
      	case "left":
        default:
        	p += y + "% " + x + "%, "; break;          
      }
    }
    
    switch(o) { 
      case "top":
        p += "100% 0%)"; break;
      case "bottom":
        p += "100% 100%)";
        break;
    	case "right":
      	p += "100% 100%)"; break;
    	case "left":
      default:
      	p += "0% 100%)"; break;
    }
    
    return p;
  }
};

var text = document.querySelector("#text");
var divs = document.querySelectorAll(".wave");
var freq=2*Math.PI; //angular frequency in radians/sec
var windowWidth = 1; //the time domain window which determines the range from [t, t+windowWidth] that will be evaluated to create the polygon
var sampleSize = 60;
divs.forEach(function(wave) {
  var loc = wave.classList[1];

  var polyCalc = new PolyCalc(
	  function(t) { //The time domain wave function
  	  return (Math.sin(freq * t) + 1)/2; //sine is [-1, -1], so we remap to [0,1]
    },
    function(y, i) { //slice function, takes the time domain result and the slice index and returns a new value in [0, 1]  
      return MapRange(y, 0.0, 1.0, 0.65, 1.0);  //Here we adjust the range of the wave to 'flatten' it out a bit.  We don't use the index in this case, since it is irrelevant
    },
    windowWidth, //1 second, which with an angular frequency of 2pi rads/sec will produce one full period.
    sampleSize, //the number of samples to make, the larger the number, the smoother the curve, but the more pionts in the final polygon
    loc //the location
  );
  
    var polyText = polyCalc.CalcPolygon(0);
    wave.style.clipPath = polyText;
    wave.style.shapeOutside = polyText;
    wave.addEventListener("click",function(e) {document.querySelector("#polygon").innerText = polyText;});
  });

function MapRange(value, min, max, newMin, newMax) {
  return value * (newMax - newMin)/(max-min) + newMin;
}

//Animation - animate the wave by uncommenting this section
//Also demonstrates a slice function which uses the index of the slice to alter the output for a dampening effect.
/*
var t = 0;
var speed = 1/180;

var polyTop = document.querySelector(".top");

var polyTopCalc = new PolyCalc(
	  function(t) {
  	  return (Math.sin(freq * t) + 1)/2;
    },
    function(y, i) {       
      return MapRange(y, 0.0, 1.0, (sampleSize-i)/sampleSize, 1.0);
    },
    windowWidth, sampleSize, "top"
  );

function animate() {
		var polyT = polyTopCalc.CalcPolygon(t);    
    t+= speed;
    polyTop.style.clipPath = polyT;    
    requestAnimationFrame(animate);
}

requestAnimationFrame(animate);
*/
div div {
  padding:10px;
  /*overflow:scroll;*/
}

.left {
  height:100%;
  width:35%;
  float:left;
}

.right {
  height:200px;
  width:35%;
  float:right;
}

.top { 
  width:100%;
  height: 200px;  
}

.bottom {
  width:100%;
  height:200px;
}

.green {
  background:linear-gradient(to bottom, #b4ddb4 0%,#83c783 17%,#52b152 33%,#008a00 67%,#005700 83%,#002400 100%); 
} 

.mainContainer {
  width:100%;
  float:left;
}

#polygon {
  padding-left:20px;
  margin-left:20px;
  width:100%;
}
<div class="mainContainer">

  <div class="wave top green">
    Click to see the polygon CSS
  </div>
  
  <!--div class="wave left green">
  </div-->
  <!--div class="wave right green">
  </div-->  
  <!--div class="wave bottom green"></div-->  
</div>
<div id="polygon"></div>

Erikest
quelle