How to make sub menu span full width of the browser window? - html

I want my sub menu to span the full width of the browser window like the below image:
I am using Bootstrap, also my main menu is floated to the right.
I have created a demo on what I have done so far. How do I achieve this result?
http://codepen.io/ifusion/pen/oLVVXj

First of all, bootstrap makes you really unflexible. So if you want to use it I suggest to move the submenu out of the menu's elements, because the width:100%; is dependent on the parent. So everything that should be wider than the parent, shouldn't be the child of this parent element. In addition position:absolute is dependent on the next parent with position:absolute or position:relative. So there are many things that don't make it easy. To move the submenu would make it a lot easier. There you can just use width:100%; and position:absolute with left:0.
Alternatively to get the submenu out of the flow of the page, you could use position:fixed. And width:100%. Check out the Codepen for this solution. I like the first one more, even if it's more work. However, fixed positioning has some side effects, but maybe it's not important for you.

The position absolute child will position with respect to the closest position relative parent, so removing the position relative for main-menu li will solve this issue. Also remove the padding and margin from the body and html.
body, html{
margin: 0;
padding: 0;
}
.main-menu {
list-style-type: none;
padding: 0;
margin: 0;
float: right;
}
.main-menu li {
float: left;
}
.main-menu li a {
display: block;
background: #c2c2c2;
padding: 20px;
color: #337ab7;
text-decoration: none;
}
.main-menu-dropdown {
position: absolute;
left: 0;
right: 0;
display: block;
padding: 0;
list-style-type: none;
background-color: black;
text-align: center;
}
.main-menu-dropdown li {
float: none;
display: inline-block;
margin-left: -4px;
}
.main-menu-dropdown li a {
background: black;
display: inline-block;
}
<div class="container">
<div class="col-md-12">
<ul class="main-menu">
<li>First item</li>
<li>
<a class="has-dropdown" href="#">Second Item</a>
<ul class="main-menu-dropdown clearfix">
<li>Sub item 1</li>
<li>Sub item 2</li>
<li>Sub item 3</li>
</ul>
</li>
<li>Third Item</li>
<li>Fourth Item</li>
</ul>
<div class="col-md-12">
I need the sub menu to span the width of the browser
</div>
</div>
</div>

First off, the width of the submenu is being restricted because it's parent element has position: relative.
Once that is removed the submenu becomes full width, however the items are still aligned left.
In the example below I made .main-menu-dropdown use display: flex and then centered the items within it.
http://codepen.io/adrianlynch/pen/RRddjk
.main-menu-dropdown {
position: absolute;
left: -15px;
right: -15px;
display: flex;
justify-content: center;
margin: 0;
padding: 0;
list-style-type: none;
background: black;
}

Related

100% width flex horizontal list with justify-content:space-evenly, how to put bullets centered in spaces?

I have an horizontal navigation bar, which is a UL list with a LI for each menu item, which has display:flex and justify-content:space-evenly
I can't fix the UL width, it should be as wide as its container, and I don't know the number of the items either.
How can I, by means of pure css and without adding tags in the html, put bullets always exactly in the middle of free space between items?
You can build something to that effect by using after pseudo elements of the li elements for bullets and display: contents; to treat them as direct children of the ul-container which means they are put exactly in the middle of the real items. However this only works if there is only one "real" child inside the individual li elements (the a element in my example below)
ul {
display: flex;
padding: 0;
margin: 0;
justify-content:space-evenly;
align-items: center;
}
li {
display: contents;
list-style-type: none;
position: relative;
}
li:not(:last-child):after {
content: "";
width: 5px;
height: 5px;
border-radius: 5px;
background-color: currentcolor;
display: block;
}
<ul>
<li>Point 1</li>
<li>Point 2</li>
<li>Point 3</li>
<li>Point 4</li>
</ul>

Position a pseudo :after element to the right of a list item

