score:2

Accepted answer

although support is lacking, masonry grids are what you are looking for. it is extremely similar to columns layout, but less "plain text" focussed. columns are what you would go for when you want a newspaper-like layout, which is what you are requesting, but horizontally. from my experience, it has some really weird quirks, like margins that don't behave normally, as well as visual glitches where box-shadows and outlines get cut off and moved over to the next column. g-cyrillus' answer beautifully displays how to use it anyway. all i needed to change, was the spacing inside the list. columns has full support, so i've added his implementation as a fallback for when masonry isn't supported (it's still being worked on and by the looks of it, will take some time to actually land in browsers. i for one can't wait for this note to be outdated, though).

now to the answer. as of this moment, if you enable the feature in firefox, you can actually see the masonry grid working in this fiddle. here is the css that matters:

{
  display: grid;
  grid-template-rows: 1fr 1fr 1fr;
  grid-template-columns: masonry;
}

like noted in the fiddle, there is one property that would make this completely css-only — grid-auto-flow: row;, but that doesn't work (for now, i hope) because the flow direction of the grid is implicitly set to column when you set grid-template-columns to masonry. it cannot be reverted.

to make the switch from flex to masonry, the script loops over the children to detect the amount of rows present in the flexbox. it does so by checking their offset from the top. if the value makes a switch for a 4th time, it adds the appropriate grid class to the list.

from your comment:

as for the overflow, it would be great if each overflowing element was added to the shortest row, although it seems impossible as it differs from the behavior it had before.

masonry actually does this automatically!

score:0

honestly, i think this is gonna be the best you can do if you are looking for a sole css only solution. all the tags keep their own width but they have spacing between them to keep it in the flex flow direction. i think align-items: center; looks better than align-items: start; but either works.

:root {
     --scpu-bg: #1b1b1b;
     --scpu-border: #3d3d3d;
     --scpu-fg: #ffffff;
     color: var(--scpu-fg);
     font-size: 14px;
}
 body {
     background-color: var(--scpu-bg);
}
 .tag-chip {
     padding: 1rem;
     border: 1px var(--scpu-border) solid;
}
 .tag-cloud {
     overflow-x: none;
     overflow-y: none;
}
 .tag-list {
     max-height: 15rem;
     display: flex;
     gap: 0.7rem;
     flex-wrap: wrap;
     overflow-x: scroll;
     overflow-y: hidden;
     flex-direction: column;
     align-items: center;
}
<div class="tag-cloud">
  <div class="tag-list nav-scroll">
    <span class="tag-chip">6000</span>
    <span class="tag-chip">alagadda</span>
    <span class="tag-chip">artifact</span>
    <span class="tag-chip">audio</span>
    <span class="tag-chip">biological</span>
    <span class="tag-chip">blackwood</span>
    <span class="tag-chip">_cc</span>
    <span class="tag-chip">co-authored</span>
    <span class="tag-chip">container</span>
    <span class="tag-chip">d-11424</span>
    <span class="tag-chip">daevite</span>
    <span class="tag-chip">deer-college</span>
    <span class="tag-chip">doctor-light</span>
    <span class="tag-chip">doctor-mcdoctorate</span>
    <span class="tag-chip">entropic</span>
    <span class="tag-chip">esoteric-class</span>
    <span class="tag-chip">ethics-committee</span>
    <span class="tag-chip">faeowynn-wilson</span>
    <span class="tag-chip">global-occult-coalition</span>
    <span class="tag-chip">grand-karcist-ion</span>
    <span class="tag-chip">hanged-king</span>
    <span class="tag-chip">hy-brasil</span>
    <span class="tag-chip">interactive</span>
    <span class="tag-chip">la-rue-macabre</span>
    <span class="tag-chip">_licensebox</span>
    <span class="tag-chip">meta</span>
    <span class="tag-chip">metallic</span>
    <span class="tag-chip">narrative</span>
    <span class="tag-chip">on-guard-43</span>
    <span class="tag-chip">portal</span>
    <span class="tag-chip">religious</span>
    <span class="tag-chip">ritual</span>
    <span class="tag-chip">s&amp;amp;c-plastics</span>
    <span class="tag-chip">scp</span>
    <span class="tag-chip">serpents-hand</span>
    <span class="tag-chip">spacetime</span>
    <span class="tag-chip">temporal</span>
    <span class="tag-chip">three-moons-initiative</span>
    <span class="tag-chip">three-portlands</span>
    <span class="tag-chip">wanderers-library</span>
    <span class="tag-chip">weapon</span>
    <span class="tag-chip">wilsons-wildlife</span>
    </div>
