<details> и <summary> в HTML с помощью CSS

HTML-элементы <details> и <summary>, которые в совокупности называются виджетами раскрытия информации, нелегко стилизовать. Из-за ограничений пользователи часто создают свои собственные версии с пользовательским компонентом. Однако с развитием CSS эти элементы стало проще настраивать. В этой статье я расскажу о том, как вы можете настроить внешний вид и поведение виджета раскрытия информации.

Как <details> и <summary> работают вместе?

<details> - это HTML-элемент, который создает виджет раскрытия информации, в котором скрыта дополнительная информация. Виджет раскрытия информации обычно представлен в виде треугольного маркера, сопровождаемого некоторым текстом.

Когда пользователь нажимает на виджет или фокусируется на нем и нажимает клавишу пробела, он открывается и отображает дополнительную информацию. Треугольный маркер направлен вниз, указывая на то, что он находится в открытом состоянии:

Details Figure

У виджета раскрытия информации есть метка, которая отображается всегда и предоставляется элементом <сводка>. Это первый дочерний элемент. Если он опущен, браузер предоставляет метку по умолчанию. Обычно в нем говорится "Подробности".:

Details Summary Figure

Вы также можете указать несколько элементов после элемента <сводка> для представления дополнительной информации:

<details>
  <summary>Do you want to know more?</summary>
  <h3>Additional info</h3>
  <p>The average human head weighs around 10 to 11 pounds (approximately 4.5 to 5 kg).</p>
</details>

Оформление <details> и <summary>

Существует несколько проблем взаимодействия, которые следует учитывать при оформлении элементов <подробности> и <краткое описание>. Давайте рассмотрим основы, прежде чем перейдем к некоторым распространенным вариантам использования.

Элемент <summary> похож на элемент <li>, поскольку его стиль по умолчанию включает в себя display: list-item. Таким образом, он поддерживает свойство shorthand в стиле списка и его свойства longhand. Поддержка браузером свойств в стиле списка довольно хороша, но Safari по-прежнему отстает.

Виджет раскрытия информации содержит два псевдоэлемента для оформления его составных частей:

  1. Псевдоэлемент ::marker: Представляет собой треугольный маркер, который находится в начале <summary>. История оформления для этого немного сложная. Мы ограничены небольшим набором свойств CSS. Поддержка браузера ::marker хороша, но Safari в настоящее время не поддерживает полный набор свойств. Я расскажу об этом более подробно в разделе "Создание сводного маркера" этой статьи. Псевдоэлемент ::details-content: Представляет "Дополнительную информацию" для <details>. Это недавнее дополнение, поэтому поддержка браузеров в настоящее время ограничена Chrome

Details-Content Pseudo-Element

В следующих разделах я продемонстрирую некоторые из новых, менее известных способов настройки виджета раскрытия информации.

Анимация действий открытия и закрытия

Когда вы открываете виджет раскрытия информации, он мгновенно открывается. Моргните, и вы его пропустите!

Предпочтительнее переходить из одного состояния в другое более постепенно, чтобы показать пользователю последствия его действий. Можем ли мы добавить анимацию перехода к действиям открытия и закрытия виджета раскрытия информации? Короче говоря, да!

Чтобы анимировать это, мы хотим, чтобы высота скрытого содержимого изменялась от нуля до конечной высоты. Значение свойства height по умолчанию - auto, что позволяет браузеру вычислять высоту на основе содержимого. Анимация со значением auto была невозможна в CSS до добавления свойства interpolate-size. Хотя поддержка браузером новых функций CSS, которые нам необходимо использовать, немного ограничена - в основном, это интерполяция размера и ::details-содержимого, - это отличный пример прогрессивного улучшения. В настоящее время это будет работать в Chrome!

Вот демонстрационное видео с анимацией:

https://blog.logrocket.com/wp-content/uploads/2024/12/details-animation-.mp4

Â' 

Вот пример анимации из CodePen.

Как работает анимация раскрытия информации?

Во-первых, мы добавляем параметр interpolate-size, чтобы мы могли перейти к высоте auto:

details {
    interpolate-size: allow-keywords;
}

Далее мы хотим описать закрытый стиль. Мы хотим, чтобы содержимое "Дополнительной информации" имело нулевую высоту и чтобы содержимое не было видно, т.е. мы хотим предотвратить переполнение.

Мы используем псевдоэлемент ::details-content для определения скрытого содержимого. Я использую свойство block-size, а не height, потому что использовать логические свойства - хорошая привычка. Нам нужно включить видимость содержимого в переход, потому что браузер устанавливает видимость содержимого: скрытое для содержимого, когда оно находится в закрытом состоянии - анимация закрытия не будет работать без ее включения:

/* closed state */
details::details-content {
  block-size: 0;

  transition: content-visibility, block-size;
  transition-duration: 750ms;

  transition-behavior: allow-discrete;
  overflow: hidden;
}

Анимация по-прежнему не будет работать должным образом, поскольку свойство видимости содержимого является дискретным анимационным свойством. Это означает, что интерполяция отсутствует; браузер будет переключаться между двумя значениями, так что измененный контент будет отображаться в течение всей продолжительности анимации. Мы этого не хотим.

Если мы включим transition-behavior: allow-discrete;, значение изменится в самом конце анимации, так что мы получим наш постепенный переход.

Кроме того, мы получаем переполнение содержимого, устанавливая размер блока равным 0, когда виджет раскрытия находится в промежуточном состоянии. Мы показываем большую часть содержимого по мере его открытия. Чтобы предотвратить это, мы добавляем overflow: hidden.

Наконец, мы добавляем стиль для открытого состояния. Мы хотим, чтобы конечное состояние имело размер auto:

/* open state */
details[open]::details-content {
  block-size: auto;
}

Таковы общие сведения. Если вы предпочитаете более подробное видео-объяснение, ознакомьтесь с пошаговым руководством Кевина Пауэлла о том, как анимировать <подробности> и <краткое описание>.

Есть ли какие-либо другие соображения при анимации виджета раскрытия информации?

Виджет раскрытия информации может увеличиваться по горизонтали, если содержимое "Дополнительная информация" шире содержимого <краткое описание>. Это может привести к нежелательному смещению макета. В этом случае вы можете захотеть установить ширину для <подробности>.

Как и в случае с любой анимацией, вам следует учитывать мнение пользователей, чувствительных к движению. Вы можете использовать медиазапрос с предпочтениями по уменьшению движения, чтобы соответствовать этому сценарию:

>@media (prefers-reduced-motion) {
  /* styles to apply if a user's device settings are set to reduced motion */

   details::details-content {
      transition-duration: 0.8s; /* slower speed */
   }
}

Реализация эксклюзивной группы <подробности> (эксклюзивный аккордеон)

Распространенным шаблоном пользовательского интерфейса является компонент "гармошка". Он состоит из набора виджетов, которые можно раскрывать, чтобы показать их содержимое. Для реализации этого шаблона вам просто нужно несколько последовательных элементов <подробности>. Вы можете стилизовать их, чтобы визуально показать, что они связаны друг с другом:

<details>
    <summary>Payment Options</summary>
    <p>...</p>
</details>
<details>
    <summary>Personalise your PIN</summary>
    <p>...</p>
</details>
<details>
    <summary>How can I add an additional cardholder to my Platinum Mastercard</summary>
    <p>...</p>
</details>

Стиль по умолчанию довольно прост:

Unstyled Accordion

Каждый элемент <подробности> занимает отдельную строку. Они расположены близко друг к другу (без полей или отступов) и воспринимаются как группа из-за их близости. Если вы хотите подчеркнуть, что они сгруппированы вместе, вы можете добавить рамку и придать им те же стили фона, что и в примере ниже.:

Посмотрите набор перьев <подробнее> - аккордеон даже от rob2 (@robatronbobby) на сайте CodePen.


Вариант этого шаблона заключается в том, чтобы сделать accordion эксклюзивным, чтобы одновременно можно было открывать только один из виджетов раскрытия информации. Как только один из них будет открыт, браузер закроет другой. Вы можете создавать эксклюзивные группы с помощью атрибута name в <details>.

Имеющие одинаковое название образуют семантическую группу:

<details name="faq-accordion">
    <summary>Payment Options</summary>
    <p>...</p>
</details>
<details name="faq-accordion">
    <summary>Personalise your PIN</summary>
    <p>...</p>
</details>
<details name="faq-accordion">
    <summary>How can I add an additional cardholder to my Platinum Mastercard</summary>
    <p>...</p>
</details>

Смотрите эксклюзивную группу Pen <подробности> от rob2 (@robatronbobby) на CodePen.


Прежде чем использовать эксклюзивные приложения accordion, подумайте, полезно ли это для пользователей. Если пользователи, скорее всего, захотят использовать больше информации, им придется часто открывать элементы, что может быть неприятно.

В настоящее время эта функция поддерживается во всех современных браузерах, так что вы можете воспользоваться ею прямо сейчас.

Стилизация маркера сводки

Виджет раскрытия информации обычно представлен небольшим треугольным маркером рядом с ним. В этом разделе мы рассмотрим процесс создания этого маркера.

Маркер связан с элементом <summary>. Добавление псевдоэлемента ::marker означает, что мы можем стилизовать поле marker напрямую. Однако мы ограничены небольшим набором свойств CSS:

  • Все свойства шрифта : цвет , пробелы , вертикальное расположение текста, сочетание символов unicode и bidi, а также свойства направления содержимого Все свойства анимации и перехода

Как упоминалось ранее, <summary> похож на <li>; он поддерживает свойство standard в стиле списка и его свойства longhand. Хотя это может показаться немного запутанным, с некоторыми примерами будет проще разобраться в вариантах оформления.

Прежде чем перейти к примерам, несколько слов о поддержке браузера. На момент написания этой статьи Safari был единственным основным браузером, который не поддерживал полностью стилизацию маркера:

  • Поддержка Safari в настоящее время ограничена настройкой свойств цвета и размера шрифта псевдоэлемента ::marker. Safari поддерживает нестандартный псевдоэлемент ::-webkit-details-marker Safari вообще не поддерживает создание свойств в стиле списка. Для справки смотрите CanIUse

Изменение цвета и размера маркера

Допустим, мы хотим изменить цвет треугольного маркера на красный и увеличить его на 50%. Мы можем сделать следующее:

summary::marker {
  color: red;
  font-size: 1.5rem;
}

Customizing Details Arrow To Be Big And Red

Это должно работать во всех браузерах. Вот пример CodePen.

Регулировка расстояния между маркерами

По умолчанию маркер находится сбоку от текстового содержимого <сводка>, и они находятся в одной и той же ограничивающей рамке. Для параметра list-style-position задано значение inside (внутри). В открытом состоянии "Дополнительная информация" находится непосредственно под маркером. Возможно, вы хотите изменить интервал и выравнивание этого поля.:

Adjusted Spacing On The Summary Marker

Если мы установим для list-style-position значение outside, маркер будет находиться за пределами ограничивающей рамки <сводка>. Это позволяет нам регулировать расстояние между текстом сводки и маркером:

summary {
  list-style-position: outside;
  padding-inline-start: 1rem;
}

Вы можете увидеть это во втором примере на скриншоте выше. Вот код для этого примера.

Изменение текста/изображения маркера

Если вы хотите изменить содержимое маркера, вы можете использовать свойство content псевдоэлемента ::marker. Исходя из ваших предпочтений, вы можете присвоить ему значение text. В моем примере я использовал эмодзи "рот на молнии" для закрытого состояния и эмодзи "открытый рот" для открытого состояния:

summary::marker {
  content: '🤐 ';
  font-size: 1.2rem;
}

details[open] summary::marker {
  content: '😮 ';
}

Посмотрите ручку <подробнее> с пользовательским текстовым маркером от rob2 (@robatronbobby) на сайте CodePen.


