Волнистая форма с CSS

80

Я пытаюсь воссоздать это изображение с помощью CSS:

своенравная форма

Мне не нужно было бы это повторять. Это то, что я начал, но у него просто прямая линия:

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

Stevenspiel
источник
2
если вы хотите воссоздать это с помощью CSS только для размера, используйте вместо этого SVG
iKamy
Были мысли? Что-нибудь, что вы пробовали?
Дэвид Фрич
1
Почему бы просто не использовать фоновое изображение? Иногда лучше не злоупотреблять и не «использовать» мощь CSS, когда простое изображение .png будет стоить вам около 20 байт.
ProfileTwist
1
Для форм с двойным изгибом вы можете проверить этот вопрос: Форма с двойным изгибом
web-tiki
Я нашел эти ботинкиnipp.com
snippets/

Ответы:

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>

iKamy
источник
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>

ThomasA
источник
1
Хотя вы можете рисовать и анимировать фигуры с помощью SVG, но большинство людей экспортируют свои файлы SVG из программного обеспечения на основе векторов, такого как Corel или Illustrator, и вставляют в файл HTML, тогда вы можете стилизовать больше с помощью CSS или даже манипулировать узлами с помощью 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/

Патч92
источник
архивная ссылка на генератор: web.archive.org/web/20180810082435/https://smooth.ie/blogs/news/…
Найджел
8
Никогда раньше не случалось, но я на самом деле вошел в систему, чтобы проголосовать за этот ответ для генератора волн. Я ненавижу SVG, и вы сэкономили мне столько времени!
GoreDefex
22

Моя реализация на чистом CSS, основанная на выше, со 100% шириной. Надеюсь, поможет!

PVermeer
источник
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 или переменные препроцессора, чтобы высота и отступы были легко читаемыми.)

Чтобы редактировать цвета, вам нужно отредактировать сам SVG с кодировкой URL.

Обратите внимание (как в первой демонстрации) на изменение,viewBox чтобы избавиться от ненужных пробелов в SVG. (Другой вариант - нарисовать другой SVG.)

Еще одна вещь, на которую следует обратить внимание, - это background-sizeнабор, 100% 100%чтобы заставить ее растягиваться в обоих направлениях.

Фабьен Снауверт
источник
18

Недавно был представлен замечательный инструмент Get Waves, в котором вы можете просто из пользовательского интерфейса создать свои собственные волны, а затем экспортировать их в формат SVG. Это так же просто, как зайти на сайт https://getwaves.io/ и насладиться им!

Редактировать:

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

Даниэль Даниелецки
источник
1
Это избавило меня от многих проблем с css. Спасибо!
Лиз
Рад помочь :)
Даниэль Даниелецки
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>

Эрикест
источник