CSS-teknikker til materialevirkningseffekt

En guide til forskellige teknikker til ringvirkningen ved hjælp af CSS og JavaScript

Jeg var for nylig nødt til at implementere ringvirkningen fra materialedesign til en webapplikation. Og så indså jeg, at jeg ikke havde nogen idé om, hvordan det blev implementeret. Dette førte mig ind i en rejse for at studere eksisterende implementeringer og endda komme med en helt ny teknik, der måske kan være nyttig for dig.

Hvad er denne ringvirkning?

Vent, kender du ikke ringvirkningen fra Googles materialdesign? Har du boet i en hule i hvor mange år?

Rippeleffekten bruges, når du trykker på en knap. Det fungerer på samme måde til interaktion mellem mus eller berøring.

Den position, du klikker på eller berører knappen, kaldes kontaktpunktet. Derfra sendes en krusning, der bevæger sig udad, og mister opaciteten, når den bliver større, indtil den fylder hele knappen. Så forsvinder det helt.

Dynamikken i denne ringvirkning ligner de krusninger, du får, når du berører en flydende overflade, eller når du slipper en klippe ned i en sø.

Krusningerne, du finder på internettet

Efter at have foretaget noget research kunne jeg finde to hovedteknikker, der bruges til at implementere ringvirkningen på webapplikationer.

Brug af :: efter pseudo-element

Ved hjælp af denne teknik er :: efter pseudo-elementet i knappen stylet som en halvtransparent cirkel og animeret til at vokse og falme. Containerknappen skal have overløb: skjult, så cirklen aldrig flyder uden for knappens overflade og position: i forhold til at gøre det let at placere cirklen inden i knappen. Du kan læse flere detaljer om denne teknik på denne artikel af Ionuț Colceriu.

En af de store ting ved denne teknik er, at det er en ren CSS-løsning til ringvirkningen. Rippeleffekten starter dog altid fra midten af ​​knappen i stedet for kontaktpunktet. Det er ikke den mest naturlige feedback.

Det kunne forbedres ved at bruge JavaScript til at gemme kontaktpunktet og bruge det til at placere krusningen. Det er præcis, hvad material.io har gjort for deres web-rippelkomponent. Det bruger CSS-variabler til at gemme kontaktpunktet, og :: efter pseudo-elementet bruger disse variabler til positionering.

Brug af børnelementer

I det væsentlige bruger denne teknik den samme strategi som før. Men i stedet for et pseudo-element tilføjer det et spanelement inde i knappen, som derefter kan placeres via JavaScript. Denne teknik er beskrevet på denne artikel af Jhey Tompkins.

Den enkleste implementering skaber et span for hvert klik på knappen og bruger musepositionen på klikbegivenheden til at ændre positionen for spændet. En CSS-animation får spennet til at vokse og falme, indtil det bliver fuldt gennemsigtigt. Vi kan vælge at fjerne spændvidden fra DOM, når animationen er færdig, eller bare lade den ligge der under gulvtæppet - ingen vil virkelig bemærke et gennemsigtigt spenn, der hænger rundt.

Jeg fandt en anden variation af dette, som barnelementet er en svg i stedet for et span, og svg er animeret via JavaScript. Denne variation er forklaret af Dennis Gaebel, men i det væsentlige ser den ud til at være den samme, og måske tillader at bruge komplekse SVG-former og effekter.

Et problem med indsende input

Begge teknikker beskrevet ovenfor synes store. Men det er, hvad der sker, da jeg prøvede at anvende dem på inputelementer med type = send:

Hvorfor fungerer de ikke?

Inputelementet er et erstattet element. Kort sagt betyder det, at der er meget lidt, du kan gøre med disse elementer, med hensyn til DOM og CSS. Specifikt kan de ikke have underordnede elementer og heller ingen pseudo-elementer. Nu er det klart, hvorfor disse teknikker mislykkes.

Så hvis du bruger Material Design, er det bedre at holde sig væk fra input [type = indsende] og holde sig til knapelementer. Eller bare læs videre.

Tilføjelse af krusninger for at indsende input

