Possible to hide all if one div active in CSS or is it only achievable in JS

Hi,

Unsure what category to put this in. I’m currently trying to create a navigation similar to the images below. You click the parent element, then the child list appears. I’ve got that working but in CSS is it possible to simply go as this parent element has been activated with the .expanded element, lets hide the other parent elements so it’s just the child and back button element displayed?



Theme from images

My HTML:

      <button class="menu-back">Back</button>
      <ul class="bignav list-unstyled">
        <li>
          <a href="#" class="">Home</a>
        </li>
        <li>
          <a href="#" class="has_children">Services</a>
          <ul class="sub-menu">
            <li><a href="">Service 1</a></li>
            <li><a href="">Service 2</a></li>
            <hr>
            <li>
              <a href="#" class="has_children">Clients</a>
              <ul class="sub-menu">
                <li><a href="">Something</a></li>
                <li><a href="">Something 1</a></li>
              </ul>
            </li>
          </ul>
        </li>
        <li>
          <a href="#" class="has_children">Contact</a>
          <ul class="sub-menu list-col-no">
            <li><a href="">London</a></li>
            <li><a href="">America</a></li>
            <li><a href="">UAE</a></li>
            <li><a href="">China</a></li>
          </ul>
        </li>
      </ul>

CSS:

.sub-menu {
  display: none;
  list-style: none;
}
.sub-menu.active {
  display: block;
}
.menu-back {
  display: none;
}
.menu-back.active {
  display: block;
}
.has_children:after {
  content: "+";
}
.has_children.expanded:after {
  content: "-";
}

.menu-back.active + .has_children {
  display: none;
}

.bignav li a {
    font-size: 3em;
    font-weight: 600;
    text-decoration: none;
    color: black;
    letter-spacing: -0.32px;
}

.list-col-no {
  column-count: 2;
}

JS:

const buttonBack = document.querySelector(".menu-back");
const hasChildren = document.querySelectorAll(".has_children");
const allContent = document.querySelectorAll(".sub-menu");

hasChildren.forEach((subMenu) => {
  subMenu.addEventListener("click", function (event) {
    const target = event.target;
    const subMenuList = event.target.nextElementSibling;
    event.preventDefault();
    if (!subMenuList.classList.contains("active")) {
      //allContent.forEach((item) => item.classList.remove("active")); //only allow one child open at a time (doesn't work with nested)
      //hasChildren.forEach((elem) => elem.classList.remove("expanded"));
      buttonBack.classList.remove("active");
    }
    target.classList.toggle("expanded");
    subMenuList.classList.toggle("active");
    buttonBack.classList.toggle("active");
  });
});
buttonBack.addEventListener("click", () => {
  allContent.forEach((elem) => elem.classList.remove("active"));
  hasChildren.forEach((elem) => elem.classList.remove("expanded"));
  buttonBack.classList.remove("active");
});

my codepen: Simple Sub-menu (codepen.io)

Also regarding my JS, how would you suggest i optimise it as i’m repeating myself a lot.
Thanks in advance. Appreciate the time it takes to help :slight_smile:

I’ve moved this thread over to CSS so that it can gain the benefit of the experts over there.

1 Like

Thanks was unsure which category to choose :slight_smile:

It’s not really possible in CSS without at least adding a class to the parent wrapper via JS when a menu is active. You could then use that class on the main parent (i.e. bignav.active) to hide all the elements except for the ones that you just expanded.

It would need a little thought though as you have nested menus within sub menus which means do you want the child nested menu to be the only one visible (thus hiding the previous sub menu). For example the clients menu is a child of the services menu.

Screen Shot 2022-02-18 at 16.36.48

Would you hide the services menu when the clients menu is open? Would you also hide the words ‘Services’ and the Word ‘Clients’ ?

Also what happens when you hide the other items? Does the page reflow because there is empty space where everything was or do you just leave blank holes in the page where the elements were originally.

There is a lot to consider before a solution could be considered but at the simplest level you would start by adding a class to the parent as mentioned and then utilising that to hide and show everything except the ones you want.

I can see this getting quite complicated very quickly . :slight_smile: I was also not quite sure what the back button was doing as surely the X or the (-) would activate the closing of the menu. If you can clarify what you want in a bit more detail we could work towards a suitable solution.

Off topic you can’t put the hr where you put it:) All content in a list must be inside list element tags. Nothing at all can live outside of a list tag.

Ahhh ok that’s good to know. Was unsure of how much I could achieve with CSS alone. JavaScript it is :slight_smile:

Yeee after my initial attempt this is exactly what I ran into. Lack of thinking far enough ahead on my end haha. Better to support deep nested navigations from outset.

So initially the +/- and back button was me wanting to make it multi-use (accordion, file tree, and a mega menu) but to keep things simple: the + acts as the trigger and the back button acts as the - taking you to the previous upper level.

I’m basically trying to replicate this navigation.
https://alioth-html.pethemes.com/light/home-personal.html#.

So for example:
[Initial state of what’s visible.]

  • Home
  • Services +
  • Contact

[You click ‘Services’, now this is only visible]

  • < Back - takes you back to its parent level
  • Service 1
  • Service 2
  • Clients +

[You click ‘Clients’, now this is only visible]

  • < Back - takes you back to its parent level
  • Something
  • Something 1

I forked this pen i found earlier that is pretty much what i’m trying to accomplish just minus the jquery lol.
Mobile Menu Prototyping (codepen.io)
Thanks for your help.

This is really good to know, I wasn’t aware. Thanks :slight_smile:

We should probably throw this back to the JS forum for refinement but here’s how I would attempt this as a starting point.

It only handles 2 nestings so any further nestings would need to be hard coded or perhaps automated in some way but I didn’t want to get any more complex for a proof of concept :slight_smile:

1 Like

Thanks Paul, ye that’s pretty much it. Yes please can we send it back to the JS forum. For unlimited/more than 2 nesting purposes how would that be automated? Would another loop be needed? or could you make use of nextElementSibling to continue getting the children.

Thanks for your help as always!

Now that we know roughly what you want let me see if I can simplify the CSS then I’ll throw it back to the js forum for refinement.

It’ll have to wait until tomorrow I’m afraid as power has been off here most of the day due to a storm so I’ll catch up tomorrow :slight_smile:

Here we go :slight_smile:

This allows for multiple levels with a much simplified css and html.

Here’s the barebones unstyled version that may be easier to follow:

(It might need testing as I’ve only just finished it :slight_smile: )

Lastly here is a version with a reset (back) button added when two levels or more of the menu are open so that you can close easily when nested in multiple levels.

https://codepen.io/paulobrien/pen/podLoJe

Still needs testing though :slight_smile:

1 Like

Wow! Yup that is it! Perfect!

Your solution works amazingly! Ill give it some testing today however I’m sure it’s all good!

I really appreciate your help and the time you spent. Thanks so much Paul

1 Like

Just added a little bit of styling to tidy it up a little and show how to style the elements if needed.

Everything else is still the same though.

1 Like

Thanks really helpful :slight_smile:

I’m gonna be editing slightly to make it mimic this behaviour, if you click menu then click services you can see the transition effect. so gotta switch from left slide in to right slide in :slight_smile:
https://www.delt.net/

A quick fork of your example
Nested menu testing only v4 (codepen.io)

1 Like

You just need to change one rule to do that.

Change left: -100vw; to left: 100vw; and it will slide in from the right.:slight_smile:

You can also stagger the list items sliding in but takes a bit more code to accomplish.

1 Like

Thankssss! Also got one question regarding the trigger. I see it’s the + that turns into a big X. For more flexibility is it possible to change the code slightly so it uses an actual back button as the trigger? Or potentially replacing the actual like replacing the actual element from a <b> to a <button>?

Thanks :slight_smile:

No you can’t have a button inside an anchor as that is not allowed.

However you can simply style the b element to look like a button or indeed look like anything you want. :slight_smile:

Rough example :slight_smile:

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.