Starting from this situation:
<div id="wrapper">
<ul class="menu">
<li>item 1</li>
<ul>
<li>item 1.1</li>
<li>item 1.2</li>
</ul>
<li>item 2</li>
</ul>
</div>
#wrapper {
/*width: 218px;*/
margin: 0px auto;
background-color: #cccccc;
overflow:hidden;
position: absolute;
top: 100px;
left: 0;
z-index: 999;
width: 31px;
}
The second level menu is visible only on click on the first level item (say item 1). The first level list will make room to show the sublevel one.
First level list have a width of 31px; when I hover an item it gets 187 extra width on the right showing labels (item 1 for example) with css3 transition. The other items will keep the 31px width.
My goal is to style the second level list so that:
width is 187px;
it is positioned with top=0 and right=0 relative to the first level item (in other words it is aligned on the right with the first level item)
has a z-index higher than wrapper so that it will not move the other items when displayed.
I tried to give position relative to the first level item and absolute to the sublevel but with no luck.
The first level menu when hovered:
The second level menu displayed actually:
A simple demo of what you are looking for is here
<div id="wrapper">
<ul class="menu">
<li>item 1
<ul class="l2">
<li>item 1.1</li>
<li>item 1.2</li>
</ul>
</li>
<li>item 2</li>
</ul>
</div>
and the css:
ul.l2 {
background-color: grey;
display: none;
position: absolute;
z-index: 99;
}
.menu li:hover ul.l2{display:block;}
If this is the kind of behavior you want, we can take it further.
Related
Problem case
I'm trying to create a scrolling, fixed-height list with flyouts for each list item.
I've used overflow-y: scroll; so that it can be scrolled in the y-axis.
However when I also try to use overflow-x: visible (in order to display the overflowing flyouts) it seems to be ignored
Code
Example 1 - List can be scrolled, but flyouts are clipped
As you can see, the flyouts (in-pink) are clipped
.list {
width: 72px;
height: 132px;
overflow-x: visible;
overflow-y: scroll;
background: lightgray;
}
.list li {
position: relative;
margin-bottom: 6px;
}
.flyout {
position: absolute;
top: 0;
bottom: 0;
left: 64px;
width: 128px;
background: pink;
}
<ul class="list">
<li>
Item 1
<div class="flyout">Item 1 Flyout</div>
</li>
<li>
Item 2
<div class="flyout">Item 2 Flyout</div>
</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
Example 2 - List cannot be scrolled, flyouts displayed just fine
Removing overflow-y: scroll shows the flyouts just fine, but as expected, the list can no longer be scrolled height-wise.
.list {
width: 72px;
height: 132px;
overflow-x: visible;
background: lightgray;
}
.list li {
position: relative;
margin-bottom: 6px;
}
.flyout {
position: absolute;
top: 0;
bottom: 0;
left: 64px;
width: 128px;
background: pink;
}
<ul class="list">
<li>
Item 1
<div class="flyout">Item 1 Flyout</div>
</li>
<li>
Item 2
<div class="flyout">Item 2 Flyout</div>
</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
A possible solution
I could of course make my .list have a width just enough so the flyouts don't overflow it.
I'd like to avoid that, as the list would be placed on top of a drawing canvas, thus it would block painting on the canvas via the mouse.
Using pointer-events: none so as not to block painting wouldn't work in this case as the pointer-events are necessary in order to detect the scroll-event for the list in the first place.
You will need to remove position: relative. Then the absolute positioned flyouts won't be restricted by overflow.
However, they won't scroll properly. You will need to trigger a relayout with JS.
// Force relayout
var li = document.querySelector('li:last-child');
setInterval(function() {
var parent = li.parentNode;
var next = li.nextSibling;
parent.removeChild(li);
parent.insertBefore(li, next);
}, 60);
.container {
position: relative;
overflow: hidden;
margin: 1em 0;
}
.list {
width: 72px;
height: 132px;
overflow-y: scroll;
background: lightgray;
margin: 0;
}
.list li {
margin-bottom: 6px;
}
.flyout {
display: inline-block;
position: absolute;
width: 128px;
background: pink;
}
<div class="container">
<ul class="list">
<li>
Item 1
<div class="flyout">Item 1 Flyout</div>
</li>
<li>
Item 2
<div class="flyout">Item 2 Flyout</div>
</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
</div>
Since you cannot force a child to exit an overflow parent - and control it's position - here's a
jQuery solution
jQuery creates dynamically a <div class="flyout"></div> element.
On LI hover it calculates the position and shows the flyout element.
The content is taken from the hovered LI data-flyout attribute:
var $flyout = $("<div/>", {
class: "flyout",
appendTo: "body",
hover: function(e) {
$(this).toggle();
}
});
$("[data-flyout]").hover(function(e) {
var par = this.parentNode; // The overlfow parent element
$flyout.css({
left: this.offsetLeft + this.offsetWidth,
top: this.offsetTop - par.scrollTop,
}).html( this.dataset.flyout ).toggle();
});
.list {
width: 72px;
height: 132px;
overflow-x: hidden;
overflow-y: scroll;
background: lightgray;
}
.list li {
position: relative;
margin-bottom: 6px;
}
/* Created in "body" by jQuery */
.flyout {
position: absolute;
z-index:99999;
display: none;
background: pink;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="list">
<li data-flyout="Item 1 Flyout">Item 1</li>
<li data-flyout="Item 2 Flyout">Item 2</li>
<li>No fly</li>
<li data-flyout="Item 4 Flyout">Item 4</li>
<li data-flyout="Item 5 Flyout">Item 5</li>
<li data-flyout="Item 6 Flyout">Item 6</li>
<li data-flyout="Item 7 Flyout">Item 7</li>
<li data-flyout="Item 8 Flyout">Item 8</li>
</ul>
Maybe you could leverage something like Superfish's vertical menu and call it a day.
I agree with the above comments in that I don't see a pure CSS way to accomplish this.
I have two divs. When I rollover on a link, I want to hide one div and show the other so it appears as if the background color has changed. Here is some example HTML:
<div id="main-nav">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
<div id="sub-nav">
<ul>
<li>SubItem 1</li>
<li>SubItem 2</li>
<li>SubItem 3</li>
</ul>
</div>
The sub-nav div is EXACTLY the same as the main-nav div, except the background-color is different.
#main-nav {
width: 500px;
height: 250px;
background-color: black;
display: block;
}
#sub-nav {
width: 500px;
height: 250px;
background-color: white;
display: none;
}
All I want to do is show the #sub-nav div whenever an item in the #main-div is hovered over. So the effect will be that the background-color appears to change from black to white on hover.
Can I do this using only CSS?
Basically I am wanting to know if I can change the display property of a containing div whenever an element inside that div (the <a> tag) is hovered over? That is, hovering on a link should cause its containing div #main-nav to change to display: none and the #sub-nav div to become display:block
No you can't do this just with CSS. You would need the subnav to be a child of the element you are hovering or directly adjacent to it.
You could use css selectors like
#main-nav li:hover .sub-nav{}
or
#main-nav li:hover + .sub-nav{}
Alternatively you could use javascript
Why not just change the background color? Like this:
<div id="main-nav">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
#main-nav:hover { background-color: black; }
Edit you can do exactly what you asked, but you'd need a wrapper for that:
<div class="navigation-wrapper">
<div class="main">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
<div class="sub">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
</div>
And in your css:
.navigation-wrapper .sub { display: none; }
.navigation-wrapper:hover .main { display: none; }
.navigation-wrapper:hover .sub { display: block; }
Fiddle demo
I'm having a bit of difficulty trying to get my drop down (sub-menu) to appear above the content. I have tried z-index and still there is no fix.
Initially the sub-menu starts off with a height of 0 and overflow-hidden (so it isnt shown). I have added JQuery to add a class of open when the parent of the sub menu is clicked. Then I have put a height on. The menu appears fine along with the transition, however the drop down sits below the content and it cannot be clicked.
Can anyone please help?
CSS
.sub-menu{
height:0;
overflow:hidden;
}
.sub-menu li {
width: 100%;
display: block;
clear: both;
border-top:1px solid;
}
.sub-menu, ul.sub-menu, .sub-menu li, ul.sub-menu li{
z-index: 5000;
}
li.sub-menu-parent:hover .sub-menu {
height: 204px;
}
HTML
<div class="col navigation">
<nav>
<ul>
<li class="sub-menu-parent">Menu Item 1
<ul class="sub-menu">
<li class="sub-close">Back</li>
<li>Sub Item 1</li>
<li>Sub Item 1</li>
<li>Sub Item 1</li>
<li>Sub Item 1</li>
</ul>
</li>
<li>Menu Item 2</li>
<li>Menu Item 3</li>
<li>Menu Item 4</li>
<li class="sub-menu-parent">Menu Item 5
<ul class="sub-menu">
<li class="sub-close">Back</li>
<li>Sub Item 5</li>
<li>Sub Item 5</li>
<li>Sub Item 5</li>
<li>Sub Item 5</li>
</ul>
</li>
</ul>
</nav>
</div>
You need to give your element some position before the z-index will kick into action. I'd suggest also adding this to your .navigation divider instead of the li elements:
div.navigation {
position: relative;
z-index: 5000;
}
You should then give a lower z-index to your content just to be on the safe side:
{contentSelector} {
position: relative;
z-index: 1;
}
z-index is not working without position you need to set a position for your element.
.sub-menu, ul.sub-menu, .sub-menu li, ul.sub-menu li{
position:relative;
z-index: 5000;
}
Reference
You won't see the transition, without the position,
you need it relative to affect the div.
..and I did it in a nice little rhyme for you too :)
Have a look at this FIDDLE
Also, because Im in a good mood, I've tweaked into a sample horizontal menu
You need to use:
ul ul{
position:absolute;
}
Without position set to absolute, the content is effectively being injected before the next list item. You dont necessarily need to use z-index for a vertical menu.
I have a menu with sub menus. I used nested uls to achive this. Now I'm facing this situation: I want all the items and subitems to be displayed horizontally at their respective level. The problem is that when an parent list has a children list, it's width grows so the next item at the same level goes far to the right.
To have things more clear here's a fiddle of what I'm taking about: http://jsfiddle.net/matias/n8gFT/
As you can see I would like to have the items B and C placed where the green dashed spaces are.
Is it possible to do this?
I would like to keep using nested uls and display: inline-block for itemes instead of float: left
SAMPLE HTML:
<ul>
<li>ITEM A
<ul>
<li>sub item A1</li>
<li>sub item A2</li>
</ul>
</li>
<li>ITEM B</li>
<li>ITEM C</li>
</ul>
SAMPLE CSS:
ul{border: 1px solid red; padding: 10px;}
li{display: inline-block; border: 1px solid blue; margin: 5px; padding: 10px; vertical-align: top;}
span{border: 1px dashed lime; margin: 0 10px; padding: 5px;}
EDIT 1: I forgot to tell you this: A, B and C have children. If I click on B, it's children are shown and A's and C's are hidden...and so on....
We will start off with a little CSS
#menu > li.sub ul {
list-style: none;
position: absolute;
top: -1000em;
left: 0px;
}
#menu li.sub ul li a {
display: inline;
}
#menu > li.sub:hover ul {
top: 3em;
}
#menu{
text-align:left;
}
li{
display:inline-block;
}
Finish with some HTML
<ul id="menu" >
<li class="sub">
ITEM A
<ul>
<li>sub A1</li>
<li>sub A2</li>
</ul>
</li>
<li class="sub">
ITEM B
<ul>
<li>sub B1</li>
<li>sub B2</li>
</ul>
</li>
<li class="sub">
ITEM C
<ul>
<li>sub C1</li>
<li>sub C2</li>
</ul>
</li>
</ul>
and a JSFIDDLE http://jsfiddle.net/ShADm/28/
You could style the lists that are being pushed over of margin-left: -20px; here is a working fiddle
http://jsfiddle.net/n8gFT/1/
Of course the amount it is pushed over can be edited by changing the margin-left
I achieved what I was looking for using display: table-cell to the li's and reducing ul's width.
See demo
Add a class to the sub lists and style them like this:
.sub { position: absolute; margin-left: -27px; }
I have a parent <ol> and couple of <li> items in that.
<ol style='width=800px;display :block;float:left;'>
<li style='display :block;float:left;'> Item 1 </li>
<li style='display :block;float:left;'> Item 2 </li>
<li style='display :block;float:left;'> Item 3 </li>
<li style='display :block;float:left;'> Item 4 </li>
</ol>
Is there any way my list item can be arranged in a way where it will equally divide the parent width (800px), and each item will have the same amount of width? I.e. each <li> will take 200px width.
I don’t want to hardcode the value. Is there any style attribute which will do that?
I dont want to hardocode the width like 20 % or something because the list items are dynamically added.it may be 4 or 5 or 6 sometimes
Try this: http://jsfiddle.net/QzYAr/
For details on display: table-cell: Is there a disadvantage of using `display:table-cell`on divs?
table-layout: fixed ensures equal width li elements.
CSS:
ol {
width: 400px;
/*width: 800px;*/
display: table;
table-layout: fixed; /* the magic dust that ensures equal width */
background: #ccc
}
ol > li {
display: table-cell;
border: 1px dashed red;
text-align: center
}
HTML:
<ol>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ol>
I think this is what you're asking for. It required jQuery though.
http://jsfiddle.net/sKPLQ/3/
CSS:
ul {
width: 800px;
}
li {
display: inline-block;
float:left;
}
JS:
var evenWidth = $(".list").width()/$(".list li").size();
$(".list li").css("width", evenWidth);
HTML:
<ul class="list">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
Here is a minimalistic design. It will produce responsive equal distance cells
<style>
div { border:1px solid red; width:400px; height:400px; }
ul { width:100%; height:50px; list-style: none; margin:0; padding:0; text-align: center; }
li { background-color:green; color:White; width:1%; position:relative; display:table-cell; border:solid 1px white; }
</style>
<div>
<ul>
<li>CELL 1</li>
<li>CELL 2</li>
<li>CELL 3</li>
<li>CELL 4</li>
</ul>
</div>
The magic is width:1%; position:relative; display:table-cell;
As Renesis pointed out, I think table cells is the only option, unless you're scripting it. Although you can use table-cell in CSS.
#menu {display: table-row;}
#menu li {display: table-cell;}
..which will simulate the behaviour. Note that in IE it will, as usual, cause problems in the lower versions.
Please note: The original poster edited their question to exclude percent after I posted this answer.
Yes, you simply need to figure out the percent that each will use. In this case, 20%.
Also, you have some slight problems with your HTML (missing quote and width= instead of the correct width:).
<style>
ol { width:800px;display :block;float:left; }
li { border:1px solid black; display :block;float:left; width:20%; }
</style>
<ol>
<li> Item 1 </li>
<li> Item 2 </li>
<li> Item 3 </li>
<li> Item 4 </li>
</ol>
Update:
While you can get away without defining pixels by using a percentage, there is no way with block elements to get away without defining any width value (and width values are only valid as a unit or a percentage).
Not that I'm suggesting you use tables, but table cells are the only elements in HTML that sort of behave like what you are asking for.