I have a menu containing some sub-menus, like this one
.menu {
position: absolute;
background: yellow;
margin-top: 2em;
}
header {
font-size: 20px;
}
ul {
-moz-column-count: 2;
-moz-column-gap: 10px;
-webkit-column-count: 2;
-webkit-column-gap: 20px;
column-count: 2;
column-gap: 10px;
list-style: none;
padding: 0;
}
li:nth-child(odd) {background: lightblue; }
li:nth-child(even) {background: lightyellow; }
div:not(.main) {
display: inline-block;
position: relative;
}
<div>menu one
<div class="menu">
<header>menu one header</header>
<ul>
<li>Item one</li>
<li>Item two 2</li>
<li>Item tree</li>
<li>Item four</li>
<li>Item five</li>
<li>six</li>
<li>Item 7</li>
</ul>
</div>
</div>
<div>menu two</div>
I need that the 2 columns appears ONLY if there are more than 4 entries in the .menu>ul
list.
Is it possible using the pure CSS?
You could make use of the trick described here - http://alistapart.com/article/quantity-queries-for-css, which has been suggested by @Jesse Kernaghan in the comments above.
However, to be able to do that you need to make a couple of things hard-wired:
ul
, and li
and ensure that this width times n
equals the height of the container ul
. Where n
is your magic number, in your case 4
. This is required so that the CSS columns
does not reflow the content and that the li
are arranged into columns in a predictable fashion.
If your markup and use-case can work with the above two constraints, then you can use the following CSS selectors:
li:nth-last-child(4):first-child,
li:nth-last-child(4):first-child ~ li {
width: 160px;
}
The first selector will select the li
which is 4th from the end and also happens to be the first, effectively selecting only the first li
in a set of exactly four li
s, where 4
being your magic number.
The second selector (the general sibling combinator) will select all the li
that exist after the first one.
Apply a fixed width to these li
s to give a faux appearance of one column.
Example Snippet:
div.menu {
display: inline-block; vertical-align: top;
background: yellow; margin: 2em 1em;
}
header { font-size: 20px; }
ul {
width: 160px; -moz-columns: 2 auto; -moz-column-fill: auto;
-webkit-columns: 2 auto; columns: 2 auto;
list-style: none; padding: 0; height: 8em;
}
li { height: 2em; }
li:nth-child(odd) {background: lightblue; }
li:nth-child(even) {background: lightyellow; }
li:nth-last-child(4):first-child, li:nth-last-child(4):first-child ~ li {
width: 160px;
}
<div class="menu">
<header>menu one</header>
<ul>
<li>Item one</li>
<li>Item two 2</li>
<li>Item tree</li>
<li>Item four</li>
<li>Item five</li>
<li>six</li>
<li>Item 7</li>
</ul>
</div>
<div class="menu">
<header>menu two</header>
<ul>
<li>Item one</li>
<li>Item two 2</li>
<li>Item tree</li>
<li>Item four</li>
</ul>
</div>
<div class="menu">
<header>menu three</header>
<ul>
<li>Item one</li>
<li>Item two 2</li>
<li>Item tree</li>
<li>Item four</li>
<li>Item five</li>
</ul>
</div>
Here is one way, tested with Chrome, FF, IE11 and Edge, though still with some fixed value, and need to be adjusted if more than 8 items.
The li
height need to be fixed and then the negative margin-top
will be 4 times that height to push the right items to the top.
The trick here is to have each item wider than 50% of the available width when 2 "columns" is needed, so the float's stay on its side and then push the right "column" up so it aligns with the left.
.menu {
position: absolute;
background: yellow;
margin-top: 2em;
}
header {
font-size: 20px;
}
ul {
list-style: none;
padding: 0;
}
li:nth-child(odd) {background: lightblue; }
li:nth-child(even) {background: lightyellow; }
li { position: relative; height: 20px; }
li:nth-child(-n+4) { float: left; width: 48%; margin-right: 3%; }
li:nth-child(n+5) { float: right; width: 48%; margin-left: 3%; top: -80px }
li:nth-last-child(4):first-child, li:nth-last-child(4):first-child ~ li {
width: 94%; margin-right: 6%
}
div:not(.main) {
display: inline-block;
position: relative;
}
<div>menu one
<div class="menu">
<header>menu one header</header>
<ul>
<li>Item one</li>
<li>Item two 2</li>
<li>Item tree</li>
<li>Item four</li>
<li>Item five</li>
<li>six</li>
<li>Item 7</li>
</ul>
</div>
</div>
<div>menu two
<div class="menu">
<header>menu two header</header>
<ul>
<li>Item one</li>
<li>Item two 2</li>
<li>Item tree</li>
<li>Item four</li>
</ul>
</div>
</div>
Update Here is another way, with flex.
Based on the li
height and the ul
height n
items will fit each column.
.menu {
position: absolute;
background: yellow;
margin-top: 2em;
}
header {
font-size: 20px;
}
ul {
list-style: none;
padding: 0;
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 100px;
}
li {
height: 22px;
}
li:nth-child(odd) {background: lightblue; }
li:nth-child(even) {background: lightyellow; }
div:not(.main) {
display: inline-block;
position: relative;
}
<div>menu one
<div class="menu">
<header>menu one header</header>
<ul>
<li>Item one</li>
<li>Item two 2</li>
<li>Item tree</li>
<li>Item four</li>
<li>Item five</li>
<li>six</li>
<li>Item 7</li>
</ul>
</div>
</div>
<div>menu two
<div class="menu">
<header>menu two header</header>
<ul>
<li>Item one</li>
<li>Item two 2</li>
<li>Item tree</li>
<li>Item four</li>
</ul>
</div>
</div>
<div>menu three
<div class="menu">
<header>menu three header</header>
<ul>
<li>Item one</li>
<li>Item two 2</li>
<li>Item tree</li>
<li>Item four</li>
<li>Item five</li>
<li>Item six</li>
<li>Item seven</li>
<li>Item eight</li>
<li>Item nine</li>
<li>Item ten</li>
</ul>
</div>
</div>
We can do with quantity query, only there is a order problem. If you compromise with that order we can use quantity query.
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
width: 40%;
border: 1px solid red;
margin: 2px;
}
ul li:nth-last-child(n+5),
ul li:nth-last-child(n+5)~li {
float: left;
}
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>
View on jsFiddle
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With