modernize / optimize the main navigation
This commit is contained in:
parent
bc421a860d
commit
00aa9643d1
6 changed files with 154 additions and 199 deletions
|
|
@ -29,15 +29,14 @@
|
|||
|
||||
{% if drawerNav %}
|
||||
<!-- template element holding a button that needs to be injected when JavaScript is finally available. -->
|
||||
<!-- based on an article by Manuel Matuzovic, https://web.dev/website-navigation/ -->
|
||||
<!-- based on solution by Manuel Matuzovic, https://web.dev/website-navigation/ and the Web Accessibility Cookbook -->
|
||||
<!-- see also: https://kittygiraudel.com/2022/09/30/templating-in-html/ -->
|
||||
|
||||
<template id="burger-template">
|
||||
<button type="button" aria-expanded="false" aria-label="Menu" aria-controls="mainnav">
|
||||
<button type="button" aria-expanded="false" aria-controls="mainnav">
|
||||
<span>{{ meta.navigation.navLabel }}</span>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
|
|
@ -54,14 +53,6 @@
|
|||
</template>
|
||||
{% endif %}
|
||||
|
||||
{% css "inline" %}
|
||||
{% include "css/nav-pills.css" %}
|
||||
{% if drawerNav %}
|
||||
{% include "css/nav-drawer.css" %}
|
||||
{% endif %}
|
||||
{% include "css/nav-desktop.css" %}
|
||||
{% endcss %}
|
||||
|
||||
{% if drawerNav %}
|
||||
{% js "defer" %}
|
||||
{% include "scripts/nav-drawer.js" %}
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
@media screen(navigation) {
|
||||
.mainnav {
|
||||
--nav-button-display: none;
|
||||
--nav-position: static;
|
||||
}
|
||||
|
||||
.mainnav ul {
|
||||
--list-background: transparent;
|
||||
--list-layout: row;
|
||||
--list-position: static;
|
||||
--list-height: auto;
|
||||
--list-width: 100%;
|
||||
--list-shadow: none;
|
||||
--list-transform: none;
|
||||
--list-visibility: visible;
|
||||
--list-width: auto;
|
||||
--list-block-padding: 0;
|
||||
--list-inline-padding: 0;
|
||||
}
|
||||
|
||||
.mainnav a {
|
||||
--item-padding: var(--space-xs) 0.2em;
|
||||
--item-border-color: transparent;
|
||||
--item-background-color: transparent;
|
||||
--item-text-decoration: transparent;
|
||||
--item-text-color: var(--color-text);
|
||||
text-decoration-line: underline;
|
||||
text-decoration-color: var(--item-text-decoration, transparent);
|
||||
text-decoration-thickness: 3px;
|
||||
text-underline-offset: 0.2em;
|
||||
}
|
||||
|
||||
.mainnav a:where(:hover, :focus) {
|
||||
--item-background-color: transparent;
|
||||
--item-text-color: var(--color-text);
|
||||
--item-text-decoration: var(--color-text);
|
||||
}
|
||||
|
||||
/* Change border-color and color for the active page */
|
||||
.mainnav [aria-current='page'],
|
||||
.mainnav [data-state='active'] {
|
||||
--item-border-color: transparent;
|
||||
--item-background-color: transparent;
|
||||
--item-text-color: var(--color-primary);
|
||||
--item-text-decoration: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
@media (scripting: enabled) {
|
||||
.mainnav {
|
||||
--nav-position: absolute;
|
||||
inset-inline-end: 0;
|
||||
}
|
||||
|
||||
.mainnav:has([aria-expanded='true']) {
|
||||
--nav-position: fixed;
|
||||
inset-inline-end: var(--gap);
|
||||
}
|
||||
|
||||
.mainnav ul {
|
||||
--gutter: var(--space-xs);
|
||||
--cluster-vertical-alignment: normal;
|
||||
--list-block-padding: var(--space-2xl);
|
||||
--list-inline-padding: var(--space-s);
|
||||
z-index: 1;
|
||||
background: var(--list-background, var(--color-bg));
|
||||
box-shadow: var(--list-shadow, -5px 0 11px 0 rgb(0 0 0 / 0.2));
|
||||
flex-direction: var(--list-layout, column);
|
||||
block-size: var(--list-height, 100vh);
|
||||
position: var(--list-position, fixed);
|
||||
inset-block-start: 0;
|
||||
inset-inline-end: 0;
|
||||
inline-size: var(--list-width, min(18rem, 100vw));
|
||||
visibility: var(--list-visibility, visible);
|
||||
}
|
||||
|
||||
.mainnav :where([aria-expanded='false']) + ul {
|
||||
transform: var(--list-transform, translateX(100%));
|
||||
--list-visibility: hidden;
|
||||
}
|
||||
|
||||
/* animates ul only when opening to avoid flash on page load, svg always */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.mainnav [aria-expanded='true'] + ul,
|
||||
.mainnav svg {
|
||||
transition:
|
||||
transform 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55),
|
||||
visibility 0.05s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.mainnav [aria-expanded='true'] + ul {
|
||||
padding-top: var(--space-2xl);
|
||||
overflow: auto;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
.mainnav button {
|
||||
display: var(--nav-button-display, flex);
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding: var(--space-2xs) 0;
|
||||
}
|
||||
|
||||
.mainnav span {
|
||||
font-weight: var(--font-extra-bold);
|
||||
text-transform: uppercase;
|
||||
padding-inline-end: 0.1em;
|
||||
font-size: var(--size-step-min-1);
|
||||
font-family: var(--font-display);
|
||||
}
|
||||
|
||||
.mainnav svg {
|
||||
inline-size: auto;
|
||||
color: var(--color-text);
|
||||
stroke-width: 3;
|
||||
}
|
||||
|
||||
.mainnav [aria-expanded='true'] svg {
|
||||
transform: var(--list-rotate, rotate(45deg));
|
||||
}
|
||||
|
||||
.mainnav a {
|
||||
--item-border-color: transparent;
|
||||
--item-padding: var(--space-m) var(--space-xs);
|
||||
--item-background-color: transparent;
|
||||
}
|
||||
|
||||
.mainnav a:where(:hover, :focus) {
|
||||
--item-background-color: var(--color-bg-accent);
|
||||
--item-text-color: var(--color-text);
|
||||
--item-border-color: transparent;
|
||||
}
|
||||
|
||||
.mainnav [aria-current='page'],
|
||||
.mainnav [data-state='active'] {
|
||||
--item-border-color: transparent;
|
||||
--item-background-color: var(--color-primary);
|
||||
--item-text-color: var(--color-light);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
.mainnav {
|
||||
--gutter: var(--space-s);
|
||||
position: var(--nav-position, relative);
|
||||
}
|
||||
|
||||
.mainnav ul {
|
||||
--gutter: var(--space-xs);
|
||||
--list-block-padding: var(--space-s);
|
||||
--list-inline-padding: 0;
|
||||
margin: 0;
|
||||
line-height: 0.5em;
|
||||
padding-block: var(--list-block-padding);
|
||||
padding-inline: var(--list-inline-padding);
|
||||
}
|
||||
|
||||
.mainnav a {
|
||||
--item-text-color: var(--color-text);
|
||||
--item-background-color: var(--color-bg);
|
||||
--item-border-color: var(--color-bg-accent-2);
|
||||
--item-padding: var(--space-s);
|
||||
background-color: var(--item-background-color);
|
||||
color: var(--item-text-color);
|
||||
padding: var(--item-padding);
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
border-radius: var(--border-radius);
|
||||
border: 1px solid var(--item-border-color);
|
||||
}
|
||||
|
||||
/* Change the border-color on :hover and :focus */
|
||||
.mainnav a:where(:hover, :focus) {
|
||||
--item-background-color: var(--color-text);
|
||||
--item-text-color: var(--color-bg);
|
||||
--item-border-color: var(--color-bg);
|
||||
}
|
||||
|
||||
/* Change border-color and color for the active page. data-state='active' if a child is active. */
|
||||
.mainnav [aria-current='page'],
|
||||
.mainnav [data-state='active'] {
|
||||
--item-background-color: var(--color-text);
|
||||
--item-border-color: var(--color-bg);
|
||||
--item-text-color: var(--color-bg);
|
||||
}
|
||||
149
src/assets/css/global/blocks/nav-main.css
Normal file
149
src/assets/css/global/blocks/nav-main.css
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
.mainnav {
|
||||
position: var(--nav-position, absolute);
|
||||
inset-inline-end: 0;
|
||||
}
|
||||
|
||||
.mainnav:has([aria-expanded='true']) {
|
||||
--nav-position: fixed;
|
||||
inset-inline-end: var(--gap);
|
||||
}
|
||||
|
||||
.mainnav ul {
|
||||
--gutter: var(--space-xs);
|
||||
--cluster-vertical-alignment: normal;
|
||||
background: var(--nav-list-background, var(--color-bg));
|
||||
box-shadow: var(--nav-list-shadow, -5px 0 11px 0 hsl(0 0% 0% / 0.2));
|
||||
display: flex;
|
||||
flex-direction: var(--nav-list-layout, column);
|
||||
flex-wrap: wrap;
|
||||
block-size: var(--nav-list-height, 100dvh);
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: var(--nav-list-padding, var(--space-s));
|
||||
position: var(--nav-list-position, fixed);
|
||||
inset-block-start: 0;
|
||||
inset-inline-end: 0;
|
||||
inline-size: var(--nav-list-width, min(18rem, 100vw));
|
||||
visibility: var(--nav-list-visibility, hidden);
|
||||
}
|
||||
|
||||
.mainnav [aria-expanded='false'] + ul {
|
||||
transform: var(--list-transform, translateX(100%));
|
||||
}
|
||||
|
||||
.mainnav [aria-expanded='true'] + ul {
|
||||
--nav-list-visibility: visible;
|
||||
padding-top: var(--space-2xl);
|
||||
overflow: auto;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.mainnav [aria-expanded='true'] + ul,
|
||||
.mainnav svg {
|
||||
transition:
|
||||
transform 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55),
|
||||
visibility 0.05s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.mainnav button {
|
||||
display: var(--nav-button-display, flex);
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding: var(--space-2xs) 0;
|
||||
}
|
||||
|
||||
.mainnav span {
|
||||
font-weight: var(--font-extra-bold);
|
||||
text-transform: uppercase;
|
||||
padding-inline-end: 0.1em;
|
||||
font-size: var(--size-step-min-1);
|
||||
font-family: var(--font-display);
|
||||
}
|
||||
|
||||
.mainnav svg {
|
||||
inline-size: auto;
|
||||
color: var(--color-text);
|
||||
stroke-width: 3;
|
||||
}
|
||||
|
||||
.mainnav [aria-expanded='true'] svg {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.mainnav a {
|
||||
background: var(--nav-item-background, transparent);
|
||||
color: var(--nav-item-text-color, var(--color-text));
|
||||
padding: var(--nav-item-padding, var(--space-xs) var(--space-2xs));
|
||||
display: block;
|
||||
border-radius: var(--border-radius);
|
||||
text-decoration-line: underline;
|
||||
text-decoration-color: var(--nav-item-decoration-color, transparent);
|
||||
text-decoration-thickness: 3px;
|
||||
text-underline-offset: 0.2em;
|
||||
}
|
||||
|
||||
.mainnav a:where(:hover, :focus) {
|
||||
--nav-item-background: transparent;
|
||||
--nav-item-text-color: var(--color-text);
|
||||
--nav-item-decoration-color: var(--color-text);
|
||||
}
|
||||
|
||||
.mainnav [aria-current='page'],
|
||||
.mainnav [data-state='active'] {
|
||||
--nav-item-background: var(--color-bg-accent);
|
||||
--nav-item-text-color: var(--color-primary);
|
||||
--nav-item-decoration-color: transparent;
|
||||
}
|
||||
|
||||
@media screen(navigation) {
|
||||
.mainnav {
|
||||
--nav-position: static;
|
||||
--nav-button-display: none;
|
||||
}
|
||||
|
||||
.mainnav ul {
|
||||
--nav-list-layout: row;
|
||||
--nav-list-position: static;
|
||||
--nav-list-padding: 0;
|
||||
--nav-list-height: auto;
|
||||
--nav-list-width: 100%;
|
||||
--nav-list-shadow: none;
|
||||
--nav-list-visibility: visible;
|
||||
}
|
||||
|
||||
.mainnav [aria-current='page'],
|
||||
.mainnav [data-state='active'] {
|
||||
--nav-item-background: transparent;
|
||||
--nav-item-decoration-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.mainnav [aria-expanded='false'] + ul {
|
||||
--list-transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Repeat the settings to provide a different styling when JavaScript is disabled or drawerNav is set to false. The selector
|
||||
assumes that the button doesn’t exist without JS, making the list the first child within the navigation. */
|
||||
|
||||
.mainnav ul:first-child {
|
||||
--nav-list-layout: row;
|
||||
--nav-list-position: static;
|
||||
--nav-list-padding: 0;
|
||||
--nav-list-height: auto;
|
||||
--nav-list-width: 100%;
|
||||
--nav-list-shadow: none;
|
||||
--nav-list-visibility: visible;
|
||||
}
|
||||
|
||||
.mainnav ul:first-child [aria-current='page'],
|
||||
.mainnav ul:first-child [data-state='active'] {
|
||||
--nav-item-background: transparent;
|
||||
--nav-item-decoration-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.mainnav:has(ul:first-child) {
|
||||
--nav-position: relative;
|
||||
}
|
||||
|
|
@ -1,19 +1,18 @@
|
|||
// © Manuel Matuzović: https://web.dev/website-navigation/
|
||||
// © Manuel Matuzović: https://web.dev/website-navigation/ / Web Accessibility Cookbook
|
||||
|
||||
const nav = document.querySelector('nav');
|
||||
const list = nav.querySelector('ul');
|
||||
const burgerClone = document.querySelector('#burger-template').content.cloneNode(true);
|
||||
const svg = nav.querySelector('svg');
|
||||
|
||||
const button = burgerClone.querySelector('button');
|
||||
|
||||
button.addEventListener('click', e => {
|
||||
const isOpen = button.getAttribute('aria-expanded') === 'true';
|
||||
button.setAttribute('aria-expanded', !isOpen);
|
||||
});
|
||||
|
||||
// avoid DRY: disabling menu
|
||||
const disableMenu = () => {
|
||||
button.setAttribute('aria-expanded', false);
|
||||
button.focus();
|
||||
};
|
||||
|
||||
// close on escape
|
||||
|
|
|
|||
Loading…
Reference in a new issue