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ścią rozmiaru wewnętrznego i zwrotnie, 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 funkcja transition jest zadeklarowana do przejścia do właściwości width, a w elementach :hover jest zadeklarowana funkcja width: auto, 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

Browser Support

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

Source

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.

Specyfikacja:

  • 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 obsługiwanych przeglądarkach):

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 tworzenia 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 domyślnym rozmiarem za pomocą calc-size()

Browser Support

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

Source

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:

  • Obliczanie rozmiaru, które może być wyrażone za pomocą funkcji <intrinsic-size-keyword> lub zagnieżdżonej funkcji 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 rozmiar wszystkich akapitów na stronie był 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 bazy rozmiaru obliczeń są identyczne. Tego też nie można osiągnąć za pomocą 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 uwzględnieniem rozmiaru wewnętrznego. 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 kontekst. 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 takimi działaniami jak wykonywanie 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 */
    }
}

Jeśli jednak użyjesz w kodzie funkcji calc-size(), musisz uwzględnić alternatywne rozwiązania dla przeglądarek, które nie obsługują funkcji 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>

Typowym przypadkiem użycia tego typu interpolacji jest animacja widżetu wyświetlającego informacje lub wyłącznie rozszerzanej zakładki 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 działa tylko wtedy, gdy otwiera się widżet informacji. 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: