Home > Mobile >  css flex-direction: row but items in col order
css flex-direction: row but items in col order

Time:11-11

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>

JS Fiddle demo.

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>

JS Fiddle demo.

References:

  •  Tags:  
  • css
  • Related