Drop-down menu in CSS - css

I was trying to build a drop-down multi-level navigation menu bar in pure CSS.
Here is the code (I know it turns out ugly):
<!DOCTYPE HTML>
<html>
<head>
<title>Menu</title>
<style>
* {
margin: 0;
padding: 0
}
ul {
list-style: none
}
li {
float: left;
width: 120px;
height: 20px;
background: pink
}
li > ul {
display: none
}
li:hover > ul {
display: block;
position: relative;
top: -20px;
left: 120px;
background: red
}
#nav > li:hover > ul {
top: 0px;
left: 0px
}
li:hover {
background: red
}
</style>
</head>
<body>
<ul id="nav">
<li>1
<ul>
<li>1.1
<ul>
<li>1.1.1
<ul>
<li>1.1.1.1</li>
<li>1.1.1.2</li>
<li>1.1.1.3</li>
<li>1.1.1.4</li>
</ul>
</li>
<li>1.1.2</li>
<li>1.1.3</li>
</ul>
</li>
<li>1.2</li>
<li>1.3</li>
<li>1.4</li>
<li>1.5</li>
</ul>
</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</body>
</html>
The code runs fine under Firefox20 but in IE10 it is off by 1px up, and in Chrome26 it is off by 1px down. I think it is because the browsers render the list layout differently. Any help would be appreciated!
jsFiddle Demo

I would recommend starting with a reset stylesheet so that you clear any of the browser set styles. Then each browser will start from an even playing field. The browsers will not render the lists differently.
For more info on reset stylesheets see http://meyerweb.com/eric/tools/css/reset/

Related

How to Force Child element to remain open after hove

and thanks in advance,
I'm working on a css and html only (no js) menu for my website. I took the code from https://blog.logrocket.com/create-responsive-mobile-menu-with-css-no-javascript/ and adapted it. I have mostly succeeded, but have three issues I'm struggling with.
On the desktop version, I can't seem to set the children at the same height as their respective parents (I can either get the child to open at the top of the menu, or the bottom, but not in between).
On the mobile version, I want to force the children to stay open after they've been hovered on (otherwise it creates a huge disruption as the user gradually scrolls down the options in the menu (IE, the children close, shrinking the menu, while the user's scroller remains in the same place).
As the menu has a hidden checkbox to open/close the dropdown (on mobile), it only closes when clicked within the box. Is there a way without JS to close this anytime the user clicks outside the menu?
I am trying by all means NOT to use JS, if possible. Grateful for any advice.
STYLING FOR MENU
/* reset */
a{
text-decoration: none;
}
ul{
list-style: none;
}
li {
list-style-type: none;
}
/* Logo */
.logo{
display: inline-block;
color:#D7C9AA;
font-size: 1px;
}
/* Nav menu */
.nav{
width: 100%;
height: 100%;
}
.nav{
max-height: 0;
transition: max-height .5s ease-out;
}
/* Menu Icon */
.hamb{
cursor: pointer;
float: right;
padding: 20px 15px;
background-color:#7b2d26
}
.hamb-line {
background:white;
display: block;
height: 2px;
position: relative;
width: 24px;
}
.hamb-line::before,
.hamb-line::after{
background: white;
content: '';
display: block;
height: 100%;
position: absolute;
transition: all .2s ease-out;
width: 100%;
}
.hamb-line::before{
top: 5px;
}
.hamb-line::after{
top: -5px;
}
.side-menu {
display: none;
}
/* Toggle menu icon */
.side-menu:checked ~ nav{
max-height: 100%;
}
.side-menu:checked ~ .hamb .hamb-line {
background: transparent;
}
.side-menu:checked ~ .hamb .hamb-line::before {
transform: rotate(-45deg);
top:0;
}
.side-menu:checked ~ .hamb .hamb-line::after {
transform: rotate(45deg);
top:0;
}
/* Responsiveness */
#media (min-width: 881px) {
.nav{
max-height: none;
}
.hamb{
display: none;
}
.parent {
display:inline-block;
line-height:30px;
background-color:#D7C9AA;
border-right:#CCC 1px solid;}
.parent a{
margin: 20px;
color: #7b2d26;
font-weight:bold;
font-family: brandon-grotesque-1,brandon-grotesque-2,'Open Sans',Helvetica,Arial,sans-serif;
font-size:130%;}
.parent:hover > ul{
display:block;
position:absolute;}
.child {
display: none;}
.child li {
background-color:#ededed;
line-height: 40px;
border-bottom:#CCC 1px solid;
border-right:#CCC 1px solid; width:100%;
}
.child li a{
color: #7b2d26;
}
ul{
list-style: none;
margin: 0;
padding: 0px;
min-width:14em;
}
ul ul ul{
left:100%;
margin: 20px;
top:0;
margin-left:1px;}
li:hover {
background-color: #c3c3c3;}
.parent li:hover {
background-color: #c3c3c3;}
.expand{
font-size:14px; margin-right:5px;}
}
#media screen and (max-width:880px) {
.nav{
width: 100%;
height: 100%;
position: fixed;
overflow: hidden;
}
#menu {
margin-top:20px;
margin-left:0;
}
.parent {
display:block;
line-height:30px;
background-color:#ededed;
border-top:#CCC 1px solid;
border-bottom:#CCC 1px solid;
border-right:#CCC 1px solid;
padding-top:10px;}
.parent a{
margin: 16px;
color: #7b2d26;
text-decoration: none;
font-family: brandon-grotesque-1,brandon-grotesque-2,'Open Sans',Helvetica,Arial,sans-serif;
font-size:130%;}
.parent:hover > ul{
display:block;}
.child {
display: none;}
.child li {
background-color:#ededed;
line-height: 30px;
border-bottom:#CCC 1px solid;
border-right:#CCC 1px solid; width:100%;}
.child li a{
color: #7b2d26;}
ul{
list-style: none;
margin: 0;
padding: 0px;
min-width:4em;}
ul ul ul{
left: 100%;
top:0;
margin-left:10px;}
li:hover {
background-color: #c3c3c3;}
.parent li:hover {
background-color: #c3c3c3;}
.expand{
font-size:14px;text-align:center; margin-right:5px;}
}
*/CSS TO LOAD IMAGES IN HEADER, SHOULDN'T BE RELEVant
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- App title -->
<title>Responsive Pure CSS Menu</title>
<!-- Link CSS file -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- Navigation bar -->
<!-- Navigation bar -->
<header class="header">
<!-- Logo -->
LR
<!-- Hamburger icon -->
<input class="side-menu" type="checkbox" id="side-menu"/>
<label class="hamb" for="side-menu"><span class="hamb-line"></span></label>
<!-- Menu -->
<!-- Menu -->
<nav class="nav">
<ul id="menu">
<li class="parent">What We Do
<ul class="child">
<li>Mission, Vision, Values</li>
<li class="parent">Our Programs<span class="expand">»</span>
<ul class="child">
<li>Education</li>
<li>Health</li>
<li>Resource Center</li>
</ul>
<li class="parent">Our Impact<span class="expand">»</span>
<ul class="child">
<li>Financials</li>
<li>Success Stories</li>
<li>Newsletters</li>
</ul>
</li>
</ul>
</li>
<li class="parent">Who We Are
<ul class="child">
<li class="parent">Meet The Young Women<span class="expand">»</span>
<ul class="child">
<li>Grantees Seeking Sponsors</li>
<li>Grantees with Sponsors</li>
<li>Graduates</li>
</ul>
<li>Meet The Support Team</li>
<li class="parent">Meet the Boards<span class="expand">»</span>
<ul class="child">
<li>Meet the Zambian Board</li>
<li>Meet the US Board</li>
</ul>
<li>Meet The Donors</li>
<li>Our Partners</li>
</li>
</ul>
</li>
<li class="parent">Get Involved
<ul class="child">
<li>Donate</li>
<li>Sponsor a Young Woman</li>
<li>Contact Us</li>
<li>Spread the Word</li>
</ul>
</li>
</ul>
</nav>
</header>
<main>
<article>
<h1>
Some content
</h1>
<p>
More Content
</p>
</article>
</main>
</body>
</html>

Making 2nd level pure CSS dropdown menu to appear when hovering over 1st level menu item

I have created a navigation bar using pure CSS coding and no JavaScript coding at all. But I have one problem in the browser interface of it. I want to make my 2nd level MENU ITEMS appear when I hover with my mouse over the 1 st level menu item ( AKA sub menu of MAIN MENU item). But as per the current situation, when I hover over the main menu item called "Online Services", I can see the 1st level menu item, "Communication" and the corresponding 2nd level menu item list, called "Email","Instant Messaging" and "Social Networking" altogether at once!
So as I said above, I want to hide the 2nd level menu items when the main menu item, "Online Services" is hovered. BUT, I want to make it ONLY appear, when the 1st level menu item, "Communication" is hovered as per the mentioned current situation above.
Here is my HTML code:
#charset "utf-8";
#navMenu {
margin: 0;
padding: 0;
}
#navMenu ul {
margin: 0;
padding: 0;
line-height: 35px;
}
#navMenu li {
margin: 0;
padding: 0;
list-style: none;
float: left;
position: relative;
background-color: #222;
}
#navMenu ul li a {
text-align: center;
font-family: Tahoma, Geneva, sans-serif;
text-decoration: none;
height: 40px;
width: 170px;
display: block;
color: #fff;
position: relative;
}
#navMenu ul ul {
position: absolute;
visibility: hidden;
top: 40px;
}
#navMenu ul ul ul {
position: absolute;
visibility: hidden;
display: inline-block;
top: 0px;
margin-left: 160px;
}
#navMenu ul li:hover ul {
visibility: visible;
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>The Information Age</title>
<link href="css/dropDown.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="wrapper">
<div id="navMenu">
<ul>
<li>Home
</li>
<li>Online Services
<ul>
<li>Communication
<ul>
<li>Email
</li>
<li>Instant Messaging
</li>
<li>Social Networking
</li>
</ul>
<!--inner 2nd UL-->
<li>Online Education
</li>
<li>Online Entertainment
</li>
<li>E-Commerce
</li>
<li>Web Storage
</li>
</li>
<!--inner LI-->
</ul>
<!--end inner UL-->
</li>
<!--end main LI-->
</ul>
<!--end main UL-->
</div>
<!--end navMenu-->
</div>
<!--end wrapper div-->
</body>
</html>
You need to select the direct descendant on hover:
#navMenu ul li:hover > ul {
visibility: visible;
}
that way it won't select unless it is a direct child, rather than all child elements.
The > combinator separates two selectors and matches only those elements matched by the second selector that are direct children of elements matched by the first. By contrast, when two selectors are combined with the descendant selector, the combined selector expression matches those elements matched by the second selector for which there exists an ancestor element matched by the first selector, regardless of the number of "hops" up the DOM. ~ MDN
A full demo can be seen below:
#charset "utf-8";
#navMenu {
margin: 0;
padding: 0;
}
#navMenu ul {
margin: 0;
padding: 0;
line-height: 35px;
}
#navMenu li {
margin: 0;
padding: 0;
list-style: none;
float: left;
position: relative;
background-color: #222;
}
#navMenu ul li a {
text-align: center;
font-family: Tahoma, Geneva, sans-serif;
text-decoration: none;
height: 40px;
width: 170px;
display: block;
color: #fff;
position: relative;
}
#navMenu ul ul {
position: absolute;
visibility: hidden;
top: 40px;
}
#navMenu ul ul ul {
position: absolute;
visibility: hidden;
display: inline-block;
top: 0px;
margin-left: 160px;
}
#navMenu ul li:hover > ul {
visibility: visible;
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>The Information Age</title>
<link href="css/dropDown.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="wrapper">
<div id="navMenu">
<ul>
<li>Home
</li>
<li>Online Services
<ul>
<li>Communication
<ul>
<li>Email
</li>
<li>Instant Messaging
</li>
<li>Social Networking
</li>
</ul>
<!--inner 2nd UL-->
<li>Online Education
</li>
<li>Online Entertainment
</li>
<li>E-Commerce
</li>
<li>Web Storage
</li>
</li>
<!--inner LI-->
</ul>
<!--end inner UL-->
</li>
<!--end main LI-->
</ul>
<!--end main UL-->
</div>
<!--end navMenu-->
</div>
<!--end wrapper div-->
</body>
</html>

nested navigation menu positioning

I am learning CSS and trying to get a nested navigation menu working. I am able to float the main items and stack all the child elements under it, but the position relative for the child menus are not working. I intend to move the child menu items to the right relative to its parent. Please let me know where I am going wrong.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
<style>
*{
margin:0;
padding:0;
}
h1{
text-align: center;
text-decoration: underline;
margin-bottom: 10px;
}
li{
list-style: none;
}
ul li a{
text-decoration: none;
display: block;
width:100px;
height: 25px;
border: 1px solid green;
text-align: center;
}
.main > li{
float:left;
position: relative;
}
.main > li > li {
position: absolute;
top:0px;
left:10px;
}
</style>
</head>
<body>
<h1>Hello Plunker!</h1>
<ul class="main">
<li>Menu 1
<ul class="sub1">
<li>Menu 1.1
<ul class="sub2">
<li>Menu 1.1.1</li>
<li>Menu 1.1.2</li>
<li>Menu 1.1.3</li>
<li>Menu 1.1.4</li>
</ul>
</li>
<li>Menu 1.2</li>
<li>Menu 1.3</li>
<li>Menu 1.4</li>
</ul>
</li>
<li>Menu 2</li>
<li>Menu 3</li>
<li>Menu 4</li>
</ul>
</body>
</html>
Link to Plnkr - Plnkr Link
The primary issue is that your selector:
.main > li > li
Selects nothing.
This > means "immediate descendant". There only immediate descendant to .main > li is a ul, so the selector should read:
.main > li > ul
And, once you have that working, then you can hide the ul (under normal circumstances) and show it on hover:
.main > li > ul {
display: none;
position: absolute;
top:27px;
left:10px;
}
.main > li:hover ul {
display: block;
}
See this revised plunker
EDIT
Your question is not very clear. I just realized reviewing the code in the plunker that you also want a sub-sub menu.
I've revised the plunker, so it is correct. Basically, you also need to set the position / display of the sub-sub menu as well. Revised css below:
main > li > ul {
display: none;
position: absolute;
top:27px;
left:10px;
}
.main > li > ul > li > ul {
position: absolute;
top: 0;
left: 100%;
display: none;
}
.main > li:hover > ul,
.main > li:hover > ul > li:hover > ul {
display: block;
}
And, while we are at it, you do NOT need float: left. Float is something that has very specific, practical uses - and this isn't one of them. Change it simply to be display: inline-block, and you are set, without the other consequences of using float. (Note: with display inline-block, you may notice the nav items are spaced apart about 4px - this is due to whitespace and has a simple solution (hint: it's this answer)

All nested menus show when hovering over menu instead of just the first

I have used this method to centrally align my menu: http://matthewjamestaylor.com/blog/beautiful-css-centered-menus-no-hacks-full-cross-browser-support
I am having problems though with my selectors. The selectors I am using to show the sub menu and style the links is applying to all nested tags.
I have read the + operator selects the next sibling but I've tried things like #menu-main-menu-container li:hover a + ul but it doesn't work. The hover selector is confusing me a bit.
I included the snippet below. Can someone show me how I should be just selecting the first occurrence to display when hovering over the li?
I also have a problem of the second nested submenu not aligning properly but I think that might be due to the way I have centred the menu and not sure if that is fixable or not.
Any help appreciated.
#menu-main-menu-container {
width: 100%;
position: relative;
font: 300 16px/16px Lato, Arial; }
#menu-main-menu-container ul {
position: relative;
text-align: center;
float: left;
left: 50%;
margin: 0;
padding: 0; }
#menu-main-menu-container ul ul {
position: absolute;
display: none;
margin-top: 15px; }
#menu-main-menu-container ul ul ul {
right: 0; }
#menu-main-menu-container ul li {
right: 50%;
background-color: #f4f4f4; }
#menu-main-menu-container li {
list-style: none;
position: relative;
float: left;
padding: 15px;
margin: 0;
text-transform: uppercase; }
#menu-main-menu-container li:hover ul {
display: block; }
#menu-main-menu-container a {
white-space: nowrap;
text-decoration: none;
color: blue; }
#menu-main-menu-container li:hover {
background-color: blue;
transition: 1s; }
#menu-main-menu-container li:hover a {
color: white; }
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="top-nav-menu.css">
</head>
<body>
<div id="menu-main-menu-container">
<ul>
<li>Item 1</li>
<li>Item 2
<ul>
<li>Sub Item 1
<ul>
<li>Hidden Sub Item 1</li>
<li>Hidden Sub Item 2</li>
<li>Hidden Sub Item 3</li>
</ul>
</li>
<li>Sub Item 2</li>
<li>Sub Item 3</li>
</ul>
</li>
<li>Item 3</li>
</ul>
</div>
</body>
</html>
Maybe with:
#menu-main-menu-container li:hover > ul
Operator >
If you use > operator you ensure that ul must be direct child of li:hover.

IE8 not taking absolutely positioned element out of flow

so I've encountered a bug that I can't figure out in IE8. I've seen some doozies, but this one might take the cake.
I tried replicating it in Codepen, but we have a lot of code for this so I'll try including the computed styles from IE8.
Using Foundation 5, I have a Top Bar that starts out looking like this:
The dropdown is positioned absolutely, so it obviously shouldn't be stretching out the parent container. It doesn't actually stretch out the parent, but the grandparent. Here's the markup:
<nav id="global-nav" class="top-bar has-dropdown show-for-large-up" data-topbar >
<section class="top-bar-section">
<ul class="title-area">
<li class="name">
Title
</li>
</ul>
</section>
<section class="links top-bar-section">
<ul class="left">
<li class="divider"></li>
<li>Create
</li>
<li class="divider"></li>
<li class="has-dropdown">
<a>Explore</a>
<ul class="dropdown tab-left" id="explore-menu">
<li>Link 1
</li>
<li>Link 2
</li>
<li>Link 3
</li>
</ul>
</li>
<li class="divider"></li>
<li>Find
</li>
</ul>
</section>
<section class="top-bar-section">
<ul class="right">
<li class="has-form search">
<form id="header_search" name="search_form">
<input type="search" placeholder="Search" class="search" results=3 id="search_term" name="search_value" maxlength="200" />
<button id="search_submit"></button>
</form>
</li>
<li class="login">
Login
</li>
</ul>
</section>
The computed CSS from IE8:
#global-nav{ //this is the topbar that is stretching
background: #2a2d43;
background-image: none;
color: #666;
display: block !important;
font: inherit;
font-family: sans-serif;
font-size: 16px;
height: 80px;
line-height: 60px;
margin: 0px;
overflow: visible;
padding: 0;
position: relative;
vertical-align: baseline;
width: 100%;
}
li.has-dropdown .dropdown{
background: #fff;
box-sizing: border-box;
clip: rect(1px 1px 1px 1px);
z-index: 99;
color: #666;
display: block;
font: inherit;
font-family: sans-serif;
font-size: 16px;
height: auto !important;
left: 10%;
line-height: 60px;
margin: 0;
max-height: none;
max-width: 200px;
overflow: hidden;
padding: 0px;
position: absolute !important;
right: auto;
top: 64px;
vertical-align: baseline;
visibility: hidden;
width: auto;
}
li.has-dropdown.hover .dropdown{ //the open dropdown state
clip: rect(auto auto auto auto);
visibility: visible;
}
If you need more information let me know. Thanks in advance.
For reference, I'm testing on a Parallels VM of Win7 with IE8, using IE8 document mode and IE8 Standards.
Do you have a link to view this? I am wondering if maybe you should set the ul to position relative. I think the li is falling back to the first relatively positioned item. Hopes this helps.
If any of the parent elements of the absolute element has position: relative then the absolute is computed relative to that,
try removing the position: relative from the parent containers maybe it could help
also make sure you have correct
<!DOCTYPE html>
at the beginning of your file
It is not an IE8 rendering error, but a coding error/incompatibility somewhere. This demo code shows that IE8 does take absolutely positioned drop-down elements out of the flow:
<!DOCTYPE html>
<head>
<title>Demo IE8 Drop-Down Menu</title>
<meta charset="utf-8">
<style>
#navDivParent { /* = grandparent of the dropdown menu */
background-color: darkblue;
text-align: right;
color: white;
height: 100px;
width: 550px;
}
#navDiv ul {
list-style-type: none;
margin: 0;
padding: 0;
text-align: left;
}
#navDiv ul li {
float: left;
position: relative;
margin-right: 10px;
}
#navDiv ul li ul li {
clear: left;
}
#navDiv ul ul {
display: none;
}
#navDiv ul li:hover ul {
display: block;
position: absolute;
}
#navDiv a {
display: block;
padding: 0 10px 0 10px;
background: yellow;
color: blue;
text-decoration: none;
}
#navDiv #item2SubList a {
width: 175px;
}
#navDiv a:hover {
background: red;
color: white;
}
</style>
</head>
<body>
<div id="navDivParent">This is the grandparent<br> of the dropdown menu.
<div id="navDiv">
<ul>
<li>Menu item</li>
<li>Menu item w/ child
<ul id="item2SubList">
<li>Menu sub-item</li>
<li>Menu sub-item</li>
<li>Menu sub-item</li>
</ul>
</li>
<li>Menu item</li>
</ul>
</div>
</div>
</body>
</html>
.
I haven't made a live demo because JSFiddle, JSBin and the likes don't function in IE8, but I tested it in both a real IE8 and IE9 in IE8 mode.
As the in the question provided code does not contain a CSS :hover state declaration, the coding error/incompatibility might lie in the Javascript that would drive the hover state.
Your dropdown has a max-width of 200px. IE8 doesn't deal well with max-width. Essentially it's treated as a width declaration. Your forcing a width of 200px in IE8. You would need to set it to none...
max-width:none\9; /* IE8 */
I do not think this "bug" has anything to do with the position: absolute; not taking the .dropdown out of the flow. li.has-dropdown also has a .hover state applied to it. There is likely some other styling applied to li.has-dropdown that is causing #global-nav to shift. Perhaps some extra padding is being applied to li.has-dropdown. Unfortunately we don't have all the code to properly debug this.

Resources