Second level UL width issue - css only - css

I'm having an issue with trying to get the second level UL to have a 100% width based off of the parent LI and not the first level UL like it does now. I'm trying to only use css if possible too. The reason I'm trying to figure this out, is so that I can then center the dropdown under the parent.
To best understand, I'm trying to mimic this nav dropdown when you hover over MEN: http://us.gant.com/
<ul> <----first level
<li>
<ul> <----second level
<li></li>
</ul>
</li>
</ul>

You have to specify the the width of the parent li for this.
So do something like this:
ul li {
width: 50px;
}
ul li li {
width: auto; /* reset width */
}
Now the ul of the submenu has the same width of the li, because the li it the first ancestor with width specified.

Related

CSS Selector first of children, NOT siblings

How do I select only the first instance of an element without the selector triggering for any children? Children as in descendants, not siblings.
In example ul:first-of-type would select the first unordered list though any submenus (ul ul, ul li ul and ul ul ul ul ul) would also be selected. I only want to select the first instance of a ul element within #menu.
I could do the following though it's pointlessly convoluted.
#menu ul:not(ul ul):not(ul ul ul):not(ul ul ul ul) {property: value;}
No, I also can not do #menu > ul as the number of elements between #menu and ul varies.
<nav id="menu">/* display: flex; justify-content: space-between; */
<div>
<ul>/* Primary, select THIS ul (no > in selector!) */
<li>Menu</li>
<li>Menu</li>
<li>Menu
<ul>/* Secondary menu. */
<li>Menu</li>
<li>Menu
<ul>/* Tertiary menu. */
<li>Menu</li>
<li>Menu</li>
<li>Menu</li>
</ul>
</li>
<li>Menu</li>
</ul>
</li>
<li>Menu</li>
</ul>
</div>
<div>
/* Auxiliary menu items on right side of menu bar, may contain ul (do not select these either). */
</div>
</nav>
At least at the time of this post and having gone through some extensive lists of selectors it at least appears that all type selectors are based on siblings, not descendants. So in order to make the first ul element in the menu have height: 100% without effecting secondary and tertiary ul elements I added a second selector.
#menu ul, #menu ul > li, #menu ul > li > a {align-items: center; display: flex; height: 100%;}
#menu ul ul {height: initial;}
This in part allows me to have drop down menus always horizontally centered beneath primary menus in combination with CSS variables for the total height of the primary header (in which the menu is a descendant of).
Because I work on a platform I can not add CSS classes as I please thus I must utilize what selectors are available.
Hopefully in the future CSS selectors will continue to expand to include descendant selectors in addition to the sibling selectors.

CSS: How to create a drop menu using relative position and multiple items

I am trying to create a drop-down menu for when the user hovers an item in another menu.
My current HTML:
<ul>
<li class="menu-main-items">Item1</li>
<ul id="submenu">
<li>Sub-item1</li>
<li>Sub-item2</li>
</ul>
</li>
<li class="menu-main-items">Item2</li>
</ul>
CSS:
.menu-main-items{display:inline;}
#submenu{display:none;}
li:hover #submenu{ //display the submenu below the parent main item }
To align the sub-menu with the parent item, I was thinking using position:relative; on #submenu and adding a certain offset, but that causes flickering, as the sub-menu is being displayed before item 2, rearranging the menu. As of now I have searched around and could only find explanation with one item in the main menu which doesn't cause the problem.
Is there another way to approach this?
You should make the li elements inline-block and change the positioning to absolute. The flickering is because the element is being shown and pushing the content out of the way as it is inserted into the flow. position: absolute removes it from the flow, getting rid of the flicker.
If you want to move the submenu relative to the parent, add position: relative to the parent and use top and left (bottom and right aren't really useful) to move it.
For more information, see this CSS-Tricks article.
.menu-main-items{
display:inline-block;
position: relative;
}
#submenu{
display:none;
position: absolute;
left: -10px;
}
li:hover #submenu{
display: block;
}
<ul>
<li class="menu-main-items">Item1
<ul id="submenu">
<li>Sub-item1</li>
<li>Sub-item2</li>
</ul>
</li>
<li class="menu-main-items">Item2</li>
</ul>
Li : position: relative;
Ul.submenu : position: absolute;
You can position the submenu relative to the li using:
Top, bottom, left, right.
Example
Li {position: relative}
Ul {position: absolute;top:25px;left:0;}
You can hide and show on hover
Ul {display: none;}
Li.mainmenu-items:hover > ul {display: block;}
The > in the css rule means it only targets the first element of the specified child under it. So this is the first level of ul,s inside of the current item hovered

CSS - Horizontally style list without using absolute positioning and JS

Is it possible to create a horisontally styled menu (like on image below) without using absolute positioning or JS?
Trying to create a menu. It uses standard unordered list to display.
Here is what I'm trying to achieve:
(Green list is a submenu of "How are you". It has a line break because it is limited by width.)
And currently what I have is this:
This is the pen: http://codepen.io/olegovk/pen/NNREMY
And the code:
HTML
<nav>
<ul>
<li>Hello</li>
<li>How are you
<ul>
<li>Allright!</li>
<li>And you?</li>
<li>Fine</li>
<li>La-la-la</li>
<li>Bla-bla-bla</li>
<li>Cheerio!</li>
</ul>
</li>
<li>Good bye</li>
</ul>
</nav>
<div class="clear"></div>
<p>Some paragraph to make sure it's below the menu.</p>
CSS
.clear {
clear: both;
}
p {
background-color: lightgrey;
}
li {
float: left;
list-style: none;
display: list-item;
margin: 0 0.5em;
}
li li {
margin: 0 1em;
}
li li a {
color: green;
}
nav ul ul{
max-width: 300px;
}
I know it's possible with absolutely positioning child lists or with JS. But absolute positioning of child lists takes them out of doc flow. As a result they overlap with content below them. Also I can't use JS.
for li li use this css style .
li li {
margin: 0 1em;
position:relative;
left:-110px;
}
and give a id to good bye li and then write it css
e.g
<li><a href="#" id='someId'>Good bye</a></li>
li #someId{
position:relative;
left:-150px;
}
Seems that it's impossible.
Here is another similar question: Position: absolute and parent height?
With regards to the menu, to achieve the desired result, the only solution is to have top level menu and sub-menu in different lists. That way no need to position sub-menu (second level list) absolutely.

list styling applying to nested list elements in css

when i apply width as 100% to list elements,the nested list elements will also get the same width! i dont want that to happen..how to make not applicable to listed elements.
for ex:html structure
<ul>
<li>
<ul>
<li></li>
<li></li>
</ul>
</li>
</ul>
css structure: ul li{width:100%;}
but this applies to nested elements also! i.e "ul li ul li" too gets the width as 100%..i dont want this to happen! any solution?
When you use ul li it targets all li elements which are child of ul so logically, all the li nested under ul gets affected. If you want to target only 1st level of li elements you can use
body > ul > li {
width: 100%;
}
The above selector selects li element which is directly nested under ul which is further directly nested to body. This way it won't select the nested ul element as it is not a direct child of the body element.
Replace body if you have any parent wrapper with a class or an id. Make sure you just don't use ul > li because this way it will again select the nested li as well.
You can use the > selector where ul > li means select all li whose parent is ul. You can further refine the parent-child relationship by indicating additional levels.
ul > li {
width: 100%;
background-color: yellow;
}
ul > ul > li {
width: 25%;
background-color: red;
}
<ul>
<li>A</li>
<li>B</li>
<ul>
<li>1</li>
<li>2</li>
</ul>
</ul>
By the way, if you put a list (ul) in a list item (li), you may get bullet styles you don't want like this:
A
B
1
2

Why can't an <ul> (with absolute position) inside a <li> (with relative position) auto size?

EDIT: see also my own answer below (2016)
For example:
<ul>
<li class="first">Home</li>
<li>Chi siamo
<ul><li>item1</li><li>item2</li></ul>
</li>
<li>Novità</li>
<li>Promozioni</li>
</ul>
Then styled:
/* level 1 Main menu ----------------------------------------- */
#main-menu > ul{ list-style:none; }
#main-menu > ul > li{
float:left;
display:block;
position:relative;
margin-left:1em;
}
#main-menu > ul > li.first{
margin-left:0;
}
/* sub Main menu ----------------------------------------- */
#main-menu > ul > li ul {
position: absolute;
z-index:1000;
display:none;
left:0;
top:28px;
}
#main-menu > ul > li:hover ul {
display:inline-block;
}
#main-menu > ul > li ul li{
float:left;
display:block;
list-style:none;
}
ok. So, I've got the main menu that shows up horizontal. I also want the submenu to show horizontal. But for some reason, the ul box do not resize to reach the total li tags width, so it remains vertical. The parent ul do not suffer of this problem.
I could make it work by simply adding a proper width to the child ul, but this is not the way I wanna use.
Any idea?
It's important to have the :hover twice if you use position absolute; 1st on the li, that triggers the display: block, then on the ul that is shown on trigger.
And then keep positioning and styling separate: I styled the a and not the li
See here:
http://jsfiddle.net/HerrSerker/T8x2r/2/
#main-menu > ul > li > ul:hover,
#main-menu > ul > li:hover > ul {
display: block;
}
Should work with float:left also
http://jsfiddle.net/T8x2r/3/
Elements with position: absolute take up the size of their children.
You can either set width: 100%; on the ul, or set left: 0; right: 0; which will also stretch it to the right size.
Also you might want to set list-style:none; on the nested ULs as well as top one.
To the person who suggested you use ids and classes, it is not necessary except for perhaps the very first ul being id'ed as "menu". I say this because what you're looking for is very rigid and structured.
This is what I understand you're trying to accomplish: Get a horizontal main menu that shows another horizontal sub-menu underneath when hovering over the main menu "links"
As shown here:
----------------------------------------------------------------------
Menu-Item 1 | Menu Item 2 (hovered over) | Menu Item 3
----------------------------------------------------------------------
| Sub Menu 1 | Sub Menu 2 | Sub Menu 3
-------------------------------------------------------
Now I'm no one to tell you how to design your menus. But as you can see right now, I'm not sure even how it should work. Should the second menu be left-aligned to the left most point of the main menu item it's hovered over? Or Should the second menu be left-aligned to the whole menu, all the way to the left?
If it's the first, the last menu item will have too small a space to have links under (one or two max) and if it's the second version, then people will get frustrated that they keep "losing" the sub-menu when trying to access the links all the way to the left when hovering over the last menu item (in our example: Menu Item 3). Trust me, most users are not that adept with the mouse and trust me, the first version would just look bad.
Thus people use vertical sub-menus when the main menu is horizontal, but again, I'm not going to question your motives. I'm gonna try to answer your question in the best way I can which will end up being the second way, set up as such:
----------------------------------------------------------------------
Menu-Item 1 | Menu Item 2 (hovered over) | Menu Item 3
----------------------------------------------------------------------
Sub Menu 1 | Sub Menu 2 | Sub Menu 3 | (blank)
----------------------------------------------------------------------
Firstly, your code is not even set-up to have it go this way. The way your code is currently written, it'll end up like the first example I showed you (which as I explained will have very little horizontal space for the last menu item to show things, if your menu takes up the width of your page of course)
So to accomplish this goal you will have to get rid of the relative positioning of your li. Another idea if you MUST for some reason have it set to relative is to set each li of your main menu to a different z-index and to set them left margin/padding as well as right margin/padding as to "fit" your entire menu. I find this to be a "hack" and would rather omit the relative positioning of your li.
The absolute ul nested underneath your relative object (whatever it be, in this case it is the menu ) can only take up as much space as you've designated. In this case 100% will only be the size of the li it is nested under. You could set it to something greater than 100%, such as 500px, but this would cause a problem for two reasons: 1) You will not be able to set all sub-menus to the absolute menu left as you probably want it to, becuase the absolute left of the nested element will only be the left most point of the li it is nested under. and 2) This is not good because the right most menu's sub-items will drift off to the right of the overall menu.
If you must keep the main menu positioned relative, you will have to individually set the left position of each nested ul manually. And for all but the first one this will be a negative number and will not be an exact science as all browsers do not display the same font (and thus will cause slight changes in the width of the menu items, to counter this you'll need to use images for perfect width across all browsers of all ages). But this distracts from the beauty of CSS which is using few lines to design multiple elements.
It would be much easier to remove the "relative" positioning off the main menu li (#main-menu > ul > li) and to add some bottom padding to it, else you'll never be able to hover over the sub-menu, it'll just disappear each time. If I had to guess at what you're doing and I was coding the CSS/HTML I would do it as such:
HTML:
<li>A
<ul>
<li>A1<li>
<li>A2<li>
<li>A3<li>
</ul>
</li>
<li>B
<ul>
<li>B1<li>
<li>B2<li>
<li>B3<li>
</ul>
</li>
<li>C
<ul>
<li>C1<li>
<li>C2<li>
<li>C3<li>
</ul>
</li>
</ul>
CSS:
ul#main-menu{ list-style:none;}
ul#main-menu > li {
float: left;
margin-left: 1em;
padding-bottom: 3em; /*make this the line-height space underneat the main menu, plus the heigh of the secondary menu, plus the extra space you wanna give the user to not lose focus on the second menu*/
}
ul#main-menu > li:first-child {margin-left: 0;}
ul#main-menu > li > ul {
display: none;
}
ul#main-menu > li:hover > ul {
position: absolute;
display: block;
left: 0;
list-style: none;
}
ul#main-menu > li:hover > ul > li,
ul#main-menu > li > ul:hover > li {
position: relative;
float: left;
margin-left: 1em;
}
ul#main-menu > li:hover > ul > li:first-child,
ul#main-menu > li > ul:hover > li:first-child {margin-left: 0px}
I've tested this on my own browser and it seems to work like you want it to. By now you should know two other ways to accomplish this, but with varying results and more work than this version.
Well, if you are sure that items always will be in one line, you can move "position: relative;" to parent ul, and remove "left: 0;" from second ul, it will do what you want, but if there will be to many items in the end of the line, they will be cropped.
Example: http://jsfiddle.net/ed9Wx/
Since you stated this in your code
#main-menu > ul > li:hover ul {
display:inline-block; }
it'd be best you make the display: block; margin: auto;
that way it could go full width of the li tag
#main-menu > ul > li:hover ul {
display:block; }
#main-menu > ul > li ul li{
float:left;
margin: auto;
list-style:none;}
This should do the trick.
There's one stupid thing: on the submenus, you can force the sumbenus to the inner items width by simply forcing whitespace: no-wrap on the inner items. It works despite any technique or layout you are using -- main LI items with display: inline-block, or modern flex layouts // and for the subs, regular display none/block or modern css3 fx solutions -- it doesn't matter. A raw example can be just this, in this case using flexbox and fadein/out fx for subs (but could be anything more simple no-flexbox or older, it really doesn't matter):
.main-menu{ // ul
display: flex;
flex-wrap: nowrap;
> li{
display: inline-block;
flex: 1;
position: relative;
&:hover{
.sub-menu{
visibility: visible;
opacity: 1;
transition: opacity 200ms linear;
}
}
.sub-menu{
display: inline-block;
position: absolute;
top: 50px;
left:0;
visibility: hidden;
opacity: 0;
transition: visibility 0s 200ms, opacity 200ms linear;
li{
a{
white-space: nowrap; // <<< THIS IS THE KEY!
}
}
} // sub-menu
} // > li
}

Resources