Эта лаборатория кода научит вас, как создать адаптивный компонент макета боковой навигации в Интернете. Мы будем создавать компонент по ходу дела, начиная с HTML, затем CSS, затем JavaScript.
Прочтите мою публикацию в блоге «Создание компонента Sidenav», чтобы узнать о функциях веб-платформы CSS, выбранных для создания этого компонента.
Настраивать
- Нажмите Remix to Edit, чтобы сделать проект доступным для редактирования.
- Откройте
app/index.html
.
HTML
Во-первых, разберитесь с основами настройки HTML, чтобы было содержимое и несколько полей для работы.
Поместите следующий HTML-код в тег <body>
.
<aside></aside>
<main></main>
<aside>
содержит меню навигации как дополнительный элемент <main>
, который содержит основное содержимое страницы.
Далее мы заполним эти семантические элементы остальным содержимым страницы.
Добавьте элемент навигации, несколько навигационных ссылок и ссылку закрытия внутри элемента <aside>
.
<aside>
<nav>
<h4>My</h4>
<a href="#">Dashboard</a>
<a href="#">Profile</a>
<a href="#">Preferences</a>
<a href="#">Archive</a>
<h4>Settings</h4>
<a href="#">Accessibility</a>
<a href="#">Theme</a>
<a href="#">Admin</a>
</nav>
<a href="#"></a>
</aside>
Ссылки отлично смотрятся внутри элементов <nav>
, а элементы <nav>
отлично смотрятся на боковых панелях <aside>
. Тем не менее, мы можем сделать больше, чтобы улучшиться.
В основной элемент контента добавьте заголовок и статью, чтобы семантически хранить содержимое макета.
<main>
<header>
<a href="#sidenav-open" class="hamburger">
<svg viewBox="0 0 50 40">
<line x1="0" x2="100%" y1="10%" y2="10%" />
<line x1="0" x2="100%" y1="50%" y2="50%" />
<line x1="0" x2="100%" y1="90%" y2="90%" />
</svg>
</a>
<h1>Site Title</h1>
</header>
<article>
{put some placeholder content here}
</article>
</main>
В шапке есть ссылка на открытие меню. Сбоку имеется кнопка закрытия. Скоро мы будем показывать и скрывать элементы в зависимости от размера области просмотра.
В элемент <article>
мы вставили предложение-заполнитель. Замените `` на свой собственный или вставьте лорем, представленный ниже:
<h2>Totam Header</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Cum consectetur, necessitatibus velit officia ut impedit veritatis temporibus soluta? Totam odit cupiditate facilis nisi sunt hic necessitatibus voluptatem nihil doloribus! Enim.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead Totam Odit</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
Именно этот контент и его длина обеспечивают возможность прокрутки страницы, когда она превышает высоту области просмотра.
На данный момент вы добавили элемент в сторону с навигацией, ссылками и возможностью закрыть боковую навигацию. Вы также добавили заголовок, способ открытия боковой панели и статью к основному элементу. Это уже чисто, семантично и вне времени, но мы можем сделать его чище и понятнее для всех. Открытую ссылку в боковой панели можно было бы обозначить более четко.
Добавьте атрибуты title
и aria-label
к элементу открытой ссылки заголовка:
<a href="#sidenav-open" class="hamburger">
<a href="#sidenav-open" title="Open Menu" aria-label="Open Menu" class="hamburger">
Значок открытого SVG также можно было бы обозначить более четко. Добавьте следующие атрибуты в SVG внутри элемента открытой ссылки:
<svg viewBox="0 0 50 40">
<svg viewBox="0 0 50 40" role="presentation" focusable="false" aria-label="trigram for heaven symbol">
Тесную связь в боковой навигации можно было бы обозначить более четко. Добавьте атрибуты title
и aria-label
в элемент закрытия ссылки Sidenav:
<a href="#"></a>
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
CSS
Пришло время расположить элементы. Основной контент и Sidenav являются прямыми дочерними элементами тега <body>
, так что это хорошее место для начала.
Добавьте следующий CSS в css/sidenav.css
чтобы элемент <body>
располагал дочерние элементы.
body {
display: grid;
grid: [stack] 1fr / min-content [stack] 1fr;
@media (max-width: 540px) {
& > :matches(aside, main) {
grid-area: stack;
}
}
}
По сути, этот макет говорит: создайте именованный stack
строк со всем, что в нем, и 2 столбца в этой строке, второй из которых также называется именованным stack
. Размер первого столбца должен соответствовать минимальным потребностям в содержимом, а второй столбец может занимать все остальное. Затем, если область просмотра ограничена 540px
или меньше, поместите элементы Sidenav и основного контента в одну и ту же строку и столбец, в результате чего они окажутся друг над другом в сетке 1x1.
Благодаря этой гибкой функции стекирования в качестве основы мы теперь можем использовать состояние строки URL-адреса для переключения видимости и стиля перехода боковой панели.
Обновите элемент <aside>
обратно в app/index.html
:
<aside>
<aside id="sidenav-open">
Это позволяет CSS сопоставлять элемент и хэш URL-адреса вместе. Это важно для использования :target
. Теперь идентификатор элемента может соответствовать хешу URL-адреса, который мы зададим с помощью тегов <a>
.
Кроме того, чтобы упростить таргетинг на JavaScript, добавьте идентификаторы ключевых элементов, управляющих боковой навигацией. Сначала добавьте идентификатор в ссылку открытия Sidenav:
<a href="#sidenav-open" class="hamburger" title="Open Menu" aria-label="Open Menu">
<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
Затем добавьте идентификатор в ссылку закрытия Sidenav:
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>
На этом завершается адаптивный макет стекирования макроса <body>
, а также привязывается нас к строке URL. Давайте продолжать!
<aside>
также имеет аккуратный макет. У него есть 2 дочерних элемента: <nav>
, который представляет собой выдвигающийся компонент, похожий на бумагу, и закрывающий элемент ссылки <a>
, который устанавливает URL-адрес в #
. Ссылка невидима справа от навигационной панели выдвижения бумаги; это для того, чтобы люди могли «щелкнуть» по визуальному компоненту, чтобы закрыть его.
Добавьте следующий CSS в css/sidenav.css
:
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
}
Я думаю, что пропорции и имена были здесь действительно приятным штрихом, поскольку сетка могла бы сиять и давать дизайнеру много контроля.
Далее мне нужно условно наложить основное содержимое и сохранить свою позицию при любой прокрутке документа. Это отличная работа для position: sticky
и некоторая overscroll-behavior
.
Добавьте следующие стили для боковой панели:
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
@media (max-width: 540px) {
position: sticky;
top: 0;
max-height: 100vh;
overflow: hidden auto;
overscroll-behavior: contain;
visibility: hidden; /* not keyboard accessible when closed */
}
}
Эти стили гарантируют, что Sidenav соответствует высоте области просмотра, прокручивается вертикально и содержит прокрутку. Очень важно, что он скрывает элемент. По умолчанию, когда область просмотра составляет 540px
или меньше, скройте эту боковую панель. Пока не!
Добавьте псевдоселектор :target
к элементу #sidenav-open
:
#sidenav-open {
@media (max-width: 540px) {
&:target {
visibility: visible;
}
}
}
Если идентификатор этого элемента и строка URL совпадают, установите для visibility
visible
. Откройте боковое меню после прокрутки страницы или попробуйте прокрутить страницу, пока открыта боковая навигация. Что вы думаете?
Добавьте следующий CSS в конец файла app/sidenav.css
:
#sidenav-button,
#sidenav-close {
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
user-select: none;
touch-action: manipulation;
@media (min-width: 540px) {
display: none;
}
}
Эти стили предназначены для наших кнопок открытия и закрытия, определяют их стили касания и касания, а также скрывают их, когда область просмотра составляет 540px
или больше.
Для немного изящества давайте добавим CSS-преобразования с уважительной доступностью. Добавьте следующий CSS в css/sidenav.css
:
#sidenav-open {
--easeOutExpo: cubic-bezier(0.16, 1, 0.3, 1);
--duration: .6s;
...
@media (max-width: 540px) {
...
transform: translateX(-110vw);
will-change: transform;
transition:
transform var(--duration) var(--easeOutExpo),
visibility 0s linear var(--duration);
&:target {
visibility: visible;
transform: translateX(0);
transition: transform var(--duration) var(--easeOutExpo);
}
}
@media (prefers-reduced-motion: reduce) {
--duration: 1ms;
}
}
Добавьте немного JavaScript
Клавиша Escape
должна закрыть меню. Добавьте этот JS в js/index.js
:
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', e => {
if (e.code === 'Escape') {
document.location.hash = '';
}
});
Это прослушивает ключевое событие в элементе Sidenav. Если это Escape
, хеш URL-адреса становится пустым, что приводит к отключению боковой навигации.
Следующая часть UX JS — управление фокусом. Я хочу, чтобы открытие и закрытие было простым, поэтому я жду, пока Sidenav завершит какой-либо переход, а затем перекрестно проверяю его по хешу URL-адреса, чтобы определить, вошел он или нет. Затем я использую JavaScript, чтобы установить фокус на кнопке, дополняющей ту, которую они только что нажали.
Добавьте следующий код JavaScript в js/index.js
:
const closenav = document.querySelector('#sidenav-close');
const opennav = document.querySelector('#sidenav-button');
sidenav.addEventListener('transitionend', e => {
if (e.propertyName !== 'transform') {
return;
}
const isOpen = document.location.hash === '#sidenav-open';
isOpen
? closenav.focus()
: opennav.focus();
});
Попробуйте это
- Чтобы просмотреть сайт, нажмите «Просмотреть приложение» . Затем нажмите Полноэкранный режим .
Заключение
Это подведение итогов того, что у меня было с этим компонентом. Не стесняйтесь развивать его, управляйте им с помощью состояния JavaScript вместо URL-адреса и в общем сделайте его своим! Всегда есть что добавить или охватить больше вариантов использования.
Откройте css/brandnav.css
, чтобы проверить стили, не связанные с макетом, которые я применил к этому компоненту. Я не чувствовал, что это важно для набора функций, на которых я сосредоточился, и надеялся, что отделение стилей от макета будет способствовать копированию и вставке. Там вы могли бы получить больше знаний!
Как сделать выдвижные адаптивные компоненты боковой навигации? У вас когда-нибудь было больше одного, например, по одному с обеих сторон? Я хотел бы представить ваше решение в видео на YouTube. Обязательно напишите мне в Твиттере или оставьте комментарий на YouTube со своим кодом, это всем поможет!
,Эта лаборатория кода научит вас, как создать адаптивный компонент макета боковой навигации в Интернете. Мы будем создавать компонент по ходу дела, начиная с HTML, затем CSS, затем JavaScript.
Прочтите мою публикацию в блоге «Создание компонента Sidenav», чтобы узнать о функциях веб-платформы CSS, выбранных для создания этого компонента.
Настраивать
- Нажмите Remix to Edit, чтобы сделать проект доступным для редактирования.
- Откройте
app/index.html
.
HTML
Во-первых, разберитесь с основами настройки HTML, чтобы было содержимое и несколько полей для работы.
Поместите следующий HTML-код в тег <body>
.
<aside></aside>
<main></main>
<aside>
содержит меню навигации как дополнительный элемент <main>
, который содержит основное содержимое страницы.
Далее мы заполним эти семантические элементы остальным содержимым страницы.
Добавьте элемент навигации, несколько навигационных ссылок и ссылку закрытия внутри элемента <aside>
.
<aside>
<nav>
<h4>My</h4>
<a href="#">Dashboard</a>
<a href="#">Profile</a>
<a href="#">Preferences</a>
<a href="#">Archive</a>
<h4>Settings</h4>
<a href="#">Accessibility</a>
<a href="#">Theme</a>
<a href="#">Admin</a>
</nav>
<a href="#"></a>
</aside>
Ссылки отлично смотрятся внутри элементов <nav>
, а элементы <nav>
отлично смотрятся на боковых панелях <aside>
. Тем не менее, мы можем сделать больше, чтобы улучшиться.
В основной элемент контента добавьте заголовок и статью, чтобы семантически хранить содержимое макета.
<main>
<header>
<a href="#sidenav-open" class="hamburger">
<svg viewBox="0 0 50 40">
<line x1="0" x2="100%" y1="10%" y2="10%" />
<line x1="0" x2="100%" y1="50%" y2="50%" />
<line x1="0" x2="100%" y1="90%" y2="90%" />
</svg>
</a>
<h1>Site Title</h1>
</header>
<article>
{put some placeholder content here}
</article>
</main>
В шапке есть ссылка на открытие меню. Сбоку имеется кнопка закрытия. Скоро мы будем показывать и скрывать элементы в зависимости от размера области просмотра.
В элемент <article>
мы вставили предложение-заполнитель. Замените `` на свой собственный или вставьте лорем, представленный ниже:
<h2>Totam Header</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Cum consectetur, necessitatibus velit officia ut impedit veritatis temporibus soluta? Totam odit cupiditate facilis nisi sunt hic necessitatibus voluptatem nihil doloribus! Enim.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead Totam Odit</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
Именно этот контент и его длина обеспечивают возможность прокрутки страницы, когда она превышает высоту области просмотра.
На данный момент вы добавили элемент в сторону с навигацией, ссылками и возможностью закрыть боковую навигацию. Вы также добавили заголовок, способ открытия боковой панели и статью к основному элементу. Это уже чисто, семантично и вне времени, но мы можем сделать его чище и понятнее для всех. Открытую ссылку в боковой панели можно было бы обозначить более четко.
Добавьте атрибуты title
и aria-label
к элементу открытой ссылки заголовка:
<a href="#sidenav-open" class="hamburger">
<a href="#sidenav-open" title="Open Menu" aria-label="Open Menu" class="hamburger">
Значок открытого SVG также можно было бы обозначить более четко. Добавьте следующие атрибуты в SVG внутри элемента открытой ссылки:
<svg viewBox="0 0 50 40">
<svg viewBox="0 0 50 40" role="presentation" focusable="false" aria-label="trigram for heaven symbol">
Тесную связь в боковой навигации можно было бы обозначить более четко. Добавьте атрибуты title
и aria-label
в элемент закрытия ссылки Sidenav:
<a href="#"></a>
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
CSS
Пришло время расположить элементы. Основной контент и Sidenav являются прямыми дочерними элементами тега <body>
, так что это хорошее место для начала.
Добавьте следующий CSS в css/sidenav.css
чтобы элемент <body>
располагал дочерние элементы.
body {
display: grid;
grid: [stack] 1fr / min-content [stack] 1fr;
@media (max-width: 540px) {
& > :matches(aside, main) {
grid-area: stack;
}
}
}
По сути, этот макет говорит: создайте именованный stack
строк со всем, что в нем, и 2 столбца в этой строке, второй из которых также называется именованным stack
. Размер первого столбца должен соответствовать минимальным потребностям в содержимом, а второй столбец может занимать все остальное. Затем, если область просмотра ограничена 540px
или меньше, поместите элементы Sidenav и основного контента в одну и ту же строку и столбец, в результате чего они окажутся друг над другом в сетке 1x1.
Благодаря этой гибкой функции стекирования в качестве основы мы теперь можем использовать состояние строки URL-адреса для переключения видимости и стиля перехода боковой панели.
Обновите элемент <aside>
обратно в app/index.html
:
<aside>
<aside id="sidenav-open">
Это позволяет CSS сопоставлять элемент и хэш URL-адреса вместе. Это важно для использования :target
. Теперь идентификатор элемента может соответствовать хешу URL-адреса, который мы зададим с помощью тегов <a>
.
Кроме того, чтобы упростить таргетинг на JavaScript, добавьте идентификаторы ключевых элементов, управляющих боковой навигацией. Сначала добавьте идентификатор в ссылку открытия Sidenav:
<a href="#sidenav-open" class="hamburger" title="Open Menu" aria-label="Open Menu">
<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
Затем добавьте идентификатор в ссылку закрытия Sidenav:
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>
На этом завершается адаптивный макет стекирования макроса <body>
, а также привязывается нас к строке URL. Давайте продолжать!
<aside>
также имеет аккуратный макет. У него есть 2 дочерних элемента: <nav>
, который представляет собой выдвижной компонент, похожий на бумагу, и закрывающий элемент ссылки <a>
, который устанавливает URL-адрес в #
. Ссылка невидима справа от навигационной панели выдвижения бумаги; это для того, чтобы люди могли «щелкнуть» по визуальному компоненту, чтобы закрыть его.
Добавьте следующий CSS в css/sidenav.css
:
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
}
Я думаю, что пропорции и имена были здесь действительно приятным штрихом, поскольку сетка могла бы сиять и давать дизайнеру много контроля.
Далее мне нужно условно наложить основное содержимое и сохранить свою позицию при любой прокрутке документа. Это отличная работа для position: sticky
и некоторая overscroll-behavior
.
Добавьте следующие стили для боковой панели:
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
@media (max-width: 540px) {
position: sticky;
top: 0;
max-height: 100vh;
overflow: hidden auto;
overscroll-behavior: contain;
visibility: hidden; /* not keyboard accessible when closed */
}
}
Эти стили гарантируют, что Sidenav соответствует высоте области просмотра, прокручивается вертикально и содержит прокрутку. Очень важно, что он скрывает элемент. По умолчанию, когда область просмотра составляет 540px
или меньше, скройте эту боковую панель. Пока не!
Добавьте псевдоселектор :target
к элементу #sidenav-open
:
#sidenav-open {
@media (max-width: 540px) {
&:target {
visibility: visible;
}
}
}
Если идентификатор этого элемента и строка URL совпадают, установите для visibility
visible
. Откройте боковое меню после прокрутки страницы или попробуйте прокрутить страницу, пока открыта боковая навигация. Что вы думаете?
Добавьте следующий CSS в конец файла app/sidenav.css
:
#sidenav-button,
#sidenav-close {
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
user-select: none;
touch-action: manipulation;
@media (min-width: 540px) {
display: none;
}
}
Эти стили предназначены для наших кнопок открытия и закрытия, определяют их стили касания и касания, а также скрывают их, когда область просмотра составляет 540px
или больше.
Для немного изящества давайте добавим CSS-преобразования с уважительной доступностью. Добавьте следующий CSS в css/sidenav.css
:
#sidenav-open {
--easeOutExpo: cubic-bezier(0.16, 1, 0.3, 1);
--duration: .6s;
...
@media (max-width: 540px) {
...
transform: translateX(-110vw);
will-change: transform;
transition:
transform var(--duration) var(--easeOutExpo),
visibility 0s linear var(--duration);
&:target {
visibility: visible;
transform: translateX(0);
transition: transform var(--duration) var(--easeOutExpo);
}
}
@media (prefers-reduced-motion: reduce) {
--duration: 1ms;
}
}
Добавьте немного JavaScript
Клавиша Escape
должна закрыть меню. Добавьте этот JS в js/index.js
:
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', e => {
if (e.code === 'Escape') {
document.location.hash = '';
}
});
Это прослушивает ключевое событие в элементе Sidenav. Если это Escape
, хеш URL-адреса становится пустым, что приводит к отключению боковой навигации.
Следующая часть UX JS — управление фокусом. Я хочу, чтобы открытие и закрытие было простым, поэтому я жду, пока Sidenav завершит какой-либо переход, а затем перекрестно проверяю его по хешу URL-адреса, чтобы определить, вошел он или нет. Затем я использую JavaScript, чтобы установить фокус на кнопке, дополняющей ту, которую они только что нажали.
Добавьте следующий код JavaScript в js/index.js
:
const closenav = document.querySelector('#sidenav-close');
const opennav = document.querySelector('#sidenav-button');
sidenav.addEventListener('transitionend', e => {
if (e.propertyName !== 'transform') {
return;
}
const isOpen = document.location.hash === '#sidenav-open';
isOpen
? closenav.focus()
: opennav.focus();
});
Попробуйте это
- Чтобы просмотреть сайт, нажмите «Просмотреть приложение» . Затем нажмите Полноэкранный режим .
Заключение
Это подведение итогов того, что у меня было с этим компонентом. Не стесняйтесь развивать его, управляйте им с помощью состояния JavaScript вместо URL-адреса и в общем сделайте его своим! Всегда есть что добавить или охватить больше вариантов использования.
Откройте css/brandnav.css
, чтобы проверить стили, не связанные с макетом, которые я применил к этому компоненту. Я не чувствовал, что это важно для набора функций, на которых я сосредоточился, и надеялся, что отделение стилей от макета будет способствовать копированию и вставке. Там вы могли бы получить больше знаний!
Как сделать выдвижные адаптивные компоненты боковой навигации? У вас когда-нибудь было больше одного, например, по одному с обеих сторон? Я хотел бы представить ваше решение в видео на YouTube. Обязательно напишите мне в Твиттере или оставьте комментарий на YouTube со своим кодом, это всем поможет!
,Эта лаборатория кода научит вас, как создать адаптивный компонент макета боковой навигации в Интернете. Мы будем создавать компонент по ходу дела, начиная с HTML, затем CSS, затем JavaScript.
Прочтите мою публикацию в блоге «Создание компонента Sidenav», чтобы узнать о функциях веб-платформы CSS, выбранных для создания этого компонента.
Настраивать
- Нажмите Remix to Edit, чтобы сделать проект доступным для редактирования.
- Откройте
app/index.html
.
HTML
Во-первых, разберитесь с основами настройки HTML, чтобы было содержимое и несколько полей для работы.
Поместите следующий HTML-код в тег <body>
.
<aside></aside>
<main></main>
<aside>
содержит меню навигации как дополнительный элемент <main>
, который содержит основное содержимое страницы.
Далее мы заполним эти семантические элементы остальным содержимым страницы.
Добавьте элемент навигации, несколько навигационных ссылок и ссылку закрытия внутри элемента <aside>
.
<aside>
<nav>
<h4>My</h4>
<a href="#">Dashboard</a>
<a href="#">Profile</a>
<a href="#">Preferences</a>
<a href="#">Archive</a>
<h4>Settings</h4>
<a href="#">Accessibility</a>
<a href="#">Theme</a>
<a href="#">Admin</a>
</nav>
<a href="#"></a>
</aside>
Ссылки отлично смотрятся внутри элементов <nav>
, а элементы <nav>
отлично смотрятся на боковых панелях <aside>
. Тем не менее, мы можем сделать больше, чтобы улучшиться.
В основной элемент контента добавьте заголовок и статью, чтобы семантически хранить содержимое макета.
<main>
<header>
<a href="#sidenav-open" class="hamburger">
<svg viewBox="0 0 50 40">
<line x1="0" x2="100%" y1="10%" y2="10%" />
<line x1="0" x2="100%" y1="50%" y2="50%" />
<line x1="0" x2="100%" y1="90%" y2="90%" />
</svg>
</a>
<h1>Site Title</h1>
</header>
<article>
{put some placeholder content here}
</article>
</main>
В шапке есть ссылка на открытие меню. Сбоку имеется кнопка закрытия. Скоро мы будем показывать и скрывать элементы в зависимости от размера области просмотра.
В элемент <article>
мы вставили предложение-заполнитель. Замените `` на свой собственный или вставьте лорем, представленный ниже:
<h2>Totam Header</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Cum consectetur, necessitatibus velit officia ut impedit veritatis temporibus soluta? Totam odit cupiditate facilis nisi sunt hic necessitatibus voluptatem nihil doloribus! Enim.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead Totam Odit</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
Именно этот контент и его длина обеспечивают возможность прокрутки страницы, когда она превышает высоту области просмотра.
На данный момент вы добавили элемент в сторону с навигацией, ссылками и возможностью закрыть боковую навигацию. Вы также добавили заголовок, способ открытия боковой панели и статью к основному элементу. Это уже чисто, семантично и вне времени, но мы можем сделать его чище и понятнее для всех. Открытую ссылку в боковой панели можно было бы обозначить более четко.
Добавьте атрибуты title
и aria-label
к элементу открытой ссылки заголовка:
<a href="#sidenav-open" class="hamburger">
<a href="#sidenav-open" title="Open Menu" aria-label="Open Menu" class="hamburger">
Значок открытого SVG также можно было бы обозначить более четко. Добавьте следующие атрибуты в SVG внутри элемента открытой ссылки:
<svg viewBox="0 0 50 40">
<svg viewBox="0 0 50 40" role="presentation" focusable="false" aria-label="trigram for heaven symbol">
Тесную связь в боковой навигации можно было бы обозначить более четко. Добавьте атрибуты title
и aria-label
в элемент закрытия ссылки Sidenav:
<a href="#"></a>
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
CSS
Пришло время расположить элементы. Основной контент и Sidenav являются прямыми дочерними элементами тега <body>
, так что это хорошее место для начала.
Добавьте следующий CSS в css/sidenav.css
чтобы элемент <body>
располагал дочерние элементы.
body {
display: grid;
grid: [stack] 1fr / min-content [stack] 1fr;
@media (max-width: 540px) {
& > :matches(aside, main) {
grid-area: stack;
}
}
}
По сути, этот макет говорит: создайте именованный stack
строк со всем, что в нем, и 2 столбца в этой строке, второй из которых также называется именованным stack
. Размер первого столбца должен соответствовать минимальным потребностям в содержимом, а второй столбец может занимать все остальное. Затем, если область просмотра ограничена 540px
или меньше, поместите элементы Sidenav и основного контента в одну и ту же строку и столбец, в результате чего они окажутся друг над другом в сетке 1x1.
Благодаря этой гибкой функции стекирования в качестве основы мы теперь можем использовать состояние строки URL-адреса для переключения видимости и стиля перехода боковой панели.
Обновите элемент <aside>
обратно в app/index.html
:
<aside>
<aside id="sidenav-open">
Это позволяет CSS сопоставлять элемент и хэш URL-адреса вместе. Это важно для использования :target
. Теперь идентификатор элемента может соответствовать хешу URL-адреса, который мы зададим с помощью тегов <a>
.
Кроме того, чтобы упростить таргетинг на JavaScript, добавьте идентификаторы ключевых элементов, управляющих боковой навигацией. Сначала добавьте идентификатор в ссылку открытия Sidenav:
<a href="#sidenav-open" class="hamburger" title="Open Menu" aria-label="Open Menu">
<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
Затем добавьте идентификатор в ссылку закрытия Sidenav:
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>
На этом завершается адаптивный макет стекирования макроса <body>
, а также привязывается нас к строке URL. Давайте продолжать!
<aside>
также имеет аккуратный макет. У него есть 2 дочерних элемента: <nav>
, который представляет собой выдвигающийся компонент, похожий на бумагу, и закрывающий элемент ссылки <a>
, который устанавливает URL-адрес в #
. Ссылка невидима справа от навигационной панели выдвижения бумаги; это для того, чтобы люди могли «щелкнуть» по визуальному компоненту, чтобы закрыть его.
Добавьте следующий CSS в css/sidenav.css
:
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
}
Я думаю, что пропорции и имена были здесь действительно приятным штрихом, поскольку сетка могла бы сиять и давать дизайнеру много контроля.
Далее мне нужно условно наложить основное содержимое и сохранить свою позицию при любой прокрутке документа. Это отличная работа для position: sticky
и некоторая overscroll-behavior
.
Добавьте следующие стили для боковой панели:
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
@media (max-width: 540px) {
position: sticky;
top: 0;
max-height: 100vh;
overflow: hidden auto;
overscroll-behavior: contain;
visibility: hidden; /* not keyboard accessible when closed */
}
}
Эти стили гарантируют, что Sidenav соответствует высоте области просмотра, прокручивается вертикально и содержит прокрутку. Очень важно, что он скрывает элемент. По умолчанию, когда область просмотра составляет 540px
или меньше, скройте эту боковую панель. Пока не!
Добавьте псевдоселектор :target
к элементу #sidenav-open
:
#sidenav-open {
@media (max-width: 540px) {
&:target {
visibility: visible;
}
}
}
Если идентификатор этого элемента и строка URL совпадают, установите для visibility
visible
. Откройте боковое меню после прокрутки страницы или попробуйте прокрутить страницу, пока открыта боковая навигация. Что вы думаете?
Добавьте следующий CSS в конец файла app/sidenav.css
:
#sidenav-button,
#sidenav-close {
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
user-select: none;
touch-action: manipulation;
@media (min-width: 540px) {
display: none;
}
}
Эти стили предназначены для наших кнопок открытия и закрытия, определяют их стили касания и касания, а также скрывают их, когда область просмотра составляет 540px
или больше.
Для немного изящества давайте добавим CSS-преобразования с уважительной доступностью. Добавьте следующий CSS в css/sidenav.css
:
#sidenav-open {
--easeOutExpo: cubic-bezier(0.16, 1, 0.3, 1);
--duration: .6s;
...
@media (max-width: 540px) {
...
transform: translateX(-110vw);
will-change: transform;
transition:
transform var(--duration) var(--easeOutExpo),
visibility 0s linear var(--duration);
&:target {
visibility: visible;
transform: translateX(0);
transition: transform var(--duration) var(--easeOutExpo);
}
}
@media (prefers-reduced-motion: reduce) {
--duration: 1ms;
}
}
Добавьте немного JavaScript
Клавиша Escape
должна закрыть меню. Добавьте этот JS в js/index.js
:
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', e => {
if (e.code === 'Escape') {
document.location.hash = '';
}
});
Это прослушивает ключевое событие в элементе Sidenav. Если это Escape
, хеш URL-адреса становится пустым, что приводит к отключению боковой навигации.
Следующая часть UX JS — управление фокусом. Я хочу, чтобы открытие и закрытие было простым, поэтому я жду, пока Sidenav завершит какой-либо переход, а затем перекрестно проверяю его по хешу URL-адреса, чтобы определить, включен он или нет. Затем я использую JavaScript, чтобы установить фокус на кнопке, дополняющей ту, которую они только что нажали.
Добавьте следующий код JavaScript в js/index.js
:
const closenav = document.querySelector('#sidenav-close');
const opennav = document.querySelector('#sidenav-button');
sidenav.addEventListener('transitionend', e => {
if (e.propertyName !== 'transform') {
return;
}
const isOpen = document.location.hash === '#sidenav-open';
isOpen
? closenav.focus()
: opennav.focus();
});
Попробуйте это
- Чтобы просмотреть сайт, нажмите «Просмотреть приложение» . Затем нажмите Полноэкранный режим .
Заключение
Это подведение итогов того, что у меня было с этим компонентом. Не стесняйтесь развивать его, управляйте им с помощью состояния JavaScript вместо URL-адреса и в общем сделайте его своим! Всегда есть что добавить или охватить больше вариантов использования.
Откройте css/brandnav.css
, чтобы проверить стили, не связанные с макетом, которые я применил к этому компоненту. Я не чувствовал, что это важно для набора функций, на которых я сосредоточился, и надеялся, что отделение стилей от макета будет способствовать копированию и вставке. Там вы могли бы получить больше знаний!
Как сделать выдвижные адаптивные компоненты боковой навигации? У вас когда-нибудь было больше одного, например, по одному с обеих сторон? Я хотел бы представить ваше решение в видео на YouTube. Обязательно напишите мне в Твиттере или оставьте комментарий на YouTube со своим кодом, это всем поможет!