Offcanvas navigation
von pathologicalplay am
Ich habe für ein neues Projekt an einer responsiven Offcanvas navigation gearbeitet, die ich euch hier zur Verfügung stellen möchte. Diese habe ich mit HTML5, CSS3 und JS umgesetzt. Ihr dürft diese frei verwenden.
Bugfix: Ich habe das JS angepasst, um das unschöne Scroll chaining zu verhindern.
<!-- Offcanvas demo -->
<!-- V1.0.0 -->
<!-- MSCRATCH -->
<!-- MMXXV -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Offcanvas demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
:root {
font-size: 62.5%; /*10PX*/
/* primary declarations */
--primary_border: 1px solid rgba(255,255,255,.07);
--primary_font_color: #eeeeee;
--primary_border_radius: 5px;
/* body */
--body_background: #111111;
/* navbar */
--navbar_background: #161616;
/* off_canvas */
--off_canvas_background: #151515;
--off_canvas_shadow: 0 24px 80px rgba(0,0,0,.55);
--off_canvas_menu_hover: rgba(255,255,255,.045);
--off_canvas_backdrop_background: rgba(0,0,0,.38);
/* content */
--content_background: #181818;
/* btn */
--btn_background: 202020;
--btn_border: 1px solid rgba(255, 255, 255, .12);
--btn_font_color: #eeeeee;
--btn_hover_background: #282828;
}
body {
display: flex;
flex-direction: column;
background: var(--body_background);
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.6;
color: var(--primary_font_color);
}
.main_wrapper {
width: 100%;
margin-top: 5rem;
}
.content_wrapper {
width: 100%;
max-width: 750px;
margin: 0 auto;
background: var(--content_background);
border: var(--primary_border);
border-radius: var(--primary_border_radius);
font-size: 1.5rem;
}
.content {
padding: 2rem;
}
.content_title {
padding: 1rem 2rem 1rem 2rem;
background: var(--content_background);
border-top-left-radius: var(--primary_border_radius);
border-top-right-radius: var(--primary_border_radius);
border-bottom: var(--primary_border);
}
.navbar {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: baseline;
width: 100%;
padding: 1rem;
background: var(--navbar_background);
border-bottom: var(--primary_border);
z-index: 15;
}
.navbar_title {
font-size: 2rem;
}
.toggle_button {
font-size: 2rem;
text-decoration: none;
color: var(--primary_font_color);
}
.off_canvas_menu {
position: fixed;
width: 350px;
height: 100dvh;
max-height: 100dvh;
transform: translateX(-100%);
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
overflow-y: auto;
-webkit-overflow-scrolling: touch;
border-right: var(--primary_border);
background: var(--off_canvas_background);
box-shadow: var(--off_canvas_shadow);
z-index: 25;
}
.off_canvas_menu.active {
transform: translateX(0);
}
.off_canvas_menu ul {
display: flex;
flex-direction: column;
}
.off_canvas_menu li {
list-style: none;
border-bottom: var(--primary_border);
}
.off_canvas_menu li:last-child {
border-bottom: none;
}
.off_canvas_menu a {
display: block;
padding: 1rem;
font-size: 1.5rem;
text-decoration: none;
color: #ffffff;
}
.off_canvas_menu a:hover {
background: var(--off_canvas_menu_hover);
transition: background .2s ease, color .2s ease;
}
ul.off_canvas_submenu {
display: none;
}
ul.off_canvas_submenu_active {
display: flex;
}
li.off_canvas_submenu_li {
border: none;
}
a.off_canvas_submenu_link {
color: #a9a9a9;
padding-left: 2.5rem;
}
.off_canvas_backdrop {
position: fixed;
inset: 0;
background: var(--off_canvas_backdrop_background);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
opacity: 0;
visibility: hidden;
transition: .3s ease;
z-index: 10;
}
.off_canvas_backdrop.off_canvas_backdrop_active {
opacity: 1;
visibility: visible;
}
h1 {
font-size: 2rem;
font-weight: normal;
}
footer {
display: flex;
flex-direction: column;
width: 100%;
max-width: 750px;
margin: 0 auto;
}
.footer_content {
font-size: 1.5rem;
padding: 1.5rem;
text-align: left;
}
button {
margin-top: 1rem;
padding: 1rem 2rem;
appearance: none;
border: var(--btn_border);
border-radius: var(--primary_border_radius);
background: var(--btn_background);
font-family: inherit;
font-size: 1.5rem;
font-weight: 500;
color: var(--btn_font_color);
cursor: pointer;
transition: background .2s ease, border-color .2s ease, box-shadow .2s ease, transform .15s ease;
}
button:hover {
background: var(--btn_hover_background);
transform: translateY(-1px);
}
/*responsive elements*/
@media only screen and (max-width: 1200px) {
.main_wrapper {
margin: 2.5rem 1.5rem 1.5rem 1.5rem;
width: auto;
}
.off_canvas_menu {
top: 0;
left: 0;
width: 100%;
border-right: none;
}
.off_canvas_menu ul {
min-height: 100%;
margin: 0;
padding: 0;
align-items: flex-start;
}
.off_canvas_menu li {
width: 100%;
text-align: left;
}
.off_canvas_menu a {
width: 100%;
}
}
@media only screen and (max-width: 992px) {
.main_wrapper {
margin: 2.5rem 1.5rem 1.5rem 1.5rem;
width: auto;
}
.off_canvas_menu {
top: 0;
left: 0;
width: 100%;
border-right: none;
}
.off_canvas_menu ul {
min-height: 100%;
margin: 0;
padding: 0;
align-items: flex-start;
}
.off_canvas_menu li {
width: 100%;
text-align: left;
}
.off_canvas_menu a {
width: 100%;
}
}
@media only screen and (max-width: 768px) {
.main_wrapper {
margin: 2.5rem 1.5rem 1.5rem 1.5rem;
width: auto;
}
.off_canvas_menu {
top: 0;
left: 0;
width: 100%;
border-right: none;
}
.off_canvas_menu ul {
min-height: 100%;
margin: 0;
padding: 0;
align-items: flex-start;
}
.off_canvas_menu li {
width: 100%;
text-align: left;
}
.off_canvas_menu a {
width: 100%;
}
}
@media only screen and (max-width: 480px) {
.main_wrapper {
margin: 2.5rem 1.5rem 1.5rem 1.5rem;
width: auto;
}
.off_canvas_menu {
top: 0;
left: 0;
width: 100%;
border-right: none;
}
.off_canvas_menu ul {
min-height: 100%;
margin: 0;
padding: 0;
align-items: flex-start;
}
.off_canvas_menu li {
width: 100%;
text-align: left;
}
.off_canvas_menu a {
width: 100%;
}
}
/*responsive elements*/
</style>
</head>
<body>
<div class="off_canvas_backdrop"></div>
<nav class="navbar">
<div class="navbar_title">Offcanvas demo</div>
<a href="#" onclick="off_canvas_menu(event)" class="toggle_button">Menu</a>
</nav>
<div class="off_canvas_menu">
<ul>
<li><a href="#" onclick="off_canvas_menu(event)">Close</a></li>
<li><a href="#">Element</a></li>
<li><a href="#">Element</a></li>
<li><a href="#">Element</a></li>
<li><a href="#">Element</a></li>
<li><a href="#">Element</a></li>
<li><a href="#">Element</a></li>
<li><a href="#">Element</a></li>
<li>
<a href="#" onclick="off_canvas_submenu(event)">#Submenu 1</a>
<ul class="off_canvas_submenu">
<li class="off_canvas_submenu_li"><a class="off_canvas_submenu_link" href="#">1.1 Submenu element</a></li>
<li class="off_canvas_submenu_li"><a class="off_canvas_submenu_link" href="#">1.2 Submenu element</a></li>
<li class="off_canvas_submenu_li"><a class="off_canvas_submenu_link" href="#">1.3 Submenu element</a></li>
</ul>
</li>
<li>
<a href="#" onclick="off_canvas_submenu(event)">#Submenu 2</a>
<ul class="off_canvas_submenu">
<li class="off_canvas_submenu_li"><a class="off_canvas_submenu_link" href="#">2.1 Submenu element</a></li>
<li class="off_canvas_submenu_li"><a class="off_canvas_submenu_link" href="#">2.2 Submenu element</a></li>
<li class="off_canvas_submenu_li"><a class="off_canvas_submenu_link" href="#">2.3 Submenu element</a></li>
</ul>
</li>
</ul>
</div>
<div class="main_wrapper">
<div class="content_wrapper">
<div class="content_title">
<h1>Offcanvas demo</h1>
</div>
<div class="content">
<p>Willkommen bei der Offcanvas demo. Diese Navigation steht euch zur freien Verwendung für eure eigenen Projekte zur Verfügung. Der auf der Hauptseite bereitgestellte Code kann direkt kopiert und unkompliziert in eure Projekte integriert werden.</p>
<button onclick="off_canvas_menu(event)">Open</button>
</div>
</div>
<footer>
<div class="footer_content">
<p>Offcanvas demo developed by MSCRATCH</p>
</div>
</footer>
</div>
</body>
<script>
function off_canvas_menu(e) {
e.preventDefault();
const OFF_CANVAS_MENU = document.querySelector(".off_canvas_menu");
const OFF_CANVAS_BACKDROP = document.querySelector(".off_canvas_backdrop");
OFF_CANVAS_MENU.classList.toggle('active');
if (OFF_CANVAS_MENU.classList.contains('active')) {
OFF_CANVAS_BACKDROP.classList.toggle('off_canvas_backdrop_active');
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = '';
OFF_CANVAS_BACKDROP.classList.remove('off_canvas_backdrop_active');
}
if (! OFF_CANVAS_MENU.classList.contains('active')) {
const ALL_SUBMENUS = document.querySelectorAll(".off_canvas_submenu");
ALL_SUBMENUS.forEach(submenu => {
submenu.classList.remove('off_canvas_submenu_active');
});
}
}
function off_canvas_submenu(e) {
e.preventDefault();
const CURRENT_SUBMENU = e.currentTarget.nextElementSibling;
if (CURRENT_SUBMENU && CURRENT_SUBMENU.classList.contains('off_canvas_submenu')) {
CURRENT_SUBMENU.classList.toggle('off_canvas_submenu_active');
}
}
</script>
</html>