Pierce Colman
Pierce Colman

Reputation: 25

How do I create a drop down menu without nested lists?

I am trying to achieve a basic css drop down menu with NO nested lists within lists. In other words the normal way is:

<ul>
    <li><a>Blah</a></li>
    <li><a>Blah Parent</a>
        <ul>
            <li><a>Blah Child</a></li>
        </ul>
    </li>
</ul>

The way that I need to do it is:

<ul>
    <li><a>Blah</a></li>
    <li><a>Blah Parent</a></li>
    <li class="childitem"><a>Blah Parent</a><li>
    <li class="childitem"><a>Blah Parent</a><li>
    <li><a>Blah</a></li>
    <li><a>Blah</a></li>
    <li class="childitem"><a>Blah Parent</a><li>
    <li class="childitem"><a>Blah Parent</a><li>
</ul>

Is there any way to do this with purely css? Or with some basic js help?

Upvotes: 1

Views: 1434

Answers (4)

Ike Evens
Ike Evens

Reputation: 13

Here is an example which uses CSS and a javascript.

<div class="topnav" id="myTopnav">
  <a href="home.html" class="active">Home</a>

  <div class="dropdown">
    <button class="dropbtn">Products
      <i class="fa fa-caret-down"></i>
    </button>
    <div class="dropdown-content">
      <a href="plinkone.html">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>
  </div>

  <div class="dropdown">
    <button class="dropbtn">Services
      <i class="fa fa-caret-down"></i>
    </button>
    <div class="dropdown-content">
      <a href="slinkone.html">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>
  </div>

 <a href="a.html">About</a>
  <a href="news.html">News</a>
  <a href="c.html">Contact</a>
  <a href="javascript:void(0);" style="font-size:15px;" class="icon" onclick="myFunction()">&#9776;</a>
</div>

Here is the javascript:

<script>
function myFunction() {
    var x = document.getElementById("myTopnav");

    if (!x.classList.contains("responsive")) {
        x.classList.add("responsive");
    } else {

        x.classList.remove("responsive");
    }
}
</script>

and the CSS

.topnav {
  background-color: #333;
  overflow: ;

}

.topnav::after {
    clear: both;
    content: "";
    display: block;
}

.topnav a {
  float: left;
  display: block;
  color: #f2f2f2;
  text-align: center;
  padding: 14px 16px;
  text-decoration: none;
  font-size: 17px;
}

.active {
  background-color: ;
  color: white;
}

.topnav .icon {
  display: none;
}

.dropdown {
    float: left;
    overflow: ;
}

.dropdown .dropbtn {
    font-size: 17px;   
    border: none;
    outline: none;
    color: white;
    padding: 14px 16px;
    background-color: #333;
    font-family: inherit;
    margin: 0;
}

.dropdown-content {
    display: none;
    position: absolute;
    background-color: #f9f9f9;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1;
}

.dropdown-content a {
    float: none;
    color: black;
    padding: 12px 16px;
    text-decoration: none;
    display: block;
    text-align: left;
}

.topnav a:hover, .dropdown:hover .dropbtn {
  background-color: #555;
  color: white;
}

.dropdown-content a:hover {
    background-color: #ddd;
    color: black;
}

.dropdown:hover .dropdown-content {
    display: block;
}

@media screen and (max-width: 600px) {
  .topnav a:not(:first-child), .dropdown .dropbtn {
    display: none;
  }
  .topnav a.icon {
    float: right;
    display: block;
  }
}

@media screen and (max-width: 600px) {
  .topnav.responsive {position: relative;}
  .topnav.responsive .icon {
    position: absolute;
    right: 0;
    top: 0;
  }
  .topnav.responsive a {
    float: none;
    display: block;
    text-align: left;
  }
  .topnav.responsive .dropdown {float: none;}
  .topnav.responsive .dropdown-content {position: relative;}
  .topnav.responsive .dropdown .dropbtn {
    display: block;
    width: 100%;
    text-align: left;
  }
}

Upvotes: 0

GitaarLAB
GitaarLAB

Reputation: 14645

Indeed, "with some basic js help", you'd need just a simple 'one-liner' (in your function) to fix up the HTML, here it is formatted for better readability (and explanation in comments):

function nestSubULbyClass(par, cls){
  for( var elms=par.getElementsByTagName('li'), L=elms.length, t
     ; L-- //loop through elements in reverse to avoid nested look-ahead loop(s)
     ; ~(' '+elms[L].className+' ').indexOf(cls)  //if   current elm contains specified class
       ? (t || (t=document.createElement('ul'))   //then take temp UL or create a new one
         ).appendChild(par.removeChild(elms[L]))  //     and move current elm to temp UL
       : t && (elms[L].appendChild(t), t=0)       //else append temp UL to current elm 
     );                                           //     and clear temp with falsy value
}

