Stretch text to fit width of div

HtmlCss

Html Problem Overview


I have a div with a fixed width, but the text inside the div can change.

Is there a way of setting, with css or other, the spacing between the letters so the text always fills the div perfectly?

Html Solutions


Solution 1 - Html

This can be done with text-align:justify and a small hack. See here:

div{
  background-color:gold;
  text-align:justify;
}

span{
  background-color:red;
  width:100%;
  height:1em;
  display:inline-block;
}

<div>
  Lorem ipsum sit dolor
  <span> </span>
</div>

The trick is to add an element after the text that pretends to be really long word. The fake word is actually a span element with display:inline-block and width:100%.

In my example the fake word is in red and given a height of 1em, but the hack will work even without it.

Solution 2 - Html

As Mark said, text-align:justify; is the simplest solution. However, for short text, it won't have any effect. The following jQuery code stretches the text to the width of the container.

It calculates the space for each character and sets letter-spacing accordingly so the text streches to the width of the container.

If the text is too long to fit in the container, it lets it expand to the next lines and sets text-align:justify; to the text.

Here is a demo :

$.fn.strech_text = function(){
    var elmt          = $(this),
        cont_width    = elmt.width(),
        txt           = elmt.html(),
        one_line      = $('<span class="stretch_it">' + txt + '</span>'),
        nb_char       = elmt.text().length,
        spacing       = cont_width/nb_char,
        txt_width;
    
    elmt.html(one_line);
    txt_width = one_line.width();
    
    if (txt_width < cont_width){
        var  char_width     = txt_width/nb_char,
             ltr_spacing    = spacing - char_width + (spacing - char_width)/nb_char ; 
  
        one_line.css({'letter-spacing': ltr_spacing});
    } else {
        one_line.contents().unwrap();
        elmt.addClass('justify');
    }
};


$(document).ready(function () {
    $('.stretch').each(function(){
        $(this).strech_text();
    });
});

p { width:300px; padding: 10px 0;background:gold;}
a{text-decoration:none;}

.stretch_it{ white-space: nowrap; }
.justify{ text-align:justify; }

.one{font-size:10px;}
.two{font-size:20px;}
.three{font-size:30px;}
.four{font-size:40px;}
.arial{font-family:arial;}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p class="stretch one">Stretch me</p>
<p class="stretch two">Stretch me</p>
<p class="stretch three">Stretch <a href="#">link</a></p>
<p class="stretch two">I am too slong, an I would look ugly if I was displayed on one line so let me expand to several lines and justify me.</p>
<p  class="stretch arial one">Stretch me</p>
<p class="stretch arial three">Stretch me</p>
<p class="stretch arial four">Stretch me</p>
<p class="arial two">Don't stretch me</p>

Js fiddle demo

Solution 3 - Html

Even easier HTML/CSS method would be to use flexbox. It's also immediately responsive. But worth noting SEO won't pick it up if you were to use it as a h1 or something.

HTML:

<div class="wrapper">
<div>H</div>
<div>e</div>
<div>l</div>
<div>l</div>
<div>o</div>
<div>&nbsp</div>
<div>W</div>
<div>o</div>
<div>r</div>
<div>l</div>
<div>d</div>

CSS:

.wrapper{
  width: 100%;
  text-align: center;
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-between;
  border: 1px solid black;
}

jsfiddle here

Solution 4 - Html

Maybe this could help:

text-align:justify;

Solution 5 - Html

I found a better solution for text shorter than one line, without any extra js or tag, only one class.

.stretch{ 
  /* We got 2rem to stretch */
  width: 5rem;
  /* We know we only got one line */
  height: 1rem;
  
  text-align: justify; 
}
.stretch:after{
    /* used to stretch word */
    content: '';
    width: 100%;
    display: inline-block; 
}

<div class="stretch">你好么</div>
<div class="stretch">你好</div>

Solution 6 - Html

A little late to the party, but for a simple, pure CSS implementation consider using flexbox:

h1.stretch {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}

<h1 class="stretch">
  <span>F</span>
  <span>o</span>
  <span>o</span>
  <span>B</span>
  <span>a</span>
  <span>r</span>
</h1>

Not sure if wrapping each letter in a span (note any element will work) will mess with SEO, but I imagine search engines will strip tags from the innerHTML of tags used for important markup such as headings, etc. (Someone who knows SEO to confirm?)

Solution 7 - Html

MARCH 2018 If you are landing on this question in a more current time...

I was attempting do do what the OP asked about but with a single word and found success with the following:

1. Use a <span> and set css: span { letter-spacing: 0px; display:block} (this makes the element only as wide as the content)

2. On load capture the width of the span let width = $('span').width();

3. Capture the length of the span let length = $('span').length;

4. Reset the width of the span to the container $('span').css({'width','100%'});

5. Capture the NEW width of the span (or just use the container width) let con = $('span').width();

6. Calculate and set the letter spacing to fill the container $('span').css({'letter-spacing':(cont-width)/length})

Obviously this can be converted to use vanilla js and it is useful even with most font styles including non mono-space fonts.

Solution 8 - Html

Some of the above answers work well but the text has to wrap with many child div
and it's a lot of extra codes.
The text inside the div should be clean, so I made it with a help of JS.

const words = document.querySelector(".words"); words.innerHTML = words.innerText.split("").map(e => !e.trim() ? "

 
" : <div>${e}</div>).join("");

.words {
  width: 100%;
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-between;
}

<div class="words">This is the demo text</div>

Solution 9 - Html

I think what you're actually looking for is scaling.

Render your font with some nice-looking resolution that makes sense and then use JS to stretch it to the container by using css transforms:

transform: scale(1.05);

The benefits of this is that your text will always wit, but you run into the problem of it becoming too small to be readable.

Quick note is that you'll need to make the element you're trying to shrink/expand have absolute position:

position: absolute;

Solution 10 - Html

If someone is interested on how to justify the content and center only the last line you can use

text-align: justify;
text-align-last: center;

see the example:

.custom-justify{
   text-align: justify;
   text-align-last: center;
   padding: 0 10px 0 10px;
}

<div class="custom-justify">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis elementum bibendum. Cras pellentesque sed augue nec lacinia. Duis at eros vel lorem cursus laoreet ac vel justo. Maecenas ornare, ligula ut porttitor sollicitudin, turpis urna auctor ipsum, a consectetur felis nibh vel est. Nullam id lorem sit amet magna mollis iaculis eu vitae mauris. Morbi tempor ut eros ut vulputate. Quisque eget odio velit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed posuere enim tellus, ut vestibulum libero dapibus ac. Nulla bibendum sapien non luctus vehicula. Aenean feugiat neque nunc, in fermentum augue posuere vel. Maecenas vitae diam in diam aliquet aliquam.<div>

Solution 11 - Html

So, still nibbling away at the edges of this problem, if you combine wener's answer that stretches short lines of text with this suggestion to use a real element from another thread, you can do the whole thing without needing an :after pseudo class.

You're substituting in an actual element and placing it after the one you want to justify. And this will trigger the justify alignment in the same way:

header {
  background-color: #ace;
  text-align: justify;
}

.hack {
  display: inline-block;
  width: 100%;
}

<header>
  <div>
    A line of text to justify
    <div class="hack"></div>
  </div>
</header>

This variation lets you use this trick with React and style objects:

const style = {
  backgroundColor: '#ace',
  textAlign: 'justify'
};

const hack = {
  display: 'inline-block',
  width: '100%'
};

const example = (
  <header style={ style }>
    <div>
      A line of words to stretch
      <div style={ hack } />
    </div>
  </header>
);

ReactDOM.render(example, document.getElementById('root'));

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

This is ugly and hacky enough already, but from there you'll have to pick your poison on which way you want to "fix" the excess height of the container: fixed height or negative margins for the container? relative positioning and overlapping from following elements? match the container background to the page background and pretend like that extra margin is intentional?

Solution 12 - Html

With the lineclamp module I wrote you can accomplish what you want. You set a max number of lines or height you want text to take up and it finds the max font size that will fit in that number of lines, and/or trims text to make it fit.

import LineClamp from "//unpkg.com/@tvanc/lineclamp/dist/esm.min.js";

const clamp = new LineClamp(document.querySelector("#elementToClamp"), {
  useSoftClamp: true,
  // Set an arbitrarily high max font size. Default min is already 1
  maxFontSize: 10000,
  maxLines: 1
});

// .apply() to apply the clamp now
// .watch() to re-apply if content changes or window resizes
clamp.apply().watch();

Working example: https://codepen.io/tvanc/pen/BaNmVXm


In the question, OP says letter spacing. In a comment, OP says letter spacing or font size.

Solution 13 - Html

jsfiddle link

For a purely HTML/CSS solution for when you are working with even shorter text (short enough that

text-align: justify;

wouldn't work)

I followed this great post as an inspiration, and placed each letter within a div

HTML:

<div class="wrapper">
    <div class="letters">H</div>
    <div class="letters">e</div>
    <div class="letters">l</div>
    <div class="letters">l</div>
    <div class="letters">o</div>
    <div class="letters">&nbsp</div>
    <div class="letters">W</div>
    <div class="letters">o</div>
    <div class="letters">r</div>
    <div class="letters">l</div>
    <div class="letters">d</div>
    <span class="stretch"></span>
</div>

CSS:

.wrapper {
    width: 300px; /*for example*/
    border: 1px solid gray; /*only for demonstrative purposes*/
    text-align: justify;
    -ms-text-justify: distribute-all-lines;
    text-justify: distribute-all-lines;
}

.letters {
    vertical-align: top;
    display: inline-block;
    *display: inline;
    zoom: 1
}

.stretch {
    width: 100%;
    display: inline-block;
    font-size: 0;
    line-height: 0
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCurtisView Question on Stackoverflow
Solution 1 - HtmlAakil FernandesView Answer on Stackoverflow
Solution 2 - Htmlweb-tikiView Answer on Stackoverflow
Solution 3 - HtmlnathanView Answer on Stackoverflow
Solution 4 - HtmlMarkView Answer on Stackoverflow
Solution 5 - HtmlwenerView Answer on Stackoverflow
Solution 6 - HtmlsaricdenView Answer on Stackoverflow
Solution 7 - HtmlKyleMView Answer on Stackoverflow
Solution 8 - HtmlronaldtgiView Answer on Stackoverflow
Solution 9 - HtmlMcTrafikView Answer on Stackoverflow
Solution 10 - HtmlAntonio CorreiaView Answer on Stackoverflow
Solution 11 - HtmlworcView Answer on Stackoverflow
Solution 12 - HtmltvancView Answer on Stackoverflow
Solution 13 - Htmltalker90View Answer on Stackoverflow