</div>

score:0

based on deckerz's answer, i think this is closer to what you want. i used grid instead of flexbox, but note that you could get the same result with their answer by just adding some extra style to tag-chip and changing align-items: center to align-items: stretch.

:root {
     --scpu-bg: #1b1b1b;
     --scpu-border: #3d3d3d;
     --scpu-fg: #ffffff;
     color: var(--scpu-fg);
     font-size: 14px;
}
 body {
     background-color: var(--scpu-bg);
}
.tag-chip {
     display: flex;
     padding: 1rem;
     border: 1px var(--scpu-border) solid;
     min-width: max-content;
     justify-content: center;
}
.tag-cloud {
     overflow-x: none;
     overflow-y: none;
}
.tag-list {
     width: auto;
     display: grid;
     gap: 0.7rem;
     overflow-x: scroll;
     overflow-y: hidden;
     grid-template-columns: repeat(auto-fit, 1fr);
     grid-template-rows: repeat(3, 1fr);
     grid-auto-flow: column;
}
<div class="tag-cloud">
  <div class="tag-list nav-scroll">
    <span class="tag-chip">6000</span>
    <span class="tag-chip">alagadda</span>
    <span class="tag-chip">artifact</span>
    <span class="tag-chip">audio</span>
    <span class="tag-chip">biological</span>
    <span class="tag-chip">blackwood</span>
    <span class="tag-chip">_cc</span>
    <span class="tag-chip">co-authored</span>
    <span class="tag-chip">container</span>
    <span class="tag-chip">d-11424</span>
    <span class="tag-chip">daevite</span>
    <span class="tag-chip">deer-college</span>
    <span class="tag-chip">doctor-light</span>
    <span class="tag-chip">doctor-mcdoctorate</span>
    <span class="tag-chip">entropic</span>
    <span class="tag-chip">esoteric-class</span>
    <span class="tag-chip">ethics-committee</span>
    <span class="tag-chip">faeowynn-wilson</span>
    <span class="tag-chip">global-occult-coalition</span>
    <span class="tag-chip">grand-karcist-ion</span>
    <span class="tag-chip">hanged-king</span>
    <span class="tag-chip">hy-brasil</span>
    <span class="tag-chip">interactive</span>
    <span class="tag-chip">la-rue-macabre</span>
    <span class="tag-chip">_licensebox</span>
    <span class="tag-chip">meta</span>
    <span class="tag-chip">metallic</span>
    <span class="tag-chip">narrative</span>
    <span class="tag-chip">on-guard-43</span>
    <span class="tag-chip">portal</span>
    <span class="tag-chip">religious</span>
    <span class="tag-chip">ritual</span>
    <span class="tag-chip">s&amp;amp;c-plastics</span>
    <span class="tag-chip">scp</span>
    <span class="tag-chip">serpents-hand</span>
    <span class="tag-chip">spacetime</span>
    <span class="tag-chip">temporal</span>
    <span class="tag-chip">three-moons-initiative</span>
    <span class="tag-chip">three-portlands</span>
    <span class="tag-chip">wanderers-library</span>
    <span class="tag-chip">weapon</span>
    <span class="tag-chip">wilsons-wildlife</span>
    </div>
</div>

score:0

