Falisty kształt z CSS

80

Próbuję odtworzyć ten obraz za pomocą CSS:

bystry kształt

Nie potrzebowałbym tego powtarzać. To jest to, co zacząłem, ale ma tylko prostą linię:

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

stevenspiel
źródło
2
jeśli chcesz odtworzyć to z css tylko dla rozmiaru, użyj zamiast tego SVG
iKamy
Czy masz jakieś myśli? Coś, czego próbowałeś?
David Fritsch
1
Dlaczego nie użyć po prostu obrazu tła? Czasami najlepiej jest nie nadużywać ani nie „wykorzystywać” mocy CSS, gdy prosty obraz .png kosztowałby około 20 bajtów.
ProfileTwist
1
W przypadku podwójnie zakrzywionych kształtów możesz sprawdzić to pytanie: Podwójnie zakrzywiony kształt
web-tiki
Znalazłem to bootsnipp.com/snippets/yN3Zo
core114

Odpowiedzi:

81

Nie jestem pewien, czy to Twój kształt, ale jest blisko - możesz bawić się wartościami:

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
źródło
1
To rozpada się bez określonej szerokości. Zawsze potrzebuję szerokości = 100%. Dobra robota.
MH
4
Istnieje niewiarygodna luka, w której spotykają się oba pseudo elementy.
Fabien Snauwaert
90

Myślę, że to właściwy sposób na stworzenie takiego kształtu, jaki chcesz. Korzystając z możliwości SVG i kontenera, aby zachować responsywność kształtu.

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
źródło
1
Chociaż możliwe jest rysowanie i animowanie kształtów za pomocą SVG, ale większość ludzi eksportuje swoje pliki SVG z oprogramowania Vector, takiego jak Corel lub Illustrator i wstawia do pliku HTML, możesz bardziej stylizować za pomocą CSS lub nawet manipulować węzłami za pomocą JS lub SVG Biblioteki. i tak jest w przypadku SVG, ponieważ ma on rozwiązać problemy z rysowaniem w CSS
iKamy
Oparłem się na tym w mojej odpowiedzi , dodając dwa elementy div, aby przykład był bardziej realistyczny, przycinając plik SVG, aby pozbyć się niechcianych marginesów, i usuwając wbudowany plik SVG na rzecz rozwiązania CSS.
Fabien Snauwaert
43

Moja implementacja używa elementu svg w html, a także stworzyłem generator do tworzenia fali, którą chcesz:

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
źródło
8
Nigdy wcześniej się to nie zdarzyło, ale faktycznie zalogowałem się, aby zagłosować za tą odpowiedzią dla generatora fal. Nienawidzę plików SVG i zaoszczędziłeś mi dużo czasu!
GoreDefex
22

Moja czysta implementacja CSS oparta na powyższym ze 100% szerokością. Mam nadzieję, że to pomoże!

PVermeer
źródło
2
Bez zbytniego wnikania w kod wydaje się to lepsze niż obecnie akceptowana odpowiedź, która dla mnie (Firefox 61.0a1) wyświetla kilka prostych poziomych pikseli pośrodku.
Sebastian Simon,
Zmień kolory, a zobaczysz :)
PVermeer,
18

Podoba mi się odpowiedź Thomasa A, ale chciałem bardziej realistycznego kontekstu z falą używaną do oddzielenia dwóch elementów div. Stworzyłem więc bardziej kompletne demo, w którym separator SVG jest idealnie umieszczony między dwoma elementami div.

css falisty separator w CSS

Teraz pomyślałem, że fajnie byłoby pójść dalej. A co by było, gdybyśmy mogli to wszystko zrobić w CSS bez potrzeby wbudowanego SVG ? Chodzi o to, aby uniknąć dodatkowych znaczników. Oto jak to zrobiłem:

Dwa proste <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 Falista dzielnik (z pseudoelementami CSS, aby uniknąć dodatkowych znaczników)

Pozycjonowanie było nieco trudniejsze niż w przypadku wbudowanego SVG, ale działa równie dobrze. (Można użyć niestandardowych właściwości CSS lub zmiennych preprocesora, aby wysokość i wypełnienie były łatwe do odczytania).

Aby edytować kolory, musisz edytować sam plik SVG zakodowany w adresie URL.

Zwróć uwagę (jak w pierwszym demo) na zmianę wviewBox usuwaniu niechcianych spacji w SVG. (Inną opcją byłoby narysowanie innego pliku SVG).

Kolejną rzeczą, na którą należy zwrócić uwagę, jest background-sizeustawienie 100% 100%, aby rozciągnąć go w obu kierunkach.

Fabien Snauwaert
źródło
18

Niedawno wprowadzono niesamowite narzędzie o nazwie Get Waves, w którym można po prostu z interfejsu użytkownika tworzyć własne fale, a następnie eksportować je do formatu SVG. Jest to tak proste, jak wejście na stronę https://getwaves.io/ i korzystanie z niej!

Edytować:

Niedawno odkryłem też nowe narzędzie - https://shapedivider.app/

Daniel Danielecki
źródło
1
To zaoszczędziło mi wielu kłopotów z CSS. Dziękuję Ci!
Liz
Cieszę się, że pomogłem :)
Daniel Danielecki
3

Oto kolejny sposób, aby to zrobić :) Koncepcja polega na utworzeniu wielokąta ścieżki klipu z falą po jednej stronie.

To podejście jest dość elastyczne. Możesz zmienić pozycję (lewą, prawą, górną lub dolną), w której pojawia się fala, zmienić funkcję falową na dowolną funkcję (t), która jest odwzorowywana na [0,1]). Wielokąt może być również używany do kształtowania na zewnątrz, co pozwala tekstowi opływać falę w orientacji „w lewo” lub „w prawo”.

Na koniec przykład, który możesz odkomentować, który demonstruje animację fali.

 

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
źródło