I have a standard navigation menu with sub menus on some items. I want the sub menus to have a min-width and a max-width. For example, the sub items are at least 150px wide and can grow up to 250px wide before breaking on multiple lines. However, since the sub menus are absolutely positioned inside of a relatively positioned element, the sub items will not expand to the full max-width before breaking on multiple lines:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul,
li {
list-style: none;
}
nav > ul {
font-size: 0;
}
nav > ul > li {
position: relative;
display: inline-block;
font-size: 1rem;
}
nav > ul > li > a {
display: block;
padding: 1em;
background-color: black;
color: white;
}
.sub-menu {
position: absolute;
left: 0;
top: 100%;
}
.sub-menu a {
display: block;
padding: 1em;
color: white;
background-color: red;
min-width: 150px;
max-width: 250px;
}
<nav>
<ul>
<li>
<a>Line Item 1</a>
<ul class="sub-menu">
<li>
<a>Sub Item 1</a>
</li>
<li>
<a>Sub Item 2</a>
</li>
<li>
<a>Sub Item 3</a>
</li>
<li>
<a>Sub Item 4</a>
</li>
</ul>
</li>
<li>
<a>Line Item 2</a>
</li>
<li>
<a>Line Item 3</a>
<ul class="sub-menu">
<li>
<a>Sub Item 1</a>
</li>
<li>
<a>Sub Item 2</a>
</li>
<li>
<a>Long Sub Item 3 forcing sub menu to expand</a>
</li>
<li>
<a>Sub Item 4</a>
</li>
</ul>
</li>
<li>
<a>Line Item 4</a>
</li>
</ul>
</nav>
Setting a large explicit width, like 1000px, on the a elements forced them to expand, but I want to keep the first sub-menu from expanding past the min-width of 150px.
How can I keep the first sub menu at 150px and get the second to expand to 250px?
Try adding width: max-content to .sub-menu. This should allow it to expand.
so to dynamically alter the width of the list items depending on the text content length and keep the requirements of min-width:150px; and max-width:250px; The following works:
1) remove min-width: 150px; & max-width: 250px; from .sub-menu a
2) add this:
.sub-menu {
width:max-content;
width:-webkit-max-content;
width:-moz-max-content;
max-width:250px;
min-width:150px;
}
However, max-content is not supported on IE, EDGE or Opera Mini. So it depends on how important that aspect is to you. Keep in mind its likely it will be supported in the future in those browsers.
As you mentioned the child elements do not want to be larger than the parent due to the existing css, so if you keep the absolute positioning, you will need to alter the parents size dynamically as well.
1) remove min-width: 150px; & max-width: 250px; from .sub-menu a [same as before]
2) add
ul li {
width:100%;
max-width:250px;
min-width:150px;
}
Working example [has both solutions in it, but you will need to comment out/uncomment bits where indicated] = https://codepen.io/FEARtheMoose/pen/GXJzaV
Hope this helps.
Related
I'm trying to make a basic navigation bar where a child dropdown appears when hovering over a list item. I want to position this dropdown starting at the right most edge of the list item I am hovering over, but I want it this dropdown be able to scale bigger than the list item you're hovering over.
The trouble is that when I position the parent relative, the dropdown's width is constricted to the width of the list item you're hovering over, when I remove postion relative I lose the ability to position it the way I want it.
When the parent List item doesn't have position relative it looks like this:
But I want the right edge of that dropdown to align with the right side of the list item I'm hovering on. When I add position relative to the list items, the width of the dropdown is contsrained like this:
The markup looks like follows:
<nav>
<ul class="outer-list">
<li>
<a>
Work
</a>
<ul class="inner-list">
<li>Sub1</li>
<li>Sub2</li>
<li>Sub3</li>
</ul>
</li>
</ul>
<ul class="outer-list">
<li>
<a>
Contact
</a>
</li>
</ul>
<ul class="outer-list">
<li>
<a>
Helpdesk
</a>
<ul class="inner-list">
<li>Sub1</li>
<li>Sub2</li>
<li>Sub3</li>
</ul>
</li>
</ul>
<ul class="outer-list">
<li>
<a>
Subscriptions
</a>
<ul class="inner-list">
<li>Sub1</li>
<li>Sub2</li>
<li>Sub3</li>
</ul>
</li>
</ul>
I am not in charge of the markup, but if it needs to change to allow for a solution that is fine.
My CSS is as follows:
.outer-list{
.dropdown{
padding-right: 20px;
a{
color: black;
text-decoration: none;
position: relative;
.icon-dropdown{
position: absolute;
display: inline-block;
width: 6px;
height: 4px;
background-image: url('./Assets/BlueArrowIcon.svg');
background-size: cover;
background-position: center;
top: 50%;
right: -11px;
transform: translateY(-50%)
}
}
.inner-list{
padding: 25px 20px;
display: none;
position: absolute;
background-color: $color-white;
box-shadow: 5px 0px 50px rgba(0,0,0,0.16);
z-index: 1;
max-width: 310px;
li{
margin-bottom: 20px;
&:hover{
a{
color: $color-dark-red;
}
}
}
}
&:hover{
a{
color: $color-blue;
}
.inner-list{
display: block;
a{
color: black;
}
}
}
}
&:last-of-type{
.dropdown{
padding-right: 0px;
}
}
}
If anyone could help me that would be much appreciated.
I'm having an issue where my dropdown is always on the left. I need to have it so it's directly under each menu item.
I tried playing around with the positioning because the absolute of the subitems is why it's going on the left all the time. But putting position: relative on subitem breaks the menu completely on hover.
Demo of issue: https://jsfiddle.net/dsngpsxb/2/
Code below:
HTML:
<nav class="main-navigation">
<ul>
<li class="item">item
<ul class="subitem">
<li>subitem</li>
<li>subitem</li>
<li>subitem</li>
</ul>
</li>
<li class="item">item
<ul class="subitem">
<li>subitem</li>
<li>subitem</li>
<li>subitem</li>
</ul>
</li>
<li class="item">item</li>
<li class="item">item</li>
<li class="item">item</li>
<li class="item">item</li>
<li class="item">item</li>
</ul>
</nav>
SCSS/SASS:
.main-navigation {
width: 100%;
position: relative;
ul {
margin: 0 auto;
padding: 18px;
.item {
display: inline;
padding-right: 43px;
font-size: 13px;
text-transform: uppercase;
&:hover ul {
display: block;
}
}
}
}
.subitem {
display: none;
position: absolute;
top: 50px;
li {
line-height: 30px;
font-size: 14px;
}
}
Please note that I did indeed do research here and found several questions on SO that explain my problem and I tried all accepted answers but none work.
I have included each example with a corresponding JSfiddle example below:
Dropdown menu appearing not below parent
adding position: relative to my subitem completely breaks menu: https://jsfiddle.net/mtp2cg7c/2/
CSS: make dropdown submenu appear below parent <ul> <li>
block display, relative positioning and a left float on my <li> with absolute positioning, 100% top and left: 0 on my <ul> "smashes" all the items togther: https://jsfiddle.net/9s9Lmr1h/4/
CSS dropdown menu element moving to left?
In the fiddle attached I noted that the global container as a property of clear: both; - I tried that in conjunction with floats and positioning. All sub items still float to the left: https://jsfiddle.net/3x3krdsd/1/
Is my <nav> tag to blame? I can't find anything that suggests this tag alters behavior of these rules: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/nav
Add a position: relative; to your .item and left: 0; to your .subitem.
This will make the sub-item position itself relative to the parent item, which should give you the result you want: https://jsfiddle.net/58sb3rL4/
So, I have an unordered list which contains buttons for a keypad. The problem is that for some reason, There's an extra <li> element in the end of the list and this just ends up screwing everything. How could I fix this?
<ul id="buttons">
<li><div><a><span>1</span></a></div><div><a><span>2</span></a></div><div><a><span>3</span></a></div></li>
<li><div><a><span>4</span></a></div><div><a><span>5</span></a></div><div><a><span>6</span></a></div></li>
<li><div><a><span>7</span></a></div><div><a><span>8</span></a></div><div><a><span>9</span></a></div></li>
<li style="max-width:80px;margin:auto;"><div><a><span>0</span></a></div><li>
</ul>
//as you can see only 4 li elements
//styles
li {
width: 100%;
border-spacing: 10px 5px;
display: table;
table-layout:fixed;
text-align: center;
}
ul {
position: relative;
margin: 0;
outline: 0;
padding: 0;
vertical-align: baseline;
list-style-type: none;
}
But when I open the document in chrome, There are 5 <li> elements.
There is a typo error. Problem is at your last list item . It is not closed properly. It should be like this :
<li style="max-width:80px;margin:auto;"><div><a><span>0</span></a></div></li>
You have used <li> instead of </li> to close your last list item
so your could should be
<ul id="buttons">
<li>
<div><a><span>1</span></a></div>
<div><a><span>2</span></a></div>
<div><a><span>3</span></a></div>
</li>
<li>
<div><a><span>4</span></a></div>
<div><a><span>5</span></a></div>
<div><a><span>6</span></a></div>
</li>
<li>
<div><a><span>7</span></a></div>
<div><a><span>8</span></a></div>
<div><a><span>9</span></a></div>
</li>
<li style="max-width:80px;margin:auto;">
<div><a><span>0</span></a></div>
</li>
I may seem really silly or outright wrong in the way I code. However, when I create a drop down menu in CSS the new li elements get pushed to the other side of the page and not in the container box. How would I fix this?
Here is the code:
<nav>
<div class="wrapper">
<div class="brand">
<img class="UKLogo" src="images/logo.png" alt="">
</div> <!-- brand -->
<div class="navigation">
<ul class="nav-ul">
<li> HOME </li>
<li> ABOUT </li>
<a href="#">
<li class="course-li">
COURSES
<ul class="drop-down">
<li class="list-item"> Driver CPC </li>
<li> First Aid </li>
<li> Other </li>
</ul>
</li>
<li> CONTACT </li>
<!-- <li> TESTOMONIALS </li> -->
<!-- <li> FAQs </li> -->
</ul>
</div> <!-- Navigation -->
</div> <!-- Wrapper -->
</nav>
nav {
margin: 0px;
padding: 0px;
height: 75px;
background-color: #FFF;
}
.brand {
margin: auto;
width: 960px;
}
.company-name {
padding: 0px;
margin: 0px;
}
.UKLogo {
padding: 0px;
margin: 0px;
position: relative;
top: 11px;
}
.navigation ul li {
display: inline-block;
margin: 10px;
position: relative;
left: 380px;
top: -46px;
}
.navigation ul a {
color: black;
margin-left: 40px;
text-decoration: none;
font-family: Lato;
font-weight: 300;
}
.navigation ul a:hover {
color: #169ec5;
font-weight: 300;
}
.course-li:hover .drop-down {
left: 0px;
}
.drop-down {
position: absolute;
left: -5px;
z-index: 1;
background-color: white;
left: -9999px;
}
Thank you ever so much for looking and helping. Always open to criticism whether its the way I code or anything else.
Here is a JSFiddle https://jsfiddle.net/vj41qLts/
Many Thanks!
You need to declare a position in the parent, for the child to reside in. An element with position: absolute; will position itself to the first parent with position: relative;. If there is no parent with position: relative;, it will use the browser window instead.
See fix example here: https://jsfiddle.net/vj41qLts/1/
I think there are two thing you need to change:
ul li will select everything li in the navigation even the dropdown, ul>li will only select the immediate child, instead of running down the nested elements.
you need to add position:relative; in your dropdown's parent.
One of the first issues I see is the fact that your markup for your main links isn't setup correctly. Following a structure more link the below should give make it work the way you want it to:
<nav>
<ul>
<li><a href="#">Home<a></li>
<li><a href="#">About<a></li>
<li>
<a href="#">Courses<a>
<div>
<ul>
<li>A link</li>
<li>A link</li>
</ul>
</div>
</li>
</ul>
</nav>
Then use CSS or JS to control showing and hiding the dropdown of links.
I'm working on a fancy menu of some sort, but cant seem to get my head around a problem currently facing. Here's a image to illustrate the problem:
The whole thing is built using a nav tag that has a ul with li children.
Basically the right box thingy has to always stay on the top row, right edge, and when the windows is shrunken or smaller, this position/behavior has to maintain, and the other regular menu items should collapse on the second row.
The 2 boxes have to maintain a order: the one on the left is the first li element, and the one on the right is the last li element
Here's what I've tried so far:
-position absolute wont cut it, because it will indeed stay on the right, but it may or may not overlay the other elements(current situation);
-floating it, will probably collapse with the other elements on the next row
-adding a padding right to the nav or ul tag, will work, however, the other menu items will always have a right margin that wont allow them to ever fall under the right boxy thing;
Heres a js fiddle to the problem(shrink the results window): menu issue
I'm open to any ideas, even changing the whole markup if that's the solution, or some fancy js if its working. Thank you!
The markup used:
<nav class="secondary-navigation main-section">
<ul class="align-left secondary-navigation-list">
<li class="menu-item-block">
</li>
<li>
Menu Item
</li>
<li>
Menu Item
</li>
<li>
Menu Item
</li>
<li>
Menu Item
</li>
<li>
Menu Item
</li>
<li>
Menu Item
</li>
<li>
Menu Item
</li>
<li>
Menu Item
</li>
<li class="menu-item-block menu-last-item-block">
</li>
</ul>
The css used:
a{
text-decoration: none;
color: #656565;
padding: 10px;
font-size: 1.4em;
line-height: 50px;
}
.menu-item-block{
width: 50px;
height: 50px;
background: #656565;
}
.menu-last-item-block{
position: absolute;
top: 0;
right: 0;
}
ul, li {
margin: 0;
padding: 0;
list-style: none;
}
li{
float: left;
}
nav.secondary-navigation{
position: relative;
display: inline-block;
width: 100%;
}
nav.secondary-navigation:after{
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 5px;
background: #656565;
}
ul.secondary-navigation-list:after,
ul.secondary-navigation-list:before{
content: '';
position: absolute;
width: 5px;
height: 100%;
background: #656565;
}
ul.secondary-navigation-list:before{
left: 0;
}
ul.secondary-navigation-list:after{
right: 0;
}
You can do it by a little manipulation on the html and css:
change the order of the li so that the 2 special ones are on top
<ul class="align-left secondary-navigation-list">
<li class="menu-item-block">
</li>
<li class="menu-item-block menu-last-item-block">
</li>
<li>
Menu Item
</li>....
Change the css rule for secondary-navigation-list
.menu-last-item-block{
float:right;
}
see fiddle: http://jsfiddle.net/CLtCL/12/