Animeren op hoogte: automatisch; (en andere intrinsieke maatzoekwoorden) in CSS

Gebruik de eigenschap interpolate-size of de functie calc-size() om vloeiende overgangen en animaties mogelijk te maken van lengtes naar trefwoorden voor intrinsieke grootte en terug.

Gepubliceerd: 17 september 2024

Invoering

Een veelgevraagde CSS-functie is de mogelijkheid om naar height: auto . Een kleine variatie op dat verzoek is om de eigenschap width over te zetten in plaats van de height , of om over te stappen naar een van de andere intrinsieke grootten die worden weergegeven door trefwoorden zoals min-content , max-content en fit-content .

In de volgende demo zou het bijvoorbeeld leuk zijn als de labels soepel zouden animeren naar hun natuurlijke breedte wanneer ze over de pictogrammen bewegen.

De gebruikte CSS is de volgende:

nav a {
    width: 80px;
    overflow-x: clip;
    transition: width 0.35s ease; /* 👈 Transition the width */

    &:hover,
    &:focus-visible {
        width: max-content; /* 👈 Doesn't work with transitions */
    }
}

Hoewel een transition is gedeclareerd om de width eigenschap over te zetten, en width: auto is gedeclareerd op :hover , vindt er geen vloeiende overgang plaats. In plaats daarvan is de verandering abrupt.

Animeer van en naar zoekwoorden met intrinsieke grootte met interpolate-size

Browserondersteuning

  • Chroom: 129.
  • Rand: niet ondersteund.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

De eigenschap CSS interpolate-size geeft u controle over de vraag of animaties en overgangen van zoekwoorden met intrinsieke CSS-grootte moeten worden toegestaan ​​of niet.

De standaardwaarde is numeric-only waardoor interpolatie niet mogelijk is. Wanneer u de eigenschap instelt op allow-keywords , geeft u toestemming voor interpolaties van lengtes naar trefwoorden met CSS-intrinsieke grootte in de gevallen waarin de browser die trefwoorden kan animeren.

Volgens specificatie :

  • numeric-only : Een <intrinsic-size-keyword> kan niet worden geïnterpoleerd.
  • allow-keywords : Twee waarden kunnen worden geïnterpoleerd als een ervan een <intrinsic-size-keyword> is en de andere een <length-percentage> is. […]

Omdat de eigenschap interpolate-size er een is die overerft, kunt u deze declareren op :root om de overgang naar en van trefwoorden voor intrinsieke grootte voor het hele document mogelijk te maken. Dit is de aanbevolen aanpak.

/* Opt-in the whole page to interpolate sizes to/from keywords */
:root {
    interpolate-size: allow-keywords; /* 👈 */
}

In de volgende demo wordt deze regel aan de code toegevoegd. Hierdoor werken de animaties van en naar width: auto prima (in browsers met ondersteuning):

Beperk het bereik van de opt-in door de selector te verkleinen

Als u de opt-in allow-keywords wilt beperken tot slechts een subboom van uw document, past u de selector aan van :root naar alleen het element dat u wilt targeten. Als de <header> van uw pagina bijvoorbeeld niet compatibel is met dit soort overgangen, kunt u de aanmelding als volgt beperken tot alleen het <main> -element en de onderliggende elementen:

main { /* 👈 Scope the opt-in to only <main> and its descendants */
    interpolate-size: allow-keywords;
}

Waarom staat u animatie van en naar de grootte van zoekwoorden niet standaard toe?

Een veelgehoorde feedback op dit opt-in-mechanisme is dat browsers standaard overgangen en animaties van intrinsieke grootte van trefwoorden naar lengtes zouden moeten toestaan.

De mogelijkheid om dit gedrag in te schakelen is onderzocht tijdens de ontwikkeling van de functie. De werkgroep ontdekte dat het standaard inschakelen hiervan niet achterwaarts compatibel is, omdat veel stijlbladen ervan uitgaan dat zoekwoorden met intrinsieke grootte (zoals auto of min-content ) niet kunnen worden geanimeerd. U kunt de details vinden in dit commentaar op het relevante CSS Working Group-probleem .

Daarom is de woning een opt-in. Dankzij de overervingseigenschap is het kiezen voor een heel document slechts een interpolate-size: allow-sizes declaratie op :root , zoals eerder beschreven.

Animatie van en naar trefwoorden voor intrinsieke grootte met calc-size()

Browserondersteuning

  • Chroom: 129.
  • Rand: 129.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

Een andere manier om interpolatie van en naar trefwoorden met intrinsieke grootte mogelijk te maken, is door de functie calc-size() te gebruiken. Het maakt het mogelijk wiskunde op een veilige, goed gedefinieerde manier uit te voeren op intrinsieke groottes.

De functie accepteert twee argumenten, in de volgende volgorde:

  • Een calc-size basis , die een <intrinsic-size-keyword> kan zijn, maar ook een genest calc-size() .
  • Een calc-size-berekening , waarmee u berekeningen kunt uitvoeren op basis van de calc-size-basis. Gebruik het sleutelwoord size om naar de basis van de calc-size te verwijzen.

Hier zijn enkele voorbeelden:

width: calc-size(auto, size);        // = the auto width, unaltered
width: calc-size(min-content, size); // = the min-content width, unaltered

Door calc-size() aan de originele demo toe te voegen, ziet de code er als volgt uit:

nav a {
    width: 80px;
    overflow-x: clip;
    transition: width 0.35s ease;

    &:hover,
    &:focus-visible {
        width: calc-size(max-content, size); /* 👈 */
    }
}

Visueel is het resultaat precies hetzelfde als bij gebruik van interpolate-size . In dit specifieke geval moet u dus interpolate-size gebruiken.

Waar calc-size() wel in uitblinkt, is de mogelijkheid om berekeningen uit te voeren, iets dat niet gedaan kan worden met interpolate-size :

width: calc-size(auto, size - 10px); // = The auto width minus 10 pixels
width: calc-size(min-content, size + 1rem); // = The min-content width plus 1rem
width: calc-size(max-content, size * .5);   // = Half the max-content width

Als u bijvoorbeeld wilt dat alle alinea's op een pagina de grootte krijgen van het dichtstbijzijnde veelvoud van 50px , kunt u het volgende gebruiken:

p {
    width: calc-size(fit-content, round(up, size, 50px));
    height: calc-size(auto, round(up, size, 50px));
}

Wat u met calc-size() ook kunt doen, is interpoleren tussen twee calc-size() -bestanden wanneer beide calc-size-bases identiek zijn. Ook dit is iets dat niet kan worden bereikt met interpolate-size .

#element {
    width: min-content; /* 👈 */
    transition: width 0.35s ease;

    &:hover {
        width: calc-size(min-content, size + 10px); /* 👈 */
    }
}

Waarom staat <intrinsic-size-keyword> niet toe in calc() ?

Een vraag die vaak opduikt bij calc-size() is waarom de CSS-werkgroep de functie calc() niet heeft aangepast om zoekwoorden met intrinsieke grootte te ondersteunen.

Een van de redenen hiervoor is dat u bij het uitvoeren van berekeningen geen trefwoorden voor intrinsieke grootte mag combineren. U zou bijvoorbeeld in de verleiding kunnen komen om calc(max-content - min-content) te schrijven, wat er geldig uitziet, maar dat in werkelijkheid niet is. calc-size() dwingt correctheid af omdat het, in tegenstelling tot calc() , slechts één enkel <intrinsic-size-keyword> als eerste argument accepteert.

Een andere reden is contextbewustzijn. Sommige lay-outalgoritmen gedragen zich speciaal voor specifieke trefwoorden met intrinsieke grootte. calc-size() is expliciet gedefinieerd om een ​​intrinsieke grootte weer te geven, niet een <length> . Dankzij dit kunnen deze algoritmen calc-size(<intrinsic-size-keyword>, …) behandelen als het <intrinsic-size-keyword> , waarbij het speciale gedrag voor dat trefwoord behouden blijft.

Welke aanpak gebruiken?

In de meeste gevallen declareert u interpolate-size: allow-keywords op :root . Het is de gemakkelijkste manier om animatie van en naar zoekwoorden met intrinsieke grootte mogelijk te maken, omdat het in wezen een oneliner is.

/* Opt-in the whole page to animating to/from intrinsic sizing keywords */
:root {
    interpolate-size: allow-keywords; /* 👈 */
}

Dit stukje code is een mooie progressieve verbetering, omdat browsers die dit niet ondersteunen terugvallen op het gebruik van geen overgangen.

Als u meer gedetailleerde controle over zaken nodig heeft (zoals het uitvoeren van berekeningen) of als u een gedrag wilt gebruiken dat alleen calc-size() kan uitvoeren, kunt u uw toevlucht nemen tot het gebruik van calc-size() .

#specific-element {
    width: 50px;

    &:hover {
        width: calc-size(fit-content, size + 1em); /* 👈 Only calc-size() can do this */
    }
}

Als u calc-size() in uw code gebruikt, moet u echter fallbacks opnemen voor browsers die calc-size() niet ondersteunen. U kunt bijvoorbeeld extra groottedeclaraties toevoegen of terugvallen op functiedetectie met @supports .

width: fit-content;
width: calc-size(fit-content, size + 1em);
       /* 👆 Browsers with no calc-size() support will ignore this second declaration,
             and therefore fall back to the one on the line before it. */

Meer demo's

Hier zijn nog enkele demo's die interpolate-size: allow-keywords in hun voordeel gebruiken.

Meldingen

De volgende demo is een afsplitsing van deze @starting-style demo . De code is aangepast zodat artikelen met verschillende hoogtes kunnen worden toegevoegd.

Om dit te bereiken kiest de hele pagina voor de grootte van trefwoordinterpolatie en wordt de height van elk .item element ingesteld op auto . Anders is de code precies hetzelfde als vóór het forken.

:root {
    interpolate-size: allow-keywords; /* 👈 */
}

.item {
    height: auto; /* 👈 */

    @starting-style {
        height: 0px;
    }
}

Animeer het <details> -element

Een typisch gebruiksscenario waarbij u dit type interpolatie wilt gebruiken, is het animeren van een openbaarmakingswidget of een exclusieve accordeon terwijl deze wordt geopend. In HTML gebruik je hiervoor het <details> element.

Met interpolate-size: allow-keywords kun je behoorlijk ver komen:

@supports (interpolate-size: allow-keywords) {
    :root {
        interpolate-size: allow-keywords;
    }
    
    details {
        transition: height 0.5s ease;
        height: 2.5rem;
        
        &[open] {
            height: auto;
            overflow: clip; /* Clip off contents while animating */
        }
    }
}

Zoals u echter kunt zien, wordt de animatie alleen uitgevoerd wanneer de openbaarmakingswidget wordt geopend. Om hieraan tegemoet te komen, werkt Chrome aan de ::details-content pseudo die later dit jaar in Chrome zal verschijnen (en die in een toekomstige post zal worden behandeld). Door interpolate-size: allow-keywords en ::details-content te combineren, kun je een animatie in beide richtingen krijgen: