Instantly share code, notes, and snippets.
Last active
June 5, 2022 12:18
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save nfreear/06c99c07d3783004b331e6c1b6f5ba28 to your computer and use it in GitHub Desktop.
Responsive navigation component - <my-nav>
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> <title> my-nav </title> | |
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><!-- --> | |
<style> | |
:root { | |
--my-nav-color: navy; | |
--my-nav-bg-color: #f9f9f9; | |
--my-nav-border: 1px solid #ddd; | |
--my-nav-mobile-width: 8rem; | |
} | |
body { font: 1rem sans-serif; margin: 1rem auto; max-width: 36rem; X-min-width: 5rem; padding: 0 .5rem; } | |
main { border: 1px solid #ccc; margin: 1rem 0; padding: 0 1rem; } | |
pre { font-size: x-small; white-space: pre-wrap;} | |
input, button { font: inherit; } | |
[ role = search ] input { width: 5rem; } | |
* { X-border-radius: .2rem; } | |
.my-nav { | |
line-height: 1.3rem; | |
width: 100%; | |
} | |
.my-nav ul { | |
display: flex; | |
flex-direction: row; | |
list-style: none; | |
margin: 0; | |
padding: 0; | |
width: 100%; | |
} | |
.my-nav li { | |
display: inline-block; | |
margin: 0; | |
padding: 0; | |
} | |
.my-nav li a { | |
background: var(--my-nav-bg-color); | |
border: var(--my-nav-border); | |
color: var(--my-nav-color); | |
display: inline-block; | |
min-width: 5.8rem; | |
padding: .6rem 1rem; | |
text-decoration: none; | |
} | |
.my-nav > button { | |
display: none; | |
cursor: pointer; | |
height: 2.5rem; | |
width: 2.5rem; | |
} | |
.my-nav .nav-toggle i { | |
border-top: 2px solid var(--my-nav-color); | |
display: block; | |
height: 0; | |
margin: .4rem 0; | |
} | |
.my-nav :focus, | |
.my-nav a:hover, | |
.my-nav button:hover { | |
background: #e8e8e8; | |
border-color: #bbb; | |
transition: all 1s; | |
} | |
@keyframes MyNavExpand { | |
from { | |
border-width: 0; | |
font-size: 1px; | |
min-width: 0; | |
X-width: 0; | |
X-height: 0; | |
padding: 0; | |
} | |
to { | |
border-width: 1px; | |
font-size: inherit; | |
min-width: var(--my-nav-mobile-width); | |
padding: .6rem 1rem; | |
} | |
} | |
@media screen and (max-width: 600px) { | |
.my-nav ul { | |
flex-direction: column; | |
position: absolute; | |
} | |
.my-nav li a { | |
min-width: var(--my-nav-mobile-width); | |
} | |
.my-nav > button { | |
display: block; | |
} | |
/* .nav-collapsed:not(.nav-animate) ul */ | |
.nav-collapsed ul { | |
display: none; | |
} | |
.nav-expanded li * { | |
animation-duration: 250ms; | |
animation-name: MyNavExpand; | |
animation-timing-function: linear; | |
} | |
.XX_nav-collapsed ul a { | |
animation-direction: reverse; | |
animation-duration: 250ms; | |
animation-name: MyNavExpand; | |
animation-timing-function: linear; | |
} | |
} | |
@media screen and (max-width: 376px) { | |
body { margin-top: .5rem; } | |
.my-nav ul { | |
left: 0; | |
right: 0; | |
} | |
.my-nav li a { | |
border-width: .5px; | |
min-width: 0; | |
padding: .4rem; | |
width: calc(100% - .8rem - 1px); | |
} | |
} | |
</style> | |
<nav class="my-nav nav-collapsed"> | |
<button class="nav-toggle" aria-expanded="false" aria-label="Toggle" title="Toggle"><i></i><i></i><i></i><!--<hr aria-hidden="true">--></button> | |
<ul> | |
<li><a href="#_1">First item</a> | |
<li><a href="#_2">Second item</a> | |
<li><a href="#_3">Third item</a> | |
<li><a href="#_4">Fourth item</a> | |
<li><a href="#_5">Fifth item</a> | |
<li><a href="#_6">Sixth item</a> | |
<li><form role="search"><input name=q aria-label="Search" placeholder="Search"><!--<button aria-label="Search">🔎</button>--></form> | |
</ul> | |
</nav> | |
<main> | |
<h1> my-nav </h1> | |
<p> Hello world! </p> | |
</main> | |
<script> | |
const ANIMATE_MS = 1000; | |
const MY_NAV = document.querySelector('.my-nav'); | |
const BTN = MY_NAV.querySelector('.nav-toggle'); | |
BTN.addEventListener('click', ev => { | |
ev.preventDefault(); | |
const IS_EXPANDED = BTN.getAttribute('aria-expanded') === 'true'; | |
BTN.setAttribute('aria-expanded', IS_EXPANDED ? 'false' : 'true'); | |
MY_NAV.classList.remove(IS_EXPANDED ? 'nav-expanded' : 'nav-collapsed'); | |
MY_NAV.classList.add(IS_EXPANDED ? 'nav-collapsed' : 'nav-expanded'); | |
MY_NAV.classList.add('nav-animate'); | |
setTimeout(() => { | |
MY_NAV.classList.remove('nav-animate'); | |
}, | |
ANIMATE_MS); | |
console.debug('my-nav ~ Toggle:', IS_EXPANDED, ev); | |
}); | |
const SEARCH_FORM = document.querySelector('form[ role = search]'); | |
SEARCH_FORM.addEventListener('submit', ev => { | |
ev.preventDefault(); | |
const QUERY = ev.target.elements.q.value; | |
console.debug('Search submit:', QUERY, ev); | |
}) | |
</script> | |
<pre> | |
NDF, 04-Jun-2022. | |
</pre> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment