I have <ul> element which is a flex items. This <ul> element contains several <li> elements which are not flex items.
When I add percentage paddings to <li> elements then <ul> element is split in several lines like in the photo:
When I set fixed paddings (like 30px) the <ul> element is displayed in one line:
So, my question is: Why percentage paddings make <ul> behave this way?
P.S: I don't need solutions to fix it, I just need an explanation of the behaviour
li {
display: inline-block;
padding: 0 5%;
/* padding: 0 30px; */
border: 1px solid black;
}
header {
display: flex;
}
ul {
border:1px solid red;
}
<header>
<ul>
<li>Library</li>
<li>Telegram channel</li>
<li>Contacts</li>
<li>Donate</li>
</ul>
</header>
As I explained in a previous similar situation there is a kind of complex calculation involved here. Padding used with percentage value will be relative to the width of the containing blockref and logically the width of the containing block will be defined by its content (or any fixed width value).
In our case, we cannot resolve percentage value of padding before calculating the width, so we first caclulate the width based on our content to obtain this:
console.log(document.querySelector('ul').offsetWidth);
li {
display: inline-block;
border: 1px solid black;
}
header {
display: flex;
}
ul {
border:1px solid red;
margin:0;
padding:0;
}
<header>
<ul>
<li>Library</li>
<li>Telegram channel</li>
<li>Contacts</li>
<li>Donate</li>
</ul>
</header>
Then we will consider the above calculated width in order to calculate the padding
After that, the padding will logically be added to the width which will increase the overall width and create the line break. The browser won't go back to re-caclulate the width of the ul again because we will have a cycle, so the calculation is done only once.
console.log(document.querySelector('ul.pad').offsetWidth);
li {
display: inline-block;
border: 1px solid black;
}
.pad li {
padding:0 0.5%; /*any small value will create the issue*/
}
header {
display: flex;
}
ul {
border:1px solid red;
margin:5px;
padding:0;
}
<header>
<ul>
<li>Library</li>
<li>Telegram channel</li>
<li>Contacts</li>
<li>Donate</li>
</ul>
</header>
<header>
<ul class="pad">
<li>Library</li>
<li>Telegram channel</li>
<li>Contacts</li>
<li>Donate</li>
</ul>
</header>
We can clearly notice how in both case the width of the ul is exactly the same.
This won't happen with pixel values because they are absolute values that the browser can include in the initial calculation.
li {
display: inline-block;
border: 1px solid black;
}
.pad li{
padding:0 30px;
}
header {
display: flex;
}
ul {
border:1px solid red;
margin:0;
padding:0;
}
<header>
<ul>
<li>Library</li>
<li>Telegram channel</li>
<li>Contacts</li>
<li>Donate</li>
</ul>
</header>
<header>
<ul class="pad">
<li>Library</li>
<li>Telegram channel</li>
<li>Contacts</li>
<li>Donate</li>
</ul>
</header>
I have <ul> element which is a flex items. This <ul> element contains several <li> elements which are not flex items.
When I add percentage paddings to <li> elements then <ul> element is split in several lines like in the photo:
When I set fixed paddings (like 30px) the <ul> element is displayed in one line:
So, my question is: Why percentage paddings make <ul> behave this way?
P.S: I don't need solutions to fix it, I just need an explanation of the behaviour
li {
display: inline-block;
padding: 0 5%;
/* padding: 0 30px; */
border: 1px solid black;
}
header {
display: flex;
}
ul {
border:1px solid red;
}
<header>
<ul>
<li>Library</li>
<li>Telegram channel</li>
<li>Contacts</li>
<li>Donate</li>
</ul>
</header>
As I explained in a previous similar situation there is a kind of complex calculation involved here. Padding used with percentage value will be relative to the width of the containing blockref and logically the width of the containing block will be defined by its content (or any fixed width value).
In our case, we cannot resolve percentage value of padding before calculating the width, so we first caclulate the width based on our content to obtain this:
console.log(document.querySelector('ul').offsetWidth);
li {
display: inline-block;
border: 1px solid black;
}
header {
display: flex;
}
ul {
border:1px solid red;
margin:0;
padding:0;
}
<header>
<ul>
<li>Library</li>
<li>Telegram channel</li>
<li>Contacts</li>
<li>Donate</li>
</ul>
</header>
Then we will consider the above calculated width in order to calculate the padding
After that, the padding will logically be added to the width which will increase the overall width and create the line break. The browser won't go back to re-caclulate the width of the ul again because we will have a cycle, so the calculation is done only once.
console.log(document.querySelector('ul.pad').offsetWidth);
li {
display: inline-block;
border: 1px solid black;
}
.pad li {
padding:0 0.5%; /*any small value will create the issue*/
}
header {
display: flex;
}
ul {
border:1px solid red;
margin:5px;
padding:0;
}
<header>
<ul>
<li>Library</li>
<li>Telegram channel</li>
<li>Contacts</li>
<li>Donate</li>
</ul>
</header>
<header>
<ul class="pad">
<li>Library</li>
<li>Telegram channel</li>
<li>Contacts</li>
<li>Donate</li>
</ul>
</header>
We can clearly notice how in both case the width of the ul is exactly the same.
This won't happen with pixel values because they are absolute values that the browser can include in the initial calculation.
li {
display: inline-block;
border: 1px solid black;
}
.pad li{
padding:0 30px;
}
header {
display: flex;
}
ul {
border:1px solid red;
margin:0;
padding:0;
}
<header>
<ul>
<li>Library</li>
<li>Telegram channel</li>
<li>Contacts</li>
<li>Donate</li>
</ul>
</header>
<header>
<ul class="pad">
<li>Library</li>
<li>Telegram channel</li>
<li>Contacts</li>
<li>Donate</li>
</ul>
</header>
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've written the folloning code:
<ul>
<li>Text</li>
<li>text</li>
</ul>
and styles:
list-style-type: none;
padding: 5px;
display: inline;
background-color: #A9A9A9;
But i have spacing between two li elements like the following:
How can I remove this spacing?
By put them inline
<ul>
<li>Text</li><li>text</li>
</ul>
Js Fiddle Demo
If you float your li items, it should remove the margin between li output.
<ul>
<li>item 1</li>
<li>item 2</li>
</ul>
ul {
list-style-type: none;
}
ul li {
float:left;
padding: 5px;
display: block;
background-color: #A9A9A9;
}
Here are two common ways to avoid the space:
<ul>
<li>
one</li><li> <!-- use this to avoid the linebreak -->
two</li><li>
three</li>
</ul>
Or you can use Comments:
<ul>
<li>one</li><!--
--><li>two</li><!-- Comments so there is no white-space
--><li>three</li>
</ul>
You can check it in this Demo
You get the space because there is some space between the elements.
(Tabs, Newline count as space ). With this Minimized HTML it should work :)
You can read more about it here Examples at CSS-Tricks
try floats and use list-style-type for ul:
ul {
list-style-type: none;
}
li {
padding: 5px;
float:left;
background-color: #A9A9A9;
}
Just Add float:left in your Css
ul li {
background-color: #A9A9A9;
display: inline;
float: left;
padding: 5px;
}
Demo
There are many ways as mentioned above few of them..however you can achieve with another method. using font-size:0
ul
{font-size:0; /*This will remove the space totally*/
list-style-type: none;
}
li{
padding: 5px;
display: inline;
background-color: #A9A9A9;
font-size:16px; /*This is important line so the font come again in same shape*/
}
Here is the Demo.
Is it possible to style this html ...
<ul>
<li>Dogs</li>
<li>Cats</li>
<li>Lions</li>
<li>Tigers</li>
<li>Zebras</li>
<li>Giraffes</li>
<li>Bears</li>
<li>Hippopotamuses</li>
<li>Antelopes</li>
<li>Unicorns</li>
<li>Seagulls</li>
</ul>
... like this ...
... without adding classes to specific list items, or resorting to javascript? And if so how?
The line breaks are not fixed; the list widens to take up additional space, and list items are center aligned.
Just
li + li::before {
content: " | ";
}
Of course, this does not actually solve the OP's problem. He wants to elide the vertical bars at the beginning and end of lines depending on where they are broken. I will go out on a limb and assert that this problem is not solvable using CSS, and not even with JS unless one wants to essentially rewrite the browser engine's text-measurement/layout/line breaking logic.
The only pieces of CSS, as far as I can see, that "know" about line breaking are, first, the ::first-line pseudo element, which does not help us here--in any case, it is limited to a few presentational attributes, and does not work together with things like ::before and ::after. The only other aspect of CSS I can think of that to some extent exposes line-breaking is hyphenation. However, hyphenating is all about adding a character (usually a dash) to the end of lines in certain situations, whereas here we are concerned about removing a character (the vertical line), so I just can't see how to apply any kind of hyphenation-related logic, even with the help of properties such as hyphenate-character.
We have the word-spacing property, which is applied intra-line but not at line beginnings and endings, which seems promising, but it defines the width of the space between words, not the character(s) to be used.
One wonders if there's some way to use the text-overflow property, which has the little-known ability to take two values for display of overflow text at both left and right, as in
text-overflow: '' '';
but there still doesn't seem to be any obvious way to get from A to B here.
This is possible with flex-box
The keys to this technique:
A container element set to overflow: hidden.
Set justify-content: space-between on the ul (which is a flex-box) to force its flex-items to stretch to the left and right edges.
Set margin-left: -1px on the ul to cause its left edge to overflow the container.
Set border-left: 1px on the li flex-items.
The container acts as a mask hiding the borders of any flex-items touching its left edge.
.flex-list {
position: relative;
margin: 1em;
overflow: hidden;
}
.flex-list ul {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
margin-left: -1px;
}
.flex-list li {
flex-grow: 1;
flex-basis: auto;
margin: .25em 0;
padding: 0 1em;
text-align: center;
border-left: 1px solid #ccc;
background-color: #fff;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css" rel="stylesheet"/>
<div class="flex-list">
<ul>
<li>Dogs</li>
<li>Cats</li>
<li>Lions</li>
<li>Tigers</li>
<li>Zebras</li>
<li>Giraffes</li>
<li>Bears</li>
<li>Hippopotamuses</li>
<li>Antelopes</li>
<li>Unicorns</li>
<li>Seagulls</li>
</ul>
</div>
Before showing the code, it's worth mentioning that IE8 supports :first-child but not :last-child, so in similar situations, you should use the :first-child pseudo-class.
Demo
#menu{
list-style: none;
}
#menu li{
display: inline;
padding: 0 10px;
border-left: solid 1px black;
}
#menu li:first-child{
border-left: none;
}
<ul id="menu">
<li>Dogs</li>
<li>Cats</li>
<li>Lions</li>
<li>More animals</li>
</ul>
Use :after pseudo selector. Look http://jsfiddle.net/A52T8/1/
<ul>
<li>Dogs</li>
<li>Cats</li>
<li>Lions</li>
<li>Tigers</li>
<li>Zebras</li>
<li>Giraffes</li>
<li>Bears</li>
<li>Hippopotamuses</li>
<li>Antelopes</li>
<li>Unicorns</li>
<li>Seagulls</li>
</ul>
ul li { float: left; }
ul li:after { content: "|"; padding: 0 .5em; }
EDIT:
jQuery solution:
html:
<div>
<ul id="animals">
<li>Dogs</li>
<li>Cats</li>
<li>Lions</li>
<li>Tigers</li>
<li>Zebras</li>
<li>Giraffes</li>
<li>Bears</li>
<li>Hippopotamuses</li>
<li>Antelopes</li>
<li>Unicorns</li>
<li>Seagulls</li>
<li>Monkey</li>
<li>Hedgehog</li>
<li>Chicken</li>
<li>Rabbit</li>
<li>Gorilla</li>
</ul>
</div>
css:
div { width: 300px; }
ul li { float: left; border-right: 1px solid black; padding: 0 .5em; }
ul li:last-child { border: 0; }
jQuery
var maxWidth = 300, // Your div max-width
totalWidth = 0;
$('#animals li').each(function(){
var currentWidth = $(this).outerWidth(),
nextWidth = $(this).next().outerWidth();
totalWidth += currentWidth;
if ( (totalWidth + nextWidth) > maxWidth ) {
$(this).css('border', 'none');
totalWidth = 0;
}
});
Take a look here. I also added a few more animals. http://jsfiddle.net/A52T8/10/
I know I'm a bit late to the party, but if you can put up with having the lines left-justified, one hack is to put the pipes before the items and then put a mask over the left edge, basically like so:
li::before {
content: " | ";
white-space: nowrap;
}
ul, li {
display: inline;
}
.mask {
width:4px;
position: absolute;
top:8px; //position as needed
}
more complete example:
http://jsbin.com/hoyaduxi/1/edit
This should solve the problem without using borders.
li {
display: inline-block !important;
list-style: none;
margin: 0 auto;
height: 14px;
}
ul li::after {
content: " | ";
margin: 0 10px;
}
ul li:last-child:after {
content: '';
margin: 0 10px;
}
<div>
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
<li>Five</li>
<li>Six</li>
<li>Seven</li>
<li>Eight</li>
<li>Nine</li>
<li>Ten</li>
<li>Eleven</li>
<li>Twelve</li>
<li>Thirteen</li>
<li>Fourteen</li>
<li>Fifteen</li>
<li>Sixteen</li>
<li>Seventeen</li>
<li>Eighteen</li>
<li>Nineteen</li>
<li>Twenty</li>
<li>Twenty One</li>
<li>Twenty Two</li>
<li>Twenty Three</li>
<li>Twenty Four</li>
<li>Twenty Five</li>
<li>Twenty Six</li>
<li>Twenty Seven</li>
<li>Twenty Eight</li>
<li>Twenty Nine</li>
<li>Thirty</li>
</ul>
</div>
One solution is to style the left border like so:
li { display: inline; }
li + li {
border-left: 1px solid;
margin-left:.5em;
padding-left:.5em;
}
However, this may not give you desirable results if the entire lists wraps, like it does in your example. I.e. it would give something like:
foo | bar | baz
| bob | bill
| judy
I came across a solution today that does not appear to be here already and which seems to work quite well so far. The accepted answer does not work as-is on IE10 but this one does.
http://codepen.io/vithun/pen/yDsjf/ credit to the author of course!
.pipe-separated-list-container {
overflow-x: hidden;
}
.pipe-separated-list-container ul {
list-style-type: none;
position: relative;
left: -1px;
padding: 0;
}
.pipe-separated-list-container ul li {
display: inline-block;
line-height: 1;
padding: 0 1em;
margin-bottom: 1em;
border-left: 1px solid;
}
<div class="pipe-separated-list-container">
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
<li>Five</li>
<li>Six</li>
<li>Seven</li>
<li>Eight</li>
<li>Nine</li>
<li>Ten</li>
<li>Eleven</li>
<li>Twelve</li>
<li>Thirteen</li>
<li>Fourteen</li>
<li>Fifteen</li>
<li>Sixteen</li>
<li>Seventeen</li>
<li>Eighteen</li>
<li>Nineteen</li>
<li>Twenty</li>
<li>Twenty One</li>
<li>Twenty Two</li>
<li>Twenty Three</li>
<li>Twenty Four</li>
<li>Twenty Five</li>
<li>Twenty Six</li>
<li>Twenty Seven</li>
<li>Twenty Eight</li>
<li>Twenty Nine</li>
<li>Thirty</li>
</ul>
</div>
Slightly modified SCSS version which gives you control of the pipe | size and will eliminate padding from first and last list items while respects borders.
$pipe-list-height: 20px;
$pipe-list-padding: 15px;
.pipe-list {
position: relative;
overflow: hidden;
height: $pipe-list-height;
> ul {
display: flex;
flex-direction: row;
> li {
position: relative;
padding: 0 $pipe-list-padding;
&:after {
content: " ";
position: absolute;
border-right: 1px solid gray;
top: 10%;
right: 0;
height: 75%;
margin-top: auto;
margin-bottom: auto;
}
&:first-child {
padding-left: 0;
}
&:last-child {
padding-right: 0;
&:after {
border-right: none;
}
}
}
}
}
<div class="pipe-list">
<ul>
<li>Link</li>
<li>Link</li>
<li>Link</li>
</ul>
</div>
Yes, you'll need to use pseudo elements AND pseudo selectors: http://jsfiddle.net/cYky9/
You can use the following CSS to solve.
ul li { float: left; }
ul li:before { content: "|"; padding: 0 .5em; }
ul li:first-child:before { content: ""; padding: 0; }
Should work on IE8+ as well.