1

I want to visualize source-code-like structures in HTML using some sort of "block" analogy. But for whatever reason I walk into some strange sizing issues with my flexboxes. The following snippet displays a visualisation of a program that would "normally" be printed like this:

while(true) {
  goForward();
  goForward();
  goForward();
  goForward();
  goForward();
}

The outer box for the while is displayed as inline-flex to consume as little horizontal space as possible. But as you can see in the screenshot (or you may run the snippet yourself) there is quite a lot space wasted:

Wasted horizontal space

What I expect would look like this:

No wasted horizontal space

If you however click the goForward() blocks (which marks them with display: none), the width of the parenting block suddenly shrinks. From what I can tell it shrinks about as much as the width of the now hidden block.

The "linebreaks" between goForward() blocks are implemented using height: 0 but width: 100% elements. I also tried to do the breaks without empty elements and break-after: always, but this leads to the exact some behavior of the outer flexbox. I have observed this behavior in the most recent versions of Firefox and Chrome.

Why does the width of the outermost inline-flex element change (seemingly) with the number of items it displays vertically? And how could I "properly" implement this kind of layout where I basically want to have a block layout with arbitrary "linebreaks"?

// Hide blocks on click to demonstrate width changes
Array.from(document.querySelectorAll(".forward")).forEach(
  elem => elem.addEventListener('click', () => elem.classList.add("hide"))
);
.code-block {
  border: 2px solid blue;
  border-radius: 5px;
  padding: 5px;
  display: inline-flex;
  flex-flow: row wrap;
  align-items: baseline;
}

.line-break {
  width: 100%;
}

.forward {
  cursor: pointer;
}

.hide {
  display: none;
}
<div class="code-block">
  <div class="terminal">while(</div>
  <div class="code-block">true</div>
  <div class="terminal">)</div>
  <div class="line-break"></div>
  <div class="code-block forward">
    <div class="terminal">goForward()</div>
  </div>
  <div class="line-break"></div>
  <div class="code-block forward">
    <div class="terminal">goForward()</div>
  </div>
  <div class="line-break"></div>
  <div class="code-block forward">
    <div class="terminal">goForward()</div>
  </div>
  <div class="line-break"></div>
  <div class="code-block forward">
    <div class="terminal">goForward()</div>
  </div>
  <div class="line-break"></div>
  <div class="code-block forward">
    <div class="terminal">goForward()</div>
  </div>
</div>
Marcus Riemer
  • 7,244
  • 8
  • 51
  • 76

1 Answers1

1

Instead of flex-flow: row wrap;, try flex-direction: column;. This gets each item to go vertically. Then wrap everything you want to be in a single "line" in its own inside of .code-block, to keep the contents of each line together. So,

<div class="code-block">
  <div class="line-break">
    <div class="terminal">while(</div>
    <div class="code-block">true</div>
    <div class="terminal">)</div>
  </div>

...and so on for the others.

(You shouldn't need align-items: baseline; either.)

Eriyu
  • 124
  • 2
  • 12
  • Hmm, this would be quite a lot of refactoring work. The current representation of the backing datastructure is designed around the notion of linebreaks. I will see whether this would solve my problem, but would strongly prefer to understand why my current approach fails. Or even better: I would love to make it work. – Marcus Riemer Jan 17 '19 at 15:48
  • 1
    Hm, as the other questions show this is actually "working as intended". So it seems I am left with the approach that you have proposed. Thanks alot! – Marcus Riemer Jan 17 '19 at 15:51