A two col layout like:
ul {
display: flex;
flex-flow: row wrap;
border: 2px solid red;
list-style-type: none;
padding: 0;
gap: 1%;
}
li {
flex-basis: calc(49vw - 10px);
border: 1px solid black;
box-sizing: border-box;
}
<ul>
<li>text 1</li>
<li>text 2</li>
<li>text 3</li>
<li>text 4</li>
</ul>
Does nicely layout two cols like
text1 text2
text3 text4
What needs to be changed (in css) that items are ordered like?
text1 text3
text2 text4
CodePudding user response:
One solution is as below, relying on CSS multi-column layouts instead of flex-box or grid:
// utilities:
const D = document,
get = (selector, context = D) => context.querySelector(selector),
fragment = () => D.createDocumentFragment(),
getAll = (selector, context = D) => [...context.querySelectorAll(selector)],
// a simple function to generate a random number between the supplied
// minimum and maximum:
getRandom = (min, max) => {
return Math.floor(Math.random() * (max - min 1) min);
};
// here we retrieve an Array of all <li> elements:
getAll('li').forEach(
// we use Array.prototype.forEach() to iterate over
// all elements in the Array, and pass a reference
// to the Array-element ('el') into the function
// body:
(el) => {
// we use a template literal string to interpolate
// the result of getRandom(3, 9) into a string with
// which we can set the height of the current <li>:
let blockSize = `${getRandom(3, 9)}em`;
// we update the CSS custom property to that size:
el.style.setProperty('--randomHeight', blockSize);
// and set the text of the <span> element to state
// the defined size:
get('span', el).textContent = blockSize;
});
/* the question asks for two columns, though I'm explicitly
defining 3 here, to demonstrate a problem with this approach
as-is: */
ul {
/* removing the default list-style: */
list-style-type: none;
/* defining the number of columns: */
column-count: 3;
}
li {
/* setting the block-size of the element
to the value of the --randomHeight
custom property or to 2em if the
property is invalid or absent: */
block-size: var(--randomHeight, 2em);
background-color: hsl(100deg 90% 70% / 0.3);
display: grid;
place-content: center;
}
li:nth-child(odd) {
background-color: hsl(200deg 90% 70% / 0.3);
}
span {
display: block;
text-align: center;
}
<ul>
<li>List-item: 01<span></span></li>
<li>List-item: 02<span></span></li>
<li>List-item: 03<span></span></li>
<li>List-item: 04<span></span></li>
<li>List-item: 05<span></span></li>
<li>List-item: 06<span></span></li>
<li>List-item: 07<span></span></li>
<li>List-item: 08<span></span></li>
<li>List-item: 09<span></span></li>
<li>List-item: 10<span></span></li>
<li>List-item: 11<span></span></li>
<li>List-item: 12<span></span></li>
</ul>
It may take a few runs to realise, but if you look at the layout it becomes obvious that the <li>
elements fragment from – for example – the end of one column to the start of the next. This is due to fragmentation, which is to be expected as the browser will try to match column-sizes within the container.
To avoid that, we can use the break-inside
property on the <li>
elements, and set it to avoid
; in the following example we have two <ul>
elements, the first does not have break-inside: avoid
specified on the <li>
elements, the second does. This should allow for a clear visualisation of the layout difference:
const D = document,
get = (selector, context = D) => context.querySelector(selector),
fragment = () => D.createDocumentFragment(),
getAll = (selector, context = D) => [...context.querySelectorAll(selector)],
getRandom = (min, max) => {
return Math.floor(Math.random() * (max - min 1) min);
},
frag = fragment();
getAll('li').forEach(
(el) => {
let blockSize = `${getRandom(3, 9)}em`;
el.style.setProperty('--randomHeight', blockSize);
get('span', el).textContent = blockSize;
frag.append(el.cloneNode(true));
});
get('ul.column-contained').append(frag);
ul {
list-style-type: none;
column-count: 3;
}
ul.column-contained>* {
break-inside: avoid;
}
li {
block-size: var(--randomHeight, 2em);
background-color: hsl(100deg 90% 70% / 0.3);
display: grid;
place-content: center;
}
li:nth-child(odd) {
background-color: hsl(200deg 90% 70% / 0.3);
}
span {
display: block;
text-align: center;
}
<ul>
<li>List-item: 01<span></span></li>
<li>List-item: 02<span></span></li>
<li>List-item: 03<span></span></li>
<li>List-item: 04<span></span></li>
<li>List-item: 05<span></span></li>
<li>List-item: 06<span></span></li>
<li>List-item: 07<span></span></li>
<li>List-item: 08<span></span></li>
<li>List-item: 09<span></span></li>
<li>List-item: 10<span></span></li>
<li>List-item: 11<span></span></li>
<li>List-item: 12<span></span></li>
</ul>
<ul >
</ul>
References:
- CSS:
- JavaScript: