skip to Main Content

Since there are no spaces in between the <span> elements, I expect them not to wrap but all sit on the same line, which seems to be the case in all browsers

span {
  position: relative;
}
<span>Fooooooooooooooooooooooooooooooooooooooooooooooooo</span><span>foo</span><span>Baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar</span><span>bar</span>

But when adding a ::before tooltip element this behaviour changes. While they stay on the same line in Firefox (114), they start wrapping in Safari (16) and Chrome (114).

span {
  position: relative;
}

span::before {
  content: 'tooltip';
  position: absolute;
  left: 0;
  top: 0;
  opacity: 0;
  background: grey;
  color: white;
  transition: opacity 100ms;
}

span:hover::before {
  opacity: 100;
}
<span>Fooooooooooooooooooooooooooooooooooooooooooooooooo</span><span>foo</span><span>Baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar</span><span>bar</span>

Why is that and is there a way to prevent it?

Different display options on the ::before elements didn’t have an effect.

But I just noticed that setting inline-block on the spans actually seems to have the same effect as adding the ::before element

span {
  position: relative;
  display: inline-block;
}
<span>Fooooooooooooooooooooooooooooooooooooooooooooooooo</span><span>foo</span><span>Baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar</span><span>bar</span>

Is there a logical explanation for the wrapping, or can this be considered unexpected behaviour?

Since in the real example there are whitespaces which should break, wrapping everything in a white-space: nowrap; container isn’t an option.

Here’s an example with whitespaces where FoooooooBaaaaaaar should stay together and not split into two lines

span {
  position: relative;
}

span::after {
  content: 'tooltip';
  position: absolute;
  left: 0;
  top: 0;
  opacity: 0;
  background: grey;
  color: white;
  transition: opacity 100ms;
}

span:hover::after {
  opacity: 100;
}
<span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span>

While the abstract examples already illustrate the problem, here’s also a more realistic one: Given a sentence that contains special characters such as quotation marks and parentheses, and words that are a combination of two words. For styling purposes, and because the words have a translation tooltip, everything is split into span elements.

span {
  position: relative;
}

.word::after {
  content: 'tooltip';
  position: absolute;
  left: 0;
  top: 0;
  opacity: 0;
  background: grey;
  color: white;
  transition: opacity 100ms;
}

.word:hover::after {
  opacity: 100;
}
This is an "example sentence" containing a comboword and also something in (parenthesis).<br><br>

<span class="word">This</span><span class="char"> </span><span class="word">is</span><span class="char"> </span><span class="word">an</span><span class="char"> </span><span class="char">"</span><span class="word">example</span><span class="char"> </span><span class="word">sentence</span><span class="char">"</span><span class="char"> </span><span class="word">containing</span><span class="char"> </span><span class="word">a</span><span class="char"> </span><span class="word">combo</span><span class="word">word</span><span class="char"> </span><span class="word">and</span><span class="char"> </span><span class="word">also</span><span class="char"> </span><span class="word">something</span><span class="char"> </span><span class="word">in</span><span class="char"> </span><span class="char">(</span><span class="word">parenthesis</span><span class="char">)</span><span class="char">.</span>

Usually there wouldn’t be a break between the special characters and the word next to it or in betweeen the comboword, but with the ::after element that’s the case.

unexpected breaks

3

Answers


  1. <div style="white-space: nowrap;">
      <span>Fooooooo</span><span>Baaaaaaar</span> <span>Fooooooo</span><span>Baaaaaaar</span> ...
    </div>
    

    This will prevent the spans from wrapping to the next line.

    <div style="white-space: nowrap;">
      <span class="word">This</span><span class="char"> </span><span class="word">is</span> ...
    </div>
    

    By setting white-space: nowrap; on the containing element, you can prevent wrapping even when using ::after elements or having whitespaces in the content.

    Login or Signup to reply.
  2. By default, inline elements have a shrink to fit behavior, which means they will try to fit on a single line and wrap if necessary. However, now when you add absolute positioning to the :before element, it takes the element out of the normal flow of the document, and the span elements revert to their default behavior of sitting on separate lines.

    One way to solve this is to add display flex to the parent container of said span elements as this will make them sit on the same line, but still break on whitespaces.

    I made the :before become position: relative on hover, so it does not clip into the span elements, this is not necessary if you want it to show over the other elements, just make sure you add a z-index to it then, so it gets placed on top of the span it is related to.

    div {
      display: flex;
    }
    
    span {
      position: relative;
    }
    
    span::before {
      content: 'tooltip';
      position: absolute;
      left: 0;
      top: 0;
      opacity: 0;
      background: grey;
      color: white;
      transition: opacity 100ms;
    }
    
    span:hover::before {
      position: relative;
      opacity: 100;
    }
    <div>
      <span>Fooooooooooooooooooooooooooooooooooooooooooooooooo</span><span>foo</span><span>Baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar</span><span>bar</span>
      <div>

    I hope this is the answer you are looking for, if you need any more help just let me know!

    Login or Signup to reply.
  3. I was reading the specs here and it says that:

    Out-of-flow elements and inline element boundaries do not introduce a
    forced line break or soft wrap opportunity in the flow.

    According to my understanding, position: absolute should not cause the elements to wrap and Chromimum based browsers are doing it wrong!

    The article further states that:

    For Web-compatibility there is a soft wrap opportunity before and
    after each replaced element or other atomic inline, even when adjacent
    to a character that would normally suppress them, such as U+00A0
    NO-BREAK SPACE.

    So display: inline-block could a soft line break.

    body {
      font: medium monospace;
    }
    .test>:nth-child(odd) {
      background-color: #FC0;
    }
    .test>:nth-child(even) {
      background-color: #CF0;
    }
    .test-1>* {
      position: relative;
    }
    .test-1>*::before {
      content: "tooltip";
      position: absolute;
      left: 0;
      top: 0;
      background-color: rgb(0, 0, 0, .5);
    }
    .test-2>* {
      display: inline-block;
    }
    <h1>position: relative + absolute<br>should not wrap</h1>
    <p class="test test-1"><span>Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</span><span>Cccccccccccccccccccccccccccccccccccccccc</span><span>Bbbbbbbbbbbbbbbbbbbb</span><span>Dddddddddddddddddddd</span></p>
    <h1>display: inline-block<br>should wrap</h1>
    <p class="test test-2"><span>Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</span><span>Cccccccccccccccccccccccccccccccccccccccc</span><span>Bbbbbbbbbbbbbbbbbbbb</span><span>Dddddddddddddddddddd</span></p>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search