Force empty <span> to next line when wrapping occurs

84 Views Asked by At

The following snippet generates for me this result:

enter image description here

(The borders are just a quick way to easily show all the elements, including the <span>s containing the space as well as the empty <span>s. They are not part of the solution)

My aim is to have the first foo to stay on the line it is, and the second foo to be at the following line.

If the "space" <span> in the middle keeps occupying no space, it's not important where it is (after the foo on the first line or before the foo on the second line); but if it does end up showing as an actual space, then I definitely want it at the end of the first line.

:root {
  font-size: 3em;
}
div {
  border: 1px solid black;
  width: 10rem;
}
span {
  border: 1px solid black;
}
.foo {
  border-color: red;
}
<div>
<span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span> </span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span class="foo"></span><!--
--><span> </span><!--
--><span class="foo"></span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span>
</div>


In my usecase, there's only one foo at any given time (in practice, that <span class="foo"></span> is moved around), but I've shown both for simplicity. After all, I don't exclude that at some point I might want to show multiple of those.

2

There are 2 best solutions below

0
On

Like the other deleted answer, the answer below assumes that one knows which a <span>s containing just the space are indeed the trailing element on that visual line.

Luckily, I have that information at hand, because I already have in place some JavaScript logic that puts the foo right before the line wraps.


Just a bit of JavaScript to stick display: flex; to the trailing space seems to do the trick, leading to the desired result:

enter image description here

I tend to look at it as a sub-optimal solution, because it uses JavaScript, so I'll wait for other answers.

let div = document.getElementsByTagName('div')[0];
// or any other way to get the parent of the <span>s
let findLastFoo = e => e.findLastIndex(s => s.classList.contains('foo'));
// or any other way to get the <span class="foo"></span> to be sent to newline

div.children[findLastFoo(Array.from(div.children)) - 1].classList.add('trailing-space');
:root {
  font-size: 3em;
}
div {
  border: 1px solid black;
  width: 10rem;
}
span {
  border: 1px solid black;
}
.foo {
  border-color: red;
}

.trailing-space {
  display: flex;
}
<div>
<span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span> </span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span class="foo"></span><!--
--><span> </span><!--
--><span class="foo"></span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span>
</div>

12
On

You could use float: left on the spans and clear: left; on the second .foo using .foo ~ .foo as a selector for that:

:root {
  font-size: 3em;
}
div {
  border: 1px solid black;
  width: 10rem;
}
span {
  border: 1px solid black;
  float: left;
}
.foo {
  border-color: red;
}
.foo ~ .foo {
  clear: left;
}
<div>
<span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span> </span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span class="foo"></span><!--
--><span> </span><!--
--><span class="foo"></span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span><!--
--><span>a</span>
</div>