Animacja do wysokości: auto; (i inne kluczowe słowa dotyczące rozmiaru) w CSS

Aby włączyć płynne przejścia i animacje z słów kluczowych z długością na słowa kluczowe z właściwościami rozmiaru, użyj właściwości interpolate-size lub funkcji calc-size().

Opublikowano: 17 września 2024 r.

Wprowadzenie

Często żądaną funkcją CSS jest możliwość animacji do height: auto. Nieznaczną odmianą tej prośby jest przejście na usługę width zamiast height lub na dowolną inną właściwą wielkość reprezentowaną przez słowa kluczowe takie jak min-content, max-contentfit-content.

Na przykład w tym demo dobrze byłoby, gdyby etykiety płynnie animowały się do naturalnej szerokości po najechaniu na ikony.

Użyty kod 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 */
    }
}

Mimo że transition jest deklarowana jako element przejściowy w przypadku właściwości width, a width: auto jest deklarowana w przypadku :hover, nie następuje płynne przejście. Zamiast tego zmiana jest gwałtowna.

Animacja słów kluczowych z uwzględnieniem rozmiaru bezwzględnego za pomocą interpolate-size

Obsługa przeglądarek

  • Chrome: 129.
  • Edge: nieobsługiwane.
  • Firefox: nieobsługiwane.
  • Safari: nieobsługiwane.

Źródło

Właściwość CSS interpolate-size pozwala określić, czy animacje i przejścia z użyciem kluczowych słów dotyczących rozmiaru domyślnego w CSS mają być dozwolone.

Wartość domyślna to numeric-only, która nie umożliwia interpolacji. Gdy ustawisz tę właściwość na allow-keywords, akceptujesz interpolację z długości na słowa kluczowe z domyślnym rozmiarem CSS w przypadkach, gdy przeglądarka może animować te słowa kluczowe.

Zgodnie ze specyfikacją:

  • numeric-only: nie można interpolować wartości <intrinsic-size-keyword>.
  • allow-keywords: można interpolować 2 wartości, jeśli jedna z nich jest wartością <intrinsic-size-keyword>, a druga – <length-percentage>. […]

Właściwość interpolate-size jest dziedziczona, więc możesz ją zadeklarować w elementach :root, aby umożliwić przejście z kluczowych słów z właściwościami rozmiaru bezwzględnego w przypadku całego dokumentu. To zalecane podejście.

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

W tym pokazie reguła jest dodawana do kodu. W rezultacie animacje do i z width: auto działają prawidłowo (w przeglądarkach, które obsługują tę funkcję):

Ogranicz zasięg zgody na udział, zawężając selektor

Jeśli chcesz ograniczyć allow-keywords tylko do poddrzewa dokumentu, zmień selektor z :root na element, który chcesz uwzględnić w kierowaniu. Jeśli na przykład <header> na Twojej stronie jest niezgodny z tym typem przejść, możesz ograniczyć rejestrację do samego elementu <main> i jego potomków w ten sposób:

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

Dlaczego domyślnie nie zezwalać na animację i wymiar słów kluczowych?

W przypadku tego mechanizmu często słyszymy, że przeglądarki powinny domyślnie zezwalać na przejścia i animacje z użyciem słów kluczowych z właściwymi rozmiarami do długości domyślnie.

Opcja włączenia tego zachowania została zbadana podczas opracowywania funkcji. Grupa robocza odkryła, że włączenie tej opcji domyślnie nie jest zgodne z wsteczną kompatybilnością, ponieważ wiele arkuszy stylów zakłada, że nie można animować elementów z właściwymi rozmiarami (np. auto lub min-content). Szczegółowe informacje znajdziesz w tym komentarzu do odpowiedniego problemu w grupie roboczej CSS.

Dlatego usługa jest opcjonalna. Dzięki właściwości dziedziczenia włączenie w całym dokumencie jest tylko deklaracją interpolate-size: allow-sizes w :root, jak opisano wcześniej.

Animacja słów kluczowych z uwzględnieniem rozmiaru bezwzględnego za pomocą calc-size()

Obsługa przeglądarek

  • Chrome: 129.
  • Edge: 129.
  • Firefox: nieobsługiwane.
  • Safari: nieobsługiwane.

Źródło

Innym sposobem włączenia interpolacji do i z słów kluczowych z własną wielkością jest użycie funkcji calc-size(). Umożliwia ono bezpieczne i dobrze zdefiniowane wykonywanie obliczeń na podstawie rozmiarów wewnętrznych.