På den webapplikation, jeg arbejdede med, havde vi allerede mange indsendelsesknapper. At ændre dem alle til at blive et andet element kræver en masse arbejde og en høj risiko for at bryde stilark og JavaScript-logik. Så jeg var nødt til at finde ud af, hvordan jeg tilføjede rippler til de eksisterende indsenderknapper.

Brug af en indpakningsbeholder

Jeg indså hurtigt, at jeg kunne vikle indsendelsesknappen inde i et inline-block-element og bruge inline-block-elementet som krusningsoverfladen. Her er en hurtig demo:

Mens jeg kan lide denne løsning på grund af dens enkelhed, krævede den mig stadig at ændre markeringen for mange steder. Og jeg vidste, at det ville være en skrøbelig løsning - nye udviklere ville komme ind i projektet og oprette indsendelsesknapper uden at pakke dem ordentligt ind i en krusningsoverflade. Så jeg fortsatte med at søge efter andre løsninger, som ikke krævede ændring af DOM.

Radiale gradienter

Den radiale gradient-syntaks tillader mig at kontrollere både midten og størrelsen på gradienten. Selvfølgelig tillader det mig også at kontrollere farve på gradienten, inklusive halvtransparente farver. Og det oversvømmer aldrig det element, det er anvendt på. Så det ser ud til, at det allerede gør alt, hvad jeg har brug for!

Ikke så hurtigt ... der mangler en ting: egenskaben baggrundsbillede er ikke animeret. Jeg kunne ikke få gradienten til at vokse og falme til gennemsigtig ved hjælp af CSS-animationer. Det lykkedes mig at få det til at vokse ved at animere egenskaben i baggrundstørrelse, men det var alt, hvad jeg kunne gøre.

Jeg prøvede et par andre ting, såsom at have en falmende cirkel som et animeret billede (ved hjælp af apng-formatet) og anvendte det som et baggrundsbillede. Men så kunne jeg ikke kontrollere, hvornår billedsløjfen startede og sluttede.

Endelig en løsning med JavaScript

Hvad du ikke kan gøre i CSS, kan du gøre det i JavaScript. Efter at have brugt mere tid, end jeg er villig til at indrømme at forsøge at få denne effekt til at bruge CSS-animationer, opgav jeg bare og besluttede at skrive animationen i JavaScript.

Jeg startede med den radiale gradientopløsning ovenfor og brugte windows.requestAnimationFrame til at lave en flydende animation af den radiale gradient, vokse og falme. Her er min endelige løsning:

Konklusion

Så det er muligt at have ringvirkninger på indsendelsesknapper, bare ikke med CSS alene.

Jeg kunne ikke finde denne teknik dokumenteret overalt på nettet, så jeg kalder den min egen. Leonardos krusningsteknik kræver ikke ændringer i DOM og fungerer for ethvert element, fordi den ikke er afhængig af pseudo-elementer eller underordnede elementer. Det er dog ikke en fejlfri løsning.

Først er der præstation. Ved at animere gradienten med JavaScript, mister du en masse browseroptimeringer. Men fordi den eneste egenskab, der ændres, er baggrundsbilledet, ville jeg have mistanke om, at browsere ikke behøver at flytte igen, og bare ville kræve genanvendelse af typografier og maling af elementet igen. I praksis er det nøjagtigt, hvad der sker, og ydelsen er virkelig god. Undtagelsen fra denne erklæring er Firefox Mobile, som af en eller anden grund ikke følger med animationen. (rediger: animation er glat i moderne Firefox Mobile-versioner)

For det andet bruger teknikken knappens baggrundsbilledeegenskab. Hvis dit design kræver, at dine knapper har et billede, der anvendes på dens baggrund, vil ringvirkningen tilsidesætte det. Hvis du virkelig har brug for dette billede på dit design, kunne JavaScript blive ændret for at tegne den radiale gradient oven på det eksisterende baggrundsbillede.

For det tredje ser det ud til, at dette ikke fungerer i Internet Explorer. Jeg ser dog ikke nogen grund til, at det ikke skulle fungere med IE10 og nyere. Måske er det fordi IE bruger en anden syntaks til radial gradient. Men hvem er interesseret i IE i dag? (rediger: denne metode fungerer uden problemer på Internet Explorer 11)