Аккордеон, faq, спойлер и другие раскрывающиеся виджеты

от автора

Аккордеон и faq

Создать аккордеон, faq, спойлер и подобное, можно при помощи Div и JavaScript.
Но лучше: Details и Summary

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

  1. Людям с ограниченными возможностями проще будет пользоваться вашим сайтом! Их софт (скринридеры и подобное) прекрасно понимает html5 теги и будет правильно обрабатывать их и правильно информировать людей о содержимом.
  2. Улучшится связанность текста, и поисковики смогут более качественно индексировать сайт, так как будут лучше понимать, как связаны между собой видимый и скрытый текст.
  3. Будет доступно управление элементами с клавиатуры и других устройств.
  4. Уменьшается количество javascript кода, который нужно подгружать, что увеличивает скорость загрузки страницы, скорость обработки и корректность.
  5. Улучшаются показатели в Lighthouse, Google PageSpeed и других подобных инструментах.
  6. Работает при выключенном javascript.


Минус:

  1. Старые браузеры не знают таких тегов и не будут скрывать информацию.

HTML:

<details>     <summary>Покажи-скрой меня</summary>     <p>Скандинавская мифология — мифология древних скандинавов</p> </details> <details open>     <summary>Покажи-скрой меня 2</summary>     <p>Основным источником сведений о ней являются тексты поэтической </p> </details> <details>     <summary>Покажи-скрой меня 3</summary>     <p>Скандинавская мифология — мифология древних скандинавов</p> </details> 

Простой пример Details/Summary

Демонстрация:

С одной стороны выглядит не очень красиво, с другой стороны нейтрально и легко может вписаться во многие дизайны. Кстати, дефолтный вид тега Details очень похож на спойлер от хабра, только нужно чуть перекрасить, сделать подчеркивание и получим семантически правильный, без javascript и дивов, хабровский спойлер.

Спойлер от Хабра

К сожалению, у дефолтного маркера есть два недостатка:

  1. Старые браузеры его не видят.
  2. Вебкит баузеры не позволяют менять символ маркера.

По этой причине, дефолтный маркер надо спрятать и создать свой.

Рассмотрим первый пример Details/Summary с измененным текстовым маркером:

Details/Summary с измененным текстовым маркером

CSS:

summary::-webkit-details-marker{display:none;} summary::-moz-list-bullet{list-style-type:none;} summary::marker{display:none;}  summary {    display:inline-block;    padding: .3em .5em .3em .4em;    font-size:1.4em;    cursor: pointer; } summary:before {     content: "+";   margin-right: .3em; } details[open] > summary:before {   content: "–"; } summary ~ * {    padding:0 1em 0 1em; } summary:focus {   outline:0;   box-shadow: inset 0 0 1px rgba(0,0,0,0.3), inset 0 0 2px rgba(0,0,0,0.3); } details{   display:block;   margin-bottom: .5rem; } 

Дефолтным маркерам делаем display:none и показываем альтернативный при помощи summary:before {content: «+»;}

summary:focus — обводка при помощи box-shadow, это нужно для клавиатуры, чтоб видно было активный элемент и можно было перемещаться клавишей таб и открывать и закрывать при помощи пробела.

Для тега summary я поставил display:inline-block — это чтоб он не растягивался на всю ширину и были кликабельными только слова, а не вся строка.

Демонстрация:

Текстовый маркер справа + простейшая анимация текста и маркера:

Details/Summary - текстовый маркер справа + простейшая анимация текста и маркера

CSS:

summary::-webkit-details-marker{display:none;} summary::-moz-list-bullet{list-style-type:none;} summary::marker{display:none;}  summary {    display:inline-block;    padding: .3em .5em .3em .4em;    font-size:1.4em;    cursor: pointer; } summary:after {     content: "+";   margin-left: .3em;   display: inline-block;   transition: transform .5s; } details[open] > summary:after {   transform: scale(1,-1); } summary ~ * {    padding:0 1em 0 1em; } summary:focus {   outline:0;   box-shadow: inset 0 0 1px rgba(0,0,0,0.3), inset 0 0 2px rgba(0,0,0,0.3); } details[open] summary ~ *{    animation: sweep .5s ease-in-out; } @keyframes sweep {   0%    {opacity: 0;}   100%  {opacity: 1;} } details{   display:block;   margin-bottom: .5rem; } 

