Tehnici CSS pentru efect de ondulare a materialului

Un ghid în diferite tehnici pentru efectul de ondulare folosind CSS și JavaScript

Recent, a trebuit să implementez efectul de ondulare de la proiectarea materialelor într-o aplicație web. Și atunci mi-am dat seama că habar nu aveam cum a fost implementată asta. Acest lucru m-a condus într-o călătorie pentru a studia implementările existente și chiar a venit cu o tehnică complet nouă, care vă poate fi utilă.

Care este acest efect de ondulare?

Așteptați, nu știți efectul de ondulare din proiectarea materialelor Google? Locuiți pe o peșteră de câți ani?

Efectul de ondulare este utilizat atunci când apăsați un buton. Funcționează în același mod pentru interacțiuni cu mouse-ul sau atingerea.

Poziția pe care faceți clic sau atingeți butonul se numește punctul de contact. De acolo, o ondulare este trimisă în mișcare spre exterior, pierzând opacitatea pe măsură ce crește mai mare până când umple întregul buton. Apoi dispare complet.

Dinamica acestui efect de ondulare este similară cu ondulările pe care le obțineți când atingeți o suprafață lichidă sau când aruncați o stâncă într-un lac.

Ondulările pe care le veți găsi pe web

După ce am făcut câteva cercetări, am putut găsi două tehnici principale care sunt utilizate pentru implementarea efectului de ondulare asupra aplicațiilor web.

Utilizarea :: după pseudo-element

Folosind această tehnică, pseudo-elementul :: după buton este conceput ca un cerc semi-transparent și animat să crească și să se estompeze. Butonul de container trebuie să aibă preaplin: ascuns, astfel încât cercul să nu se revadă niciodată în afara suprafeței butonului și poziția: relativ pentru a ușura poziționarea cercului în interiorul butonului. Puteți citi mai multe detalii despre această tehnică pe acest articol de Ionuț Colceriu.

Unul dintre lucrurile deosebite despre această tehnică este că este o soluție CSS pură a efectului de ondulare. Cu toate acestea, efectul de ondulare începe întotdeauna de la centrul butonului, în loc de punctul de contact. Acesta nu este cel mai natural feedback.

Ar putea fi îmbunătățit folosind JavaScript pentru a stoca punctul de contact și îl puteți folosi pentru a poziționa ondularea. Exact ceea ce a făcut material.io pentru componenta lor de ondulare web. Utilizează variabile CSS pentru a stoca punctul de contact, iar pseudo-element :: după folosește aceste variabile pentru poziționare.

Utilizarea elementelor copilului

În esență, această tehnică folosește aceeași strategie ca înainte. Dar în loc de un pseudo-element, adaugă un element de span în interiorul butonului, care poate fi apoi poziționat prin JavaScript. Această tehnică este descrisă în acest articol de Jhey Tompkins.

Cea mai simplă implementare creează un interval pentru fiecare clic pe buton și folosește poziția mouse-ului la evenimentul de clic pentru a schimba poziția intervalului. O animație CSS face ca intervalul să crească și să se estompeze până să devină complet transparent. Putem alege să înlăturăm intervalul din DOM odată ce animația va fi terminată sau pur și simplu să o lăsăm acolo sub covor - nimeni nu va observa cu adevărat un interval transparent atârnat.

Am găsit o altă variantă în care elementul copil este un svg în loc de un interval, iar svg este animat prin JavaScript. Această variație este explicată de Dennis Gaebel, dar, în esență, pare să fie aceeași și poate să permită utilizarea formelor și efectelor SVG complexe.

Problemă cu intrările de trimitere

Ambele tehnici descrise mai sus par grozave. Dar asta se întâmplă când am încercat să le aplic pe elementele de intrare cu tip = submit:

De ce nu funcționează?

Elementul de intrare este un element înlocuit. Pe scurt, asta înseamnă că puteți face foarte puține lucruri cu aceste elemente, în ceea ce privește DOM și CSS. Mai exact, nu pot avea elemente pentru copii și nici pseudo-elemente. Acum este clar de ce aceste tehnici nu reușesc.

Așadar, dacă utilizați Design material, este mai bine să stați departe de intrare [type = submit] și să rămâneți la elementele butonului. Sau doar continuă să citești.

