Centering Block Elements - css

First, I'll start off by saying that I do not have control over the HTML and this is what the HTML looks like:
<ul class="orbit-bullets">
<li>1</li>
<li>2</li>
</ul>
Second note I'll put is that I wouldn't mind using inline-block, but I need a fallback for non-supportive browsers.
I am trying to center the list. The list items must display inline but they must be block elements because I'm declaring a width, height and text-indent. So I know that I can use display:block; float:left;, but I would like the elements to be centered. And sometimes there are three list items or four or more, so I do not want to set a fixed width on the unordered list smaller than 500px. If I set the width to 500px, when there are just two or three list items, they appear very off centered.
I need to center the list items themselves within the unordered list while still using display:block; float:left;. Or is there a way to have a variable width on the unordered list while still having it centered? I'm up to any suggestions.
Thanks.

Try this one - http://jsfiddle.net/jD6yp/
ul {
width: 500px;
text-align: center;
background: beige;
}
li {
display: inline-block;
zoom: 1; /* for old IE-s */
*display: inline; /* for old IE-s */
padding: 10px;
margin: 20px;
border: 1px solid pink;
}

Related

Fluid navigation items of different widths with equidistant spacing

I'd like to create a fluid horizontal navigation list of links, where the nav links are evenly spaced and take up the full width of the enclosing container . Nav links are all different widths. The first link should be left-aligned and the last link should be right aligned.
I've had limited success using techniques such as:
ul {display: table;width: 100%;}
li {display: table-cell;}
a {display: block;}
and also using
ul {text-align: justify}
li {inline-block }
but no code I've written seems to deal at all well with elements that are different widths. The spacing does not seem to stay equal as the nav is resized.
I need the nav to be fluid, first and last elements to be flush against the edge of the containing ul and for the elements to be equidistant from each other
I thought about this for a while and came up with two reasonable approaches, both of which are pretty good but not exactly pixel perfect. One is CSS based only and the second is aided by jQuery (JavaScript).
CSS Approach - pretty good approximation
Consider the following HTML:
<ul class="nav ex1">
<li class="first">Home</li>
<li>Collections</li>
<li class="tight">About Us</li>
<li>Slocklists</li>
<li class="tight">Trade Enquiries</li>
<li>Press</li>
<li class="last">Contact Us</li>
</ul>
I added some classes as hooks for the styling.
The CSS is as follows:
.nav.ex1 {
outline: 1px dashed blue;
width: 100%;
margin: 0;
padding: 0;
display: table;
}
.nav.ex1 li {
display: table-cell;
outline: 1px dotted gray;
width: 20%;
white-space: pre;
text-align: center;
}
.nav.ex1 li.first {
width: 1%;
}
.nav.ex1 li.last {
width: 1%;
}
.nav.ex1 li.tight {
width: 1%;
}
In Example 1, the ul.nav parent container uses display: table and width: 100%. The child li elements are table-cell's. I added white-space: pre to prevent some of the links from wrapping into two lines, and text-align: center to keep the text centered.
The trick is to force some of the table-cell's to shrink-to-fit the text, and you can do this by setting width: 1% which is non-zero but too small to hold the text (unless your screen is 10,000 pixels wide). I shrink-to-fit the first and last cells which forces them to align to the left and right edges of the parent container. I then force every other table-cell to shrink-to-fit by added the .tight class.
The remaining table's cells will have a width of 20% which will keep them evenly spaced between their two nearest neighbors. HOWEVER, there will be some slight variation in spacing among the links in the row, which is why I call it an approximation.
jQuery Aided Solution
In Example 2, the markup is essentially the same and the CSS is:
.nav.ex2 {
outline: 1px dashed blue;;
margin: 0;
padding: 0;
display: block;
overflow: auto;
width: 100%;
}
.nav.ex2 li {
float: left;
display: block;
outline: 1px dotted gray;
width: auto;
}
In this case, the li elements are floated left and I use width: auto.
The trick is to calculate the magic left-margin value and apply it to all the li elements except for the first one.
The jQuery action is:
$(window).resize(function () {
navResizer();
});
// On load, initially, make sure to set the size.
navResizer();
function navResizer() {
var $li_w = 0;
var $ul_w = $(".nav.ex2").innerWidth();
$( ".nav.ex2 li" ).each(function( index ) {
$li_w += $(this).innerWidth();
});
var li_margin = Math.floor(($ul_w-$li_w)/6);
$(".nav.ex2 li").not(".first").css("margin-left",li_margin);
$("p.note").text( "Widths: ul.nav: " + $ul_w + " all li: " + $li_w + " Left margin: " + li_margin);
}
Basically, the action calculates the width of ul.nav ($ul_w), and the total widths of all the li child elements ($li_w).
The left-margin is calculated by ($ul_w - $li_w)/6 where 6 is the number of gaps between the 7 links.
The key line of code is: $(".nav.ex2 li").not(".first").css("margin-left",li_margin);
I use .not(".first") to omit the first li element and then .css to set the left margin.
The one slight defect is at the far right where the link is not quite right justified, but you can fix that by floating the last li to the right.
For the most part, if your link texts were similar in length, you would be hard pressed to distinguish the two. Both approaches are not quite pixel perfect, but pretty good.
Fiddle: http://jsfiddle.net/audetwebdesign/xhSfs/
Footnote
I tried some other approaches using text-align: justify and inline-block, but the CSS engine does not treat inline-blocks like regular words, so will not justify a line of inline-blocks.
Setting left-margin to a % value will not quite work at some window widths and the right-most link will not be on the edge as desired.
The jQuery approach has been tried before, see:
Evenly-spaced navigation links that take up entire width of ul in CSS3
You can use text-align: justify; and ignore the last left-justified row. #last is invisible and takes up the last row because of padding-left: 100%;: http://jsfiddle.net/mwRbn/
if you want to align the text of the menu vertically, use height in combination with line-height:
ul#nav {
text-align: justify;
width: 100%;
background: yellow;
height: 2em;
line-height: 2em;
}
http://jsfiddle.net/mwRbn/1/. Do you need a IE<8 hack?

Position: fixed inside display: table bug

I've come across a really frustrating issue. I'm working to create a menu drawer that is inside a <ul>. When the nested <div> inside the table is display: {fixed,absolute}, a whitespace placeholder shows up where another table cell would be. I can't understand why or how to get around it.
CodePen of the code is here: http://codepen.io/quicksnap/pen/gsHrb and you can toggle the topmost class to see what I'm talking about.
Appreciate any insight on why or how to retain this markup structure and get it to display fixed/absolute without altering the parent table display.
Markup:
<ul>
<li>
<span>Lorem</span>
</li>
<li>
<span>Lorem</span>
</li>
<li>
<span>Lorem</span>
</li>
<li>
<span>Lorem</span>
</li>
<div class="fixed"/>
</ul>
CSS:
/*
Why does the display: table show an empty placeholder for
an element inside that is position: fixed/absolute?
*/
/* Comment out/remove !important to see bug */
.fixed { display: none !important; }
.fixed {
display: block;
position: fixed; top: 60px; left: 0;
width: 100%; height: 100px;
background: salmon;
}
ul {
padding: 0;
margin: 0;
width: 100%;
height: 60px;
display: table;
table-layout: fixed;
position: relative;
background: #ccc;
}
ul > li {
display: table-cell;
text-align: center;
vertical-align: middle;
}
I really don't know if this is a bug or expected behavior (I have not researched it), as it appears to do the same on a normal table element. However, it apparently has to do with the table-layout: fixed property being set. I am guessing that is because the table-layout: fixed calculates its size based on the number of columns, and it appears to be counting that as a "column element" upon page render, apparently before even recognizing that the css position: fixed pulls it out of flow. The display: none causes the element to not count (as one would expect) for column purposes.
Your issue seems to resolve by having the table (in your case ul) be table-layout: auto and then setting the cells (your li) to the appropriate width (25% in your case) unless they all have exactly the same width text.
See this fiddle for an illustration of all these things happening on a normal table element.
As a side note, a naked div in a ul is not valid html structure (the ul should only have li elements as direct children).
What is the purpose of your div / fixed class? You can nest another ul or list however and put the "fixed" class on that. If you add height 100% then the whole background is the salmon color you have.
It seems that display: table will render children elements in the fixed layout regardless if their display is set to absolute or fixed--If they're displaying as a block element, the cell gets drawn.
This is a simplified version of the "bug":
http://codepen.io/quicksnap/pen/xuDwG ( notice the extra space to the right of the Lorem items )
When using table-caption for an li and then nesting in a fixed or absolute element, it seems to escape the element from being drawn as a cell.
Here is an example of what I was looking for: http://codepen.io/quicksnap/pen/noBvm
Thanks ScottS for pointing out my invalid HTML--it clued me into why it works like this, though I still don't understand why the table is drawing a cell space for an element that isn't table-cell and positioned absolute/fixed.

Allow text to wrap in css menu

I have a template that uses an unordered list to create the menu. See here
When I translate the website using Google translate the menu breaks if the translations are too long, causing the floated list items to drop down. Translating it into French seem to cause the problem.
See here
Is there a way I can force the text to wrap if it is too long for the menu?
I don't mind if I have to change the unordered list to something else, but I would prefer not to use a table.
use word-wrap property of css
word-wrap: break-word;
The short version: we're going to use display: table-cell.
The long version is.. long:
On .access, remove the padding rule.
On .sf-menu, remove float: left and add display: table.
On .sf-menu li, remove float: left and add display: table-cell and vertical-align: middle.
On #header and #footer, add position: relative.
On .access, remove height: 32px and margin-top: -32px and add position: absolute and width: 100%.
On #header .access, add bottom: 0.
Move the border-left from sf-menu a to sf-menu li.
Change the selector .sf-menu a.first to .sf-menu .first.
This part isn't great, but to get back that 20px padding on the left (and right), add an extra li at the start: <li class="noHover" style="width: 20px; border-left: 0"> </li>; and at the end: <li class="noHover" style="width: 20px; border-left: 0"> </li>. You might not need the s. You'll need to do the same thing with #footer.
To stop the :hover on the "padding" lis, add something like this:
.sf-menu li.noHover:hover {
background: none !important
}
On #footer, add padding-top: 48px.
That's everything (unless I screwed up somewhere), except for IE6/7 support. If you want that, you're going to have to put a new version up with my fixes applied (can be in a temporary new folder if you like). It's too much work to attempt to fix IE6/7 when I have to apply all those changes first to test it properly.
#Pranay pointed to the right direction but you need to set the width to the lis not the ul! so for example:
ul.sf-menu li {
width: 80px; /* make this the maximum width possible! */
word-wrap: break-word;
}
And insert a clearing div right after the menu ul:
<div class="clear"></div>
Where the clear class is defined as:
.clear {
clear: both;
width: 0;
height: 0;
}

Horizontal Centering of Multi-Line List Items in Unordered List

I have an unordered list that wraps onto a second line, and needs to be centered horizontally within the containing UL. Each LI is a set width and height. I've seen many approaches that work for a single line, but nothing I've tried is working when the list wraps to a second line. Would be ideal if this worked in IE7+ -- Thanks for the help.
See here for an illustration:
http://grab.by/8UIl
Here is the best method I could find.
ul li {
/* make list elements fall inline as block elements */
position: relative;
display: inline-block;
/* next two lines only for display purposes */
text-align: center;
border:1px solid red;
}
/* horizontally center ul element */
ul { text-align:center; }
See the link for an example: http://jsfiddle.net/gfkPG/

CSS multi-column layout of list items doesn't align properly in Chrome

I am building a menu system presented to the user in multi-column format. The column-count property in CSS3 gets me 90% of the way there, but I'm having difficulties with alignment under Chrome.
The menu is relatively simple:
an unordered list divided into multiple-columns by the column-count property
columns should fill sequentially, so column-fill: auto
menu items are represented as list items
each list item has a a clickable anchor tag, extended fully via display: block
The alignment issue I'm having is most noticeable with a top-border and some background coloring on each list item. In Firefox, the list items are always aligned cleanly across each column, never bleeding into the previous/next column. In Chrome, alignment is a crapshoot, varying with how many list items are present and any padding/margin properties.
I've posted the code for a simple test case here: http://pastebin.com/Ede3JwdG
The problem should be immediately evident: in Chrome, the first list item in the second column bleeds back into the first column. As you remove list items (click on them), you can see that alignment breaks down further.
I've tried tweaking the padding/margin for the list items to no avail: Chrome appears to have a flawed algorithm for how it flows content across a multi-column layout.
The primary reason I haven't ditched column-count altogether (in favor of manual generation/Columnizer/etc.) is that the menu system also involves drag-and-drop functionality across multiple sub-menus, and having the menu data laid out as a cohesive list-based hierarchy makes for clean code.
Is there a way to fix the alignment issue in Chrome or should I just give up on column-count for now?
ADDED:
jsFiddle prototype: http://jsfiddle.net/VXsAU/
JS Bin prototype: http://jsbin.com/ebode5/
You need each item in the column to be displayed as "inline-block". That will solve your problem without needing to use jQuery.
Additionally, each element can be specified to have width: 100% in order to get the them to use the full width of the rows.
Here is a working example:
$(document).ready(function() {
for( var i = 0; i < 24; i++ ) {
$("ul.newslist").append("<li><a href='#'>Item</a></li>");
}
$("ul.newslist > li").click(function() {
$(this).remove();
})
});
ul.newslist {
columns: 5;
background-color: #ccc;
padding: 16px 0;
list-style: none;
}
ul.newslist > li {
display: inline-block;
width: 100%;
border-top: 1px solid #000;
}
ul.newslist > li > a {
display: block;
padding: 4px;
background-color: #f6b;
text-decoration: none;
color: inherit;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="newslist"></ul>
I managed to balance uneven vertically-aligned columns by applying margin-* properties to the elements inside the multicolumn'd container.
.content {
column-width: 15em; /* or could be column-count, however you want to set up multi columns */
}
.content > section {
-webkit-margin-before: 0;
-webkit-margin-after: 0;
}
As for vertical margins leakage. You can replace margin with pseudo-element. Then set its height to desired margin value. You also need to set -webkit-column-break-inside: avoid; on the element containing pseudo-element so that it is not moved to another column. Do that only for webkit with the help of css-hack (not recommended) or js-detection (best way). Here is CSS:
.element {
-webkit-column-break-inside: avoid;
}
.element:after {
content: '';
display: block;
height: 20px;
}
I've played around as well, and several sources I've seen online make it seem to be a known issue with webkit. A good breakdown can be found here: http://zomigi.com/blog/deal-breaker-problems-with-css3-multi-columns/
Someday, CSS 3!
Maybe try a jQuery plugin like http://welcome.totheinter.net/columnizer-jquery-plugin/ ?
I was having trouble with vertical alignment on a multi-column list. Turned out that the problem was that I was using bottom padding on my list li's-- I changed the li style to use a bottom margin instead, and the columns aligned to top again.
My desired outcome was wanting to get a large list of links to display across 3 columns. Simply using column-break-inside:avoid; alone didn't work in webkit.
HTML
<div class="links">
<ol>
<li><a>link</a></li> <!-- x 50 -->
</ol>
</div>
css:
.links ol {
-webkit-column-count: 3;
-moz-column-count: 3;
column-count: 3;
}
.links li {
display: block;
border: 1px solid $background-colour; //to appear invisible
-moz-column-break-inside:avoid;
-webkit-column-break-inside:avoid;
column-break-inside:avoid;
}
.links a {
display: block;
margin-bottom: 10px;
}
Solution (quirk if you will)
I added a 1px border around the list items which seemed to contain the margins of it's children and each column then aligned to the top.
Edit: This only seems to be required if you're using global border-box
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
I solved this by removing vertical margins on the child elements, and then increasing the line-height of the children to replicate desired spacing.
I also noticed I could fix this vertical alignment issue by removing the child margins and converting it to grandchild padding.
I'm struggling with this as well, for a reporting system with many many data and titles with padding/margin that I need to flow on several columns for wider screens.
I've worked around my first big deal-breaker, the padding of the initial title element, with the :first-child pseudo-class (this is included in an #media rule for wide screens not shown here) :
The columns definition :
.dimSlider .multicol {
-moz-columns: 4;
-webkit-columns: 4;
columns: 4;
}
Canceling padding on top when in .multicol
.dimSlider .multicol h3 {
padding-top: 0;
}
Cancelling padding and margin for the first element (color: blue; is so that I see if the rule catches) :
.dimSlider .multicol .criteria:first-child h3 {
padding: 0 2%;
margin: 0;
color: blue;
}
So far, this looks way much neater in my Firefox. I'll see if there's some more tinkering to do but currently in Firefox the text looks aligned on the top, what is the most important.
EDIT :
The problem seems quite worse with webkit-based browsers indeed. To solve it entirely, I modified the template in order to have a <div></div>around all the titled sections so I can add padding / margin at the end of the divs and not at the beginning of the titles. Now in webkit browsers it looks fine too.
BTW, using percentages measurements in multicolumns is quite tricky because the percentage seems calculated to the width of the column and not the global width of the parent element. I changed this by adding padding in the parent element of the columns.
But the biggest difficulty is that Firefox doesn't support any column-span or break-inside property, so when I have very few content, it is spread over the columns nonetheless, like one or two lines on each. Again, Smarty on the rescue :
{if $element|#count <= 10}
<div class="nocol">
{/if}
So far it works now for me...
while searching for information about this i came across your question and today I've been inspecting the elements of the list.
I found that the UL element applies a margin only on the first column.
Just apply 0 padding and margin in the css and they will align
margin:0;
padding:0;
hope it helps
I had a two-column ordered list, and the left column was pushed down by default margin - so it did not align with the right column.
This fixed it.
ol > :first-child {
margin-top: 0;
}
I saw some solutions about placing -webkit-column-break-inside:avoid;. But that does not seems to work for me. Then I found out I have to place 2 things to get it working.
Place padding on the li, and give the property break-inside: avoid; on the li.
This is my code:
ul {
column-count: 2;
}
li {
font-size: 10px;
line-height: 12px;
padding: 10px 0;
width: fit-content;
min-width: 143px;
border-bottom: 0.5px solid #ccc;
break-inside: avoid;
}
this is solution for multicolumn space problem
ul li { line-height:40px; }

Resources