От автора: в этом руководстве мы создадим адаптивный макет панели администрирования с помощью CSS и немного JavaScript. Чтобы создать его, мы позаимствуем некоторые идеи из панели управления WordPress, например, ее боковое меню. В процессе создания мы столкнемся со множеством проблем, но они дадут нам хорошую практику для повышения навыков.
Что мы будем создавать
Без дальнейших предисловий, давайте посмотрим на окончательную демонстрацию панели администрирования (нажмите кнопку Collapse в нижней части боковой панели, чтобы увидеть раскрывающееся меню в действии, и посмотрите полноэкранную версию, чтобы поэкспериментировать с адаптивностью):
1. Начинаем с разметки страницы
Для начала нам понадобятся SVG, header и section:
<svg style="display:none;">...</svg> <header class="page-header">...</header> <section class="page-content">...</section>
SVG-спрайты
Как вы можете представить, нам понадобится куча иконок. К счастью, Envato Elements предоставляет постоянно расширяющуюся коллекцию полезных векторных иконок, поэтому давайте воспользуемся этой библиотекой и загрузим эти Trade and Dashboard Icons.
Вместо того, чтобы включать их непосредственно в страницу с помощью тега img или svg, давайте создадим SVG-спрайт. Для этого мы обернем все иконки в контейнер SVG. Контейнер должен быть скрытым, поэтому мы применим к нему display: none. Если мы не скроем его, в верхней части страницы появится большая пустая область.
Каждая иконка будет размещена внутри элемента symbol с уникальным идентификатором и атрибутом viewBox, который будет зависеть от размера иконки. Затем мы можем отобразить целевую иконку в любое время, вызвав элемент use (я покажу, как это делается чуть позже).
А пока давайте просто ознакомимся с разметкой, необходимой для SVG-спрайта:
<svg style="display:none;"> <symbol id="down" viewBox="0 0 16 16"> <polygon points="3.81 4.38 8 8.57 12.19 4.38 13.71 5.91 8 11.62 2.29 5.91 3.81 4.38" /> </symbol> <symbol id="users" viewBox="0 0 16 16"> <path d="M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0ZM8,15a7,7,0,0,1-5.19-2.32,2.71,2.71,0,0,1,1.7-1,13.11,13.11,0,0,0,1.29-.28,2.32,2.32,0,0,0,.94-.34,1.17,1.17,0,0,0-.27-.7h0A3.61,3.61,0,0,1,5.15,7.49,3.18,3.18,0,0,1,8,4.07a3.18,3.18,0,0,1,2.86,3.42,3.6,3.6,0,0,1-1.32,2.88h0a1.13,1.13,0,0,0-.27.69,2.68,2.68,0,0,0,.93.31,10.81,10.81,0,0,0,1.28.23,2.63,2.63,0,0,1,1.78,1A7,7,0,0,1,8,15Z" /> </symbol> <!-- more symbols here --> </svg>
И это все, что нам нужно для создания встроенного SVG-спрайта.
Header
Перейдем к макету панели администрирования, давайте посмотрим на header страницы. В нем мы определим элемент nav, который будет выполнять роль оболочки для следующих элементов:
Логотип
Кнопка Collapse, которая переключает меню на экранах мобильных устройств.
Само меню, которое будет содержать ссылки меню, два заголовка и кнопку свертывания / развертывания. Возможно, было бы более семантически верно создать два отдельных меню и размещать заголовки вне их, но вы можете использовать подход, который нравится вам.
Вот как это будет выглядеть на широких экранах (> 767 пикселей):
Структура заголовка:
<header class="page-header"> <nav> <a href="#0"> <img class="logo" src="logo.svg" alt="forecastr logo"> </a> <button class="toggle-mob-menu" aria-expanded="false" aria-label="open menu"> <svg width="20" height="20" aria-hidden="true"> <use xlink:href="#down"></use> </svg> </button> <ul class="admin-menu"> <li class="menu-heading"> <h3>Admin</h3> </li> <li> <a href="#0"> <svg> <use xlink:href="#pages"></use> </svg> <span>Pages</span> </a> </li> <!-- more list items here --> <li> <button class="collapse-btn" aria-expanded="true" aria-label="collapse menu"> <svg aria-hidden="true"> <use xlink:href="#collapse"></use> </svg> <span>Collapse</span> </button> </li> </ul> </nav> </header>
Обратите внимание на две вещи:
Как мы используем use элемент для ссылки на целевые иконки.
Атрибуты ARIA (aria-expanded, aria-label, aria-hidden) , которые мы добавляем к кнопкам переключения. Эти атрибуты помогут нам сделать компонент немного более доступным. Позже мы рассмотрим, как их значения будут обновляться в зависимости от состояния кнопки.
Section
Section будет содержать два вложенных раздела.
Section 1
Внутри первого раздела мы разместим форму поиска и некоторую информацию (имя, аватар и уведомления) о текущем вошедшем в систему пользователе. Вот его отображение на широких экранах (> 767 пикселей):
Структура Section:
<section class="search-and-user"> <form> <input type="search" placeholder="Search Pages..."> <button type="submit" aria-label="submit form"> <svg aria-hidden="true"> <use xlink:href="#search"></use> </svg> </button> </form> <div class="admin-profile"> <span class="greeting">...</span> <div class="notifications"> <span class="badge">...</span> <svg> <use xlink:href="#users"></use> </svg> </div> </div> </section>
Опять же, обратите внимание, что мы добавляем некоторые атрибуты ARIA к кнопке отправки.
Section 2
Во втором разделе, просто для того, чтобы заполнить демо-версию некоторым фиктивным контентом, мы разместим несколько заполнителей статей. Как правило, они могут содержать табличные данные, диаграммы или каналы какого-либо рода.
«Используйте максимум 5–7 различных виджетов для создания представления. В противном случае пользователю будет сложно сосредоточиться и получить четкое понимание». — Тарас Бакусевич
Вот, как панель отображается на широких экранах (> 767 пикселей):
Структура раздела:
<section class="page-content"> <section class="grid"> <article></article> <article></article> <article></article> <article></article> <article></article> <article></article> <article></article> <article></article> </section> </section>
2. Определение основных стилей
Когда разметка для панели администрирования будет готова, мы перейдем к CSS. Первый шаг, как всегда, заключается в указании некоторых переменных CSS и общих стилей сброса:
:root { --page-header-bgColor: #242e42; --page-header-bgColor-hover: #1d2636; --page-header-txtColor: #dde9f8; --page-header-headingColor: #7889a4; --page-header-width: 220px; --page-content-bgColor: #f0f1f6; --page-content-txtColor: #171616; --page-content-blockColor: #fff; --white: #fff; --black: #333; --blue: #00b9eb; --red: #ec1848; --border-radius: 4px; --box-shadow: 0 0 10px -2px rgba(0, 0, 0, 0.075); } * { padding: 0; margin: 0; box-sizing: border-box; } ul { list-style: none; } a, button { color: inherit; } a { text-decoration: none; } button { background: none; cursor: pointer; } input { -webkit-appearance: none; } button, input { border: none; } svg { display: block; } body { font: 16px/1.5 "Lato", sans-serif; }
Примечание: Для простоты я не буду рассматривать все правила CSS в руководстве. Здесь почти 400 строк CSS. Если вы хотите, вы можете проверить их все, нажав на вкладку CSS демонстрационного проекта.
3. Определение основных стилей панели администрирования
На данный момент мы готовы сосредоточиться на стилях страницы.
Стили header
Header будет элементом с фиксированной позицией. Его ширина будет 220px, а высота равна высоте окна просмотра. Если его содержимое превышает высоту области просмотра, появится вертикальная полоса прокрутки. Элемент nav будет вести себя как flex-контейнер с минимальной высотой 100%. Помните, что у него три дочерних элемента:
логотип,
кнопка переключения мобильного меню,
и меню.
Кнопка переключения будет видна только на маленьких экранах (< 768 пикселей). Вот стили, которые нам нужны:
/*CUSTOM VARIABLES HERE*/ .page-header { position: fixed; top: 0; left: 0; right: 0; bottom: 0; overflow: auto; padding-top: 20px; width: var(--page-header-width); color: var(--page-header-txtColor); background: var(--page-header-bgColor); } .page-header nav { display: flex; flex-direction: column; min-height: 100%; } .page-header .toggle-mob-menu { display: none; }
Совет: Если вы предпочитаете абсолютно позиционированный заголовок, который охватывает всю высоту страницы, добавьте следующие стили:
body { position: relative; } .page-header { position: absolute; top: 0; left: 0; height: 100%; /*Comment these styles*/ /*position: fixed; top: 0; left: 0; right: 0; bottom: 0; overflow: auto;*/ }
Стили меню
Меню будет flex-контейнером, и мы зададим для него flex: 1, чтобы оно расширялось и охватывало всю высоту родительского контейнера.
Для последнего пункта меню мы зададим margin-top: auto, потому что он должен быть расположен в самом низу меню. Это поведение будет понятнее, когда нет полосы прокрутки заголовка. Чтобы проверить это, попробуйте удалить некоторые пункты меню или посмотреть демонстрацию на большом экране.
Ссылки и кнопка внутри меню также будут действовать как flex-контейнеры, а их содержимое (текст и иконки) должны быть выровнены по вертикали.
Заголовки меню будут немного меньше по сравнению с другими элементами меню. Кроме того, мы увеличим для них расстояние между символами. Вот часть стилей меню:
/*CUSTOM VARIABLES HERE*/ .page-header .admin-menu { display: flex; flex-direction: column; flex-grow: 1; margin-top: 35px; } .page-header .admin-menu li:last-child { margin-top: auto; margin-bottom: 20px; } .page-header .admin-menu li > * { width: 100%; padding: 12px 15px; } .page-header .admin-menu a, .page-header .admin-menu button { display: flex; align-items: center; font-size: 0.9rem; transition: background 0.2s, color 0.2s; } .page-header .admin-menu .menu-heading h3 { text-transform: uppercase; letter-spacing: 0.15em; font-size: 12px; margin-top: 12px; color: var(--page-header-headingColor); }
Стили содержимого страницы
Помните, что раздел .page-content содержит два подраздела. Этот раздел будет размещен на расстоянии 220px от левого края области просмотра. Плюс мы зададим для него width: calc(100% — 220px). Обратите внимание, что значение его свойства left равно ширине заголовка. Его стили:
/*CUSTOM VARIABLES HERE*/ .page-content { position: relative; left: var(--page-header-width); width: calc(100% - var(--page-header-width)); min-height: 100vh; padding: 30px; color: var(--page-content-txtColor); background: var(--page-content-bgColor); }
Поиск и пользовательские стили
Также помните, что раздел .search-and-user содержит два элемента: форму поиска и .admin-profile. Чтобы разместить их, мы будем использовать CSS Grid. Форма поиска будет охватывать все доступное пространство, и между ней и ее смежным элементом будет зазор в 50 пикселей. Оба элемента будут выровнены вертикально.
Кнопка отправки внутри формы будет позиционирована абсолютно. Она будет содержать только декоративную иконку, и поэтому нам понадобится атрибут ARIA, который позволит программам чтения с экрана интерпретировать ее и тем самым сделать ее доступной.
Объект .admin-profile, содержащий два элемента, будет вести себя как flex-контейнер с вертикально центрированным содержимым. Элемент badge (counter) будет абсолютно позиционирован внутри своего родителя с горизонтально и вертикально центрированным содержимым. Вот часть необходимых стилей для этого раздела:
/*CUSTOM VARIABLES HERE*/ .search-and-user { display: grid; grid-template-columns: 1fr auto; grid-column-gap: 50px; align-items: center; background: var(--page-content-bgColor); margin-bottom: 30px; } .search-and-user form { position: relative; } .search-and-user form button { position: absolute; top: 50%; right: 15px; transform: translateY(-50%); } .search-and-user .admin-profile { display: flex; align-items: center; } .search-and-user .admin-profile .notifications { position: relative; } .search-and-user .admin-profile .badge { display: flex; align-items: center; justify-content: center; position: absolute; top: -10px; right: -3px; width: 18px; height: 18px; border-radius: 50%; font-size: 10px; color: var(--white); background: var(--red); }
Стили сетки
Чтобы разместить статьи панели администрирования, мы воспользуемся CSS сеткой. Мы зададим всем статьям фиксированную высоту 300 пикселей. Помимо первой и последней статей, которые будут охватывать всю ширину родительского элемента, все остальные будут частью макета из двух столбцов. Связанные стили:
/*CUSTOM VARIABLES HERE*/ .page-content .grid { display: grid; grid-template-columns: repeat(2, 1fr); grid-gap: 30px; } .page-content .grid > article { display: flex; height: 300px; background: var(--page-content-blockColor); border-radius: var(--border-radius); box-shadow: var(--box-shadow); } .page-content .grid > article:first-child, .page-content .grid > article:last-child { grid-column: 1 / -1; }
4. Переключение заголовка
Каждый раз, когда мы нажимаем кнопку «Свернуть / развернуть», состояние заголовка будет меняться.
Имейте в виду, что эта функция будет доступна только на экранах с разрешением более 767 пикселей. Для небольших экранов наш заголовок будет иметь другую компоновку, о которой мы вскоре расскажем.
При свернутом состояния заголовка тело получает класс collapsed. В этот момент происходят следующие вещи:
Заголовок сжимается. Его ширина уменьшается с 220 до 40 пикселей.
В ответ на это раздел .page-content увеличивается. В частности, его ширина меняется с width: calc(100% — 220px) на width: calc(100% — 40px). Кроме того, значение его свойства left становится 40px вместо 220px.
Логотип, заголовки меню, текст ссылок меню и текст кнопки меню исчезают.
Значении атрибутов aria-expanded и aria-label переключателя обновляется. Кроме того, его значок поворачивается на 180 градусов, поэтому он выглядит как значок расширения.
Вот код JavaScript, который реализует это поведение:
const body = document.body; const collapseBtn = document.querySelector(".admin-menu button"); const collapsedClass = "collapsed"; collapseBtn.addEventListener("click", function() { this.getAttribute("aria-expanded") == "true" ? this.setAttribute("aria-expanded", "false") : this.setAttribute("aria-expanded", "true"); this.getAttribute("aria-label") == "collapse menu" ? this.setAttribute("aria-label", "expand menu") : this.setAttribute("aria-label", "collapse menu"); body.classList.toggle(collapsedClass); });
И все связанные стили:
/*CUSTOM VARIABLES HERE*/ @media screen and (min-width: 768px) { .collapsed .page-header { width: 40px; } .collapsed .page-header .admin-menu li > * { padding: 10px; } .collapsed .page-header .logo, .collapsed .page-header .admin-menu span, .collapsed .page-header .admin-menu .menu-heading { display: none; } .collapsed .page-header .admin-menu svg { margin-right: 0; } .collapsed .page-header .collapse-btn svg { transform: rotate(180deg); } .collapsed .page-content { left: 40px; width: calc(100% - 40px); } }
5. Отображение всплывающей подсказки в пунктах меню
Теперь давайте добавим еще одну новую функцию в заголовок. Как мы уже говорили в предыдущем разделе, когда заголовок свернут, текст ссылок меню исчезнет. Это означает, что в этот момент будут видны только значки SVG. Итак, давайте отобразим всплывающую подсказку, которая поможет пользователям лучше понять, что делает каждая ссылка.
Для этого при наведении на ссылку меню (иконку) мы добавляем ей атрибут title, значение которого представляет собой обычный текст. Но опять же, это должно происходить только тогда, когда заголовок свернут и ширина окна составляет не менее 768 пикселей.
Вот соответствующий JavaScript:
const body = document.body; const menuLinks = document.querySelectorAll(".admin-menu a"); const collapsedClass = "collapsed"; for (const link of menuLinks) { link.addEventListener("mouseenter", function() { body.classList.contains(collapsedClass) && window.matchMedia("(min-width: 768px)").matches ? this.setAttribute("title", this.textContent) : this.removeAttribute("title"); }); }
6. Адаптивность
На экранах шириной до 767 пикселей наша страница будет выглядеть следующим образом:
Это большая разница с нашей боковой панелью, верно? Давайте выделим наиболее важные различия по сравнению с настольной версией:
И заголовок, и .page-content имеют position: static и width: 100%.
flex-направление для элемента nav изменяется с column на row.
Кнопка переключения мобильного меню становится видимой.
Меню абсолютно позиционировано прямо под заголовком и изначально скрыто. Оно будет отображаться каждый раз, когда мы нажимаем на кнопку переключения.
Кнопка свертывания / развертывания и элемент .greeting скрыты.
Раздел .search-and-user абсолютно позиционирован и помещен рядом с кнопкой переключения мобильного меню.
Ниже вы можете увидеть часть адаптивных стилей:
@media screen and (max-width: 767px) { .page-header, .page-content { position: static; width: 100%; } .page-header nav { flex-direction: row; } .page-header .toggle-mob-menu { display: block; } .page-header .admin-menu { position: absolute; left: 98px; top: 57px; margin-top: 0; z-index: 2; border-radius: var(--border-radius); background: var(--page-header-bgColor); visibility: hidden; opacity: 0; transform: scale(0.95); transition: all 0.2s; } .page-header .admin-menu li:last-child, .search-and-user .admin-profile .greeting { display: none; } .search-and-user { position: absolute; left: 131px; top: 10px; padding: 0; grid-column-gap: 5px; width: calc(100% - 141px); border-radius: var(--border-radius); background: transparent; } }
7. Переключение мобильного меню
Каждый раз, когда мы нажимаем на кнопку переключения, состояние меню будет меняться. Если его развернуть, оно раздвинется, и наоборот.
В расширенном состоянии тело меню получает класс mob-menu-opened. В этот момент происходят следующие вещи:
Меню отображается.
Значении атрибутов aria-expanded и aria-label переключателя обновляются. Кроме того, его иконка поворачивается на 180 градусов, и выглядит, как иконка расширения.
Вот необходимый код JavaScript:
const body = document.body; const toggleMobileMenu = document.querySelector(".toggle-mob-menu"); toggleMobileMenu.addEventListener("click", function() { this.getAttribute("aria-expanded") == "true" ? this.setAttribute("aria-expanded", "false") : this.setAttribute("aria-expanded", "true"); this.getAttribute("aria-label") == "open menu" ? this.setAttribute("aria-label", "close menu") : this.setAttribute("aria-label", "open menu"); body.classList.toggle("mob-menu-opened"); });
И связанный CSS:
.page-header .toggle-mob-menu svg { transition: transform 0.2s; } .page-header .admin-menu { transition: all 0.2s; } .mob-menu-opened .toggle-mob-menu svg { transform: rotate(180deg); } .mob-menu-opened .page-header .admin-menu { transform: scale(1); visibility: visible; opacity: 1; }
Заключение
Вот и все, ребята! Мы успешно создали полнофункциональный макет панели администрирования. Вы сможете расширить эту основу для создания интерфейсов различных видов. Надеюсь, вам понравилось это руководство.
Просто заметка напоследок. Я, конечно, не эксперт по доступности, но я попытался сделать этот компонент более доступным, добавив некоторые общие атрибуты ARIA. Во время этого процесса я посмотрел для справки информационные панели WordPress и Codepen. Мы могли бы включить в код и другие атрибуты ARIA. Например, я исключил атрибут aria-controls, который отвечает за идентификацию связанного содержимого, но это произошло потому, что Aria-Controls — это Poop.
Если я что-то пропустил или вы думаете, что некоторые вещи должны были быть сделаны по-другому, дайте мне знать в комментариях ниже. Как всегда, спасибо за прочтение!
Автор: George Martsoukos
Источник: https://webdesign.tutsplus.com
Редакция: Команда webformyself.