I'm looking for a way to make a horizontal menu in which the menu items are justified across the width, have padding, and overflow to a new line when the number of menu items exceed the container space.
HTML:
<div id='upper-menu-wrapper'>
<div id='upper-menu'>
<ul>
<li>About</li>
<li>Parenting</li>
<li>Receipes</li>
<li>Devotional</li>
<li>DIY Projects</li>
<li>Home-making</li>
<li>Pregnancy</li>
<li>Frugal Living</li>
</ul>
</div>
</div>
CSS:
#upper-menu-wrapper {
width: 100%;
}
#upper-menu {
width: 1200px;
margin: 0 auto;
overflow: auto;
}
#upper-menu > ul {
list-style-type: none;
text-align: justify;
width: 100%;
}
#upper-menu > ul > li {
display: inline-block;
padding: 1em;
text-align: center;
}
Getting the elements to justify with wrapping to next line is tricky. Using display:table and table-cell can justify elements like tables but only in one row. Because your requirement is to also keep elements justified while wrapping within a fixed width container, the table-cell won't work.
There is a hack based on :after pseudo-element which can make this possible with wrapping across rows.
Demo: http://jsfiddle.net/abhitalks/MXZ6w/3/
Apply a fixed width to the wrapping div, text-align:justify on the ul and display:inline-block on li are required.
#upper-menu-wrapper {
width: 500px; /* fixed width on wrapping container */
}
#upper-menu { } /* this div is not really needed */
#upper-menu > ul {
list-style-type: none; /* getting rid of bullets */
margin: 0px; padding: 0px; /* getting rid of default indents */
text-align: justify; /* important to justify contents */
}
#upper-menu > ul > li {
display: inline-block; /* required. float won't work. */
text-align: left; /* to properly align list items */
white-space: no-wrap; /* to prevent wrapping of list items if required */
}
#upper-menu > ul:after {
/* this is the hack without which the list items won't get justified */
content:''; display: inline-block; width: 100%; height: 0;
}
Note 1: The display: inline-block is required, however it generates html white-spaces. In order to get rid of those white-spaces, html comments can be used in the markup of list items.
Note 2: The :after pseudo element in the hack is what seems to do the trick. However, that will create an unintended space below the ul. This space seems to be there because the elements are flushed across. If not justified, then this space does not appear.
IMPORTANT: Credit: #SamGoody from his answer here.
Related
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/
I am trying to have equal spacing between four different li elements, but I end up with this:
HTML:
<ul><li>Inbox</li></li><li>Drafts</li></li><li>Sent</li></li><li>Trash</li></ul>
CSS:
ul li {
width: 25%;
display: inline-block;
text-align: center;
}
I have tested the CSS and it is working as it should. I think the problem is that the li's don't all have the same amount of letters, so you end up with some weird visual effects. My reason for believing this:
(Equal spacing)
My approach with this issue is to center the li on the ul since the ul will naturally be the same width than the parent.
ul {
/* Use flex boxes to align li items */
display: flex;
justify-content: space-around;
/* Remove default padding from major browsers */
padding: 0;
/* Hide the default decorations for li items */
list-style: none;
}
ul > li {
/* Display the elements in one line */
display: inline-block;
}
Check out this JSFiddle to see it working.
Try this
ul {
width:100%;
margin-left: 0;
margin-bottom: 0
}
li {
list-style-type: none;
display: inline-block;
margin-right: 20px;
}
I know I could fix this with relative positioning, but I'm more wanting to know the why behind my button getting pushed down when I give height to .toggle. I figured out that giving absolute positioning to #menu made it so I could give top margin to .toggle, but when I gave it a height, the button got pushed down. When I changed the height on the button, it changed the vertical height of the button itself. When I tried line-height, again, the button itself changed size.
What is causing the button to get pushed down, and how would I fix this outside of using relative positioning, or switching to in-line block instead of using floats? (I gave .toggle a background-color of blue so I could visualize what was pushing down the button)
http://jsfiddle.net/7rj67454/
HTML:
<div id="menu">
<div id="logo">Codeplayer</div>
<ul class="toggle">
<li>HTML</li>
<li>CSS</li>
<li>JS</li>
<li>Result</li>
</ul>
<button>Run</button>
</div>
CSS:
/* ----------- UNIVERSAL -----------*/
a, body, html, ul, li, div {
margin: 0;
padding: 0;
list-style: none;
font-family: helvetica;
}
#logo, .toggle {
line-height: 50px;
}
/* ----------- MENU BAR -----------*/
#menu {
background-color: #EDEBED;
width: 100%;
height: 50px;
box-shadow: 1px 1px 1px #000000;
position: absolute;
}
/* ----------- LOGO -----------*/
#logo {
float: left;
font-weight: bold;
margin-left: 15px;
font-size: 20px;
height: 20px;
}
/* ----------- TOGGLE BAR -----------*/
.toggle li {
list-style: none;
float: left;
margin-left: 20px;
}
.toggle {
margin: 0 auto;
width: 250px;
background-color: blue;
height: 30px;
margin-top: 10px;
}
/* ----------- BUTTON -----------*/
button {
float: right;
margin-right: 15px;
}
This is happening because the li elements in your ul are floated. When you float an element it takes it out of the normal document flow. As far as a containing element is concerned a floated child element doesn't take up any space within it, so it collapses.
The only reason that the Run button isn't sitting all the way at the top of the page is because .toggle has margin-top: 10px; and is taking up the full width of .menu. Try removing margin-top and you'll see Run move up.
The Run button is sitting under your .toggle ul because .toggle is taking up the full width of the shared parent.
This is how your elements are currently laid out:
#######################################
# .toggle #
#######################################
# Run #
#######
By adding height to you .toggle you're simply pushing and element that is already below it further down.
http://jsfiddle.net/7rj67454/1/
If that's what you're looking for then it's because you're confusing or having a hard time grasping the concept of float, position: absolute, and inline-block.
You'd essentially want to avoid position absolute in your case as you don't really need to take anything out of the normal flow.
You want to display things as inline-blocks rather than their default block style because you want to put things inline.
Floating them to the left can achieve the same as inline-block styling but it wasn't meant to be used for what you're aiming for.
Here's a quote from the following page:
Advantages of using display:inline-block vs float:left in CSS
Inline Block
The only drawback to the display: inline-block approach is that in IE7
and below an element can only be displayed inline-block if it was
already inline by default. What this means is that instead of using a
<div> element you have to use a <span> element. It's not really a huge
drawback at all because semantically a is for dividing the page
while a is just for covering a span of a page, so there's not a
huge semantic difference. A huge benefit of display:inline-block is
that when other developers are maintaining your code at a later point,
it is much more obvious what display:inline-block and text-align:right
is trying to accomplish than a float:left or float:right statement. My
favorite benefit of the inline-block approach is that it's easy to use
vertical-align: middle, line-height and text-align: center to
perfectly center the elements, in a way that is intuitive. I found a
great blog post on how to implement cross-browser inline-block, on the
Mozilla blog. Here is the browser compatibility.
Float
The reason that using the float method is not suited for layout of
your page is because the float CSS property was originally intended
only to have text wrap around an image (magazine style) and is, by
design, not best suited for general page layout purposes. When
changing floated elements later, sometimes you will have positioning
issues because they are not in the page flow. Another disadvantage is
that it generally requires a clearfix otherwise it may break aspects
of the page. The clearfix requires adding an element after the floated
elements to stop their parent from collapsing around them which
crosses the semantic line between separating style from content and is
thus an anti-pattern in web development.
use display: table;
/* ----------- UNIVERSAL -----------*/
a, body, html, ul, li, div {
margin: 0;
padding: 0;
list-style: none;
font-family: helvetica;
}
.toggle {
line-height: 50px;
}
/* ----------- MENU BAR -----------*/
#menu {
background-color: #EDEBED;
width: 100%;
height: 50px;
box-shadow: 1px 1px 1px #000000;
display: table;
}
#menu .item{
display: table-cell;
vertical-align: middle;
width: 25%;
}
#menu .item-center{
width: 50%;
}
#menu .item-right{
text-align: right;
}
/* ----------- LOGO -----------*/
#logo {
font-weight: bold;
margin-left: 15px;
font-size: 20px;
height: 20px;
}
/* ----------- TOGGLE BAR -----------*/
.toggle li {
list-style: none;
display: inline-block;
margin-left: 20px;
}
.toggle {
margin: 0 auto;
width: 250px;
background-color: blue; /* I added this to show what's causing run to push down */
}
/* ----------- BUTTON -----------*/
button {
margin-right: 15px;
}
<div id="menu">
<div class="item item-left">
<div id="logo">Codeplayer</div>
</div>
<div class="item item-center">
<ul class="toggle">
<li>HTML</li>
<li>CSS</li>
<li>JS</li>
<li>Result</li>
</ul>
</div>
<div class="item item-right">
<button>Run</button>
</div>
</div>
Figured it out: I switched the placement of the .toggle and "run" button in my html so that the logo was first, then the run button, then the toggle. This way, when I floated the button and put top margin on .toggle, it wasn't pushed down.
I'm trying that all the li's width to match my ul's width, here's my code:
http://jsfiddle.net/4XR5V/2/
I already saw some questions on the site and some seem to work adding
ul {
width: 100%;
display: table;
table-layout: fixed; /* optional */
}
ul li {
display: table-cell;
width: auto;
text-align: center;
}
But it hasn't worked. My javascript function works, I dont know why in jsfiddle it doesn't work. How can I solve this issue?
Thanks!!
use flexbox. The children will fill up available area by default.
http://jsfiddle.net/4XR5V/3/
#tabs_header ul {
display: flexbox;
}
#tabs_header li {
flex: 1 1 auto;
}
Remove float: left. This declaration is not necessary when elements are displayed as table-cell. Floated elements shrinkwrap their contents.
Remove float: left; from list items:
#tabs_header li {
float: left;
}
fiddle1, fiddle2 - a working script ( by using jQuery )
I've been having trouble finding this one.
I have a div that is centered in the body margin: 0 auto;.
It contains multiple divs. I want it to expand to the width of it's widest child width: auto;
The problem is I want to have one of the child div's aligned on the right, however this expands my parent to 100%. How would I accomplish this without a fixed width for the parent?
You could do what you are after by setting the wrapper div to inline-block, and setting text-align: center on its parent (instead of using margin: 0 auto;). Here is an example: http://jsfiddle.net/joshnh/6Ake5/
Here is the HTML:
<div class="wrapper">
<div class="foo"></div>
<div></div>
<div></div>
</div>
And the CSS:
body {
text-align: center;
}
div {
border: 1px solid red; /* To see what is going on */
}
.wrapper {
display: inline-block;
text-align: left; /* Resetting the text alignment */
vertical-align: top; /* Making sure inline-block element align to the top */
/* Inline-block fix for IE7 and below */
zoom: 1;
*display: inline;
}
.wrapper div {
float: left;
height: 200px; /* To see what is going on */
margin: 10px; /* To see what is going on */
width: 200px; /* To see what is going on */
}
.foo {
border-color: blue; /* To see what is going on */
float: right;
}