you can use a script like following

   <div class="tag-cloud">
  <div id="elment_flex" class="tag-list nav-scroll">
    <span class="tag-chip">6000</span><span class="tag-chip">alagadda</span
    ><span class="tag-chip">artifact</span><span class="tag-chip">audio</span
    ><span class="tag-chip">biological</span
    ><span class="tag-chip">blackwood</span><span class="tag-chip">_cc</span
    ><span class="tag-chip">co-authored</span
    ><span class="tag-chip">container</span><span class="tag-chip">d-11424</span
    ><span class="tag-chip">daevite</span
    ><span class="tag-chip">deer-college</span
    ><span class="tag-chip">doctor-light</span
    ><span class="tag-chip">doctor-mcdoctorate</span
    ><span class="tag-chip">entropic</span
    ><span class="tag-chip">esoteric-class</span
    ><span class="tag-chip">ethics-committee</span
    ><span class="tag-chip">faeowynn-wilson</span
    ><span class="tag-chip">global-occult-coalition</span
    ><span class="tag-chip">grand-karcist-ion</span
    ><span class="tag-chip">hanged-king</span
    ><span class="tag-chip">hy-brasil</span
    ><span class="tag-chip">interactive</span
    ><span class="tag-chip">la-rue-macabre</span
    ><span class="tag-chip">_licensebox</span><span class="tag-chip">meta</span
    ><span class="tag-chip">metallic</span
    ><span class="tag-chip">narrative</span
    ><span class="tag-chip">on-guard-43</span
    ><span class="tag-chip">portal</span><span class="tag-chip">religious</span
    ><span class="tag-chip">ritual</span
    ><span class="tag-chip">s&amp;amp;c-plastics</span
    ><span class="tag-chip">scp</span><span class="tag-chip">serpents-hand</span
    ><span class="tag-chip">spacetime</span
    ><span class="tag-chip">temporal</span
    ><span class="tag-chip">three-moons-initiative</span
    ><span class="tag-chip">three-portlands</span
    ><span class="tag-chip">wanderers-library</span
    ><span class="tag-chip">weapon</span
    ><span class="tag-chip">wilsons-wildlife</span>
  </div>
</div>

<script type="text/javascript" >
var flex_elm = document.getelementbyid('elment_flex');

 let clientwidth = math.max(
  flex_elm.scrollwidth,
  flex_elm.offsetwidth,
  flex_elm.clientwidth
  );
var rem = parsefloat(getcomputedstyle(document.documentelement).fontsize);

flex_elm.style.maxwidth = ((clientwidth/3)+rem*1*flex_elm.children.length)+"px";
flex_elm.style.width = ((clientwidth/3)+rem*1*flex_elm.children.length)+"px";


flex_elm.style.flexwrap = 'wrap';


</script>

load the page without putting wrap and then set the length depending on the content, then set the 'wrap'.

score:1

let tag = document.queryselector(".tag-chip");
let font = parseint(getcomputedstyle(tag).getpropertyvalue("font-size"));
let gap = parseint(getcomputedstyle(tag).getpropertyvalue("margin-right"));

const blocks = document.queryselectorall(".tag-chip");
widths = [];
blocks.foreach((block) => {
  let width = block.getboundingclientrect().width;
  widths.push(width + gap);
});
const sum = widths.reduce(function(a, b) {
  return a + b;
}, 0);

finalwidth = math.ceil(sum / (3 * font) + 5); //change 3 by row required.

let taglist = document.queryselector(".tag-list");
let setwidth = taglist.style.setproperty("--finalwidth", `${finalwidth}rem`);
:root {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  --scpu-bg: #1b1b1b;
  --scpu-border: #3d3d3d;
  --scpu-fg: #ffffff;
  --font-400: 16px;
  /*decides 1 rem*/
  --finalwidth: 10rem;
  /*changed by js*/
  color: var(--scpu-fg);
  font-size: var(--font-400);
}

body {
  background-color: var(--scpu-bg);
  overflow: hidden;
}

.tag-chip {
  display: inline-block;
  padding: 0.4em 1em;
  margin-bottom: 0.5em;
  margin-right: 0.5em;
  border: 1px var(--scpu-border) solid;
}

.tag-cloud {
  width: 95vw;
  overflow-x: auto;
  border: 1px solid black;
  white-space: nowrap;
  padding: 0.5em;
}

