Cum să creați forme și modele ondulate în CSS PlatoBlockchain Data Intelligence. Căutare verticală. Ai.

Cum să creați forme și modele ondulate în CSS

Valul este probabil una dintre cele mai dificile forme de realizat în CSS. Întotdeauna încercăm să o aproximăm cu proprietăți precum border-radius și o mulțime de numere magice până când obținem ceva care se simte cam aproape. Și asta chiar înainte de a intra în modele ondulate, care sunt mai dificile.

„SVG it!” ai putea spune și probabil că ai dreptate că este o cale mai bună. Dar vom vedea că CSS poate face valuri frumoase și codul pentru el nu trebuie să fie nebunesc. Si ghici ce? eu am un generator online ca să fie și mai banal!

Dacă te joci cu generatorul, poți vedea că CSS-ul pe care îl scuipă este doar doi gradienți și o proprietate de mască CSS - doar acele două lucruri și putem crea orice fel de formă de undă sau model. Ca să nu mai vorbim de faptul că putem controla cu ușurință dimensiunea și curbura valurilor în timp ce suntem la asta.

Unele dintre valori pot arăta ca „numere magice” dar există de fapt o logică în spatele lor și vom diseca codul și vom descoperi toate secretele din spatele creării valurilor.

Acest articol este o continuare a una anterioară unde am construit tot felul de chenaruri diferite în zig-zag, cu lunetă, festonat și da, chenaruri ondulate. Recomand cu căldură să verificați acel articol, deoarece folosește aceeași tehnică pe care o vom trata aici, dar mai detaliat.

Matematica din spatele valurilor

Strict vorbind, nu există o singură formulă magică în spatele formelor ondulate. Orice formă cu curbe care merg în sus și în jos poate fi numită undă, așa că nu ne vom limita la matematică complexă. În schimb, vom reproduce o undă folosind elementele de bază ale geometriei.

Să începem cu un exemplu simplu folosind două forme de cerc:

Cum să creați forme și modele ondulate în CSS

Avem două cercuri cu aceeași rază unul lângă celălalt. Vedeți linia aceea roșie? Acoperă jumătatea superioară a primului cerc și jumătatea inferioară a celui de-al doilea. Acum imaginează-ți că iei acea linie și o repeți.

O linie roșie ondulată în formă de valuri.
Cum să creați forme și modele ondulate în CSS

Vedem deja valul. Acum să umplem partea de jos (sau cea de sus) pentru a obține următoarele:

Model de undă roșie.
Cum să creați forme și modele ondulate în CSS

Tada! Avem o formă ondulată și una pe care o putem controla folosind o variabilă pentru razele cercului. Acesta este unul dintre cele mai ușoare valuri pe care le putem face și este cel în care m-am arătat this anterioară articol

Să adăugăm un pic de complexitate luând prima ilustrație și mutând puțin cercurile:

Două cercuri gri cu două linii întrerupte, care indică spațierea.
Cum să creați forme și modele ondulate în CSS

Mai avem două cercuri cu aceleași raze dar nu mai sunt aliniate orizontal. În acest caz, linia roșie nu mai acoperă jumătate din suprafața fiecărui cerc, ci o zonă mai mică. Această zonă este limitată de linia roșie întreruptă. Acea linie traversează punctul în care ambele cercuri se întâlnesc.

Acum luați acea linie și repetați-o și veți obține un alt val, unul mai fin.

O linie roșie ondulată.
Cum să creați forme și modele ondulate în CSS
Un model de undă roșie.
Cum să creați forme și modele ondulate în CSS

Cred că ai înțeles ideea. Controlând poziția și dimensiunea cercurilor, putem crea orice val ne dorim. Putem chiar să le creăm variabile, pe care le voi numi P și S, respectiv.

Cum să creați forme și modele ondulate în CSS PlatoBlockchain Data Intelligence. Căutare verticală. Ai.
Cum să creați forme și modele ondulate în CSS

Probabil ați observat că, în generatorul online, controlăm valul folosind două intrări. Acestea sunt mapate la variabilele de mai sus. S este „Mărimea valului” și P este „curbura undei”.

eu definesc P as P = m*S Unde m este variabila pe care o ajustați când actualizați curbura undei. Acest lucru ne permite să avem întotdeauna aceeași curbură, chiar dacă actualizăm S.

