I have created a custom non sticky sub menu that I want to appear when a certain menu item is clicked on. I'm having it scrolled to location when clicked and I've decided I want to control visibility with the height attribute. What is the correct way of doing this with CSS?
Also this is my first question ever. I appreciate tips on asking better questions.
The structure looks something like this
#submenu {
height: 0;
overflow: hidden;
}
.submenu-trigger:focus~#submenu {
height: 134px !important;
}
<div id="wrapper">
<header>
<nav>
<ul>
<li><a>Item 1</a></li>
<li><a>Item 2</a></li>
<li><a class="submenu-trigger" href="#submenu">Item 3</a></li>
<li><a>Item 4</a></li>
</ul>
</nav>
</header>
<!-- Placed outside to follow page scroll -->
<section>
<div id="submenu">
<nav>
<ul>
<li><a>Item 1</a></li>
<li><a>Item 2</a></li>
<li><a>Item 3</a></li>
</ul>
</nav>
</div>
</section>
<main>
…
</main>
</div>
Edit: It seems this isn't possible with CSS. How do I get the submenu to retract using JS when the main menu item is no longer in focus?
Edit 2: Implemented a variant of @biberman's suggestion at https://ensjotannklinikk.no/forside-wip/. Here's the differences in the live version:
"Behandlinger" = the menu item in question
.behandlinger-meny
instead of #submenu
.behandlinger-item
instead of .submenu-trigger
55px
instead of auto
, to preserve CSS transition
document.querySelector('.behandlinger-item').addEventListener('click', function() {
var submenu = document.querySelector('.behandlinger-meny');
submenu.style.height = '55px';
});
It's really close, kudos to @biberman.
Only thing missing is
Having it stay open on every click (not toggle on and off). Figured myself.
Toggle off (back to height 0) when clicking anywhere else but @biberman strikes again..behandlinger-meny
and .behandlinger-item
This fix doesn't work on mobile. New question.
Thank you so much, Stack Overflow!
This can easily be done with js (in a script tag or a seperate js file). You just need an event listener for 'click' and a small function for changing the height:
document.querySelector('.submenu-trigger').addEventListener('click', function() {
var submenu = document.querySelector('#submenu');
submenu.style.height = submenu.style.height == 'auto' ? 0 : 'auto';
});
#submenu {
height: 0;
overflow: hidden;
}
.submenu-trigger:focus ~ #submenu {
height: 134px !important;
}
<div id="wrapper">
<header>
<nav>
<ul>
<li><a>Item 1</a></li>
<li><a>Item 2</a></li>
<li><a class="submenu-trigger" href="#submenu">Item 3</a></li>
<li><a>Item 4</a></li>
</ul>
</nav>
</header>
<section>
<div id="submenu">
<nav>
<ul>
<li><a>Item 1</a></li>
<li><a>Item 2</a></li>
<li><a>Item 3</a></li>
</ul>
</nav>
</div>
</section>
<main>
…
</main>
</div>
If you search a solution without extra javascript, may be you could reduce it to a minimum and do it inline. (it is better not to mix html structure and programcode, but it works):
#submenu {
height: 0;
overflow: hidden;
}
<div id="wrapper">
<header>
<nav>
<ul>
<li><a>Item 1</a></li>
<li><a>Item 2</a></li>
<li><a class="submenu-trigger" href="#submenu" onclick="document.querySelector('#submenu').style.height = (document.querySelector('#submenu').style.height == 'auto') ? '0' : 'auto';">Item 3</a></li>
<li><a>Item 4</a></li>
</ul>
</nav>
</header>
<section>
<div id="submenu">
<nav>
<ul>
<li><a>Item 1</a></li>
<li><a>Item 2</a></li>
<li><a>Item 3</a></li>
</ul>
</nav>
</div>
</section>
<main>
…
</main>
</div>
If you want to close the menu when you click somewhere else (not .submenu-trigger and not #submenu) or when you press 'Esc', then you need two more event listeners. But this is not inline:
var submenu = document.querySelector('#submenu');
var menuTrigger = document.querySelector('.submenu-trigger');
function isChild(item, parentItem) {
while (item != undefined && item != null && item.tagName.toUpperCase() != 'BODY'){
if (item == parentItem){
return true;
}
item = item.parentNode;
}
return false;
}
menuTrigger.addEventListener('click', function() {
submenu.style.height = 'auto';
});
document.querySelector('body').addEventListener('click', function(e) {
if ( !isChild(e.target, menuTrigger) && !isChild(e.target, submenu) ) {
submenu.style.height = 0;
}
});
document.addEventListener('keyup', function(e) {
if ( e.key == 'Escape' ) {
submenu.style.height = 0;
}
});
#submenu {
height: 0;
width: 100px;
background-color: #ddd;
overflow: hidden;
}
<div id="wrapper">
<header>
<nav>
<ul>
<li><a>Item 1</a></li>
<li><a>Item 2</a></li>
<li><a class="submenu-trigger" href="#submenu">Item 3</a></li>
<li><a>Item 4</a></li>
</ul>
</nav>
</header>
<section>
<div id="submenu">
<nav>
<ul>
<li><a>Item 1</a></li>
<li><a>Item 2</a></li>
<li><a>Item 3</a></li>
</ul>
</nav>
</div>
</section>
<main>
...
</main>
</div>
jQuery example:
var submenu = $('#submenu');
$('.submenu-trigger').on('click', function() {
submenu.css('height', 'auto');
});
$('body').on('click', function(e) {
if (!$(e.target).is('.submenu-trigger') &&
!$(e.target).parents().is('#submenu')) {
submenu.css('height', 0);
}
});
$(document).on('keyup', function(e) {
if (e.key == 'Escape') {
submenu.css('height', 0);
}
});
#submenu {
height: 0;
width: 100px;
background-color: #ddd;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wrapper">
<header>
<nav>
<ul>
<li><a>Item 1</a></li>
<li><a>Item 2</a></li>
<li><a class="submenu-trigger" href="#submenu">Item 3</a></li>
<li><a>Item 4</a></li>
</ul>
</nav>
</header>
<section>
<div id="submenu">
<nav>
<ul>
<li><a>Item 1</a></li>
<li><a>Item 2</a></li>
<li><a>Item 3</a></li>
</ul>
</nav>
</div>
</section>
<main>
...
</main>
</div>