Vier nieuwe CSS-functies voor vloeiende in- en uitstapanimaties

Beweging is een kernonderdeel van elke digitale ervaring en begeleidt uw gebruiker van de ene interactie naar de volgende. Maar er zijn een paar hiaten in vloeiende animaties op het webplatform. Deze omvatten de mogelijkheid om eenvoudig animaties bij binnenkomst en vertrek te animeren, en om soepel van en naar de bovenste laag te animeren voor verwijderbare elementen zoals dialogen en popovers.

Om deze hiaten op te vullen, bevatten Chrome 116 en 117 vier nieuwe webplatformfuncties, die vloeiende animaties en overgangen voor discrete eigenschappen mogelijk maken.

Deze vier nieuwe functies omvatten:

  • De mogelijkheid om display en content-visibility te animeren op een keyframe-tijdlijn (vanaf Chrome 116).
  • De eigenschap transition-behavior met het sleutelwoord allow-discrete om overgangen van discrete eigenschappen zoals display mogelijk te maken (vanaf Chrome 117).
  • De @starting-style om invoereffecten van display: none en in de bovenste laag (vanaf Chrome 117).
  • De overlay eigenschap om het gedrag van de bovenste laag tijdens een animatie te regelen (vanaf Chrome 117).

Geef animaties weer in keyframes

Vanaf Chrome 116 kunt u display en content-visibility gebruiken in sleutelframeregels. Deze zullen dan wisselen op het moment dat het keyframe optreedt. Er zijn geen aanvullende nieuwe waarden vereist om dit te ondersteunen:

.card {
  animation: fade-out 0.5s forwards;
}

@keyframes fade-out {
  100% {
    opacity: 0;
    display: none;
  }
}

In het voorgaande voorbeeld wordt de dekking gedurende een periode van 0,5 seconde naar 0 geanimeerd en vervolgens wordt de weergave op nul ingesteld. Bovendien zorgt het trefwoord forwards ervoor dat de animatie in de eindstatus blijft, zodat het element waarop het wordt toegepast, display: none en opacity: 0 .

Dit is een eenvoudig voorbeeld dat nabootst wat u met een transitie kunt doen (zie demo in de sectie Overgang ). Overgangen kunnen echter geen complexere animaties maken, zoals in het volgende voorbeeld:

.card {
  animation: spin-and-delete 1s ease-in forwards;
}

@keyframes spin-and-delete {
  0% {
    transform: rotateY(0);
    filter: hue-rotate(0);
  }
  80% {
    transform: rotateY(360deg);
    filter: hue-rotate(180deg);
    opacity: 1;
  }
  100% {
    opacity: 0;
    display: none;
  }
}

De spin-and-delete -animatie is een exit-animatie. Eerst draait de kaart op de y-as, doorloopt hij een tintrotatie en vervolgens met 80% door de tijdlijn, verandert de dekking van 1 naar 0. Ten slotte wisselt de kaart van display: block naar display: none .

Voor deze exit-animaties kunt u, in plaats van ze rechtstreeks op een element toe te passen, een trigger voor de animaties instellen. Bijvoorbeeld door een gebeurtenislistener aan een knop te koppelen die een klasse activeert om de animatie toe te passen, zoals:

.spin-out {
   animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
 document.querySelector('.card').classList.add('spin-out');
})

Het bovenstaande voorbeeld heeft nu de eindstatus display:none . Er zijn veel gevallen waarin u verder wilt gaan en het DOM-knooppunt met een time-out wilt verwijderen, zodat de animatie eerst kan worden voltooid.

Overgang van discrete eigenschappen

Eigenschappen die discreet animeren, activeren standaard geen overgangsgebeurtenissen. Om dit in te schakelen, stelt u de overgangsgedragsmodus in op allow-discrete .

De eigenschap transition-behavior

De eigenschap transition-behavior specificeert of transities wel of niet worden gestart voor discrete eigenschappen. Het accepteert twee waarden: normal en allow-discrete , waarbij de beginwaarde normal is.

  • normal : Overgangen worden niet gestart voor discrete eigenschappen, alleen voor interpoleerbare eigenschappen.
  • allow-discrete : Er worden overgangen gestart voor zowel discrete eigenschappen als interpoleerbare eigenschappen.

Om allow-discrete modus voor een specifieke eigenschap in te schakelen, neemt u deze op in de transition :

.card {
  transition: opacity 0.25s, display 0.25s allow-discrete; /* Enable allow-discrete for the display property */
}

.card.fade-out {
  opacity: 0;
  display: none;
}
Opmerking: deze overgangsdemo toont een andere techniek dan de eerste animatiedemo, maar ziet er visueel hetzelfde uit.

Wanneer u meerdere afzonderlijke eigenschappen overzet, moet u voor elke overgangseigenschap allow-discrete instellen. Bijvoorbeeld:

.card {
  transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}

Als alternatief kunt u, om het gedrag voor alle overgangseigenschappen in te stellen, transition-behavior: allow-discrete declareren na de transition . Dit is vaak de gemakkelijkste aanpak.

.card {
  transition: opacity 0.5s, display 0.5s, overlay 0.5s;
  transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}

De @starting-style voor invoeranimaties

Tot nu toe heeft dit artikel exit-animaties behandeld. Om entry-animaties te maken, moet je de @starting-style regel gebruiken.

Gebruik @starting-style om een ​​stijl toe te passen die de browser kan opzoeken voordat het element op de pagina wordt geopend. Dit is de 'before-open'-status (waarvandaan je animeert).

/*  0. IS-OPEN STATE   */
/*  The state at which the element is open + transition logic */
.item {
  height: 3rem;
  display: grid;
  overflow: hidden;
  transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}

/*  1. BEFORE-OPEN STATE   */
/*  Starting point for the transition */
@starting-style {
  .item {
    opacity: 0;
    height: 0;
  }
}

/*  2. EXITING STATE   */
/*  While it is deleting, before DOM removal in JS, apply this
    transformation for height, opacity, and a transform which
    skews the element and moves it to the left before setting
    it to display: none */
.is-deleting {
  opacity: 0;
  height: 0;
  display: none;
  transform: skewX(50deg) translateX(-25vw);
}

Nu heb je zowel een entry- als een exit-status voor deze TODO-lijstitems:

Animatie van elementen van en naar de bovenste laag

Om elementen van en naar de bovenste laag te animeren, specificeert u de @starting-style in de status "open" om de browser te vertellen waar vandaan moet worden geanimeerd. Voor een dialoog wordt de open status gedefinieerd met het [open] attribuut. Gebruik voor een popover de :popover-open pseudo-klasse.

Een eenvoudig voorbeeld van een dialoogvenster zou er als volgt uit kunnen zien:

/*   0. IS-OPEN STATE   */
dialog[open] {
  translate: 0 0;
}

/*   1. BEFORE-OPEN STATE   */
@starting-style {
  dialog[open] {
    translate: 0 100vh;
  }
}

/*   2. EXIT STATE   */
dialog {
  transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
  translate: 0 100vh;
}

In het volgende voorbeeld zijn de entry- en exit-effecten verschillend. Ga naar binnen door vanaf de onderkant van de viewport naar boven te animeren en verlaat het effect naar de bovenkant van de viewport. Het is ook geschreven met geneste CSS voor meer visuele inkapseling.

Wanneer u een popover animeert, gebruikt u de :popover-open pseudo-klasse in plaats van het eerder gebruikte open -attribuut.

.settings-popover {
  &:popover-open {
    /*  0. IS-OPEN STATE  */
    /*  state when popover is open, BOTH:
        what we're transitioning *in* to 
        and transitioning *out* from */
    transform: translateY(0);
    opacity: 1;

    /*  1. BEFORE-OPEN STATE  */
    /*  Initial state for what we're animating *in* from, 
        in this case: goes from lower (y + 20px) to center  */
    @starting-style {
      transform: translateY(20px);
      opacity: 0;
    }
  }
  
  /*  2. EXIT STATE  */
  /*  Initial state for what we're animating *out* to , 
      in this case: goes from center to (y - 50px) higher */
  transform: translateY(-50px);
  opacity: 0;
  
  /*  Enumerate transitioning properties, 
      including display and allow-discrete mode */
  transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}

overlay eigenschap

Als u ten slotte een popover of dialog uit de bovenste laag wilt vervagen, voegt u de eigenschap overlay toe aan uw lijst met overgangen. popover en dialog ontsnappen aan voorouderclips en transformaties, en plaatsen de inhoud ook in de bovenste laag. Als u overlay niet overschakelt, wordt uw element onmiddellijk weer geknipt, getransformeerd en bedekt, en ziet u de overgang niet gebeuren.

[open] {
  transition: opacity 1s, display 1s allow-discrete;
}

Neem in plaats daarvan overlay op in de overgang of animatie om overlay samen met de rest van de functies te animeren en ervoor te zorgen dat deze tijdens het animeren in de bovenste laag blijft. Dit zal er veel soepeler uitzien.

[open] {
  transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}

Als u meerdere elementen open heeft in de bovenste laag, helpt overlay u bovendien de vloeiende overgang in en uit de bovenste laag te regelen. Je kunt het verschil zien in dit eenvoudige voorbeeld . Als u bij het overbrengen geen overlay op de tweede popover toepast, zal deze eerst uit de bovenste laag komen en achter de andere popover springen voordat de overgang wordt gestart. Dit is geen erg vloeiend effect.

Een opmerking over weergaveovergangen

Als u DOM-wijzigingen aanbrengt, zoals het toevoegen en verwijderen van elementen uit de DOM, zijn weergaveovergangen een andere geweldige oplossing voor vloeiende animaties. Hier zijn twee van de bovenstaande voorbeelden gebouwd met behulp van weergaveovergangen.

In deze eerste demo zullen weergaveovergangen, in plaats van @starting-style en andere CSS-transformaties in te stellen, de overgang afhandelen. De weergaveovergang is als volgt opgezet:

Geef eerst in CSS elke kaart een individuele view-transition-name .

.card-1 {
  view-transition-name: card-1;
}

.card-2 {
  view-transition-name: card-2;
}

/* etc. */

Verpak vervolgens in JavaScript de DOM-mutatie (in dit geval het verwijderen van de kaart) in een weergaveovergang.

deleteBtn.addEventListener('click', () => {
  // Check for browser support
  if (document.startViewTransition) {
    document.startViewTransition(() => {
      // DOM mutation
      card.remove();
    });
  } 
  // Alternative if no browser support
  else {
    card.remove();
  }
})

Nu kan de browser de fade-out en morph van elke kaart naar zijn nieuwe positie afhandelen.

Een ander voorbeeld waar dit handig kan zijn is de demo voor het toevoegen/verwijderen van lijstitems. In dit geval moet u er rekening mee houden dat u voor elke gemaakte kaart een unieke view-transition-name moet toevoegen.

Conclusie

Deze nieuwe platformfuncties brengen ons een stap dichter bij soepele in- en uitstapanimaties op het webplatform. Bekijk deze links voor meer informatie: