1 HTML-Element + 5 CSS-Eigenschappen = Magic!

0
40

Laten we zeggen dat ik je vertelde, we kunnen de resultaten hieronder met slechts één HTML-element en vijf CSS-eigenschappen voor elke. Geen SVG, geen foto ‘ s (behalve de achtergrond op de root, dat is er gewoon om duidelijk te maken dat ons een HTML-element heeft een aantal transparante delen), geen JavaScript. Wat denk je dat het gaat?

De gewenste resultaten.

Goed, dit artikel gaat uit te leggen hoe om dit te doen en ook om te laten zien hoe om leuke dingen door het toevoegen van een aantal animaties.

CSS-ing het Verloop Stralen

De HTML is slechts een <div>.

<div class=’stralen’></div>

In de CSS, moeten we de afmetingen van het element en we moeten met het geven van een achtergrond, zodat wij het kunnen zien. We maken er ook circulaire het gebruik van border-radius:

.stralen {
breedte: 80vmin; height: 80vmin;
border-radius: 50%;
background: linear-gradient(#b53, #f90);
}

En… we hebben al opgebruikt vier van de vijf eigenschappen om het resultaat hieronder:

Zie de Pen door thebabydino (@thebabydino) op CodePen.

Dus wat is de vijfde? masker met een herhalend-conisch-gradient () – waarde!

Laten we zeggen dat we willen hebben 20 stralen. Dit betekent dat we moeten alloceren $p: 100%/20 van de volledige cirkel voor een ray en het gat na.

Het verdelen van de schijf in stralen en lacunes (live).

Hier houden we de hiaten tussen de stralen die gelijk is aan de stralen (dat is dus .5*$p voor een ray-of ruimte), maar we kunnen ze breder of smaller. We willen een abrupte verandering na het beëindigen van de stop positie van het ondoorzichtige deel (de straal), dus de start-stop-positie voor het transparante deel (de gap) moet gelijk zijn aan of kleiner dan het is. Dus als het laatste stop positie voor de ray is .5*$p, dan is de start-stop-positie voor de kloof kan niet groter zijn. Het kan echter kleiner zijn en dat ons helpt met de dingen eenvoudig te houden, omdat het betekent dat we kunnen gewoon de nul.

Hoe herhalen-conisch-gradient() werkt (live).

$nr: 20; // aantal stralen
$p: 100%/$nr; // procent van de cirkel toegewezen aan een ray en gap na

.stralen {
/* hetzelfde als voorheen */
masker: herhalen-conisch-gradient(#000 0% .5*$p, transparante 0% $p);
}

Merk op dat, in tegenstelling tot het lineaire en radiale verlopen, stop posities voor conische verlopen, kan niet worden eenheidloze. Ze moeten een percentage of hoekige waarden. Dit betekent dat het gebruik van iets als transparante 0 $p niet werkt, moeten we transparant 0% $p (of 0deg in plaats van 0%, het maakt niet uit wat we kiezen, het kan gewoon niet eenheidloze).

Verloop stralen (live demo, geen Edge support).

Er zijn een paar dingen om hier op te merken wanneer het gaat om de ondersteuning van:

  • Edge ondersteunt niet het maskeren van HTML-elementen op dit punt, al is dit vermeld In Ontwikkeling en een vlag voor het (dat doet niets voor nu) heeft al aangetoond in over:vlaggen.
    Het Inschakelen van CSS Maskeren vlag in de Rand.
  • conic-gradient() wordt alleen ondersteund door Knipperen browsers achter de Experimentele Web-Platform functies vlag (die kan worden ingeschakeld in chrome://flags of opera://vlaggen). Ondersteuning komt naar Safari, maar totdat dat gebeurt, Safari nog steeds is gebaseerd op de polyfill, net als Firefox.
    De Experimentele Web-Platform functies vlag ingeschakeld in Chrome.
  • WebKit browsers moeten nog steeds de -webkit – voorvoegsel voor masker eigenschappen van HTML-elementen. Je zou denken dat is geen probleem, omdat we met behulp van de polyfill die zich baseert op -prefix-gratis toch, dus als we gebruik maken van de polyfill, we need to -prefix-vrij vóór dat toch. Helaas, het is een beetje ingewikkelder dan dat. Dat komt omdat -prefix-free werkt via zijn voorzien van detectie, die niet in dit geval omdat alle browsers ondersteunen masker unprefixed… op SVG-elementen! Maar we gebruiken masker op een HTML-element hier, we zitten dus in de situatie waar WebKit browsers moet de -webkit prefix, maar -prefix-free niet toevoegen. Dus ik denk dat dat betekent dat we moeten handmatig toevoegen:
    $nr: 20; // aantal stralen
    $p: 100%/$nr; // procent van de cirkel toegewezen aan een ray en gap na
    $m: herhalen-conisch-gradient(#000 0% .5*$p, transparante 0% $p); // masker

    .stralen {
    /* hetzelfde als voorheen */
    -webkit-masker: $m;
    masker: $m;
    }

    Ik denk dat we kunnen ook gebruik maken Autoprefixer, zelfs als we moeten zijn -prefix-gratis toch, maar met beide alleen voor dit voelt een beetje als het gebruik van een geweer te doden vliegen.

Het toevoegen van een Animatie

Een koele ding over conic-gradient() wordt ondersteund in Blink browsers is dat we gebruik kunnen maken van CSS variabelen in hen (niet dat bij het gebruik van de polyfill). En CSS-variabelen kunnen nu ook worden geanimeerd Knipperen browsers met een beetje Houdini magic (we moeten de Experimentele Web-Platform functies vlag worden ingeschakeld voor dat, maar we moeten ook ingeschakeld voor native conic-gradient() ondersteuning, dus dat moet geen probleem zijn).

Ter voorbereiding van onze code voor de animatie, veranderen we onze maskeren verloop, zodat het gebruikt variabele alpha-waarden:

$m: herhalen-conisch-gradient(
rgba(#000, var (–) 0% .5*$p,
rgba(#000, calc(1 – var (–))) 0% $p);

We registreer de alpha –een aangepaste eigenschap:

CSS.registerProperty({
naam: ‘–‘,
syntaxis: ‘<aantal>’,
initialValue: 1;
})

En ten slotte voegen we in een animatie in de CSS:

.stralen {
/* hetzelfde als voorheen */
animatie: een 2s lineaire oneindige plaatsvervanger;
}

@keyframes een {{ –a: 0 } }

Dit geeft ons het volgende resultaat:

Ray alpha animatie (live demo, alleen werkt in Blink browsers met de Experimentele Web-Platform functies vlag ingeschakeld).

Meh. Ziet er niet echt geweldig. We kunnen er echter dingen meer interessant door het gebruik van meerdere alpha-waarden:

$m: herhalen-conisch-gradient(
rgba(#000, var(–a0)) 0%, rgba(#000, var(–a1)) .5*$p,
rgba(#000, var(–a2)) 0%, rgba(#000, var(–a3)) $p);

De volgende stap is om te registreren van elke van deze aangepaste eigenschappen:

voor(i = 0; i < 4; i++) {
CSS.registerProperty({
naam: `–${i}`,
syntaxis: ‘<aantal>’,
initialValue: 1 – ~~(i/2)
})
}

En tot slot, voeg de animaties in de CSS:

.stralen {
/* hetzelfde als voorheen */
animatie: een 2s oneindige plaatsvervanger;
animatie-naam: a0, a1, a2, a3;
animatie-timing-functie:
/* easings van easings.net */
cubic-bezier(.57, .05, .67, .19) /* easeInCubic */,
cubic-bezier(.21, .61, .35, 1); /* easeOutCubic */
}

@$i van 0 tot en met 4 {
@keyframes een#{$i} {{ –a#{$i}: #{vloer($i/2)} } }
}

Merk op dat aangezien we de waarden voor de instelling voor aangepaste eigenschappen, moeten we interpoleren van de grond() functie.

Meerdere ray alpha animaties (live demo, alleen werkt in Blink browsers met de Experimentele Web-Platform functies vlag ingeschakeld).

Het ziet er nu een beetje meer interessant, maar zeker kunnen we het beter doen?

Laten we proberen met behulp van een CSS-variabele voor de stop-positie tussen de straal en de kloof:

$m: herhalen-conisch-gradient(#000 0% var (- p), transparante 0% $p);

Vervolgens hebben We registreren deze variabele:

CSS.registerProperty({
naam: de ‘- p’,
syntaxis: ‘<percentage>’,
initialValue: ‘0%’
})

En we animeren van de CSS met een keyframe animatie:

.stralen {
/* hetzelfde als voorheen */
animatie: p .5s lineaire oneindige alternatieve
}

@keyframes p {{ –p: #{$p} } }

Het resultaat is meer interessant in dit geval:

Afwisselend ray formaat animatie (live demo, alleen werkt in Blink browsers met de Experimentele Web-Platform functies vlag ingeschakeld).

Maar we kunnen nog steeds spice it up een beetje meer door het omkeren van het hele ding horizontaal in tussen elke herhaling, zodat het altijd omgedraaid om de omgekeerde degenen. Dit betekent niet gespiegeld wanneer –p gaat van 0% tot $p en gespiegeld wanneer –p gaat terug van $p naar 0%.

De manier waarop we spiegelen van een element horizontaal is door het toepassen van een transformatie: scalex(-1). Daar willen we dit omdraaien om te worden toegepast op het einde van de eerste iteratie en vervolgens verwijderd aan het einde van de tweede (reverse), we passen het in een keyframe animatie ook—in een met een stappen() de functie van de timing en het dubbele van het animatie-duur.

$t: .5s;

.stralen {
/* hetzelfde als voorheen */
animatie: p $t oneindige lineaire alternatieve,
s 2*$t stappen(1) oneindig;
}

@keyframes p {{ –p: #{$p} } }

@keyframes s { 50% { transform: scalex(-1); } }

Nu hebben we uiteindelijk een resultaat dat ziet er echt pretty cool:

Afwisselend ray formaat animatie met horizontaal spiegelen tussen iteraties (live demo, alleen werkt in Blink browsers met de Experimentele Web-Platform functies vlag ingeschakeld).

CSS-ing Verloop Stralen en Golven

Om de stralen en golven resultaat, moeten we een tweede gradiënt aan het masker, dit keer een herhalend-radiaal verloop().

Hoe herhalen-radiaal verloop() werkt (live).

$nr: 20;
$p: 100%/$nr;
$stop-lijst: #000 0% .5*$p, transparante 0% $p;
$m: herhalen-conisch-gradient($stop-lijst),
herhalen-radiaal verloop(dichtstbijzijnde kant, $stop-lijst);

.stralen-rimpelingen {
/* hetzelfde als voorheen */
masker: $m;
}

Helaas, het gebruik van meerdere posities stoppen werkt alleen in Blink browsers met dezelfde Experimentele Web-Platform functies vlag ingeschakeld. En terwijl de kegelsnede-gradient() polyfill dit dekt voor het herhalen-conisch-gradient (deel) in browsers ondersteunen CSS maskeren op HTML-elementen, maar niet de ondersteuning van kegelvormig verlopen native (Firefox, Safari, Blink browsers zonder de vlag ingeschakeld), niets lost het probleem voor de herhaling-radiaal verloop (deel) in deze browsers.

Dit betekent dat we gedwongen worden om wat herhaling in onze code:

$nr: 20;
$p: 100%/$nr;
$stop-lijst: #000, #000 .5*$p, transparante 0%, transparante $p;
$m: herhalen-conisch-gradient($stop-lijst),
herhalen-radiaal verloop(dichtstbijzijnde kant, $stop-lijst);

.stralen-rimpelingen {
/* hetzelfde als voorheen */
masker: $m;
}

We zijn uiteraard steeds dichterbij, maar we zijn er nog niet:

Intermediair resultaat met de twee masker lagen (live demo, geen Edge support).

Om het resultaat te krijgen die we willen, moeten we gebruik maken van het masker-samengestelde goederen en stel deze in te sluiten:

$m: herhalen-conisch-gradient($stop-lijst) uitsluiten,
herhalen-radiaal verloop(dichtstbijzijnde kant, $stop-lijst);

Merk op dat masker-composiet wordt alleen ondersteund in Firefox 53+ voor nu, hoewel Rand mag meedoen, wanneer het ten slotte ondersteunt CSS-maskeren van HTML-elementen.

XOR-stralen en golven (live demo van Firefox 53+).

Als je denkt dat het eruit ziet als de stralen en de gaten tussen de stralen zijn niet gelijk, je hebt gelijk. Dit is te wijten aan een polyfill probleem.

Het toevoegen van een Animatie

Sinds masker-composiet werkt alleen in Firefox voor nu en Firefox biedt nog geen ondersteuning voor conic-gradient() native, kunnen we niet plaatsen CSS variabelen in de herhaling-conisch-gradient() (omdat Firefox nog steeds valt terug op de polyfill en de polyfill ondersteunt geen CSS gebruik van de variabele). Maar kunnen we ze in de herhaling-radiaal verloop (), en zelfs als we dit niet doen ze met CSS keyframe animatie, wij kunnen dit doen met JavaScript!

Omdat we nu zetten CSS variabelen in de herhaling-radiaal verloop(), maar niet in de herhaling-conisch-gradient() (als de XOR-effect werkt alleen via masker-composiet, die wordt alleen ondersteund in Firefox voor nu en in Firefox niet ondersteund kegelvormige verlopen native, dus het valt terug op de polyfill, die niet de ondersteuning van CSS gebruik van de variabele), kunnen we niet gebruiken dezelfde $stop-lijst voor beide verloop lagen van ons masker meer.

Maar als we te herschrijven ons masker zonder een gemeenschappelijke $stop-lijst toch kunnen we van deze gelegenheid gebruik te maken van verschillende posities stoppen voor de twee hellingen:

// voor conisch verloop
$nc: 20;
$pc: 100%/$nc;
// voor radiaal verloop
$nr: 10;
$pr: 100%/$nr;

De CSS variabele wij animeren is een alpha –een, net als voor de eerste animatie in de stralen geval. We introduceren ook het c0 –en –c1 variabelen omdat we hier geen meerdere posities per stop en we willen om te voorkomen dat herhaling zo veel mogelijk:

$m: herhalen-conisch-gradient(#000 .5*$pc, transparante 0% $pc) uitsluiten,
herhalen-radiaal verloop(dichtstbijzijnde kant,
var(–c0), var(–c0) .5*$pr,
var(–c1) 0, var(–c1) $pr);

body {
–a: 0;
/* de lay-out, achtergrond en andere irrelevante dingen */
}

.xor {
/* hetzelfde als voorheen */
–c0: #{rgba(#000, var (–))};
–c1: #{rgba(#000, calc(1 – var (–)))};
masker: $m;
}

De alpha-variabele-een we animeren heen en weer (van 0 tot 1 en vervolgens terug naar 0) met een beetje vanille JavaScript. We beginnen met het instellen van een totaal aantal frames NF de animatie gebeurt er dan, een huidige frame index f en een actuele animatie richting dir:

const NF = 50;

laat f = 0, dir = 1;

In een update() functie, we een update van de huidige frame index f en dan zetten we de huidige vooruitgang waarde (f/NF) om de huidige alpha –. Als f heeft bereikt 0 van NF, we veranderen van de richting. Vervolgens de update () – functie wordt opnieuw aangeroepen op de volgende vernieuwing.

(update functie() {
f += dir;

document.lichaam.stijl.setProperty (‘–‘, (f/NF).toFixed(2));

if(!(f%NF)) dir *= -1;

requestAnimationFrame(update)
})();

En dat alles voor de JavaScript! We hebben nu een geanimeerde resultaat:

Rimpeling alpha animatie, lineaire (live demo, alleen werkt in Firefox 53+).

Dit is een lineaire animatie, de alpha waarde –een die wordt ingesteld om de voortgang f/NF. Maar we kunnen de timing van de functie van iets anders, zoals uitgelegd in een eerder artikel schreef ik over het emuleren van CSS timing functies met JavaScript.

Bijvoorbeeld, als we willen dat een gemak-in de vorm van de functie van de timing, stellen we de alpha-waarde te easeIn(f/NF) in plaats van slechts f/NF, waar hebben we dat easeIn() is:

functie easeIn(k, e = 1.675) {
terug Math.pow(k, e)
}

Het resultaat bij het gebruik van een ease-in de functie van de timing kan worden gezien in deze Pen werkt alleen in Firefox 53+). Als je geïnteresseerd bent in hoe we deze functie, het is allemaal uitgelegd in de eerder gelinkte artikel op timing functies.

De exacte dezelfde aanpak werkt voor easeOut() of easeInOut():

functie easeOut(k, e = 1.675) {
return 1 – Wiskunde.pow(1 – k, e)
};

functie easeInOut(k) {
terug .5*(Math.sin((k) – .5)*Wiskunde.PI) + 1)
}

Sinds we met behulp van JavaScript hoe dan ook, we kunnen de hele zaak interactieve, zodat de animatie gebeurt alleen op klik/tik op, bijvoorbeeld.

Om dit te kunnen doen, voegen we een aanvraag ID-variabele (rID), dat aanvankelijk nietig, maar dan neemt de waarde die wordt geretourneerd door requestAnimationFrame() in de update() functie. Dit stelt ons in staat om de animatie te stoppen met een stopAni() functie wanneer we willen:

/* hetzelfde als voorheen */

laat rID = null;

functie stopAni() {
cancelAnimationFrame(rID);
rID = null
};

functie-update() {
/* hetzelfde als voorheen */

if(!(f%NF)) {
stopAni();
terug
}

rID = requestAnimationFrame(update)
};

Op klik op, we stoppen een animatie dat kan worden uitgevoerd, keren de animatie richting dir en het aanroepen van de update() functie:

addEventListener(‘klik’, e => {
als(rID) stopAni();
dir *= -1;
update()
}, false);

Sinds we beginnen met het huidige frame index f zijnde 0, willen we in de positieve richting, in de richting van NF bij de eerste klik. En omdat we het omkeren van de richting op elke klik, het gevolg is dat de initiële waarde voor de richting moet worden -1 nu dus dat het wordt teruggedraaid tot +1 op de eerste klik.

Het resultaat van al het bovenstaande kan worden gezien in deze interactieve Pen (werkt alleen in Firefox 53+).

We konden ook gebruik maken van een andere alpha variabele voor elke stoppen, net zoals we dat deden in het geval van de stralen:

$m: herhalen-conisch-gradient(#000 .5*$pc, transparante 0% $pc) uitsluiten,
herhalen-radiaal verloop(dichtstbijzijnde kant,
rgba(#000, var(–a0)), rgba(#000, var(–a1)) .5*$pr,
rgba(#000, var(–a2)) 0, rgba(#000, var(–a3)) $pr);

In de JavaScript, we hebben de ease-in en ease-out timing functies:

const TFN = {
‘gemak-in’: function(k, e = 1.675) {
terug Math.pow(k, e)
},
het ‘gemak’: function(k, e = 1.675) {
return 1 – Wiskunde.pow(1 – k, e)
}
};

In de update() functie, het enige verschil met de eerste geanimeerde demo is dat we niet de waarde van slechts één CSS-variabele—we hebben nu vier verzorgen van: –a0, –a1, –a2, –a3. We doen dit in een lus, met het gemak-in functie voor degenen die zelfs indices en het gemak-out functie voor de anderen. Voor de eerste twee, de voortgang wordt gegeven door f/NF, terwijl voor de laatste twee, de voortgang wordt gegeven door 1 – f/NF. Zet dit alles in een formule, die we hebben:

(update functie() {
f += dir;

for(var i = 0; i < 4; i++) {
laat j = ~~(i/2);

document.lichaam.stijl.setProperty(
`–${i}`,
TFN[i%2 ? ‘gemak’ : ‘het gemak’](j + Wiskunde.pow(-1, j)*f/NF).toFixed(2)
)
}

if(!(f%NF)) dir *= -1;

requestAnimationFrame(update)
})();

Het resultaat is hieronder te zien:

Meerdere rimpeling alpha animaties (live demo, alleen werkt in Firefox 53+).

Net zoals voor de kegelsnede verlopen, kunnen we ook animeren van de stop positie tussen de ondoorzichtige en transparante gedeelte van het maskeren radiaal verloop. Om dit te doen, maken we gebruik van een CSS-variabele-p voor de voortgang van de stop-positie:

$m: herhalen-conisch-gradient(#000 .5*$pc, transparante 0% $pc) uitsluiten,
herhalen-radiaal verloop(dichtstbijzijnde kant,
#000, #000 calc(var (- p)*#{$pr}),
transparant 0, transparant $pr);

JavaScript is bijna identiek aan die voor de eerste alpha animatie, behalve dat we het niet bijwerken van een alpha-een variabele, maar een vooruitgang –p variabele en we gebruiken een gemak-in-out soort functie:

/* hetzelfde als voorheen */

functie easeInOut(k) {
terug .5*(Math.sin((k) – .5)*Wiskunde.PI) + 1)
};

(update functie() {
f += dir;

document.lichaam.stijl.setProperty (‘- p’, easeInOut(f/NF).toFixed(2));

/* hetzelfde als voorheen */
})();

Afwisselend rimpeling grootte animatie (live demo, alleen werkt in Firefox 53+).

We kunnen het effect interessanter als we een transparante strip voor het ondoorzichtige en wij ook animeren van de voortgang van de positie stop –p0 waar we gaan vanaf deze transparante strook aan de ondoorzichtige:

$m: herhalen-conisch-gradient(#000 .5*$pc, transparante 0% $pc) uitsluiten,
herhalen-radiaal verloop(dichtstbijzijnde kant,
transparant, transparant calc(var (p0–)*#{$pr}),
#000, #000 calc(var(–p1)*#{$pr}),
transparant 0, transparant $pr);

In de JavaScript, moeten we nu animeren twee CSS-variabelen: p0 –en –p1. We maken gebruik van een gemak-in de functie van de timing voor de eerste en een gemak-out voor de tweede. We hebben ook nog niet achteruit de animatie richting meer:

const NF = 120,
TFN = {
‘gemak-in’: function(k, e = 1.675) {
terug Math.pow(k, e)
},
het ‘gemak’: function(k, e = 1.675) {
return 1 – Wiskunde.pow(1 – k, e)
}
};

laat f = 0;

(update functie() {
f = (f + 1)%NF;

for(var i = 0; i < 2; i++)
document.lichaam.stijl.setProperty(`–p${i}`, TFN[i ? ‘gemak’ : ‘het gemak’](f/NF);

requestAnimationFrame(update)
})();

Dit geeft ons een vrij interessante resultaat:

Dubbele rimpeling grootte animatie (live demo, alleen werkt in Firefox 53+).