Используйте свойство interpolate-size
или функцию calc-size()
, чтобы обеспечить плавные переходы и анимацию от длин к ключевым словам внутреннего размера и обратно.
Опубликовано: 17 сентября 2024 г.
Введение
Часто запрашиваемая функция CSS — возможность анимации по height: auto
. Небольшим вариантом этого запроса является переход к свойству width
вместо height
или к любому другому внутреннему размеру, представленному такими ключевыми словами, как min-content
, max-content
и fit-content
.
Например, в следующей демонстрации было бы неплохо, если бы метки плавно анимировались до своей естественной ширины при наведении курсора на значки.
Используемый 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 */
}
}
Несмотря на то, что transition
объявлен для перехода свойства width
, а width: auto
объявлена для :hover
, плавного перехода не происходит. Вместо этого изменения происходят резко.
Анимация к ключевым словам внутреннего размера и обратно с помощью interpolate-size
Свойство CSS interpolate-size
позволяет контролировать, следует ли разрешать анимацию и переходы ключевых слов внутреннего размера CSS или нет.
Его значение по умолчанию numeric-only
, что не позволяет интерполяцию. Устанавливая свойствоallow allow-keywords
, вы соглашаетесь на интерполяцию от длины до ключевых слов внутреннего размера CSS в тех случаях, когда браузер может анимировать эти ключевые слова.
-
numeric-only
:<intrinsic-size-keyword>
слово размера> не может быть интерполировано. -
allow-keywords
: два значения могут быть интерполированы, если одно из них —<intrinsic-size-keyword>
, а другое —<length-percentage>
. […]
Поскольку свойство interpolate-size
является наследуемым, вы можете объявить его в :root
, чтобы обеспечить переход к ключевым словам внутреннего размера и обратно для всего документа. Это рекомендуемый подход.
/* Opt-in the whole page to interpolate sizes to/from keywords */
:root {
interpolate-size: allow-keywords; /* 👈 */
}
В следующей демонстрации это правило добавлено в код. В результате анимация по width: auto
и обратно работает нормально (в браузерах с поддержкой):
Ограничьте охват подписки, сузив селектор.
Если вы хотите ограничить возможность allow-keywords
только поддеревом вашего документа, настройте селектор с :root
только на тот элемент, на который вы хотите ориентироваться. Например, если <header>
вашей страницы несовместим с этими типами переходов, вы можете ограничить согласие только элементом <main>
и его потомками следующим образом:
main { /* 👈 Scope the opt-in to only <main> and its descendants */
interpolate-size: allow-keywords;
}
Почему бы не разрешить анимацию изменения размера ключевых слов по умолчанию?
Обычный отзыв об этом механизме согласия заключается в том, что браузеры по умолчанию должны просто разрешать переходы и анимацию от ключевых слов внутреннего размера к длинам.
Возможность включения этого поведения была исследована во время разработки этой функции. Рабочая группа обнаружила, что включение этого параметра по умолчанию не обеспечивает обратной совместимости, поскольку многие таблицы стилей предполагают, что ключевые слова внутреннего размера (такие как auto
или min-content
) не могут быть анимированы. Подробности вы можете найти в этом комментарии к соответствующему вопросу Рабочей группы CSS .
Таким образом, собственность является добровольной. Благодаря свойству наследования выбор всего документа — это просто объявление interpolate-size: allow-sizes
в :root
как подробно описано ранее.
Анимация для ключевых слов внутреннего размера и обратно с помощью calc-size()
Другой способ включить интерполяцию к ключевым словам внутреннего размера и обратно — использовать функцию calc-size()
. Это позволяет выполнять математические вычисления с внутренними размерами безопасным и четко определенным способом.
Функция принимает два аргумента по порядку:
- Базис Calc-size , который может быть
<intrinsic-size-keyword>
, но также и вложеннымcalc-size()
. - Расчет расчетного размера , позволяющий выполнять расчеты на основе расчетного размера. Чтобы обратиться к базе расчета размера, используйте ключевое слово
size
.
Вот несколько примеров:
width: calc-size(auto, size); // = the auto width, unaltered
width: calc-size(min-content, size); // = the min-content width, unaltered
Если добавить calc-size()
в исходную демонстрацию, код будет выглядеть следующим образом:
nav a {
width: 80px;
overflow-x: clip;
transition: width 0.35s ease;
&:hover,
&:focus-visible {
width: calc-size(max-content, size); /* 👈 */
}
}
Визуально результат точно такой же, как и при использовании interpolate-size
. Итак, в этом конкретном случае вам следует использовать interpolate-size
.
В чем calc-size()
действительно хорош, так это в его способности выполнять вычисления, чего нельзя сделать с помощью 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
Например, если вы хотите, чтобы все абзацы на странице имели размер, кратный 50px
, вы можете использовать следующее:
p {
width: calc-size(fit-content, round(up, size, 50px));
height: calc-size(auto, round(up, size, 50px));
}
calc-size()
также позволяет вам интерполировать между двумя calc-size()
, когда обе их базы Calc-размера идентичны. Этого тоже нельзя достичь с помощью interpolate-size
.
#element {
width: min-content; /* 👈 */
transition: width 0.35s ease;
&:hover {
width: calc-size(min-content, size + 10px); /* 👈 */
}
}
Почему бы не разрешить <intrinsic-size-keyword>
в calc()
?
Вопрос, который обычно возникает при использовании calc-size()
заключается в том, почему рабочая группа CSS не настроила функцию calc()
для поддержки внутренних ключевых слов определения размера.
Одна из причин этого заключается в том, что вам не разрешено смешивать и сопоставлять ключевые слова внутреннего размера при выполнении вычислений. Например, у вас может возникнуть соблазн написать calc(max-content - min-content)
, который выглядит корректным, но на самом деле это не так. calc-size()
обеспечивает корректность, поскольку он, в отличие от calc()
, принимает только одно единственное <intrinsic-size-keyword>
в качестве первого аргумента.
Другая причина — контекстная осведомленность. Некоторые алгоритмы макета имеют особое поведение для определенных ключевых слов внутреннего размера. calc-size()
явно определен для представления внутреннего размера, а не <length>
. Благодаря этому эти алгоритмы могут обрабатывать calc-size(<intrinsic-size-keyword>, …)
как <intrinsic-size-keyword>
, сохраняя свое особое поведение для этого ключевого слова.
Какой подход использовать?
В большинстве случаев объявляйте interpolate-size: allow-keywords
в :root
. Это самый простой способ включить анимацию для ключевых слов внутреннего размера и обратно, поскольку по сути это однострочный вариант.
/* Opt-in the whole page to animating to/from intrinsic sizing keywords */
:root {
interpolate-size: allow-keywords; /* 👈 */
}
Этот фрагмент кода является хорошим прогрессивным усовершенствованием, поскольку браузеры, которые его не поддерживают, откажутся от использования переходов.
Когда вам нужен более детальный контроль над чем-то, например, выполнением вычислений, или вы хотите использовать поведение, которое может выполнять только calc-size()
, вы можете прибегнуть к использованию calc-size()
.
#specific-element {
width: 50px;
&:hover {
width: calc-size(fit-content, size + 1em); /* 👈 Only calc-size() can do this */
}
}
Однако использование calc-size()
в вашем коде потребует включения резервных вариантов для браузеров, которые не поддерживают calc-size()
. Например, добавление дополнительных объявлений размера или возврат к обнаружению функций с помощью @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. */
Больше демонстраций
Вот еще несколько демонстраций, которые используют interpolate-size: allow-keywords
в своих интересах.
Уведомления
Следующая демонстрация является ответвлением этой демонстрации @starting-style
. Код был скорректирован, чтобы можно было добавлять элементы разной высоты.
Для этого вся страница использует интерполяцию ключевых слов по размеру, а height
каждого элемента .item
устанавливается на auto
. В остальном код точно такой же, как и до разветвления.
:root {
interpolate-size: allow-keywords; /* 👈 */
}
.item {
height: auto; /* 👈 */
@starting-style {
height: 0px;
}
}
Анимируйте элемент <details>
Типичный вариант использования этого типа интерполяции — анимация виджета раскрытия или эксклюзивного аккордеона при его открытии. В HTML для этого используется элемент <details>
.
С помощью interpolate-size: allow-keywords
вы можете продвинуться довольно далеко:
@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 */
}
}
}
Однако, как вы можете видеть, анимация запускается только тогда, когда открывается виджет раскрытия. Чтобы удовлетворить эту потребность, Chrome работает над псевдо- ::details-content
, который появится в Chrome позднее в этом году (о нем будет рассказано в следующем посте). Комбинируя interpolate-size: allow-keywords
и ::details-content
, вы можете получить анимацию в обоих направлениях: