Hannes Schneidermayer Hannes Schneidermayer -4 years ago 103
CSS Question

CSS: Class of first menu layer applied on submenu

I've got a navigation menu. But the menu get's wild.

The submenu class (this is the dropdown if you hover firstmenu). 'firstmenu' are the main areas of the site, hence the first level of the list.

Problem: Submenu get's the Firstmenus values. Even the tiny arrow

background: url(images/nav-arrow.png) no-repeat center bottom;
in - BUT WHY?!

We already looked into this, split up the code, removed typo3, all JavaScript and ended up with this css code:

#firstmenu {
list-style: none;
margin: 0;
padding: 0;
}

#firstmenu .firstLevel {
float: left;
}

#firstmenu .firstLevel a {
display: block;
font-size: 1.166em;
font-weight: 600;
line-height: normal;
color: #333;
padding: 41px 20px 26px;
margin-bottom: 4px;
}

#firstmenu .firstLevel .current a,
#firstmenu .firstLevel a:hover,
#firstmenu .firstLevel a.selected {
color: #fff;
background: url(images/nav-arrow.png) no-repeat center bottom;
}

#firstmenu .firstLevel a:hover,
#firstmenu .firstLevel a.selected {
background-color: #333;
}

/* Drop-Down Menus */

.submenu {
list-style: none;
margin: 0;
padding: 0;
position: absolute;
}

.submenu > ul {
top: 4px !important;
}

.submenu .secoundLevel {
width: 200px;
background: #fca500;
}

.submenu .secoundLevel a {
display: block;
color: #fff;
padding: 8px 15px;
border-top: 1px solid rgba(255,255,255,0.2);
}

.submenu .secoundLevel a:hover {
background-color: #333;
border-color: #1a1a1a;
}

.submenu .secoundLevel:first-child a {
border-top: none;
}


Anyone knows the fix?

EDIT, html:

<nav id="nav">
<ul id="firstmenu" class="clearfix">
<li class="firstLevel"><a href="index.php?id=99" >Startseite</a></li>
<li class="firstLevel current"><a href="index.php?id=91">Rootserver</a>
<ul class="submenu">
<li class="secoundLevel"><a href="index.php?id=96" >Vergleich</a></li>
</ul>
</li>
<li class="firstLevel"><a href="index.php?id=92">Voiceserver</a>
<ul class="submenu">
<li class="secoundLevel"><a href="index.php?id=97">Preisvergleich</a></li>
</ul>
</li>
</ul>
</nav>

Answer Source

I think the problem is a matter of understanding of CSS selectors. This selector:

#firstmenu .firstLevel a.selected {
  color: #fff;
  background: url(images/nav-arrow.png) no-repeat center bottom;
}

States the following: Match ALL <a> links that have a parent with class name firstLevel and it having a parent with ID firstmenu

That means this HTML bit matches:

<ul id="firstmenu" class="clearfix">
    // snip
    <li class="firstLevel current"><a href="index.php?id=91">Rootserver</a>
        <ul class="submenu">
            <li class="secoundLevel"><a href="#">Vergleich</a></li>
        </ul>
    </li>
    // snip

because the "secondLevel" menu has an anchor tag (<a>) that is a child (of any order, ie child, grandchild, great-grandchild, etc) of .firstLevel which is a child (of any order) of #firstmenu.

This is exactly how CSS is suppose to work but there ways to prevent what you're seeing.

The first option is to use the child selector (what I sometimes refer to as "direct descendent" selector) >

.firstLevel > a:hover{ /* code */ }

This selector specifically states: "all anchor tag that you hover which are directly descendent from .firstLevel, but no deeper.

Which means, it matches:

<li class="firstLevel"><a href="#">A</a></li>

but not the link with value "B" below

<li class="firstLevel"><a href="#">A</a>
    <ul>
        <li><a href="#">B</b></li>
    </ul>
</li>

because the second <a> tag is not directly descendant of .firstLevel, there's a <ul> and <li> between them.

The second option is to "overwrite" the previous style by having another rule with a higher CSS specificity.

#firstmenu .firstLevel .submenu a.selected {
  background-image: none; /* remove the arrow from drop-down menus*/
}

There's reasons for doing one or the other.

Using the child selector is good when the styles are very specific to that element. You don't want ANY of the styles to carry over to further elements.

Use the "replacement" technique (for lack of a better term) when you're looking to modify only one specific style from another element. Ie. You want to keep the color, font, font-weight, but only want to remove the background image.

I hope that helps!

Here's some (bad) fiddles showing the base case:

http://jsfiddle.net/zTCbF/

with child selector

http://jsfiddle.net/zTCbF/1/

with the replacement technique

http://jsfiddle.net/zTCbF/2/

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download