I have the below shown css only menu, but am wondering how I can, when the browser window gets smaller and the menu items doesnt fit, how I can move them one by one! onto the last, right most item "more..." so they create a sub menu there instead. Please see the following pictures of how first item "seventh" and "eighth" are moved onto "more..." and the second picture shows what should happen when you hover over "seventh", it should reveal its original sub menu items.
My current code: (pen with same for easier resizing: https://codepen.io/anon/pen/oZoMbK)
* {box-sizing:border-box;}
.nav{
background-color:#d6336c;
font-size:20px;
}
.nav ul{
list-style: none;
}
.nav ul li{
padding:2px 20px;
float: left;
position:relative;
background: #1bc2a2;
white-space: nowrap;
}
.nav ul li ul {
display:none;
position: absolute;
background-color:orange;
left: 0;
}
.nav ul li ul, .nav li li {
min-width: 100%;
}
.nav ul li:hover > ul{
display: block;
}
.nav ul ul ul{
left:100%;
top:0;
}
.nav a{
color:#ffffff;
}
ul,li{
margin:0;
padding:0;
}
<div class="nav">
<ul>
<li>first</li>
<li>second
<ul>
<li>sub1 first</li>
<li>sub1 second
<ul>
<li>sub2 first</li>
<li>sub2 second
<ul>
<li>sub3 first</li>
<li>sub3 second</li>
<li>sub3 third</li>
</ul>
</li>
</ul>
</li>
<li>sub2 third</li>
</ul>
</li>
<li>third
<ul>
<li>.
<li>.
<li>.
</ul>
</li>
<li>fourth</li>
<li>fifth</li>
<li>sixth</li>
<li>seventh
<ul>
<li>cats</li>
<li>dogs
<ul>
<li>beagle</li>
<li>boxer</li>
</ul>
</li>
<li>birds</li>
</ul>
</li>
<li>eighth</li>
<li>more...</li>
</ul>
</div>
First image when hovering "more...":
Second image, when hovering "seventh" under "more...":
I cant figure out how its done, only with media queries but I dont want set specific values as the menu items width might change/be dynamic. The following two pens somehow moves the items one by one as they dont fit when resizing the screen:
https://codepen.io/VPenkov/pen/wMZBOg & https://codepen.io/tejasukmana/pen/bZKNrJ
I really want to keep this css only, no javascript.
thanks in advance for any help!
Frank
Related
My understanding of flexbox, is that if you display a element as flex, that item become flex container and it direct children will become flex items and these flex items behave as inline block items,
so i am following this logic, and it was working fine, untill i added the last in my css, please read the comment i left the comment in my css code, which line is confusing me.
in short i was expecting similiar outcome, but i am confuse about the space, please see the image to understand as well,
HTML CODE
<ul class="menu">
<li>Home</li>
<li>About</li>
<li class="menu-item-has-children">Services
<ul class="sub-menu">
<li>Plumbing</li>
<li class="menu-item-has-children">Heating
<ul class="sub-menu">
<li>Residential</li>
<li>Commercial</li>
<li>Industrial</li>
</ul>
</li>
<li>Electrical</li>
</ul>
</li>
<li>Pricing</li>
<li>Contact Us</li>
</ul>
CSS CODE
/*basic style no need to pay attention*/
*{font-family:helvetica;
margin:0px;padding:0;
list-style-type:none;
}
ul{margin:5px;}
ul ul a:link{color:red;}
ul ul ul a:link{color:black}
/*displaying them as flex, work fine*/
.menu{display:flex;}
.menu li {flex:1;}
.menu li a {
display:block;
min-width:100%
}
/*this line is confusing to me*/
ul ul li{
display:flex;
}
First image
Second image
By default, flex organizes elements in rows, from left to right. In your case, that means that the two elements inside <li class="menu-item-has-children"> (the link and the sub-menu) will be positioned side by side.
You have to add flex-direction: column to fix your issue:
* {
font-family: helvetica;
margin: 0px;
padding: 0;
list-style-type: none;
}
ul {
margin: 5px;
}
ul ul a:link {
color: red;
}
ul ul ul a:link {
color: black
}
.menu {
display: flex;
}
.menu li {
flex: 1;
}
.menu li a {
display: block;
}
ul ul li {
display: flex;
flex-direction: column; /* <- specify the flex direction here */
}
<ul class="menu">
<li>Home</li>
<li>About</li>
<li class="menu-item-has-children">Services
<ul class="sub-menu">
<li>Plumbing</li>
<li class="menu-item-has-children">Heating
<ul class="sub-menu">
<li>Residential</li>
<li>Commercial</li>
<li>Industrial</li>
</ul>
</li>
<li>Electrical</li>
</ul>
</li>
<li>Pricing</li>
<li>Contact Us</li>
</ul>
The fact that your sub-menu appears to be outside your flex container is caused by the min-width: 100% setting on your .menu li a elements.
I want my dropdown menus to be no more than 250px wide, and the text to wrap to the next line. I set a max-width but they are not expanding.
http://jsfiddle.net/wtpvejjh/1/
<nav>
<ul>
<li>First
<ul>
<li>I want this to wrap to the next line at 250px</li>
<li>Something</li>
<li>Something</li>
</ul>
</li>
<li>Second
<ul>
<li>Something</li>
<li>Something</li>
<li>Something</li>
</ul>
</li>
<li>Third
<ul>
<li>Something</li>
<li>Something</li>
<li>Something</li>
</ul>
</li>
</ul>
</nav>
To restrict the specific LI (as per OP's original question):
Set the nav ul {width:250px} and clear the floated li's. They'll then sit below eachother and will only be as wide as their content up until they are as wide as the parent (250px) and are forced to wrap.
nav li {
list-style: none;
float:left;
position: relative;
padding: 10px;
background: #eee;
}
nav li a {
display:inline-block; /* Make these inline or inline block so their width is collapsed. */
}
nav li ul {
display: none;
position: absolute;
top: 100%;
left: 0;
padding: 0;
width: 250px; /* Set width. This will 'contain' the children. */
}
nav li ul li {
clear:both; /* Clear these so they stack. */
}
nav li ul li a {
padding: 5px;
color: red;
text-decoration: none;
}
li:hover ul {
display: block;
}
<nav>
<ul>
<li>First
<ul>
<li>I want this to wrap to the next line at 250px</li>
<li>Something</li>
<li>Something</li>
</ul>
</li>
<li>Second
<ul>
<li>Something</li>
<li>Something</li>
<li>Something</li>
</ul>
</li>
<li>Third
<ul>
<li>Something</li>
<li>Something</li>
<li>Something</li>
</ul>
</li>
</ul>
</nav>
To restrict the child UL to a max-width (as per OP's comment):
It feels a bit 'hacky' and your mileage may vary but the following works for me...
Use inline-block rather than floating the parent li's. Set the child ul to the desired max width and present the child lis as table-rows. This should mean that the 'table-row' will be collapsed and held open by the content up until it reaches its parent's bounds - at which point the content will wrap.
nav {
font-size:0; /* set font size to avoid the natural margin that exists between inline-block elements */
}
nav li {
font-size:16px; /* undo font size change to avoid the natural margin that exists between inline-block elements */
list-style: none;
display:inline-block; /* display inline (rather than float) */
position: relative;
background: #eee;
padding: 10px;
}
nav li:hover {
background: #ddd;
}
nav li a {
display:block;
}
nav li ul {
display: none;
position: absolute;
top: 100%;
left: 0;
padding: 0;
width:250px; /* fix at your desired max width */
}
nav li ul li {
display:table-row; /* display like a table-row */
}
nav li ul li a {
padding: 10px;
color: red;
text-decoration: none;
}
li:hover ul {
display: block;
}
<nav>
<ul>
<li>First
<ul>
<li>I want this to wrap to the next line at 250px</li>
<li>Something</li>
<li>Something</li>
</ul>
</li>
<li>Second
<ul>
<li>Something</li>
<li>Something</li>
<li>Something</li>
</ul>
</li>
<li>Third
<ul>
<li>Something</li>
<li>Something</li>
<li>Something</li>
</ul>
</li>
</ul>
</nav>
Update (as per OP's comment regarding the need for a box-shadow)
Assuming you're able to edit the HTML, you'll need to wrap the child ULs in an extra element.
See: http://jsfiddle.net/wtpvejjh/49/
FIDDLE HERE http://jsfiddle.net/wtpvejjh/30/
.Check this i just played around with your bit of code and the solution was easy , actually you need to give max width to the nav li ul li not the nav li ul as you did.
NOTE - Sometimes when you give max width and if a single word occupies greater width than the word comes out of the item, therefore use word-wrap:break-word; it will break the word and make it adjust the width.
Simply, you just need to add the width property of your second level li to your css as follows:
nav ul li ul li{
width: 250px;
}
Checkout this DEMO
for a smooth look pseudo-elements are the answer
Giving the nav ul a fixed width and clearing it's elements float is correct.
Furthermore using :before and :after pseudo elements you'll give visual width coherency to the nav li ul li elements,
check out the fiddle.
got an html list working as a dropdown menu with CSS when you hover through a < li > element like "Products" in my example. But what I want is the same effect when hover through < h3 > like "Contact" from my example. Is it possible?
Here's the html:
<h3>Contact</h3>
<ul>
<li>Home</li>
<li>About</li>
<li>
Products ▾
<ul>
<li>Laptops</li>
<li>Monitors</li>
<li>Printers</li>
</ul>
</li>
<li>Contact</li>
</ul>
And the CSS code:
ul li ul {
display: none;
}
ul li:hover ul{
display: block; /* display the dropdown */
}
Thank you very much in advance.
On hover you can only control the CSS of the element you hover over, or the CSS of elements within the element you hover over (one of its children).
So you can not make the ul change styles when you hover over the h3 because they 1) are not the same object and 2) do not have a parent-child relationship (they are siblings).
To show the menu when hovering over the h3, you can wrap both of them inside another object (div) and use this for the hover event. To distinguish between the two hovers you can add classnames to both the uls.
See this JSfiddle, or the code below:
<div class="container">
<h3>Contact</h3>
<ul class="menu">
<li>Home</li>
<li>About</li>
<li>
Products ▾
<ul class="submenu">
<li>Laptops</li>
<li>Monitors</li>
<li>Printers</li>
</ul>
</li>
<li>Contact</li>
</ul>
</div>
.container ul{
display: none;
}
.container:hover ul.menu{
display: block;
}
ul li ul.submenu {
display: none;
}
ul li:hover ul{
display: block; /* display the dropdown */
}
In short - you should nest ul inside the h3
<h3>
Contact
<ul>
<li>Home</li>
<li>About</li>
<li>
Products ▾
<ul>
<li>Laptops</li>
<li>Monitors</li>
<li>Printers</li>
</ul>
</li>
<li>Contact</li>
</ul>
</h3>
And in your css:
ul li ul {
display: none;
}
ul li:hover ul{
display: block; /* display the dropdown */
}
h3 > ul {
display: none;
}
h3:hover > ul {
display: block;
}
Here's the demo: https://jsfiddle.net/mscehjLf/1/
I am trying to make a horizontal drop down menu in CSS. However, it appears vertically:
I want the two topmost menu items to be horizontal. What can I do, besides making a table with one row?
ul ul {
display: none;
}
ul li:hover > ul {
display: block;
}
<ul>
<li>
abc
<ul>
<li>abc</li>
<li>abc</li>
</ul>
</li>
<li>
abc
<ul>
<li>abc</li>
<li>abc</li>
</ul>
</li>
</ul>
You can try floating the list items:
.root {
overflow: hidden; /* clear float */
}
.root > li {
float: left;
}
<ul class="root">
<li>
abc
<ul>
<li>abc</li>
<li>abc</li>
</ul>
</li>
<li>
abc
<ul>
<li>abc</li>
<li>abc</li>
</ul>
</li>
</ul>
You can add submenu a class/id with
.inline-menu{
display: inline;
}
http://jsfiddle.net/dyaskur/fby9fan6/
The gist of your question is actually this: what is the difference between inline and block elements? This is a fundamental question that is important to understanding the basics of layout in CSS/HTML. There is a good write-up on this topic and some of the trade-offs of the various approaches at:
http://designshack.net/articles/css/whats-the-deal-with-display-inline-block/
Basically, <li> is block-level tag, meaning that it displays as its own "block" element: receives a layout (settable dimensions), by default takes the entire width of the parent element, and has a forced break after the rendered element (is on a line to itself).
So, that leaves us with a number of approaches for having your menu items sit side-by-side:
Use inline-level elements for your menu items
Use block-level elements and float them
Use block-level elements and style them as inline-block
All of these approaches are detailed in the above link. Personally, I prefer to use floated block elements. I have a fiddle with some rough css to give you an idea. Note that there are some considerations in how to display your submenus as well. You'll note that I've implemented these as having display: block, with no float, because we want them to stack vertically.
HTML
<ul class="menu">
<li>
foo
<ul class="submenu">
<li>subfoo1</li>
<li>subfoo2</li>
</ul>
</li>
<li>
bar
<ul class="submenu">
<li>subbar1</li>
<li>subbar2</li>
</ul>
</li>
</ul>
CSS
ul.menu {
list-style: none;
}
ul.menu > li{
float: left;
position: relative;
}
ul.menu li {
background-color: #cccccc;
padding: 5px 20px;
}
ul.menu > li + li {
border-left: solid black 2px;
}
ul.menu li:hover > ul {
display: block;
}
ul.menu li a,ul.menu li a:link, ul.menu li a:hover, ul.menu li a:visited {
color: black;
text-decoration: none;
}
ul.submenu{
display: none;
list-style: none;
position:absolute;
left: 0;
padding: 0;
}
ul.submenu li {
float:none;
display: block;
}
ul.submenu > li + li {
border-top: solid black 1px;
}
You can just remove some <li> tags:
<ul>
<li>
abc
<ul>
abc
abc
</ul>
</li>
<li>
abc
<ul>
abc
abc
</ul>
</li>
</ul>
I suppose this one might be easy for you css gurus :)
I am trying to apply some css to a page that I am currently working on where I want to have a dropline menu.
I got the code from here and just did minor modifications (width of the outer ul, class instead of id for the outer ul and z-index instead of huge negative indentation)
As I see there is some misunderstanding, here is some more detail about how this menu should work:
There are two levels, one on the top and the other underneath.
The currently selected link from the top menu will have the css-class "current" attached to the li-element that contains that link. (I use the MVC SiteMapProvider for that, but this should not matter for this question)
The submenu that is associated with that "current" top menu should be displayed by default,
but it should be overlapped by another submenu if the user hovers over the link to another top menu.
(hope that clarifies it a bit)
This is the markup I am using:
<ul class="mainMenu">
<li>
Link1
<ul>
<li>
Sub1
</li>
<li>
Sub1
</li>
<li>
Sub1
</li>
</ul>
</li>
<li class="current">
Link2
<ul>
<li>
Sub2
</li>
<li>
Sub2
</li>
<li>
Sub2
</li>
</ul>
</li>
<li>
Link3
<ul>
<li>
Sub3
</li>
<li>
Sub3
</li>
<li>
Sub3
</li>
</ul>
</li>
</ul>
and it uses these styles:
* {
margin:0;
padding:0;
}
.mainMenu {
list-style:none;
height:3.8em;
position:relative;
line-height:1.4em;
}
.mainMenu li {
width:136px;
float:left;
text-align:center;
}
.mainMenu a {
height:1.5em;
display:block;
text-decoration:none;
color:#000;
background:#999;
}
.mainMenu li.current ul li.current a, .mainMenu li.current a div, .mainMenu a:active, .mainMenu a:focus, .mainMenu a:hover {
background:#777;
}
/* --------- Sub Nav --------- */
.mainMenu li.current ul {
left:0;
}
.mainMenu ul {
position:absolute;
left: 0;
z-index: 1;
width:408px;
list-style:none;
padding:.9em 0 0;
}
.mainMenu ul li {
width:auto;
margin:0 15px 0 0;
}
.mainMenu ul a {
font-size:80%;
height:auto;
padding:0 8px;
}
.mainMenu li.current ul, .mainMenu li:hover ul {
z-index: 10;
background:#fff;
}
See also here for a fiddle that includes both already.
In general this seems to work pretty well, BUT when I hover to the right (i.e. Link1) I cannot see the corresponding links from the submenu though it works when I hover to the right (i.e. Link3). Anyone got an idea why this is the case?
ps: I also do not know why the current node is not applying the style from
.mainMenu li.current ul
(at least I do not see it in firefox 17.0.1, though, when not in the fiddle itself I do not have that problem, so probably a minor issue and not my main question here)
Just add a bit of CSS :
.mainMenu ul {
display: none;
}
.mainMenu li:hover > ul {
display: block;
}
Example
EDIT
Just change or remove z-index in .mainMenu li.current:hover ul. Fiddle
You have set class="active" to second sub menu so the first menu is under (due to z-index set) the second menu. Add active class to first menu
<ul class="mainMenu">
<li class="current">
Link1
</li>
</ul>
DEMO
You miss place current class i.e. in second menu(LINK2). Remove it and place at first link(LINK1) as below
<li class="current">
Link1.......
</li>
<li> Link2 </li>