How to prevent a span from altering the distance between its two neighboring spans?

96 Views Asked by At

I've noticed that if I have

<span>x</span><span class="foo"></span><span>y</span>

with

.foo::after {
  display: inline-block;
  content: "";
  height: 1.2em;
  border: 3px solid;
  margin-right: -6px;
}

depending on which letters x and y are, it can happen that the middle empty <span> inflates the space between those two letters.

I guess it has to do with the features of the specific font (and I expect the monospace font to be unaffected by this, but I haven't tried yet, and I don't want a font-dependent solution), but my question is how do I prevent that?

The aim is that the empty <span class="foo"> is there, visible, and doesn't ever increase (or decrease, fwiw) the space between the two adjacent <span>s.


Below is a snippet showing the problem. If you look carefully, you'll see that while the red and green texts are horizontally aligned, even though one is the whole word rararara and the other is a sequence of <span>s with the individual letters, the presence of the empty <span> between every 2 spans in the blue text increases the horizontal distance between those letters.


Important:

Upon putting a checkbox in place to help the reader see the difference, I've realized that the behavior is even weirder than I expected: initially the alignment is I described above; when I turn off the visibility of the relevant <span class="foo" id="foo">, the issue disappears (expected); but when I turn it back on, the issue doesn't come back (unexpected)!

body * {
  padding: 0;
  margin: 0;
}

.main {
  font-size: 10em;
}

.foo::after {
  display: inline-block;
  content: "";
  height: 1em;
  border: 3px solid;
  margin-right: -6px;
  width: 0;
}

.one {
  color: red;
}
.two {
  color: green;
  bottom: 1.35em;
}
.three {
  color: blue;
  bottom: 2.70em;
}
.one, .two, .three {
  position: relative;
  opacity: 50%;
}

label#lab {
  font-size: 1em;
}

input:checked ~ div span#foo {
  display: none;
}
<input type="checkbox" id="cb" name="toggle" value="" />
<label for="cb">toggle to see the effect</label>
<div class="main">
<div class="one">
rararara
</div>
<div class="two">
<span>r</span><span>a</span><span>r</span><span>a</span><span>r</span><span>a</span><span>r</span><span>a</span>
</div>
<div class="three">
<span>r</span><span class="foo" id="foo"></span><span>a</span><span class="foo" id="foo"></span><span>r</span><span class="foo" id="foo"></span><span class="foo" id="foo"></span><span>a</span><span class="foo" id="foo"></span><span>r</span><span class="foo" id="foo"></span><span>a</span><span class="foo" id="foo"></span><span>r</span><span class="foo" id="foo"></span><span>a</span>
</div>

Here's a GIF showing what I see. I start thinking that it might be a browser-specific issue.

enter image description here


I've found another example that triggers the behavior I described above (including the part under the important section) also on Chromium. Here it is:

div {
  font-size: 10em;
}

.mid {
  position: relative;
}

input:checked + div > .mid::after {
  position: absolute;
  /*left: 3em;*/
  content: "";
  height: 1.2em;
  margin-bottom: -0.2em;
  border: 3px solid #999;
  border-color: magenta;
  margin-right: calc(-6px);
}

.r {
  background-color: cyan;
  opacity: 50%;
}

.comma {
  background-color: yellow;
  opacity: 50%;
}
<input type="checkbox" checked>
<div><span class="r">r</span><span class="mid"></span><span class="comma">,</span></div>
<div>r,</div>

2

There are 2 best solutions below

0
On

It seems to be a browser-specific effect/bug. I've filed a bug report here.

2
On

Remove the negative margin and add vertical-align: middle to span

.foo::after {
  display: inline-block;
  content: "";
  height: 1.2em;
  border: 3px solid;
  /* margin-right: -6px; */   /* Remove the negative margin */
}

span {
  vertical-align: middle;
}