Adăugarea ondulărilor pentru a trimite intrări

Pe aplicația web la care lucram, aveam deja multe butoane de trimitere. Schimbarea tuturor pentru a deveni un element diferit ar necesita multă muncă și un risc ridicat de rupere a foilor de stil și a logicii JavaScript. Așa că a trebuit să-mi dau seama cum să adaug ripple la butoanele de trimitere existente.

Folosind un recipient de ambalare

Mi-am dat seama repede că pot înfășura butonul de trimitere în interiorul unui element inline-block și că puteți folosi elementul inline block ca suprafață de ondulare. Iată o demonstrație rapidă:

În timp ce îmi place această soluție pentru simplitatea ei, totuși mi-a fost necesar să schimb marcajul în prea multe locuri. Și știam că va fi o soluție fragilă - noii dezvoltatori vor veni în proiect și vor crea butoane de trimitere fără a le înfășura în mod corespunzător pe o suprafață ondulată. Așa că am continuat să caut alte soluții care nu necesitau schimbarea DOM.

Gradienți radiali

Sintaxa cu gradient radial îmi permite să controlez atât centrul cât și dimensiunea gradientului. Desigur, îmi permite să controlez și culoarea gradientului, inclusiv culorile semi-transparente. Și nu va revărsa niciodată elementul la care a fost aplicat. Se pare că face deja tot ce am nevoie!

Nu este atât de rapid ... lipsește un lucru: proprietatea imaginii de fundal nu este animabilă. Nu am putut face ca gradientul să crească și să se estompeze transparent, folosind animații CSS. Am reușit să o fac să crească prin animarea proprietății de fundal, dar asta am putut face tot.

Am încercat câteva alte lucruri, cum ar fi un cerc decolorat ca imagine animată (folosind formatul apng) și l-am aplicat ca imagine de fundal. Dar atunci nu am putut controla când a început și s-a încheiat bucla de imagine.

În cele din urmă, o soluție cu JavaScript

Ce puteți face în CSS, îl puteți face în JavaScript. După ce am petrecut mai mult timp decât sunt dispus să recunosc că încerc să obțin acest efect folosind animații CSS, am renunțat și am decis să scriu animația în JavaScript.

Am început cu soluția de gradient radial de mai sus și am folosit window.requestAnimationFrame pentru a realiza o animație fluidă a gradientului radial, în creștere și decolorare. Iată soluția mea finală:

Concluzie

Deci este posibil să aveți efecte de ondulare pe butoanele de trimitere, doar nu doar cu CSS.

Nu am găsit această tehnică documentată nicăieri pe web, așa că o numesc a mea. Tehnica de ondulare a lui Leonardo nu necesită modificări la DOM și funcționează pentru orice element, deoarece nu se bazează pe pseudoelemente sau elemente copil. Cu toate acestea, nu este o soluție fără cusur.

În primul rând, există performanțe. Prin animarea gradientului cu JavaScript, pierzi o mulțime de optimizări ale browserului. Dar, deoarece singura proprietate care este schimbată este imaginea de fundal, aș bănui că browserele nu ar trebui să reflow, și ar necesita doar reaplicarea stilurilor și repictarea elementului. În practică, exact acest lucru se întâmplă, iar performanțele sunt cu adevărat bune. Excepția de la această afirmație este Firefox Mobile, care din anumite motive nu ține pasul cu animația. (edit: animația este lină pe versiunile moderne Firefox Mobile)

În al doilea rând, tehnica folosește proprietatea imaginii de fundal a butonului. Dacă design-ul dvs. necesită ca butoanele dvs. să aibă o imagine aplicată pe fundalul său, efectul de ondulare ar anula acest lucru. Dacă aveți nevoie cu adevărat de acea imagine pe designul dvs., atunci JavaScript ar putea fi modificat pentru a atrage gradientul radial deasupra imaginii de fundal existente.

În al treilea rând, acest lucru nu pare să funcționeze în Internet Explorer. Cu toate acestea, nu văd niciun motiv pentru care nu ar trebui să funcționeze cu IE10 și versiuni ulterioare. Poate pentru că IE folosește o sintaxă diferită pentru gradient radial. Dar, cui îi pasă de zilele IE? (editați: această metodă funcționează fără probleme pe Internet Explorer 11)