Search code examples
htmlcsshyphenationword-break

Show hyphens only when necessary? (soft-hyphens doesn't cut it)


Is it possible to use hyphens, or soft-hyphens in CSS, in such a way that hyphens are not rendered unnecessarily?

My goal is to keep the original text as much as possible and break any words unless absolutely critical because they are too long to fit the container width.

My specific case

I want to render the text "Hi Superman" in such a way that:

If the word "Superman" is too long to fit inside a container, I want to hyphenate it in some way, for instance:

Hi Super-
man

But if the word “Superman” could fit in the container it must be rendered without hyphens

Hi
Superman

If the case above is possible ("Superman" could be written unhyphenhated) it is UNACCEPTABLE to add unnecessary hyphens like this:

Hi Super-
man

I can change the HTML however I want. I'm allowed to inject hyphens in a way that makes sense (As long as there's more than 3 letters between each hyphen it's okay. "Superma-n" is never okay)

What I've tried

I thought soft-hyphens would be the solution. So I used: Hi Super­man

But I found out that this will result in the unacceptable case of "unnecessary hyphenation" shown above.

Snippet to show the failure:

body { 
  margin-left: 30px;
}
div {
   border: solid 1px black;
}
.wide {
  border: solid 1px blue;
      width: 500px;
}
.narrow { 
  border: solid 1px red;
  width: 360px;
}
 h2 {
   font-family: 'Courier New';
    font-weight: 400;
    font-size: 87px;
  }
code {
 background-color: #eee;
}
<p> <code>Super&amp;shy;man</code> looks good in really narrow containers where the full word "Superman" would not fit</p>
<p>
<div class="narrow"><h2>Hi Super&shy;man</h2></div>

<p>But in this case the word "Superman" would fit unhypenhated on the second row. But the damn CSS decides to add hyphens anyway. Unacceptable in my case!
Again, this uses the same code as the previous example
<code>Super&amp;shy;man</code></p>
<div class="wide"><h2>Hi Super&shy;man</h2></div>

<p>I even tried adding a wordbreak tag before "Superman", like this <code>Hi &lt;wbr&gt; Super&amp;shy;man</code> but it does not help</p>
<p>  </p>
<div class="wide"><h2>Hi <wbr>Super&shy;man</h2></div>

Can I solve the example above with just CSS? (Tried different word-break properties without any success)

My guess is that this is impossible to solve this with just simple HTML and CSS due to the nature of CSS. I assume CSS just parses text line-by-line and it can never know if a word would "fit better" on the next row of text. If it finds a hyphen, it will try to fit the maximum amount of chars on the current line of text.

I want to solve this with just HTML and CSS or not at all.

Preferably:

  • No text-parsing with JavaScript.

  • I don't want to have to set different CSS-properties per div based on how wide the div is and whether I guess the text will need hyphenation or not.

  • Would prefer not to have to add wrappers around my words

  • No auto-hyphenation that can result in laughable hyphenations like "Superma-n" (However in a pinch I would be ok with auto-hyphenation as long as there's 3 chars between each hyphen. Like "Sup-erman")


Solution

  • Use a container with display: inline-block around the long words.

    body { 
      margin-left: 30px;
    }
    div {
       border: solid 1px black;
    }
    .wide {
      border: solid 1px blue;
          width: 500px;
    }
    .narrow { 
      border: solid 1px red;
      width: 360px;
    }
     h2 {
       font-family: 'Courier New';
        font-weight: 400;
        font-size: 87px;
      }
    code {
     background-color: #eee;
    }
    
    .unbreakable {display:inline-block}
    <p> <code>Super&amp;shy;man</code> looks good in really narrow containers where the full word "Superman" would not fit</p>
    <p>
    <div class="narrow"><h2>Hi <span class="unbreakable">Super&shy;man</span></h2></div>
    
    <p>And in this case the word "Superman" would fit unhypenhated on the second row.<br/>
    This uses the same code as the previous example</p>
    <div class="wide"><h2>Hi <span class="unbreakable">Super&shy;man</span></h2></div>

    Edit: Oh, I did find a flaw: words that do break in the wrapper take up all of the two lines rather than allowing shorter words on the same line. In the below example, the text "man is" would have fit on one line if it hadn't been for this trick.

    body {
      margin-left: 30px;
    }
    
    .narrow {
      border: solid 1px red;
      width: 360px;
    }
    
    h2 {
      font-family: 'Courier New';
      font-weight: 400;
      font-size: 87px;
    }
    
    .unbreakable {
      display: inline-block
    }
    <div class="narrow">
      <h2><span class="unbreakable">Super&shy;man</span> is coming.</h2>
    </div>

    So, no, not perfect. Sorry.