.tag-list {
  display: flex;
  flex-wrap: wrap;
  width: var(--finalwidth);
}
<div class="tag-cloud">
  <div class="tag-list nav-scroll">
    <span class="tag-chip">6000</span>
    <span class="tag-chip">alagadda</span>
    <span class="tag-chip">artifact</span>
    <span class="tag-chip">audio</span>
    <span class="tag-chip">biological</span>
    <span class="tag-chip">blackwood</span>
    <span class="tag-chip">_cc</span>
    <span class="tag-chip">co-authored</span>
    <span class="tag-chip">container</span>
    <span class="tag-chip">d-11424</span>
    <span class="tag-chip">daevite</span>
    <span class="tag-chip">deer-college</span>
    <span class="tag-chip">doctor-light</span>
    <span class="tag-chip">doctor-mcdoctorate</span>
    <span class="tag-chip">entropic</span>
    <span class="tag-chip">esoteric-class</span>
    <span class="tag-chip">ethics-committee</span>
    <span class="tag-chip">faeowynn-wilson</span>
    <span class="tag-chip">global-occult-coalition</span>
    <span class="tag-chip">grand-karcist-ion</span>
    <span class="tag-chip">hanged-king</span>
    <span class="tag-chip">hy-brasil</span>
    <span class="tag-chip">interactive</span>
    <span class="tag-chip">la-rue-macabre</span>
    <span class="tag-chip">_licensebox</span>
    <span class="tag-chip">meta</span>
    <span class="tag-chip">metallic</span>
    <span class="tag-chip">narrative</span>
    <span class="tag-chip">on-guard-43</span>
    <span class="tag-chip">portal</span>
    <span class="tag-chip">religious</span>
    <span class="tag-chip">ritual</span>
    <span class="tag-chip">s&amp;amp;c-plastics</span>
    <span class="tag-chip">scp</span>
    <span class="tag-chip">serpents-hand</span>
    <span class="tag-chip">spacetime</span>
    <span class="tag-chip">temporal</span>
    <span class="tag-chip">three-moons-initiative</span>
    <span class="tag-chip">three-portlands</span>
    <span class="tag-chip">wanderers-library</span>
    <span class="tag-chip">weapon</span>
    <span class="tag-chip">specialist</span>
    <span class="tag-chip">wilsons-wildlife</span>
  </div>
</div>

edited with js included.

score:1

i wondered whether using plain static css "multi column layout" (generally just the column-width) could help solving this task and got results that are quite close to the goal, with two caveats.

recap of the task:

  • order matters: first "page" of tags should be filled and visible before next that is out of the view-port.
  • tags should be filled horizontally, wrap at the end of the line of the "page".
  • after filling the "page" by given amount of lines, next "page" begins to be filled from the top left.
  • (caveat 1!) either "rigged" non aligner right edges of tags or (ugly) uneven spacing coming from "justified" text blocks" is no issue.
  • when tags fit single line, no empty unused vertical space is reserved. (not in op's requirement.)

surprisingly for me, this is all possible, and as i've learnt in the process it's quite what columns are for: biggest surprise was column width rounding.

caveat 2 i've found is that in certain situations blink erroneously tries to balance second-to-last and last column vertically and "borrows" last line from the former and moves it to the later, despite being told to "fill columns sequentially" with column-fill: auto;. in firefox no such surprising jumps occurs. i think it's a bug, but haven't investigated further yet.

interactive demo:

let t, max = 123, c = 0;

onload = () => {
  for (let i = 8; i-- > 0;) addtag();
  t = setinterval(addtag, 500)
}

function addtag() {
  tags.insertadjacenthtml(
   'beforeend',
   ` <span>${word()}</span>`
  );
  function word() {
    const dict = ['foo', 'fi', 'fa', 'bar',
    'gazonk', 'qux', 'quux'];
    const l = dict.length;
    return dict[math.floor(math.random() * l)]
    + '-' + dict[math.floor(math.random() * l)];
  };
  c++;
  if (c >= max) clearinterval(t)
}
div {
  column-width: 100vw;
  /* this will be rounded to (fraction of) 
     actual container width, so that whole number
     of columns could be viewed together. that is
     exactly what we need in this particular case
     (and probably in general). */
  column-gap: 0; /* not default apparently. */ 
  column-rule: none; /* change to see separators. */
  column-count: auto;  /* default. */
  column-fill: auto;
  /* not default 
     - this should ensure next column will be
     start filling only after previous is fully
     vertically occupied. 
     blink does not respect this sometimes: last
     line of second-to-last column occasionaly
     jumps to last columns and back. */
  max-height: 8em; /* no calc for simplicity */
  overflow-x: scroll;
  overflow-y: hidden;
  text-align: justify;
  /* personally, i'd rather leave it left-aligned. */
  word-spacing: .5em; /* larger gaps between tags. */
  counter-reset: tags;
  outline: 1px solid;
}
span {
  display: inline-block;
  outline: 1px solid;
  padding: .2em;
  margin: .3em;
  white-space: nowrap;
  word-spacing: 0; /* undo gaps. */
}
span::before {
  counter-increment: tags;
  content: counter(tags) ' '
}
.narrow-columns {
  column-width: 40vw;
  /* again, will be rounded - to half. */
}
.rigged {
  text-align: left;
  word-spacing: 0;
  /* imho better. */
}
<!--
 demo controls:
-->
<p>
  <button onclick="clearinterval(t);addtag()">add tag</button>
  <button onclick="tags.scrollby({left:tags.getboundingclientrect().width,behavior:'smooth'})">scroll by width →</button>
  <button onclick="tags.scrollby({left:-tags.getboundingclientrect().width,behavior:'smooth'})">… ←</button>
|
  <button onclick="clearinterval(t);tags.innerhtml=''">clear tags</button>
  <label><input type="checkbox" onchange="tags.classlist.toggle('narrow-columns')">narrower columns</label>
  <label><input type="checkbox" onchange="tags.classlist.toggle('rigged')">rigged</label>
</p>
<div id="tags">
 <!--
  bunch of 
   <span>foo-bar</span>
  for demonstrative purposes added by js here.
 -->
</div>

score:5

via css only, you may try writing-mode and column css and finally reset size via min-content/max-content and also max-height:100%;


mind that once masonry layout will be widely implemented (only ff at the time of that answer), this answer will be obsolete and this answer is the one you'll be looking for.

warning: this feature is only implemented in firefox, and can be enabled by setting the flag layout.css.grid-template-masonry-value.enabled to true in about:config, in order to allow testing and providing of feedback.


here is the idea in action (feedback about browser's failure is welcome)

:root {
  --scpu-bg: #1b1b1b;
  --scpu-border: #3d3d3d;
  --scpu-fg: #ffffff;
  color: var(--scpu-fg);
  font-size: 14px;
}

body {
  background-color: var(--scpu-bg);
}

.tag-chip {
  padding: 1rem;
  border: 1px var(--scpu-border) solid;
}

.tag-cloud {
  overflow-x: scroll;
  max-height: 11rem;
  padding-bottom: 1.2rem;
  display: flex;
}

.tag-list {
  column-count: 3;
  column-rule-width:0;
  writing-mode: vertical-lr;
  width: max-content;
  height: min-content;
  max-height: 100%;
  padding-right:2px;
}

.tag-chip {
  writing-mode: horizontal-tb;
  margin: 2px;
}
<div class="tag-cloud">
  <div class="tag-list nav-scroll">
    <span class="tag-chip">6000</span><span class="tag-chip">alagadda</span
    ><span class="tag-chip">artifact</span><span class="tag-chip">audio</span
    ><span class="tag-chip">biological</span
    ><span class="tag-chip">blackwood</span><span class="tag-chip">_cc</span
    ><span class="tag-chip">co-authored</span
    ><span class="tag-chip">container</span><span class="tag-chip">d-11424</span
    ><span class="tag-chip">daevite</span
    ><span class="tag-chip">deer-college</span
    ><span class="tag-chip">doctor-light</span
    ><span class="tag-chip">doctor-mcdoctorate</span
    ><span class="tag-chip">entropic</span
    ><span class="tag-chip">esoteric-class</span
    ><span class="tag-chip">ethics-committee</span
    ><span class="tag-chip">faeowynn-wilson</span
    ><span class="tag-chip">global-occult-coalition</span
    ><span class="tag-chip">grand-karcist-ion</span
    ><span class="tag-chip">hanged-king</span
    ><span class="tag-chip">hy-brasil</span
    ><span class="tag-chip">interactive</span
    ><span class="tag-chip">la-rue-macabre</span
    ><span class="tag-chip">_licensebox</span><span class="tag-chip">meta</span
    ><span class="tag-chip">metallic</span
    ><span class="tag-chip">narrative</span
    ><span class="tag-chip">on-guard-43</span
    ><span class="tag-chip">portal</span><span class="tag-chip">religious</span
    ><span class="tag-chip">ritual</span
    ><span class="tag-chip">s&amp;amp;c-plastics</span
    ><span class="tag-chip">scp</span><span class="tag-chip">serpents-hand</span
    ><span class="tag-chip">spacetime</span
    ><span class="tag-chip">temporal</span
    ><span class="tag-chip">three-moons-initiative</span
    ><span class="tag-chip">three-portlands</span
    ><span class="tag-chip">wanderers-library</span
    ><span class="tag-chip">weapon</span
    ><span class="tag-chip">wilsons-wildlife</span>
  </div>
</div>


Related Query

More Query from same tag