Animieren zu Höhe: auto; (und andere unveränderliche Keywords zur Größenanpassung) in CSS

Mit der Eigenschaft interpolate-size oder der Funktion calc-size() können Sie fließende Übergänge und Animationen von Längen zu Keywords für die intrinsische Größenanpassung und zurück ermöglichen.

Veröffentlicht: 17. September 2024

Einführung

Eine häufig angeforderte CSS-Funktion ist die Möglichkeit, zu height: auto zu animieren. Eine leichte Abweichung dieser Anfrage besteht darin, die Eigenschaft width anstelle von height oder zu einer der anderen systeminternen Größen zu wechseln, die durch Keywords wie min-content, max-content und fit-content dargestellt werden.

In der folgenden Demo wäre es beispielsweise schön, wenn die Labels beim Bewegen des Mauszeigers auf die Symbole reibungslos auf ihre natürliche Breite animiert würden.

Hier ist das verwendete CSS:

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 */
    }
}

Obwohl eine transition für die Umstellung der width-Eigenschaft deklariert und width: auto auf :hover deklariert ist, erfolgt keine reibungslose Umstellung. Stattdessen ist die Veränderung abrupt.

Mit interpolate-size von und zu Keywords für die intrinsische Größenanpassung animieren

Unterstützte Browser

  • Chrome: 129.
  • Edge: Nicht unterstützt.
  • Firefox: Nicht unterstützt.
  • Safari: Nicht unterstützt.

Quelle

Mit der CSS-Eigenschaft interpolate-size können Sie festlegen, ob Animationen und Übergänge von CSS-internen Größen-Keywords zulässig sein sollen.

Der Standardwert ist numeric-only, wodurch keine Interpolation aktiviert wird. Wenn Sie die Eigenschaft auf allow-keywords festlegen, aktivieren Sie Interpolationen von Längen zu CSS-internen Größen-Keywords, wenn der Browser diese Keywords animieren kann.

Gemäß Spezifikation:

  • numeric-only: Ein <intrinsic-size-keyword> kann nicht interpoliert werden.
  • allow-keywords: Zwei Werte können interpoliert werden, wenn einer von ihnen ein <intrinsic-size-keyword> und der andere ein <length-percentage> ist. […]

Da die interpolate-size-Eigenschaft übernommen wird, können Sie sie für :root deklarieren, um den Übergang zu und von Keywords für die intrinsische Größenanpassung für das gesamte Dokument zu ermöglichen. Dies ist der empfohlene Ansatz.

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

In der folgenden Demo wird diese Regel dem Code hinzugefügt. Die Animationen zu und von width: auto funktionieren daher einwandfrei (in Browsern, die diese Funktion unterstützen):

Reichweite der Einwilligung einschränken, indem Sie die Auswahl eingrenzen

Wenn Sie die allow-keywords-Einwilligung auf einen untergeordneten Knoten Ihres Dokuments beschränken möchten, passen Sie die Auswahl von :root auf das Element an, auf das Sie das Targeting vornehmen möchten. Wenn das <header>-Element Ihrer Seite beispielsweise nicht mit diesen Übergängen kompatibel ist, können Sie die Aktivierung auf das <main>-Element und seine untergeordneten Elemente beschränken. Gehen Sie dazu so vor:

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

Warum ist es nicht möglich, Animationen für die Größenanpassung von Keywords standardmäßig zuzulassen?

Häufig wird uns gesagt, dass Browser standardmäßig Übergänge und Animationen von Keywords für die benutzerdefinierte Textgröße zu Längen zulassen sollten.

Die Option zum Aktivieren dieses Verhaltens wurde bei der Entwicklung der Funktion erforscht. Die Arbeitsgruppe hat festgestellt, dass eine Aktivierung standardmäßig nicht abwärtskompatibel ist, da viele Stylesheets davon ausgehen, dass Keywords mit unveränderlicher Größe (wie auto oder min-content) nicht animiert werden können. Weitere Informationen finden Sie in diesem Kommentar zum entsprechenden Problem der CSS-Arbeitsgruppe.

Daher ist die Property optional. Dank der Vererbungseigenschaft ist die Aktivierung eines gesamten Dokuments lediglich eine interpolate-size: allow-sizes-Erklärung für :root, wie bereits beschrieben.

Mit calc-size() von und zu Keywords für die intrinsische Größenanpassung animieren

Unterstützte Browser

  • Chrome: 129.
  • Edge: 129.
  • Firefox: Nicht unterstützt.
  • Safari: Nicht unterstützt.

Quelle

Eine weitere Möglichkeit, die Interpolation zwischen und von Keywords für die intrinsische Größenanpassung zu aktivieren, ist die Verwendung der calc-size()-Funktion. So können mathematische Berechnungen auf intrinsische Größen auf sichere und klar definierte Weise angewendet werden.

Die Funktion akzeptiert zwei Argumente:

  • Eine Berechnungsgrundlage, die ein <intrinsic-size-keyword>-Wert, aber auch ein verschachteltes calc-size()-Element sein kann.
  • Eine Berechnung vom Typ „calc-size“, mit der Sie Berechnungen anhand der Basis „calc-size“ durchführen können. Verwenden Sie das Schlüsselwort size, um auf die Basis für die Berechnung der Größe zu verweisen.

Hier einige Beispiele:

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

Wenn wir der ursprünglichen Demo calc-size() hinzufügen, sieht der Code so aus:

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

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

Visuell ist das Ergebnis genau das gleiche wie bei der Verwendung von interpolate-size. In diesem Fall sollten Sie interpolate-size verwenden.

calc-size() eignet sich jedoch hervorragend für Berechnungen, was mit interpolate-size nicht möglich ist:

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

Wenn Sie beispielsweise möchten, dass alle Absätze auf einer Seite auf das nächste Vielfache von 50px skaliert werden, können Sie Folgendes verwenden:

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

Mit calc-size() können Sie auch zwischen zwei calc-size()s interpolieren, wenn beide Basen der Berechnungsgröße identisch sind. Auch das ist mit interpolate-size nicht möglich.

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

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

Warum ist <intrinsic-size-keyword> in calc() nicht zulässig?

Eine häufig gestellte Frage zu calc-size() ist, warum die CSS Working Group die calc()-Funktion nicht so angepasst hat, dass sie Keywords zur benutzerdefinierten Größenänderung unterstützt.

Ein Grund dafür ist, dass Sie bei Berechnungen keine Keywords zur benutzerdefinierten Größenanpassung kombinieren dürfen. Sie könnten beispielsweise versucht sein, calc(max-content - min-content) zu schreiben, was zwar gültig aussieht, in Wirklichkeit aber nicht ist. calc-size() erzwingt die Korrektheit, da sie im Gegensatz zu calc() nur eine einzelne <intrinsic-size-keyword> als erstes Argument akzeptiert.

Ein weiterer Grund ist die Kontextsensitivität. Einige Layoutalgorithmen haben ein spezielles Verhalten für bestimmte Keywords zur benutzerdefinierten Größenanpassung. calc-size() ist explizit als intrinsische Größe definiert, nicht als <length>. So können diese Algorithmen calc-size(<intrinsic-size-keyword>, …) als <intrinsic-size-keyword> behandeln und das spezielle Verhalten für dieses Keyword beibehalten.

Welchen Ansatz verwenden?

In den meisten Fällen müssen Sie interpolate-size: allow-keywords auf :root deklarieren. Dies ist die einfachste Möglichkeit, Animationen zu und von Keywords mit unveränderlicher Größe zu aktivieren, da es sich im Wesentlichen um einen einzeiler handelt.

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

Dieser Code ist eine gute progressive Verbesserung, da Browser, die ihn nicht unterstützen, keine Übergänge verwenden.

Wenn Sie eine genauere Kontrolle über Dinge benötigen, z. B. Berechnungen, oder ein Verhalten verwenden möchten, das nur calc-size() ausführen kann, können Sie auf calc-size() zurückgreifen.

#specific-element {
    width: 50px;

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

Wenn Sie calc-size() in Ihrem Code verwenden, müssen Sie jedoch Fallbacks für Browser einschließen, die calc-size() nicht unterstützen. Beispielsweise können Sie zusätzliche Größendeklarationen hinzufügen oder auf die Featureerkennung mit @supports zurückgreifen.

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. */

Weitere Demos

Hier sind einige weitere Demos, in denen interpolate-size: allow-keywords zu ihrem Vorteil genutzt wird.

Benachrichtigungen

Die folgende Demo ist eine Fork von dieser @starting-styleDemo. Der Code wurde angepasst, damit Elemente mit unterschiedlichen Höhen hinzugefügt werden können.

Dazu wird die Keyword-Interpolation für die gesamte Seite aktiviert und die height in jedem .item-Element auf auto festgelegt. Andernfalls ist der Code genau derselbe wie vor der Fork.

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

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

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

<details>-Element animieren

Ein typischer Anwendungsfall für diese Art der Interpolation ist die Animation eines Offenlegungs-Widgets oder eines ausschließlichen Akkordeons beim Öffnen. In HTML verwenden Sie dazu das Element <details>.

Mit interpolate-size: allow-keywords können Sie ziemlich weit kommen:

@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 */
        }
    }
}

Wie Sie sehen, wird die Animation jedoch nur ausgeführt, wenn das Offenlegungs-Widget geöffnet wird. Um diesem Wunsch gerecht zu werden, arbeitet Chrome an dem Pseudo ::details-content, das im Laufe des Jahres in Chrome verfügbar sein wird und in einem späteren Post behandelt wird. Wenn Sie interpolate-size: allow-keywords und ::details-content kombinieren, können Sie eine Animation in beide Richtungen erhalten: