I have a list of items that I want to fit in a space that is constrained vertically:
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
<li>Five</li>
<li>Six</li>
</ul>
Since I don't want the list to have more than a specific height, but I'm free to expan it horizontally, I want to divide the list into columns, like this:
One Two Three
Four Five Six
Or, alternatively (in my case order is not important)
One Three Five
Two Four Six
The css property column-count allows to break a list into columns, but it only accepts a fixed number of columns. I don't know the number of items I am going to have (it can go from 1 to more than 40), so if I set the number of columns to 3, any list with more than 6 items will be too high, and if there is only 4 items, then only the first column will have two items and it will look uneven.
So, ideally I would need a row-count property, but it doesn't exist. I guess I can do that in Javascript too but I'm looking for a CSS-only solution.
I tried something: float:left on every li puts the list in one row. To break it into two rows, I would need to not apply float:left to the N/2 element. I don't know how to do that.
I know also that I can do it by breaking it into multiple ul, each one with two li, and float:left them, but I would like to avoid messing the HTML for something entirely presentational.
Does someone has a solution for this problem?
Edit: I think I have not been clear in explaining my requirements. I want the list to be sorted into columns without knowing how many items I'm going to have, and so that I will always have two rows.
So for example with 7 items, I want to have:
One Two Three Four
Five Six Seven
And with 3 items:
One Two
Three
Here is a simple way to do it using jquery. I know it is mentioned that a CSS way is needed, but this is just for future reference if anyone wants to refer to this question.
Get the number of LI items and divide it by the number of rows and set that value to column-count property.
Jquery
$(document).ready(function() {
var numitems = $("#myList li").length;
$("ul#myList").css("column-count",Math.round(numitems/2));
});
CSS
ul {
width: 900px;
}
li {
width: 75px;
height: 75px;
margin-top: 10px;
margin-right: 10px;
display: inline-block;
}
HTML
<ul id="myList">
<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>
</ul>
Fiddle here
EDIT:
Same implementation using simple javascript.
var ul = document.getElementById("myList");
var li = ul.getElementsByTagName("li");
var numItems = li.length;
var css = document.createElement("style");
css.type = "text/css";
css.innerHTML = "ul { column-count: " + Math.round(numItems/2) + "; }";
document.body.appendChild(css);
You need to set the width of UL, because number of rows will depend on the width also even after setting the column-count. You can set it to 100% too, but then the number of rows will change based on the window size. To restrict the number of rows to 2, fixed width for UL may be required.
You could set your li at 33% width and floating against each other, once there isn't enough room in a row they will be pushed down in rows of 3 of equal width.
ul li{
width: 33%;
float: left;
}
I know this question is 7 years old but if anyone has similar problem today, then here's a solution using CSS Grid Layout (https://www.w3.org/TR/css-grid-1/)
ul {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
Why not give it a max-width?
ul {
max-width: somevalue; // which would last when the third item ends
}
Or, you can add class to them as
<ul>
<li class="one">One</li>
<li class="one">Two</li>
<li class="one">Three</li>
<li class="two">Four</li>
<li class="two">Five</li>
<li class="two">Six</li>
</ul>
Now CSS as:
.one {
display: inline;
}
.two {
display: inline;
}
The last thing of the padding is as
ul li {
padding: somevalue;
}
And for slicing:
ul {
max-width: 200px; // to break the list
}
The good luck for you would be that you can first check the width of the list! And then slice it into two equal parts using JS, and then applying it.
If you want to get the CSS calucator, then use this:
width: calc(var1 + var2); // calc will do the math..
Here is the fiddle for this situation: http://jsfiddle.net/afzaal_ahmad_zeeshan/xN87Q/
you can use
li:nth-child(even)
li:nth-child(odd)
http://jsfiddle.net/nCmZT/
Source: Creating a two column Unordered List
Fiddle : Demo provided in the link
HMTL
<ul class="two-col-special">
<li>First Category</li>
<li>Second Category</li>
<li>Third Category</li>
<li>Fourth Category</li>
<li>Fifth Category</li>
</ul>
CSS
.two-col-special {
border: 1px dotted blue;
overflow: auto;
margin: 0;
padding: 0;
}
.two-col-special li {
display: inline-block;
width: 45%;
margin: 0;
padding: 0;
vertical-align: top; /* In case multi-word categories form two lines */
}
.two-col-special li:before {
content: '+';
padding: 5px;
margin-right: 5px; /* you can tweak the gap */
color: orange;
background-color: white; /* in case you want a color... */
display: inline-block;
}
Here's an example using display: flex and flex-direction: row to change the ordering from columns to rows:
#list-1 {
border: 3px solid red;
columns: 2;
column-gap: 5px;
width: 200px;
}
#list-2 {
border: 3px solid blue;
columns: 2;
display: flex;
flex-direction: row;
flex-wrap: wrap;
height: auto; /* can change this */
width: 200px;
}
#list-2 li {
width: 100px;
height: auto;
}
<ul id="list-1">
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
<li>f</li>
<li>g</li>
</ul>
<ul id="list-2">
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
<li>f</li>
<li>g</li>
</ul>
I think the most easies and proper way {OL tag especially} would be:
<ul>
<div class="row">
<div class="col-6">
<li>One</li>
<li>Two</li>
<li>Three</li>
</div>
<div class="col-6">
<li>Four</li>
<li>Five</li>
<li>Six</li>
</div>
</div>
</ul>
Related
I have a vertical list of items of equal but implicit size. I want a gap between the items to be a percentage relative to this implicit size.
The main problem is that vertical margins are relative to widths, not heights, so they can't be used for this. (Otherwise, one could have a child in the item add the gap as a margin.)
The gap property of flex boxes and grids is in relation to the entire container.
I think this is likely impossible but I wanted to check with the community to verify.
I'm not sure it can be done with pure css, but here is a simple version with javascript, I just looped through a lists children and dynamically set the margin in this case as 10% of its height.
var list = document.getElementById('list');
var children = list.children;
for (var i = 0; i < children.length; i++) {
children[i].style.marginTop = (parseInt(children[i].clientHeight) * .1).toString() + "px";
}
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
background-color: gray;
padding: 10px;
}
.list{
background-color: lightgray;
display: flex;
flex-direction: column;
list-style: none;
}
.list-item{
background-color: lightblue;
}
#li1{
height: 25px;
}
#li2{
height: 50px;
}
#li3{
height: 75px;
}
<div class="container">
<ul class="list" id="list">
<li class="list-item" id='li1'>Item 1</li>
<li class="list-item" id='li2'>Item 2</li>
<li class="list-item" id='li3'>Item 3</li>
</ul>
</div>
It is possible to inline part of a list with flex box? Here is what I have tried...
The HTML
<ul>
<li>Connect With Me</li>
<li>Facebook</li>
<li>Twitter</li>
<li>LinkedIn</li>
</ul>
The CSS
ul {
display: flex;
flex-direction: column;
}
/*obviously does not work, but hopefully gets my point across*/
ul li:not(:first-child) {
flex-direction:row;
}
So the end result is
Connect With Me
Facebook Twitter LinkedIn
You can use flex wrapping to do this. Setting the first list element to 100% width and enabling wrapping causes it to fill the full top line and wrap the other elements down below. Then, setting the remaining list elements as flex: 1; makes them all share the remaining space evenly between them.
Below is a snippet, along with a CodePen demonstrating this behaviour.
ul {
display: flex;
flex-wrap: wrap;
/* just to make it look cleaner */
list-style-type: none;
margin: 0;
padding: 0;
}
li:first-of-type {
width: 100%;
}
li:not(:first-of-type) {
flex: 1;
}
<!-- background just on li's so they stand out -->
<ul>
<li style="background: red;">Connect With Me</li>
<li style="background: aqua;">Facebook</li>
<li style="background: green;">Twitter</li>
<li style="background: yellow;">LinkedIn</li>
</ul>
CodePen: https://codepen.io/Kxrl/pen/zYBvZmw
Foundation's top bar navigation tool is set-up to fully flesh out a hierarchy of links, relying upon list and item tags.
<div class="top-bar">
<div class="top-bar-left">
<ul class="dropdown menu" data-dropdown-menu>
<li class="menu-text">Site Title</li>
<li>
One
<ul class="menu vertical">
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
</li>
<li>Two</li>
<li>Three</li>
</ul>
</div>
</div>
However, in an attempt to soften this structure, the goal is to have the second layer links on a single line, say
<ul><li>
One Two Three
</li></ul>
Unfortunately, either display is relinquished to the browser definition for line-item or display:block; from the base code of Foundation overrides even <li style='display: float'><a href="#" style='display: float'> with its .menu a class definition.
How can this one-liner be achieved?
Looks like you may have mixed up your css rules: display: block; and float: none. The default behaviour looks like it wants it to be vertical, and the structure looks to be built in that way. I didn't see anything in their docs for this (I skimmed them lol) but what I did to make it work was to use position:absolute; on that submenu, and then position it. I don't know what the rest of your menu looks like, but you will need to adjust I assume.
I created a codepen that might do what you need it to.
https://codepen.io/bjorniobennett/pen/bGGajWZ
ul.dropdown > li {
position: relative;
&:hover {
> ul.vertical {
display: block;
}
}
> ul.vertical {
display: none;
position: absolute;
width: 500%;
background: #c5c5c5;
top: 120%;
> li {
display: inline-block;
float: left;
}
}
}
This HTML list (ordered but my special order),
<ul class="custom">
<li value="II">Alpha</li>
<li value="III">Beta</li>
<li value="☸" >Gamma</li>
<li value="MXX">Delta</li>
</ul>
With CSS
.custom { list-style: none; }
.custom li:before {
content: attr(value) ". ";
}
Shows the list, but I not see how to align "numbers" as in usual list.
See the point-align problem at https://jsfiddle.net/0yb7aee8/
In default list the number are in the ul/ols padding.
You can make st. similar like this.
.listaEspecial {
list-style: none;
list-style-position: outside;
padding-left: 0;
margin-left: 0;
}
.listaEspecial li:before {
content: attr(value) ". ";
text-align: right;
display: inline-block;
width: 45px;
padding-right: 10px;
}
Build-in list:
<ul class="listaEspecial">
<li value="II">Alpha</li>
<li value="III">Beta</li>
<li value="☸" >Gamma</li>
<li value="MXX">Delta</li>
</ul>
<hr/>
Standard list (better spacing and point-align):
<ol type="I" start="2">
<li>Alpha</li>
<li>Beta</li>
<li value="100000" >Gamma</li>
<li>Delta</li>
</ol>
The ul/ols padding is 40px, I used 55px (45px width + 10px padding for :before because of longer number.
Look that in default lists there is a problem with longer number too, 40px is too short for gamma and delta items.
I have a block of HTML:
<ul>
<li>a</li>
<li>b</li>
<li class="nav">c</li>
<li class="nav">d</li>
</ul>
and a CSS ruleset:
ul li {
display: inline;
}
li.nav {
float: right;
}
which are not behaving to my intentions: I want it displayed like so:
ab cd
but instead it's
ab dc
the difference being the displayed order of elements. How do I have the list items of class "nav" be displayed in their syntactical order?
Well, the obvious quick fix is to just reverse the order of the elements in the list:
<ul>
<li>a</li>
<li>b</li>
<li class="nav">d</li>
<li class="nav">c</li>
</ul>
I'm guessing what happens is that whenever the rendering engine encounters an element with float:right it pushes that element as far to the right as possible. So it first encounters the "c" and pushes that all the way over to the right, then it encounters the "d" and pushes that as far right as possible - but the "c" is already occupying the rightmost spot, so "d" stays to its left. Essentially, the elements are laid out in right-to-left order rather than left-to-right order.
Another option, I think, would be to divide the elements into two lists and just apply the float: right style to the second list as a whole (i.e. to the <ul> element).
<ul>
<li>a</li>
<li>b</li>
</ul>
<ul class="nav">
<li>c</li>
<li>d</li>
</ul>
and
ul li {
display: inline;
}
ul.nav {
float: right;
}
That way the list itself would float to the right margin but the order of the elements in it wouldn't be reversed.
I fixed this issue by separating the list into two and floating them to their respective positions. I wrapped the two lists with a div and applied overflow: auto to it. My final CSS code looked like this:
ul li {
display: inline
}
div.post-info-wrap {
overflow: auto
}
ul.post-info {
float: left
}
ul.nav {
float: right
}
and my markup like:
<div class="post-info-wrap">
<ul class="post-info">
<li/>
</ul>
<ul class="nav">
<li/>
</ul>
</div>
If you want c & d to be displayed in a block at the right, you'll have to put them inside one block element, not setting the float attribute on both.
I don't think that list elements like <li> are the right choice for your intention. You don't want to display a single list, so you may try using two lists (where one of them has the float attribute) or just simple <div> elements.
So actually you want a nav list and some other list? Why not use 2 lists?
<ul class="other">
<li>a</li>
<li>b</li>
</ul>
<ul class="nav">
<li>c</li>
<li>d</li>
</ul>
And css:
ul li {
display: inline;
}
.other{
float:left;
}
.nav {
float: right;
}
Float the ul where you want the content/container situated and float the li in the order you want it displayed.
<div id="myblock">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
CSS
#myblock ul {
display:inline;
float:right;
}
#myblock li {
float:left;
}
The opposite (float to the left but in reverse order)
#myblock ul {
display:inline;
float:left;
}
#myblock li {
float:right;
}
Try this:
ul {
text-align: right;
}
ul li {
display: inline;
}
ul li.default {
float: left;
}
li.nav {
float: auto;
}
<ul>
<li class="default">a</li>
<li class="default">b</li>
<li class="nav">c</li>
<li class="nav">d</li>
</ul>