Чтобы использовать изображение в качестве маркера, вы можете использовать свойство content псевдоэлемента ::marker или свойство list-style-image <сводка>:

summary::marker {
  content: url("arrow-circle-right.svg");

  /* you can use a data URI too */
  content: url('data:image/svg+xml,<svg height="1em" width="1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path fill="white" d="M12 16.725L16.725 12 12 7.275 10.346 8.93l1.89 1.89h-4.96v2.36h4.96l-1.89 1.89zm0 7.087q-2.45 0-4.607-.93-2.156-.93-3.75-2.525-1.595-1.593-2.525-3.75Q.188 14.45.188 12q-.002-2.45.93-4.607t2.525-3.75q1.592-1.594 3.75-2.525Q9.55.188 12 .188q2.45 0 4.607.93 2.158.93 3.75 2.525 1.593 1.593 2.526 3.75.933 2.157.93 4.607-.004 2.45-.93 4.607-.93 2.157-2.526 3.75-1.597 1.594-3.75 2.526-2.154.932-4.607.93"/></svg>');
}

/* OR */

summary {
  list-style-image: url("arrow-circle-right.svg");
}

В следующем примере мы используем для маркера два значка со стрелками из Material Symbols. Стрелка, направленная вправо, обозначает закрытое состояние, а стрелка, направленная вниз, - открытое состояние:

Посмотрите на ручку <подробнее> с SVG-маркером от rob2 (@robatronbobby) в CodePen.


Эти примеры будут работать, как и ожидалось, в Chrome и Firefox, но Safari будет игнорировать стили. Вы можете рассматривать это как постепенное улучшение и на этом закончить. Но если вы хотите, чтобы во всех браузерах отображался одинаковый вид, вы можете скрыть маркер, а затем добавить свое собственное изображение в качестве замены. Это дает вам больше свободы:

/* Removes default marker. Please consider accessibility, read below. */
summary::-webkit-details-marker {
 display: none;
}

summary {
 list-style: none;
}

Вы можете визуально указать состояние, используя новый значок-маркер, например, встроенное изображение или псевдоэлементы. <Сводка> уже (в основном) указывает на состояние развертывания/сворачивания. Поэтому, если вы используете встроенную графику, ее следует рассматривать как декоративную. Это делает пустой атрибут alt:

<!-- You can add your own image inside <summary> as a decorative element instead of the hidden marker.  -->
<details>
  <summary><img src="my-marker.png" alt>Do you want to know more?</summary>
  <div>Yes</div>
</details>

Вы также можете расположить маркер в конце <краткое описание>, если хотите:

<!-- You can place it at the end of the summary text  -->
<details>
  <summary>Do you want to know more?<img src="my-marker.png" alt></summary>
  <div>Yes</div>
</details>

Однако важно отметить, что скрытие маркера вызывает проблемы с доступом в программах чтения с экрана. В Firefox, VoiceOver, JAWS и NVDA возникает проблема с постоянным сообщением о переключенном состоянии виджета раскрытия информации, если маркер удален. К сожалению, стиль привязан к состоянию. Желательно этого не делать.

Оформление раздела "Дополнительная информация" в разделе "Подробности"

Возможно, вы захотите оформить раздел "Дополнительная информация" виджета раскрытия информации без передачи стилей в <краткое описание>. Поскольку у вас может быть переменное количество элементов внутри <details>, было бы неплохо иметь универсальное правило:

<details>
  <summary>Do you want to know more about styling the hidden section?</summary>
  <h2>Styling hidden section</h2>
  <p>Tell me more.</p>
  <div>This is a div</div>
</details>

Я предлагаю исключить элемент <summary> с помощью функции :not(). Просто имейте в виду, что это нацелено на каждый элемент, а не на содержимое как на отдельный раздел!

details > *:not(summary) {
  color: palegoldenrod;
  font-size: 0.8em;
  margin-block-start: 1rem;
}

Hidden Section Styling Using Not Function

