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 angefragte CSS-Funktion ist die Möglichkeit, height: auto zu animieren. Eine kleine Abwandlung dieser Anfrage besteht darin, die Property width anstelle von height zu verwenden oder zu einer der anderen intrinsischen 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

Browser Support

  • Chrome: 129.
  • Edge: 129.
  • Firefox: not supported.
  • Safari: not supported.

Source

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. Daher funktionieren die Animationen zu und von width: auto in Browsern mit Unterstützung einwandfrei:

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

Wenn Sie die Einwilligung für allow-keywords 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 wird die Animation von und zu Größen-Keywords nicht standardmäßig zugelassen?

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 während der Entwicklung der Funktion untersucht. Die Arbeitsgruppe hat festgestellt, dass die Standardaktivierung nicht abwärtskompatibel ist, da in vielen Stylesheets davon ausgegangen wird, dass Keywords für die intrinsische Größenänderung (z. B. 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

Browser Support

  • Chrome: 129.
  • Edge: 129.
  • Firefox: not supported.
  • Safari: not supported.

Source

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 calc-size-Basis, die eine <intrinsic-size-keyword> oder auch eine verschachtelte calc-size() 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 also interpolate-size verwenden.

calc-size() eignet sich 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 sollten Sie interpolate-size: allow-keywords auf :root deklarieren. Das ist die einfachste Möglichkeit, die Animation von und zu Keywords für die benutzerdefinierte Größe zu aktivieren, da es sich im Grunde 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 detailliertere Kontrolle über bestimmte Dinge benötigen, z. B. Berechnungen, oder ein Verhalten verwenden möchten, das nur calc-size() bietet, können Sie calc-size() verwenden.

#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. Sie können beispielsweise zusätzliche Größendeklarationen hinzufügen oder mit @supports auf die Feature-Erkennung 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 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 Widget geöffnet wird. Aus diesem Grund wird in Chrome an dem Pseudonym ::details-content gearbeitet, das später in diesem Jahr in Chrome eingeführt wird. Weitere Informationen dazu folgen in einem weiteren Beitrag. Wenn Sie interpolate-size: allow-keywords und ::details-content kombinieren, können Sie eine Animation in beide Richtungen erhalten: