Text in a div: splitting in middle when it word wraps

Viewed 182

I've got a centered text phrase that fits on one line in some devices, but wraps into two lines on others. The text is in a div. On some devices it's just barely too long, so only the last word wraps. Aesthetically, this looks bad. What I wish I could do is split the phrase in the middle, so each line is centered at a similar length.

I've tried this CSS:

text-align: center;
margin: 0 auto;
width: 100%;

but that only gets me to the problem I described. After googling for how to proceed, I haven't found any viable solutions. Actually, I'm not finding anyone trying to ask the same question, so I suspect there's something off about my search terms. How do you word wrap in the middle of the text instead of on the right side?

4 Answers

This is the intrinsic nature of how HTML and web dev works. It is naturally "responsive" and text will wrap at the width of its parent element. What I am hearing from you is you would like to keep from getting "widows" in your text. This is not an easy problem to fix in web-dev, but there are a few techniques I have found, most of them require a bit of manual attention which in a way is appropriate considering every instance can be unique.

If you have a precise layout you can set a width or max-width on the parent element, and use media queries to change it when needed.

HTML

<div class="parent">
    <p>Curabitur blandit tempus porttitor. Nulla vitae elit libero, a pharetra augue.</p>
</div>

CSS

.parent {
    max-width: 288px;
}

@media (min-width: 600px) {
    .parent {
        max-width: 568px;
    }
} 

Another technique is to add a non-breaking space &nbsp; between the last two words, effectively making them one word that will not wrap to a new line without the other. This looks a little bit better and can work well especially if they are short words.

HTML

<div class="parent">
    <p>Curabitur blandit tempus porttitor. Nulla vitae elit libero, a pharetra&nbsp;augue.</p>
</div>

Another technique is similar to the &nbsp; but instead us a span and styles to achieve the same thing. This could be useful in a CMS editor or where you need to style the grouping or somewhere a non-breaking space won't work.

HTML

<div class="parent">
    <p>Curabitur blandit tempus porttitor. Nulla vitae elit libero, a <span class="nowrap">pharetra augue.</span></p>
</div>

CSS

.nowrap {
    white-space: nowrap;
}

Can you wrap each part of the phrase in its own div and center the divs using flex?

#container {
  border: 1px solid;
  width: 100%;
  margin: 0 auto;
  
  
  display: flex;
  flex-direction: column;
  align-items: center;
}
<div id="container">
<div>Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,</div> 
<div>when an unknown printer took a galley of type and scrambled it to make a type specimen book.</div>
</div>

You could set a max-width for the div which is proportionate to where you want the word to be split

div{
    max-width: 25px;
}

Ps. 25px is just a random value you can check with your code how much you need.

If you have a good idea of where you would like the break to be then CSS and/or alterations to the HTML work.

But for a general solution I think you have to resort to Javascript.

This snippet senses whether more than one line has been used, and if so iterates the width to find the minimum width that keeps the original height. This spreads the words over the lines as evenly as possible, and it works for multiple lines, not just 2.

function resize() {
  const fitme = document.querySelector('.fitme');
  fitme.style.maxWidth = '100%';
  const origH = fitme.offsetHeight;
  const str = fitme.innerHTML;
  let arr = str.split(' ');
  fitme.innerHTML = arr[0];
  if (origH > fitme.offsetHeight) { //the line is split
     fitme.innerHTML = str;
    //iterate the width to find the smallest that will keep the original height
    for (w = 55; w <= 100; w+=5) {
      fitme.style.maxWidth = w + '%';
      if (origH >= fitme.offsetHeight) { break; }
    }
  }
  fitme.innerHTML = str;
}
window.onresize = resize;
resize();
.fitmecontainer {
  margin: 0 auto;
  width: 100%;
}
.fitme {
  font-size: 70px;
  text-align: center;
  max-width: 100%;
  margin: 0 auto;
  padding: 0;
}
<div class="fitmecontainer">
  <div class="fitme">This text is sometimes on more than one line</div>
</div>

Related