Funkcja ta przyjmuje 2 argumenty w kolejności:

  • Obiekt typu calc-size, który może być obiektem typu <intrinsic-size-keyword>, ale też zagnieżdżonym calc-size().
  • Obliczenie wielkości obliczeń, które umożliwia wykonywanie obliczeń na podstawie wielkości obliczeń. Aby odwołać się do podstawy calc-size, użyj słowa kluczowego size.

Oto przykłady:

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

Dodanie calc-size() do oryginalnego dema powoduje, że kod wygląda tak:

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

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

Wizualnie efekt jest dokładnie taki sam jak w przypadku użycia interpolate-size. W tym konkretnym przypadku należy użyć interpolate-size.

calc-size() wyróżnia się możliwością wykonywania obliczeń, których nie można wykonać za pomocą 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

Jeśli na przykład chcesz, aby wszystkie akapity na stronie miały rozmiar zbliżony do wielokrotności wartości 50px, możesz użyć tego kodu:

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

Funkcja calc-size() umożliwia też interpolację między 2 wartościami calc-size(), gdy obie mają identyczne podstawy rozmiaru obliczeń. Tego też nie można osiągnąć za pomocą usługi interpolate-size.

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

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

Dlaczego nie zezwolić na <intrinsic-size-keyword>calc()?

Pytanie, które często pojawia się w związku z funkcją calc-size(), brzmi, dlaczego grupa robocza CSS nie dostosowała funkcji calc(), aby obsługiwała słowa kluczowe z własną wielkością.

Jednym z powodów jest to, że podczas wykonywania obliczeń nie można mieszać ze sobą słów kluczowych z domyślnym rozmiarem. Możesz na przykład chcieć napisać calc(max-content - min-content), co wygląda na prawidłowe, ale w rzeczywistości tak nie jest. Funkcja calc-size() wymusza poprawność, ponieważ w przeciwieństwie do funkcji calc() jako pierwszy argument przyjmuje tylko jedną wartość funkcji <intrinsic-size-keyword>.

Innym powodem jest uwzględnianie kontekstu. Niektóre algorytmy układu działają w specyficzny sposób w przypadku określonych ściśle określonych rozmiarów słów kluczowych. Wartość calc-size() jest zdefiniowana w sposób jednoznaczny, aby reprezentować rozmiar bezwzględny, a nie <length>. Dzięki temu algorytmy mogą traktować calc-size(<intrinsic-size-keyword>, …) jako <intrinsic-size-keyword>, zachowując specjalne zachowanie tego słowa kluczowego.

Jakie podejście zastosować?

W większości przypadków należy zadeklarować interpolate-size: allow-keywords w elementach :root. Jest to najprostszy sposób włączenia animacji do i z wyszukiwania z użyciem rozmiaru domyślnego, ponieważ wymaga tylko jednej linii kodu.

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

Ten fragment kodu jest przyjemnym ulepszeniem, ponieważ przeglądarki, które go nie obsługują, nie będą używać przejść.

Jeśli potrzebujesz bardziej szczegółowej kontroli nad pewnymi działaniami, np. wykonywaniem obliczeń, lub chcesz użyć zachowania, które jest możliwe tylko dla calc-size(), możesz użyć calc-size().

#specific-element {
    width: 50px;

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

Jednak użycie w kodzie wartości calc-size() wymaga uwzględnienia wartości zastępczych dla przeglądarek, które nie obsługują wartości calc-size(). Możesz na przykład dodać deklaracje dodatkowych rozmiarów lub użyć funkcji wykrywania za pomocą atrybutu @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. */

Więcej wersji demonstracyjnych

Oto kilka demonstracji, które wykorzystują interpolate-size: allow-keywords.

Powiadomienia

Poniższe demo jest pochodną tego demo @starting-style. Kod został dostosowany, aby umożliwić dodawanie elementów o różnej wysokości.

Aby to osiągnąć, cała strona korzysta z interpolacji rozmiaru słowa kluczowego, a wartość height w każdym elemencie .item jest ustawiona na auto. W pozostałych miejscach kod jest dokładnie taki sam jak przed utworzeniem gałęzi.

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

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

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

Animowanie elementu <details>

Ten typ interpolacji jest zwykle używany do animowania widżetu wyświetlającego informacje lub ekskluzywnej harmonijki podczas jej otwierania. W HTML używasz do tego elementu <details>.

Dzięki interpolate-size: allow-keywords możesz osiągnąć wiele:

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

Jak widać, animacja jest odtwarzana tylko podczas otwierania widżetu. Aby to umożliwić, pracujemy nad pseudonimem ::details-content, który zostanie dodany do Chrome jeszcze w tym roku (omówimy go w jednym z kolejnych wpisów). Połączenie właściwości interpolate-size: allow-keywords i ::details-content umożliwia animację w obie strony: