- Animate «details» tag with pure CSS
- Плавные спойлеры (HTML5 & CSS3)
- Принцип работы тега «details»
- Как создать спойлеры
- HTML-разметка
- Frequently asked questions
- Изменение стандартного маркера
- Добавление маркера и эффектов перехода
- Решение проблем кроссбраузерности
- Пример CSS-спойлеров
- В заключение
- How to fully animate the details HTML element with only CSS, no JavaScript
- The CSS Solution
- The HTML
- A note about Firefox browser
Animate «details» tag with pure CSS
Hello! I saw a post with the title «HTML can do that?» and here the dev user added the
The
The content of a
@keyframes open 0% opacity: 0; margin-left: -20px> 100% opacity: 1; margin-left: 0px> >
Here you can see the result: This is a super simple animation you can add to your projects and the result is pretty nice!
Плавные спойлеры (HTML5 & CSS3)
Существует несколько основных вариантов создания спойлеров, показывающих или скрывающих контент по требованию пользователя: посредством JavaScript, через псевдокласс с таргетированием идентификаторов и при помощи интерфейсных флажков. Благодаря специальному HTML5-элементу к этому списку добавился еще один, наиболее простой и правильный с точки зрения семантики способ реализовать спойлеры.
Принцип работы тега «details»
Элемент представляет собой одно из многочисленных семантических нововведений HTML5 и предназначается для хранения контента, отображаемого или скрываемого по желанию пользователя. В отличие от традиционных методов разработки спойлера через и псевдокласса :checked или посредством id элемента и псевдокласса :target , для корректной работы элемента не требуется добавление стороннего HTML и CSS кода, что делает его использование простым и удобным.
Содержимое тега становится видимым, когда у него появляется атрибут open , который автоматически добавляется или удаляется браузером при клике по — заголовку спойлера. В свою очередь, заголовок должен стоять первым среди дочерних элементов, но его наличие не является обязательным. В случае отсутствия заголовка браузер установит стандартное название «подробности» из Shadow DOM, однако такой тег не пройдет валидацию. Это аналогично ситуации, когда не имеет .
--> Название
Открываемый по требованию контент
Элемент может содержать после своего заголовка блочный или строчный контент, принадлежащий к категории основной поточной информации (flow content). Содержимое, указанное после , как могло бы показаться, не будет отображаться и скрываться средствами CSS, а именно — переключением значения display . Браузер переносит его в необходимое место за счёт манипуляций с Shadow DOM, что делает возможным применить к контенту эффекты перехода ( transition ). Иными словами, в примере выше при отсутствии у спойлера атрибута open , для элемента
правило display: none не применяется.
Не смотря на кажущуюся практичность и тривиальность, элемент не лишён недостатков: отсутствие полной кроссбраузерной поддержки (речь идет об ограничениях в Internet Explorer, Edge и игнорирование Opera Mini) и непрезентабельное стандартное со (простой маркер перед заголовком , отсутствие анимации), поэтому при создании спойлеров необходимо учесть эти аспекты.
Как создать спойлеры
Прежде чем приступить к разметке кода и написанию CSS, важно обозначить три принципа, которым должно соответствовать красивое оформление спойлера:
- Спойлеру необходимо выглядеть визуально интерактивным. Пользователь должен без особого труда понимать, что элемент является кликабельным;
- Для визуально привлекательного плавного отображения и скрытия контента к спойлеру следует добавить эффекты перехода;
- Открытый спойлер должен каким бы то ни было образом выделяться, чтобы сфокусировать внимание читателя на себе среди прочих неактивных, если на странице расположены несколько спойлеров подряд.
HTML-разметка
Предположим, необходимо создать такую популярную секцию для сайта, как небольшой раздел FAQ, где ответ появлялся бы после клика на сам вопрос. Для этого потребуется следующий незамысловатый HTML:
Frequently asked questions
Question #1
Answer #1
Question #2
Answer #2
Question #3
Answer #3
По умолчанию атрибут tabindex для заголовков не обязателен, но пригодится в дальнейшем для обеспечения работы спойлеров в браузерах, которые не поддерживают этот элемент. Дочерний в заголовках послужит для косметических улучшений.
Изменение стандартного маркера
Основную сложность при добавлении CSS может вызвать изменение стиля для маркера, стоящего перед заголовком спойлера. В браузерах на движке WebKit для стилизации маркеров существует специальный псевдоэлемент ::-webkit-details-marker , в то время как Firefox отображает этот элемент как часть списка, то есть с правилом display: list-item , что, соответственно, позволяет удалить маркер простой сменой свойства display или же через псевдоэлемент ::-moz-list-bullet :
summary < &::-webkit-details-marker < display: none; >&::-moz-list-bullet < list-style-type: none; >// display: block; - не всегда уместно >
Использование display: block в данном случае приведет к нежелательному последствию: кликабельная область содержимого заголовка растянется на 100% ширины родительского элемента, а в идеале она должна соответствовать ширине собственного контента, поэтому в зависимости от необходимости рекомендуется прибегнуть к значениям display , например, inline , inline-block inline-flex , table или оставить заголовок как блочный и установить ширину содержимого как max-content или fit-content , но далеко не все браузеры поддерживают такие значения для width .
Добавление маркера и эффектов перехода
Когда стандартный маркер удалён, к спойлеру может быть добавлено собственное изображение через псеводоэлемент ::before . В готовом примере для этого используется SVG-иконка из коллекции Google Material Icons, которая выводится через background-image в base64, что позволяет избежать лишних подключений к внешним ресурсам.
Особую трудность при стилизации спойлеров представляют эффекты перехода, которые должны срабатывать как при открытии, так и при закрытии контента. Для их реализации следует использовать свойство transition , в основе которого будет лежать изменяющаяся минимальная и максимальная высота спойлера, т. е. самого элемента и прозрачность — для всего контента, стоящего после :
// Иконка маркера в base64 $img-marker: 'data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjM0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIzNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNOC41OSAxNi4zNGw0LjU4LTQuNTktNC41OC00LjU5TDEwIDUuNzVsNiA2LTYgNnoiLz48L3N2Zz4='; details < // Косметические улучшения position: relative; margin-bottom: .5rem; min-height: 1rem; max-height: 3rem; transition: min-height .15s linear, max-height .5s linear; -webkit-transition: min-height .15s linear, max-height .15s linear; overflow: hidden; // Заголовок summary < // Удаление стандартного маркера &::-webkit-details-marker < display: none; >&::-moz-list-bullet < list-style-type: none; >// Ограничение кликабельной области заголовка display: inline-block; // Пространство для маркера padding-left: 1.5em; // Косметические улучшения cursor: pointer; outline: 0; transition: color .12s; -webkit-transition: color .12s; span < border-bottom: 1px currentColor dotted; >&:hover < color: #d06c6c; >// Добавление маркера &::before < content: ""; left: 0; top: .4em; position: absolute; background: url($img-marker) no-repeat 50% 50% / 1em 1em; width: 1em; height: 1em; transition: transform .1s linear; -webkit-transition: transform .1s linear; >// Контент, стоящий после заголовка & ~ * < padding-left: 1.5em; opacity: 0; transition: opacity .15s linear; -webkit-transition: opacity .15s linear; >> // Открытый спойлер &[open] < min-height: 2em; max-height: 20em; summary < color: #d06c6c; & ~ * < opacity: 1; >&:before < transform: rotate(90deg); -webkit-transform: rotate(90deg); -moz-transform: rotate(90deg); >> > >
Решение проблем кроссбраузерности
Для обеспечения правильной работы спойлеров в Internet Explorer 10+ и Edge силами одного лишь CSS предлагается совместить и псевдокласс :focus таким образом, чтобы содержимое спойлера появлялось при появлении фокуса на заголовке. Чтобы применить указанный псевдокласс к заголовкам, в HTML-разметке они должны содержать упомянутый ранее атрибут tabindex . Кроме того, браузеры от Microsoft не знают тега и не добавляют к нему атрибут open при клике, поэтому часть CSS придется дублировать. Весь полученный код скрывается от прочих браузеров:
// Фикс для IE 10-11 & Edge @mixin ie_fix() < details < max-height: none; summary < & ~ * < max-height: 0; overflow: hidden; position: absolute; // IE испытывает проблемы с обычным max-height: 0; >&:focus < color: #d06c6c; &::before < transform: rotate(90deg); -ms-transform: rotate(90deg); >& ~ * < max-height: 20em; position: static; opacity: 1; >> > > > // IE 10-11 @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) < @include ie_fix(); >// Edge @supports (-ms-ime-align:auto)
Этот фикс содержит небольшое функциональное ограничение: на странице нельзя будет открыть одновременно несколько спойлеров, т.к. фокус действует только на один элемент. Кроме того, в результате подобной реализации теряется плавный переход при открытии спойлера, но остается работать эффект прозрачности. При необходимости посредством CSS-хака миксин ie_fix() может быть добавлен и для старой Opera 12 (Presto) .
Пример CSS-спойлеров
В результате объединения всего SCSS и добавления соответствующей HTML-разметки получаются простые кроссбраузерные спойлеры без использования JS.
В заключение
Не смотря на преимущество с точки зрения семантики и практичности использования, тег не рекомендуется применять там, где требуется поддержка «древних» Internet Explorer и устаревших мобильных браузеров. В этом случае стоит прибегнуть к традиционным способам создания спойлеров на CSS, работающих практически везде, или использовать решения на JavaScript, в том числе HTML5-полифиллы. Остается надеется, что со временем старые браузеры окончательно уйдут в небытие и уступят место их обновленным версиям, и тогда новые семантические теги станут повсеместной практикой.
How to fully animate the details HTML element with only CSS, no JavaScript
Animating the
The CSS Solution
The key is to start the page with the details element in its open state (
details max-height: 4rem; /* Set a max-height value just enough to show the summary */ overflow: hidden; /* Hide the rest of the content */ transition: max-height 400ms ease-out; /* Animate the change */ >
input:checked + details, details:has(input:checked) max-height: 576px; /* Set a max-height value enough to show all the content */ >
In the CSS, the selector input:checked + details selects a element that immediately follows a checked input element. On the other hand, the selector details:has(input:checked) selects a element that has a checked input element as its descendant.
The HTML
The difference between the two approaches in HTML is that the checkbox input must come immediately before the element in the first approach, and the checkbox must be a descendant of the element in the second approach.
Inside the tag of the element , place a that toggles the checkbox:
type="checkbox" name="approach-one" id="approach-one" /> open> for="approach-one">This one uses the adjacent sibling combinator (+) approach class="rest-of-the-content">. open> type="checkbox" name="approach-two" id="approach-two" /> for="approach-two">This one uses :has() pseudo-class approach class="rest-of-the-content">.
A note about Firefox browser
One caveat to consider when using the :has() approach is that in Firefox the user must explicitly enable this feature (see caniuse.com and MDN Web Docs).