I am trying to position a pseudo :after element 30 pixels to the right of a menu list item.
No matter the length of the text of the item I want the element to be 30px to the right.
I have stripped the following code to the bare minimum that I think is required for this issue.
Note that this is a mobile menu. The menu and the a tag link extends the full width of the browser (phone).
#menu-main-menu-1 li {
position: relative;
list-style: none;
}
#menu-main-menu-1 li a {
padding: 18px 0;
display: block;
text-align: center;
}
#menu-main-menu-1 a:after {
content: "\25CF";
position: absolute;
right: 0;
left: 150px;
top: 20px;
}
<ul id="menu-main-menu-1">
<li class="menu-item">
Menu Item
</li>
<li class="menu-item">
Long Menu Item Text
</li>
</ul>
The above code produces the following result:
As you can see, I need to position it to the left 150px to get the element to go 30px to the right of the item. It works, but I can foresee an issue where if the menu item has a lot of text, it will surpass the 150px and the element will be in the text. For example:
I need the element to be 30px to the right of the text no matter the length. So it would look like:
Here is the JSFiddle link:
JSFiddle
Please note that I have stripped many of the unnecessary styles that do not affect the functionality of this question (color, fonts, etc.)
Any help would be much appreciated!
Thanks
#menu-main-menu-1 li {
list-style: none;
}
.menu-item {
display: flex; /* 1 */
justify-content: center; /* 2 */
}
.menu-item a {
margin: 0 30px; /* 3 */
padding: 18px 0;
}
.menu-item::after {
content: "\25CF";
align-self: center; /* 4 */
}
.menu-item::before {
content: "\25CF"; /* 5 */
visibility: hidden;
}
<ul id="menu-main-menu-1">
<li class="menu-item">
Menu Item
</li>
<li class="menu-item">
Long Menu Item Text
</li>
</ul>
Notes:
Establish flex container (block-level; takes full width)
Horizontally center child elements.
Anchors/menu items have 30px horizontal margins
Right-side pseudo-element is vertically-centered and always 30px to the right of menu item (regardless of text length).
A second pseudo-element is added on the left for equal balance. This keeps the menu items centered in the container. It's concealed with visibility: hidden. (more info)
#menu-main-menu-1 li {
position: relative;
list-style: none;
}
#menu-main-menu-1 li a {
padding: 18px 0;
display: inline-block;
text-align: center;
// Recommended to recenter text
width: 100%;
margin: 0 auto;
}
#menu-main-menu-1 a:after {
content: "\25CF";
padding-left: 30px;
}
I changed #menu-main-menu-1 li a to an inline-block rather than a block, meaning the block should wrap the text, then changed the :after element to pad by 30px to the right.
Is that what you want?
https://jsfiddle.net/tvfudkgt/1/

Responsive nav tweak

I'm working on making a responsive menu that by default is displayed inline with the site title. However on mobile the menu needs to display as a list below the site title and it's toggled by hitting a + or -. I've achieved all of this except for two small issues.
I can't seem to get the menu to display relative to the document flow so that it overlaps the text on the pages
I need the menu to be the full width of the page.
I'm not sure if I just need to take this menu and put it in its own div outside of the nav or if I'm just forgetting some css rule. It's currently set up as:
<nav>
<div id="nav-div">
<div id="title"></div>
<div id="menu-toggle"></div>
<div id="nav-links">
<ul>
<li>link 1</li>
<li>link 2</li>
<li>link 3</li>
</ul>
</div>
</div>
</nav>
CSS:
#nav-links {
position:absolute;
width:100%;
ul {
}
li {
display:block;
float: none;
border-bottom: 1px solid black;
&:last-child {
border-bottom: none;
}
a {
}
}
}
You need to set top and left properties on #nav-links. And if you set right too, you wont need width: 100%. Also make it position:relative. Like this:
#nav-div {
position: relative;
height: 50px;
}
#nav-links {
position:absolute;
left: 0;
right: 0;
...
}
Change 50px to whatever your navbar height is.
The way I ended up doing this was:
ul {
position: absolute;
width: 100%;
right: 0px;
left: 0px;
li {
width: 100%;
a {
width: #small-width; //defined with my variables
margin: 0px auto;
display: block;
}
}
}

centered nav with flexible left and right widths - percentage padding does not work

UPDATE: Simplified HTML & CSS as per one of the answers below. The problem is still occurring however.
I have a working nav that is something like this:
item11item2item3 Centered item4item5item6
I want to add padding between the items so it looks like this:
item1 item2 item3 Centered item4 item5 item6
The items on the left are right-justified. The items on the right are left-justified.
The Problem
If I use float: right; to justify the list, I get item3 item2 item1.
If I use float: left; and set the container width to auto, I can get the correct layout, but only when I use px padding.
When I use % padding like padding-left: 3%; it breaks and looks like this:
item1 item2 Centered item4 item5 item6
item3
Here's my HTML:
<div class="container">
<nav>
<ul class="left">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul class="center">
<li>Centered</li>
</ul>
<ul class="right">
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</nav>
</div>
Here's my CSS:
/* Reset */
html, body, nav, li {
margin: 0; padding: 0; border: 0;
}
li {
list-style-type: none;
list-style-position: outside;
}
/* Styles */
.container {
width: 100%;
height: auto;
}
nav {
width: 80%;
margin: 0 auto;
}
nav > ul.left {
position: absolute;
right: 55%;
}
nav > ul.left > li {
float: left;
padding-right: 5%;
}
.center {
position: absolute;
left: 45%;
width: 10%;
}
.center li {
text-align: center;
}
nav > ul.right {
position: absolute;
left: 55%;
width: 45%;
}
nav > ul.right > li {
float: left;
padding-left: 5%;
}
Notes:
I'm using absolute positioning & containers in order to keep "Centered" perfectly centered even if the widths of the left and right nav items aren't identical.
I'm using % based widths because it's a flexible layout (reponsive)
the above code works ok, but I'd really like to make the padding percentage based so it's flexible.
So it appears that the li-container div inherits the width correctly and accounts for the padding when I use pixels, but not when I use percentages. Is this typical behavior? What is the solution?
Here's a jsFiddle in case you want to play around with it.
ADDITIONAL UPDATE:
The chief problem seems to be the need to have the "left" items right-justified. If I use float:right then I get reverse order, which isn't good. If I use float:left on the left items, then the order is correct, but I need to remove explicit width from the container, or the items aren't right-justified. Removing explicit container width causes the issue I'm experiencing.
Using the element inspector in Chrome on that fiddle, with the padding on 3% on .left .li I gather this:
.left .li-container's calculated width: 128px
Each individual li's width: 43px
You have three li's --> 3 * 43 = 129px
That would cause the width of the child li's to extend the parent container's width, thus wrapping to a new line. So it probably has to do with rounding off in the calculation of the actual width from that percentage value.
To compensate for this, I can only think of a jQuery/JS solution at the moment but I doubt you'd want that, and just want it in pure CSS.
Note: I would just add this as a comment but unfortunately I can't because that requires 50 rep. Sorry for not providing a complete answer!
Edit: Here's a new solution. Hope this looks like expected. ;)
HTML
<nav>
<ul class="left">
<li>Item 1 longer longer</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul class="centered">
<li>Centered</li>
</ul>
<ul class="right">
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</nav>
CSS
ul, li {
margin: 0;
padding: 0;
list-style-type: none;
}
nav {
position: relative;
min-width: 700px;
}
nav > ul {
width: 100%;
background: red;
}
nav > ul > li {
display: inline-block;
text-align: center;
background: green;
color: white;
}
nav > ul.centered {
position: absolute;
left: 40%;
width: 20%;
background: orange;
}
nav > ul.centered > li {
display: block;
background: orange;
}
nav > ul.left {
position: absolute;
left: 0;
max-width: 40%;
}
nav > ul.left > li {
float: right;
padding: 2%;
}
nav > ul.right {
position: absolute;
left: 60%;
max-width: 40%;
}
nav > ul.right > li {
float: left;
padding: 2%;
}
Demo
Try before buy
Update
The only way to get all things lined up, in the right order without any breaking ever is using display: inline-block. I've updated only the left side to demonstrate it.
Final thoughts: As this will never break, you have to set a min-width for the <nav>-element, otherwise the elements will overlap on screens that are too small. What you experienced before, when the width of the parent container of floating elements gets too small and they break into the next line, is the expected behavior for floating elements.
Updated CSS
nav > ul.left {
position: absolute;
left: 0;
max-width: 40%;
text-align: right;
white-space: nowrap;
line-height: 0;
font-size: 0;
}
nav > ul.left > li {
display: inline-block;
padding: 10%;
line-height: auto;
font-size: 12px;
}
Demo
Try display: inline-block
Here's also a link to my first solution.

div height: 0; without any floating child elements?

Here's some HTML I have
<nav class="navlist">
<span class="left">
<li><a class="active" href="#">Home</a></li>
<li>Work</li>
<li>Services</li>
</span>
<span class="right">
<li>About</li>
<li>Blog</li>
<li>Contact</li>
</span>
</nav>
Relevant CSS:
.navlist {
position: fixed;
top: 0;
width: 100%;
list-style: none;
background-color: rgba(255,255,255,0.4);
}
.navlist span {
position: absolute;
margin: 10px 0;
}
.navlist .left {
right: 0px;
margin-right: 50%;
padding-right: 75px;
}
.navlist .left li {
margin-left: 75px;
}
.navlist .right {
left: 0px;
margin-left: 50%;
padding-left: 75px;
}
.navlist .right li {
margin-right: 75px;
}
.navlist li{
display: inline;
}
.navlist li a {
font-family: "Futura Thin", sans-serif;
font-size: 1.2em;
color: black;
text-decoration: none;
}
Why is the height of the <nav> element 0 instead of wrapping the height around the child elements? I've tried absolutely everything, adding overflow: auto; etc. and nothing works without simply defining the height manually, which is definitely not what I want. Any help?
<span> should be <ul> or <li> should be <span> or any inline-elements to make a valid code. best is to use <ul><li><a> for a list of links.
position:absolute;(or fixed) takes element out of the natural flow of the page, so <nav> have no content to make it grow.
this is caused by your
position:absolute
rule on the span elements.
Absolutely positioned elements don't fill the parent container, causing it to have a height of 0px.
Try making the same layout without using absolute positioning, and you should be fine.
Also, the <li> elements should be in a <ul> parent, not a <span>
You have taken <li> without <ul> or <ol> it is not a best practice.
absolute: The element is positioned relative to its first positioned (not static) ancestor element, So its container doesnt have specific value.
<ul>
<li><a class="active" href="#">Home</a></li>
<li>Work</li>
<li>Services</li>
</ul>
Need to wrap as above and need to give style to remove its default bullets.
Your child elements are positioned as absolute, thus also taking them out of the flow. Because of this, the .navlist element doesn't know how to expand.
Use floats to position your navigation lists and then user the overflow:hidden fix on the .navlist to have it expand to fit the child elements.
As others have said, positioning a child element as absolute will pull it out of the layout, its parent will then always have a height of 0 as it technically has no layout inside of it.
It completely depends on what your end result should look like so its hard to advise but a little reduced case of what you may want ( with a red background colour to make it obvious height is set on the nav is here:
http://jsbin.com/osobor/1/
.navlist {
position: fixed;
top: 0;
width: 100%;
list-style: none;
background: red;
}
.navlist ul {
float: left;
width:50%;
padding:0;
margin: 0;
list-style: none;
}
.navlist .right {
float:right;
}
.navlist li a {
font-family: "Futura Thin", sans-serif;
font-size: 1.2em;
color: black;
text-decoration: none;
}
Edit: Also your spans should be UL ( or OL ) elements if you're nesting LI's within them ( I've added this to the jsbin example )