//"Make it so, number one!!"  Note this is just an example, hook and pass UL any way you like
window.onload=function(){
  nestSubULbyClass(document.getElementsByTagName('ul')[0], 'childitem');
};
<ul>
    <li><a>Blah</a></li>
    <li><a>Blah Parent</a></li>
    <li class="childitem"><a>Blah Parent</a></li>
    <li class="childitem"><a>Blah Parent</a></li>
    <li><a>Blah</a></li>
    <li><a>Blah</a></li>
    <li class="childitem"><a>Blah Parent</a></li>
    <li class="childitem"><a>Blah Parent</a></li>
</ul>

EDIT:
From here on, one can now simply use any pure css based drop-down menu (and styling) without requiring any other javascript-handlers (nice)!

For the following example I used the css from this answer. Note: I removed comments and formatting from the one-liner (humoring anyone arguing that non-context-aware standard formatting is better to read ☺)

function nestSubULbyClass(par, cls) {
  for(var elms=par.getElementsByTagName('li'), L=elms.length, t; L--; ~(' '+elms[L].className+' ').indexOf(cls) ? (t || (t=document.createElement('ul'))).appendChild(par.removeChild(elms[L])) : t && (elms[L].appendChild(t), t=0));
}

window.onload=function(){
  nestSubULbyClass(document.getElementsByTagName('ul')[0], 'childitem');
};
ul {
    font-family: Arial, Verdana;
    font-size: 14px;
    margin: 0;
    padding: 0;
    list-style: none;
}

ul li {
    display: block;
    position: relative;
    float: left;
}

li ul {
    display: none;
}

ul li a {
    display: block;
    text-decoration: none;
    color: #ffffff;
    border-top: 1px solid #ffffff;
    padding: 5px 15px 5px 15px;
    background: #2C5463;
    margin-left: 1px;
    white-space: nowrap;
}

ul li a:hover {
    background: #617F8A;
}

li:hover ul {
    display: block;
    position: absolute;
}

li:hover li {
    float: none;
    font-size: 11px;
}

li:hover a {
    background: #617F8A;
}

li:hover li a:hover {
    background: #95A9B1;
}
<ul>
    <li><a>Blah</a></li>
    <li><a>Blah Parent</a></li>
    <li class="childitem"><a>Blah Parent</a></li>
    <li class="childitem"><a>Blah Parent</a></li>
    <li><a>Blah</a></li>
    <li><a>Blah</a></li>
    <li class="childitem"><a>Blah Parent</a></li>
    <li class="childitem"><a>Blah Parent</a></li>
</ul>

Upvotes: 1

iCollect.it Ltd
iCollect.it Ltd

Reputation: 93571

The result you want is actually a bit ambiguous, but there are several approaches to this.

Solution 1 - change the DOM

If you want to change the DOM dynamically you can make use of jQuery's nextUntil() to find the sibling elements to move:

JSFiddle: http://jsfiddle.net/TrueBlueAussie/9afavum5/

// Solution 1 - change the DOM
$("ul li:not(.childitem)").each(function () {
    var children = $(this).nextUntil(":not(.childitem)");
    if (children.length) {
        $(this).append($("<ul>").append(children));
    }
});

This works by finding the intended parents (that do :not have .childitem), then finding the siblings up until the next parent element using nextUntil.

Soution 2 - toggle existing

If you simply want to toggle to child items, and not change the DOM, you can use similar matching techniques to find the sibling items:

JSFiddle: http://jsfiddle.net/TrueBlueAussie/9afavum5/1/

// Solution 2 - toggle the siblings
$("ul li.childitem").hide();
$("ul li:not(.childitem)").click(function(){
    $(this).nextUntil(":not(.childitem)").toggle();
});

Upvotes: 1

Ghostff
Ghostff

Reputation: 1458

You can As Long as The Got Id's And Clases FIDDLE HERE

HERE

<ul>
    <li><a>Blah</a></li>
    <li class="drp"><a>Blah Parent</a></li>
    <li class="childitem"><a>Blah Parent</a><li>
    <li class="childitem"><a>Blah Parent</a><li>
</ul>

JS

$(document).ready(function(){
  $(".drp").hover(function(){
       $(".childitem").slideToggle("fast");
    },function(){
         $(".childitem").hide();
  });
  $(".childitem").hover(function(){
       $(".childitem").show();
    },function(){
         $(".childitem").hide();
  });
});

CSS

.drp:hover
{
    cursor: pointer;   
}
ul li
{
    list-style-type: none;
}
.childitem
{
    display: none;
}
.childitem:hover
{
    background: green;
    cursor: pointer;
}

Upvotes: 0

Related Questions