m poate fi orice valoare între 0 și 2. 0 ne va oferi primul caz particular în care ambele cercuri sunt aliniate orizontal. 2 este un fel de valoare maximă. Putem merge mai mare, dar după câteva teste am descoperit că orice de mai sus 2 produce forme proaste, plate.

Să nu uităm de raza cercului nostru! Acesta poate fi definit și folosind S și P asa:

R = sqrt(P² + S²)/2

Cand P este egal cu 0, noi vom avea R = S/2.

Avem totul pentru a începe să transformăm toate acestea în gradienți în CSS!

Crearea de gradiente

Undele noastre folosesc cercuri, iar când vorbim despre cercuri vorbim despre gradienți radiali. Și deoarece două cercuri definesc unda noastră, vom folosi în mod logic doi gradienți radiali.

Vom începe cu cazul particular în care P este egal cu 0. Iată ilustrarea primului gradient:

Acest gradient creează prima curbură în timp ce umple întreaga zonă de jos - „apa” valului, ca să spunem așa.

Cum să creați forme și modele ondulate în CSS PlatoBlockchain Data Intelligence. Căutare verticală. Ai.
Cum să creați forme și modele ondulate în CSS
.wave {
  --size: 50px;

  mask: radial-gradient(var(--size) at 50% 0%, #0000 99%, red 101%) 
    50% var(--size)/calc(4 * var(--size)) 100% repeat-x;
}

--size variabila definește raza și dimensiunea gradientului radial. Dacă îl comparăm cu S variabilă, atunci este egală cu S/2.

Acum să adăugăm al doilea gradient:

Al doilea gradient nu este altceva decât un cerc pentru a completa valul nostru:

radial-gradient(var(--size) at 50% var(--size), blue 99%, #0000 101%) 
  calc(50% - 2*var(--size)) 0/calc(4 * var(--size)) 100%

Dacă verificați articolul precedent veți vedea că pur și simplu repet ceea ce am făcut deja acolo.

Am urmărit ambele articole, dar configurațiile gradientului nu sunt aceleași.

Asta pentru că putem ajunge la același rezultat folosind diferite configurații de gradient. Veți observa o ușoară diferență în aliniere dacă comparați ambele configurații, dar trucul este același. Acest lucru poate fi confuz dacă nu sunteți familiarizat cu gradienții, dar nu vă faceți griji. Cu puțină practică, te obișnuiești cu ele și vei descoperi singur că o sintaxă diferită poate duce la același rezultat.

Iată codul complet pentru primul nostru val:

.wave {
  --size: 50px;

  mask:
    radial-gradient(var(--size) at 50% var(--size),#000 99%, #0000 101%) 
      calc(50% - 2*var(--size)) 0/calc(4 * var(--size)) 100%,
    radial-gradient(var(--size) at 50% 0px, #0000 99%, #000 101%) 
      50% var(--size)/calc(4 * var(--size)) 100% repeat-x;
}

Acum să luăm acest cod și să-l ajustăm acolo unde introducem o variabilă care îl face complet reutilizabil pentru a crea orice val pe care îl dorim. După cum am văzut în secțiunea anterioară, trucul principal este să mutați cercurile astfel încât să nu mai fie aliniate, așa că să actualizăm poziția fiecăruia. Pe primul îl vom muta în sus și pe al doilea în jos.

Codul nostru va arăta astfel:

.wave {
  --size: 50px;
  --p: 25px;

  mask:
    radial-gradient(var(--size) at 50% calc(var(--size) + var(--p)), #000 99%, #0000 101%) 
      calc(50% - 2*var(--size)) 0/calc(4 * var(--size)) 100%,
    radial-gradient(var(--size) at 50% calc(-1*var(--p)), #0000 99%, #000 101%) 
      50% var(--size) / calc(4 * var(--size)) 100% repeat-x;
}

Am introdus un nou --p variabilă care o folosește pentru a defini poziția centrală a fiecărui cerc. Primul gradient este folosit 50% calc(-1*var(--p)), astfel încât centrul său se mișcă în sus în timp ce al doilea este folosit calc(var(--size) + var(--p)) pentru a o muta în jos.

Un demo valorează cât o mie de cuvinte:

Cercurile nu sunt nici aliniate, nici nu se ating. Le-am distanțat departe fără a le schimba razele, așa că ne-am pierdut valul. Dar putem rezolva lucrurile folosind aceeași matematică pe care am folosit-o mai devreme pentru a calcula noua rază. Sa nu uiti asta R = sqrt(P² + S²)/2. În cazul nostru, --size este egal cu S/2; la fel pentru --p care este de asemenea egal cu P/2 întrucât deplasăm ambele cercuri. Deci, distanța dintre punctele lor centrale este dublă față de valoarea lui --p pentru aceasta:

R = sqrt(var(--size) * var(--size) + var(--p) * var(--p))

Asta ne dă un rezultat al 55.9px.

Valul nostru s-a întors! Să conectăm acea ecuație în CSS-ul nostru:

.wave {
  --size: 50px;
  --p: 25px;
  --R: sqrt(var(--p) * var(--p) + var(--size)*var(--size));

  mask:
    radial-gradient(var(--R) at 50% calc(var(--size) + var(--p)), #000 99%, #0000 101%) 
      calc(50% - 2*var(--size)) 0 / calc(4 * var(--size)) 100%,
    radial-gradient(var(--R) at 50% calc(-1*var(--p)), #0000 99%, #000 101%) 
      50% var(--size)/calc(4 * var(--size)) 100% repeat-x;
}

Acesta este un cod CSS valid. sqrt() face parte din caietul de sarcini, dar în momentul în care scriu acest lucru, nu există suport pentru browser. Asta înseamnă că avem nevoie de o stropire de JavaScript sau Sass pentru a calcula acea valoare până când vom extinde sqrt() sprijini.

Acest lucru este al naibii de cool: este nevoie doar de două degrade pentru a obține un val rece pe care îl puteți aplica oricărui element folosind mask proprietate. Gata cu încercări și erori - tot ce aveți nevoie este să actualizați două variabile și sunteți gata!

Inversarea valului

Ce se întâmplă dacă vrem ca valurile să meargă în cealaltă direcție, unde umplem „cerul” în loc de „apa”. Credeți sau nu, tot ce trebuie să facem este să actualizăm două valori:

.wave {
  --size: 50px;
  --p: 25px;
  --R: sqrt(var(--p) * var(--p) + var(--size) * var(--size));

  mask:
    radial-gradient(var(--R) at 50% calc(100% - (var(--size) + var(--p))), #000 99%, #0000 101%)
      calc(50% - 2 * var(--size)) 0/calc(4 * var(--size)) 100%,
    radial-gradient(var(--R) at 50% calc(100% + var(--p)), #0000 99%, #000 101%) 
      50% calc(100% - var(--size)) / calc(4 * var(--size)) 100% repeat-x;
}

Tot ce am făcut acolo a fost să adaug un offset egal cu 100%, evidențiat mai sus. Iată rezultatul:

Putem lua în considerare o sintaxă mai prietenoasă folosind valorile cuvintelor cheie pentru a face și mai ușor:

.wave {
  --size: 50px;
  --p: 25px;
  --R: sqrt(var(--p)*var(--p) + var(--size) * var(--size));

  mask:
    radial-gradient(var(--R) at left 50% bottom calc(var(--size) + var(--p)), #000 99%, #0000 101%) 
      calc(50% - 2 * var(--size)) 0/calc(4 * var(--size)) 100%,
    radial-gradient(var(--R) at left 50% bottom calc(-1 * var(--p)), #0000 99%, #000 101%) 
      left 50% bottom var(--size) / calc(4 * var(--size)) 100% repeat-x;
}

Folosim left și bottom cuvinte cheie pentru a specifica laturile și decalajul. În mod prestabilit, browserul este implicit left și top — de aceea folosim 100% pentru a muta elementul în jos. În realitate, o mutăm de la top by 100%, așa că este într-adevăr același lucru cu a spune bottom. Mult mai usor de citit decat matematica!

Cu această sintaxă actualizată, tot ce trebuie să facem este să schimbăm bottom pentru top — sau invers — pentru a schimba direcția undei.

Și dacă doriți să obțineți atât valuri de sus, cât și de jos, combinăm toate gradienții într-o singură declarație:

.wave {
  --size: 50px;
  --p: 25px;
  --R: sqrt(var(--p)*var(--p) + var(--size)*var(--size));

  mask:
    /* Gradient 1 */
    radial-gradient(var(--R) at left 50% bottom calc(var(--size) + var(--p)), #000 99%, #0000 101%) 
      left calc(50% - 2*var(--size)) bottom 0 / calc(4 * var(--size)) 51% repeat-x,
    /* Gradient 2 */
    radial-gradient(var(--R) at left 50% bottom calc(-1 * var(--p)), #0000 99%, #000 101%) 
      left 50% bottom var(--size) / calc(4 * var(--size)) calc(51% - var(--size)) repeat-x,
    /* Gradient 3 */
    radial-gradient(var(--R) at left 50% top calc(var(--size) + var(--p)), #000 99%, #0000 101%) 
      left calc(50% - 2 * var(--size)) top 0 / calc(4 * var(--size)) 51% repeat-x,
    /* Gradient 4 */
    radial-gradient(var(--R) at left 50% top calc(-1 * var(--p)), #0000 99%, #000 101%) 
      left 50% top var(--size) / calc(4 * var(--size)) calc(51% - var(--size)) repeat-x;
}

Dacă verificați codul, veți vedea că pe lângă combinarea tuturor gradienților, le-am redus și înălțimea de la 100% la 51% astfel încât ambele să acopere jumătate din element. Da, 51%. Avem nevoie de acel procentaj în plus pentru o suprapunere mică care să evite golurile.

Dar partea stângă și dreaptă?

Sunt temele tale! Luați ceea ce am făcut cu părțile de sus și de jos și încercați să actualizați valorile pentru a obține valorile din dreapta și din stânga. Nu-ți face griji, este ușor și singurul lucru pe care trebuie să-l faci este să schimbi valori.

Dacă aveți probleme, puteți utiliza oricând generatorul online pentru a verifica codul și a vizualiza rezultatul.

Linii ondulate

Mai devreme, am făcut primul val folosind o linie roșie, apoi am umplut porțiunea de jos a elementului. Ce zici de linia aceea ondulată? Este și un val! Și mai bine este dacă îi putem controla grosimea cu o variabilă, astfel încât să o putem reutiliza. Hai să o facem!

Nu vom începe de la zero, ci mai degrabă luăm codul anterior și îl vom actualiza. Primul lucru de făcut este să actualizați opririle de culoare ale gradienților. Ambele degrade pornesc de la o culoare transparentă la una opacă sau invers. Pentru a simula o linie sau o chenar, trebuie să începem de la transparent, să mergem la opac, apoi înapoi la transparent din nou:

#0000 calc(99% - var(--b)), #000 calc(101% - var(--b)) 99%, #0000 101%

Cred că ai ghicit deja că --b variabilă este ceea ce folosim pentru a controla grosimea liniei. Să aplicăm acest lucru la gradienții noștri:

Da, rezultatul este departe de o linie ondulată. Dar privind atent, putem vedea că un gradient creează corect curbura inferioară. Deci, tot ce trebuie să facem este să rectificăm al doilea gradient. În loc să păstrăm un cerc complet, să facem unul parțial ca celălalt gradient.

Încă departe, dar avem ambele curburi de care avem nevoie! Dacă verifici codul, vei vedea că avem două gradiente identice. Singura diferență este poziționarea lor:

.wave {
  --size: 50px;
  --b: 10px;
  --p: 25px;
  --R: sqrt(var(--p)*var(--p) + var(--size)*var(--size));

  --_g: #0000 calc(99% - var(--b)), #000 calc(101% - var(--b)) 99%, #0000 101%;
  mask:
    radial-gradient(var(--R) at left 50% bottom calc(-1*var(--p)), var(--_g)) 
      calc(50% - 2*var(--size)) 0/calc(4*var(--size)) 100%,
    radial-gradient(var(--R) at left 50% top    calc(-1*var(--p)), var(--_g)) 
      50% var(--size)/calc(4*var(--size)) 100%;
}

Acum trebuie să ajustam dimensiunea și poziția pentru forma finală. Nu mai avem nevoie ca gradientul să fie la înălțimea completă, așa că putem înlocui 100% cu asta:

/* Size plus thickness */
calc(var(--size) + var(--b))

Nu există o logică matematică în spatele acestei valori. Trebuie doar să fie suficient de mare pentru curbură. Îi vom vedea efectul asupra modelului în doar un pic. Între timp, să actualizăm și poziția pentru a centra vertical gradienții:

.wave {
  --size: 50px;
  --b: 10px;
  --p: 25px;
  --R: sqrt(var(--p)*var(--p) + var(--size)*var(--size));

  --_g: #0000 calc(99% - var(--b)), #000 calc(101% - var(--b)) 99%, #0000 101%;  
  mask:
    radial-gradient(var(--R) at left 50% bottom calc(-1*var(--p)), var(--_g)) 
      calc(50% - 2*var(--size)) 50%/calc(4 * var(--size)) calc(var(--size) + var(--b)) no-repeat,
    radial-gradient(var(--R) at left 50% top calc(-1 * var(--p)), var(--_g)) 50%
      50%/calc(4 * var(--size)) calc(var(--size) + var(--b)) no-repeat;
}

Încă nu este acolo:

Un gradient trebuie să se miște puțin în jos, iar celălalt puțin în sus. Ambele trebuie să se miște cu jumătate din înălțimea lor.

Aproape am ajuns! Avem nevoie de o reparație mică pentru ca raza să aibă o suprapunere perfectă. Ambele linii trebuie să fie compensate cu jumătate din graniță (--b) grosime:

Am inteles! O linie ondulată perfectă pe care o putem ajusta cu ușurință controlând câteva variabile:

.wave {
  --size: 50px;
  --b: 10px;
  --p: 25px;
  --R: calc(sqrt(var(--p) * var(--p) + var(--size) * var(--size)) + var(--b) / 2);

  --_g: #0000 calc(99% - var(--b)), #000 calc(101% - var(--b)) 99%, #0000 101%;
  mask:
    radial-gradient(var(--R) at left 50% bottom calc(-1 * var(--p)), var(--_g)) 
     calc(50% - 2*var(--size)) calc(50% - var(--size)/2 - var(--b)/2) / calc(4 * var(--size)) calc(var(--size) + var(--b)) repeat-x,
    radial-gradient(var(--R) at left 50% top calc(-1*var(--p)),var(--_g)) 
     50%  calc(50% + var(--size)/2 + var(--b)/2) / calc(4 * var(--size)) calc(var(--size) + var(--b)) repeat-x;
}

Știu că este nevoie de puțin pentru a înțelege logica. Este în regulă și, după cum am spus, crearea unei forme ondulate în CSS nu este ușoară, ca să nu mai vorbim de matematica complicată din spatele ei. De aceea generator online este o salvare — puteți obține cu ușurință codul final chiar dacă nu înțelegeți pe deplin logica din spatele lui.

Modele ondulate

Putem realiza un model din linia ondulată pe care tocmai am creat-o!

Oh, nu, codul modelului va fi și mai greu de înțeles!

Deloc! Avem deja codul. Tot ce trebuie să facem este să eliminăm repeat-x din ce avem deja, si tada. 🎉

Un model ondulat frumos. Îți amintești ecuația pe care am spus că o vom revedea?

/* Size plus thickness */
calc(var(--size) + var(--b))

Ei bine, acesta este ceea ce controlează distanța dintre liniile din model. Putem face o variabilă din ea, dar nu este nevoie de mai multă complexitate. Nici măcar nu folosesc o variabilă pentru asta în generator. Poate o voi schimba mai târziu.

Iată același model care merge într-o direcție diferită:

Vă ofer codul în demonstrația respectivă, dar aș dori să îl analizați și să înțelegeți ce modificări am făcut pentru ca acest lucru să se întâmple.

Simplificarea codului

În toate demo-urile anterioare, definim întotdeauna --size și --p independent. Dar vă amintiți cum am menționat mai devreme că generatorul online evaluează P ca egal cu m*S, În cazul în care m controlează curbura undei? Prin definirea unui multiplicator fix, putem lucra cu un anumit val și codul poate deveni mai ușor. Acesta este ceea ce vom avea nevoie în majoritatea cazurilor: o formă ondulată specifică și o variabilă pentru a-i controla dimensiunea.

Să ne actualizăm codul și să introducem m variabilă:

.wave {
  --size: 50px;
  --R: calc(var(--size) * sqrt(var(--m) * var(--m) + 1));

  mask:
    radial-gradient(var(--R) at 50% calc(var(--size) * (1 + var(--m))), #000 99%, #0000 101%) 
      calc(50% - 2*var(--size)) 0/calc(4 * var(--size)) 100%,
    radial-gradient(var(--R) at 50% calc(-1 * var(--size) * var(--m)), #0000 99%, #000 101%) 
      50% var(--size) / calc(4 * var(--size)) 100% repeat-x;
  }

După cum puteți vedea, nu mai avem nevoie de --p variabil. L-am inlocuit cu var(--m)*var(--size), și a optimizat o parte din matematică în consecință. Acum, dacă vrem să lucrăm cu o anumită formă ondulată, putem omite --m variabilă și înlocuiți-o cu o valoare fixă. Sa incercam .8 de exemplu.

--size: 50px;
--R: calc(var(--size) * 1.28);

mask:
  radial-gradient(var(--R) at 50% calc(1.8 * var(--size)), #000 99%, #0000 101%) 
    calc(50% - 2*var(--size)) 0/calc(4 * var(--size)) 100%,
  radial-gradient(var(--R) at 50% calc(-.8 * var(--size)), #0000 99%, #000 101%) 
    50% var(--size) / calc(4 * var(--size)) 100% repeat-x;

Vedeți cum codul este mai ușor acum? O singură variabilă pentru a vă controla valul, plus că nu mai trebuie să vă bazați sqrt() care nu are suport pentru browser!

Puteți aplica aceeași logică tuturor demo-urilor pe care le-am văzut chiar și pentru liniile ondulate și modelul. Am început cu o explicație matematică detaliată și am dat codul generic, dar este posibil să aveți nevoie de cod mai ușor într-un caz real de utilizare. Asta fac tot timpul. Folosesc rar codul generic, dar iau întotdeauna în considerare o versiune simplificată, mai ales că, în majoritatea cazurilor, folosesc niște valori cunoscute care nu trebuie stocate ca variabile. (Alerta alertă: Voi împărtăși câteva exemple la sfârșit!)

Limitări ale acestei abordări

Din punct de vedere matematic, codul pe care l-am creat ar trebui să ne ofere forme și modele ondulate perfecte, dar, în realitate, ne vom confrunta cu niște rezultate ciudate. Deci, da, această metodă are limitele ei. De exemplu, generatorul online este capabil să producă rezultate slabe, în special cu linii ondulate. O parte a problemei se datorează unei combinații speciale de valori în care rezultatul este amestecat, cum ar fi utilizarea unei valori mari pentru grosimea marginii în comparație cu dimensiunea:

Cum să creați forme și modele ondulate în CSS PlatoBlockchain Data Intelligence. Căutare verticală. Ai.
Cum să creați forme și modele ondulate în CSS

Pentru celelalte cazuri, problema legată de o anumită rotunjire va duce la nealiniere și decalaje între valuri:

Cum să creați forme și modele ondulate în CSS PlatoBlockchain Data Intelligence. Căutare verticală. Ai.
Cum să creați forme și modele ondulate în CSS

Acestea fiind spuse, încă cred că metoda pe care am abordat-o rămâne una bună, deoarece produce valuri netede în majoritatea cazurilor și putem evita cu ușurință rezultatele proaste jucându-ne cu valori diferite până când ajungem la perfectă.

La finalul

Sper că, după acest articol, nu veți mai încerca să construiți o formă sau un model ondulat. în plus la generatorul online, ai toate secretele matematice în spatele creării oricărui fel de val vrei!

Articolul se termină aici, dar acum aveți un instrument puternic pentru a crea modele fanteziste care folosesc forme ondulate. Iată inspirația pentru a începe...

Şi tu? Folosește generatorul meu online (sau scrie codul manual dacă ai învățat deja toate matematica pe de rost) și arată-mi creațiile tale! Să avem o colecție bună în secțiunea de comentarii.

Timestamp-ul:

Mai mult de la CSS Trucuri