Хвиляста форма з css


80

Я намагаюся відтворити це зображення за допомогою CSS:

похила форма

Мені не потрібно було б це повторювати. Це те, що я почав, але у нього просто пряма лінія:

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


2
якщо ви хочете заново створити це за допомогою css лише для розміру, замість цього використовуйте SVG
iKamy

Чи були у вас думки? Що-небудь, що ви пробували?
Девід Фріч

1
Чому б просто не використовувати фонове зображення? Іноді найкраще не зловживати або не використовувати силу CSS, коли просте зображення у форматі .png коштуватиме вам, можливо, 20 байт.
ProfileTwist

1
Щодо подвійних вигнутих фігур, ви можете перевірити це запитання: Подвійна вигнута фігура
web-tiki

Я знайшов це bootsnipp.com/snippets/yN3Zo
core114

Відповіді:


81

Я не впевнений, що це ваша форма, але вона близька - ви можете грати зі значеннями:

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>


1
Це розпадається без заданої ширини. Мені завжди потрібна ширина = 100%. Хороша робота.
MH

4
Існує непривабливий розрив, коли обидва псевдоелементи стикаються.
Fabien Snauwaert

90

Я думаю, що це правильний спосіб зробити таку форму, як ти хочеш. Використовуючи можливості SVG та контейнер, щоб підтримувати форму у відповідь.

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>


1
Хоча це можливо для вас, щоб малювати та анімувати фігури за допомогою SVG, але більшість людей експортують свої файли SVG із програмного забезпечення на основі Vector, таких як Corel або Illustrator та Insert у файлі HTML, тоді ви можете більше стилізувати за допомогою CSS або навіть маніпулювати Nodes за допомогою JS або SVG Бібліотеки. і це так для SVG, оскільки він повинен вирішити труднощі з малюванням у CSS
iKamy

Я підкреслив це у своїй відповіді , додавши два div, щоб зробити приклад більш реалістичним, обрізавши SVG, щоб позбутися небажаних полів, і видаливши вбудований SVG на користь рішення CSS.
Fabien Snauwaert

43

У моїй реалізації використовується елемент svg в html, і я також створив генератор для створення потрібної хвилі:

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/



8
Ніколи раніше не траплялося, але я фактично увійшов у систему, щоб лише проголосувати цю відповідь для генератора хвиль. Я ненавиджу SVG, і ти врятував мені стільки часу!
GoreDefex

22

Моя чиста реалізація CSS, заснована на вище, зі 100% шириною. Сподіваюся, це допоможе!


2
Без надто глибокого огляду коду це здається кращим, ніж прийнята в даний час відповідь, яка для мене (Firefox 61.0a1) відображає кілька прямих горизонтальних пікселів посередині.
Себастьян Саймон

Змініть кольори, і ви побачите :)
PVermeer

18

Мені подобається відповідь ThomasA, але я хотів отримати більш реалістичний контекст, коли хвиля використовується для розділення двох div. Тож я створив більш повну демонстраційну версію, де сепаратор SVG ідеально розташувався між двома div.

css хвилястий дільник у CSS

Тепер я подумав, що було б круто йти далі. Що, якби ми могли зробити все це в CSS без необхідності вбудованого SVG ? Справа в тому, щоб уникнути зайвої розмітки. Ось як я це зробив:

Два простих <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>

Демо- хвилястий дільник (із псевдоелементами CSS, щоб уникнути зайвої розмітки)

Позиціонувати було трохи складніше, ніж із вбудованим SVG, але працює так само добре. (Можна використовувати користувацькі властивості CSS або змінні попереднього процесора, щоб висота та відступ були легкими для читання.)

Щоб відредагувати кольори, потрібно відредагувати URL-кодований SVG.

Зверніть увагу (як у першій демонстрації) на зміну,viewBox щоб позбутися небажаних пробілів у SVG. (Іншим варіантом було б намалювати інший SVG.)

Інша справа, на яку слід звернути увагу, - це background-sizeнабір, щоб 100% 100%він розтягнувся в обидві сторони.


18

Нещодавно був представлений чудовий інструмент під назвою Get Waves, де ви можете просто з інтерфейсу створити власні хвилі, а потім експортувати його у формат SVG. Це так просто, як зайти на веб- сайт https://getwaves.io/ і насолодитися цим!

Редагувати:

Нещодавно я також відкрив новий інструмент - https://shapedivider.app/


1
Це врятувало мені багато клопоту. Дякую!
Ліз

Радий допомогти :)
Даніель Даніелецький

3

Ось ще один спосіб зробити це :) Концепція полягає у створенні багатокутника кліп-шляху із хвилею як однією стороною.

Цей підхід досить гнучкий. Ви можете змінити положення (ліве, праве, верхнє або нижнє), в якому з'являється хвиля, змінити хвильову функцію на будь-яку функцію (t), яка відображається на [0,1]). Багатокутник також може бути використаний для зовнішньої форми, що дозволяє тексту обтікати хвилю, коли знаходиться в "лівій" або "правій" орієнтації.

Наприкінці, приклад, який можна прокоментувати, демонструє анімацію хвилі.

 

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>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.