В качестве альтернативы вы можете использовать псевдоэлемент ::details-content, который предназначен для всего раздела. Вот почему вы хотите использовать его для анимации переходов между состояниями открытия и закрытия:

/* browser support is limited */
details::details-content {
  color: palegoldenrod;
  font-size: 0.8em;
  margin-block-start: 1rem;
}

Hidden Section Styling Using ::Details-Content Pseudo Element. Only The Section Has Margin At The Start

Заметили разницу? В начале раздела есть только одно поле. Для <p> и <div> полей нет.

Недостатком использования псевдоэлемента ::details-content является то, что поддержка браузера в настоящее время ограничена Chrome.

Распространенные ошибки при оформлении виджетов раскрытия информации

  • Исторически сложилось так, что изменить тип отображения элемента <details> было невозможно. В Chrome это ограничение было снято Будьте осторожны при изменении типа отображения <summary>. Значение по умолчанию - display: list-item;; если вы измените его на display: block;, это может привести к скрытию маркера в некоторых браузерах. Это была проблема в Firefox: /* Это может привести к скрытию маркера в некоторых браузерах */ краткое описание { дисплей: блок; } Вы не можете вложить <details> Поскольку элемент <summary> имеет роль кнопки ARIA по умолчанию, он удаляет все роли из дочерних элементов. Поэтому, если вы хотите, чтобы в <сводке> был заголовок, подобный <h2>, вспомогательные технологии, такие как программы чтения с экрана, не распознают его как заголовок. Старайтесь избегать этого шаблона: <!-- h2 не рассматривается компанией assistive technologies в качестве товарного знака --> <подробности> <краткое содержание><h2>Спойлеры</h2></краткое содержание> <ol> Стивен Спилберг снимал фильм в хронологическом порядке, чтобы вызвать реальную реакцию актеров (в основном детей) на уход Инопланетянина в конце. Все эмоциональные реакции в этой последней сцене настоящие.</li> <li>Когда Инопланетянин проходит курс лечения, голос за кадром произносит: "Мальчик возвращается. Мы теряем Инопланетянина". Эту фразу произносит Мелисса Мэтисон, которая написала сценарий к фильму.</li> </ol> </details> Скрытие маркера вызывает проблемы с доступом в некоторых программах чтения с экрана. В Firefox, VoiceOver, JAWS и NVDA возникает проблема с постоянным сообщением о переключенном состоянии виджета раскрытия информации, если маркер удален

Предстоят ли еще какие-то изменения?

Недавно поступило большое предложение помочь сделать <подробнее> более настраиваемым и совместимым между браузерами. Этап 1 включает в себя часть того, что я описал в этой статье:

  1. Удалите ограничения на свойства отображения CSS, чтобы вы могли использовать другие типы отображения, такие как flex и grid Более четко укажите структуру теневого дерева. Это должно улучшить взаимодействие с Flexbox и CSS Grid Добавьте псевдоэлемент ::details-content для обращения ко второму слоту, чтобы можно было стилизовать контейнер для "Дополнительной информации" в элементе <details>

Приятная новость заключается в том, что элементы 1 и 3 из приведенного выше списка доступны в Chrome 131 (по состоянию на ноябрь 2024 года). Следующим этапом должно стать улучшение оформления маркера. Кроме того, существует ряд связанных изменений, которые помогут улучшить возможность анимации этих элементов.

Вывод

HTML-элемент <details> стало намного проще настраивать в CSS. Теперь вы можете создавать эксклюзивные группы с полной поддержкой браузера, анимировать переход состояний открытия/ закрытия в качестве прогрессивного улучшения и выполнять простую стилизацию маркера.

Отличительной чертой <подробности> является стиль маркера. Хорошей новостью является то, что существует активное предложение, которое решает эту и некоторые другие проблемы. Это должно устранить все препятствия при использовании <подробности>. В ближайшем будущем, вы wonÃ¢Â€Â™Т должны написать свой собственный виджет разглашения или использования сторонних веб-компонента! 🤞