В новом примере я использую для маркера summary:after вместо summary:before, для того чтоб он отображался справа.

Анимация маркера при помощи transform: scale(1,-1);

Всем элементам, которые находится после summary, ставлю анимацию плавного появления при помощи animation: sweep .5s ease-in-out;

Демонстрация:

Svg маркер + анимация поворота:

Details/Summary - svg маркер + анимация поворота

CSS:

summary::-webkit-details-marker{display:none;} summary::-moz-list-bullet{list-style-type:none;} summary::marker{display:none;}  summary {    display:inline-block;    padding: .3em .6em .3em 1.5em;    font-size:1.4em;    cursor: pointer;    position: relative; } summary:before {     left: .3em;   top: .4em;   color: transparent;   background: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjM0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIzNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNOC41OSAxNi4zNGw0LjU4LTQuNTktNC41OC00LjU5TDEwIDUuNzVsNiA2LTYgNnoiLz48L3N2Zz4=") no-repeat 50% 50% / 1em 1em;   width: 1em;   height: 1em;     content: "";   position: absolute;   transition: transform .5s; } details[open] > summary:before {   transform: rotateZ(90deg); } summary ~ * {    padding:0 1em 0 1em; } details[open] summary ~ *{    animation: sweep .5s ease-in-out; } @keyframes sweep {   0%    {opacity: 0;}   100%  {opacity: 1;} } summary:focus {   outline:0;   box-shadow: inset 0 0 1px rgba(0,0,0,0.3), inset 0 0 2px rgba(0,0,0,0.3); } details{   display:block;   margin-bottom: .5rem; } 

Summary:before пришлось серьезно переделать:

  1. Поставить position: absolute; left: .3em; top: .4em; width: 1em; height: 1em;
  2. Текстовому маркеру надо обязательно поставить color: transparent; иначе он будет виден.
  3. Картинку вешаем при помощи background.

Так же нужно у summary поставить отступ padding-left: 1.5em, чтоб текст и иконка не накладывались друг на друга.

Ну и добавляем transform: rotateZ(90deg) для красивого поворота стрелки.

Демонстрация:

Если нам нужна svg иконка справа, то нужно поменять summary:before и вместо left поставить right.

Для summary поставить padding-right: 1.5em;

Details/Summary - svg маркер справа + анимация поворота

CSS:

summary::-webkit-details-marker{display:none;} summary::-moz-list-bullet{list-style-type:none;} summary::marker{display:none;}  summary {    display:inline-block;    padding: .3em 1.5em .3em .6em;    font-size:1.4em;    cursor: pointer;    position: relative; } summary:before {   right: .3em;   top: .4em;   color: transparent;   background: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjM0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIzNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNOC41OSAxNi4zNGw0LjU4LTQuNTktNC41OC00LjU5TDEwIDUuNzVsNiA2LTYgNnoiLz48L3N2Zz4=") no-repeat 50% 50% / 1em 1em;   width: 1em;   height: 1em;     content: "";   position: absolute;   transition: transform .5s; } details[open] > summary:before {   transform: rotateZ(90deg); } summary ~ * {    padding:0 1em 0 1em; } details[open] summary ~ *{    animation: sweep .5s ease-in-out; } @keyframes sweep {   0%    {opacity: 0;}   100%  {opacity: 1;} } summary:focus {   outline:0;   box-shadow: inset 0 0 1px rgba(0,0,0,0.3), inset 0 0 2px rgba(0,0,0,0.3); } details{   display:block;   margin-bottom: .5rem; } 

Демонстрация:

Давайте теперь сделаем один из наиболее распространенных примеров создания аккордиона, где будет иконка слева, фон, тени, эффекты:

Аккордион - иконка слева, фон, тени, эффекты

CSS:

body{background: #edf2f7;} details{   display:block;   background: #fff;   width:400px;   box-shadow: 0 10px 15px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);   border-radius: 8px;   overflow:hidden;   margin-bottom: 1.5rem; } summary::-webkit-details-marker{display:none;} summary::-moz-list-bullet{list-style-type:none;} summary::marker{display:none;}  summary {    display:block;    padding: .3em .3em .3em 1.4em;    font-size:1.4em;    cursor: pointer;    position: relative;    border-bottom: 1px solid #e2e8f0; } summary:before {     top: .4em;   left: .3em;   color: transparent;   background: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjM0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIzNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNOC41OSAxNi4zNGw0LjU4LTQuNTktNC41OC00LjU5TDEwIDUuNzVsNiA2LTYgNnoiLz48L3N2Zz4=") no-repeat 50% 50% / 1em 1em;   width: 1em;   height: 1em;     content: "";   position: absolute;   transition: transform .5s; } details[open] > summary:before {   transform: rotateZ(90deg); } summary ~ * {    padding: 0 2em 10px 2em; } details[open] summary ~ *{    animation: sweep .5s ease-in-out; } @keyframes sweep {   0%    {opacity: 0;}   100%  {opacity: 1;} } summary:focus {   outline:0;   box-shadow: inset 0 0 1px rgba(0,0,0,0.3), inset 0 0 2px rgba(0,0,0,0.3); } 

Демонстрация:

Svg маркер справа + эффект зеркального поворота стрелки:

Аккордион - иконка справа + эффект зеркального поворота стрелки

CSS:

body{background: #edf2f7;} details{   display:block;   background: #fff;   width:400px;   box-shadow: 0 10px 15px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);   border-radius: 8px;   overflow:hidden;   margin-bottom: 1.5rem; } summary::-webkit-details-marker{display:none;} summary::-moz-list-bullet{list-style-type:none;} summary::marker{display:none;}  summary {    display:block;    padding: .3em .3em .3em 1.4em;    font-size:1.4em;    cursor: pointer;    position: relative;    border-bottom: 1px solid #e2e8f0; } summary:before {     top: .4em;   left: .3em;   color: transparent;   background: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjM0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIzNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNOC41OSAxNi4zNGw0LjU4LTQuNTktNC41OC00LjU5TDEwIDUuNzVsNiA2LTYgNnoiLz48L3N2Zz4=") no-repeat 50% 50% / 1em 1em;   width: 1em;   height: 1em;     content: "";   position: absolute;   transition: transform .5s; } details[open] > summary:before {   transform: rotateZ(90deg); } summary ~ * {    padding: 0 2em 10px 2em; } details[open] summary ~ *{    animation: sweep .5s ease-in-out; } @keyframes sweep {   0%    {opacity: 0;}   100%  {opacity: 1;} } summary:focus {   outline:0;   box-shadow: inset 0 0 1px rgba(0,0,0,0.3), inset 0 0 2px rgba(0,0,0,0.3); } 

Демонстрация:

Теперь вы можете создавать красивые аккордионы, спойлеры и faq, без JavaScript, на чистом HTML5 и CSS.

Прежде чем убирать outline, 100 раз подумайте, чем вы можете его заменить, чтоб человек мог видеть фокус и мог перемещаться с клавиатуры или других устройств.

Если вам нужно, чтоб при открытии одного спойлера, закрывались остальные, то придется применить javascript, ниже привожу пример простого JS кода, который решит эту проблему.

JavaScript:

var details = document.querySelectorAll("details"); for(i=0;i<details.length;i++) {   details[i].addEventListener("toggle", accordion); } function accordion(event) {   if (!event.target.open) return;     var details = event.target.parentNode.children;     for(i=0;i<details.length;i++) {       if (details[i].tagName != "DETAILS" ||           !details[i].hasAttribute('open') ||           event.target == details[i]) {          continue;       }       details[i].removeAttribute("open");     } } 

Демонстрация:

Таблица поддержки Details/Summary браузерами.

С вами был разработчик конструктора лэндингов cPortfolio!


ссылка на оригинал статьи https://habr.com/ru/post/465623/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *