1

How can I create dynamic letter spacing for a line of text that starts with 100% width of a container and reduces as the screen size gets smaller? I want the letter spacing to adjust based on the container's width, and the text's width should be recalculated whenever the window is resized.

I am getting letter spacing but not the width of the container.

$(document).ready(function () {

    function adjustLetterSpacing() {
        var containerWidth = $(".container").width();
        var textElement = $(".dynamic-text");
        var maxWidth = containerWidth - 50;
        var textWidth = textElement.width();
        var letterSpacingValue = 0;

        if (maxWidth > textWidth) {
            var textLength = textElement.text().length;
            letterSpacingValue = (maxWidth - textWidth) / (textLength - 1);
        }

        $(".dynamic-text").css("letter-spacing", Math.max(0, letterSpacingValue) + "px");
    }

    // Initial adjustment on page load
    adjustLetterSpacing();

    $(window).on("resize", adjustLetterSpacing);

});
.container {
  width: 1200px;
  }

.dynamic-text {
    white-space: nowrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<div class="container">
  <p>
      <span class="dynamic-text">
          Lorem ipsum dolor sit amet
      </span>
  </p>
</div>

Any guidance on how to implement this effect would be appreciated.

Junky
  • 958
  • 7
  • 17
  • I think the main problem is `.container { width: 1200px; }`, you should use something like `100vw`. – Titus Jul 24 '23 at 18:47
  • Thanks for your comment but that won't affect the letter spacing. – Junky Jul 24 '23 at 18:54
  • Just FYI there are existing solutions for this, like FitText (http://fittextjs.com/) which is what I would use. Reduce the code base and rely on someone else to maintain the code is often a win. – ControlAltDel Jul 24 '23 at 19:01
  • Yes it does because `containerWidth` will always be `1200px` and that variable is used to calculate the spacing. – Titus Jul 24 '23 at 19:02
  • "FitText makes font-sizes flexible" but I want to adjust letter-spacing. – Junky Jul 24 '23 at 19:04
  • @Titus, if you test your suggestion using the code editor, you can see it does not matter. The width of the container at 1200px has more than enough space to stretch the text out. – Junky Jul 24 '23 at 19:05
  • I don't think you get what I'm saying. `maxWidth` which it is used to calculate the letter spacing will always be `1150px` no matter what the size of the window will be. In other words, your JavaScript code doesn't do anything (has no effect) after the first time it is run. – Titus Jul 24 '23 at 19:29
  • You could do it as described in [Letter-spacing percent to completely fit the div container](https://stackoverflow.com/questions/24557411/css-letter-spacing-percent-to-completely-fit-the-div-container) by initially wrapping each letter in a `` using JavaScript and then use flexbox. – t.niese Jul 24 '23 at 20:27

3 Answers3

1

Use the power of flexbox. All you need to do is wrap each character in a <span>.

const s = document.querySelector('.stretch')
const a = Array.from(s.innerHTML)
s.innerHTML = a.map(c => `<span>${c}</span>`).join('');
.stretch {display: flex; justify-content: space-between;}
<p class="stretch">Lorem ipsum dolor sit amet</p>
Brett Donald
  • 6,745
  • 4
  • 23
  • 51
0

You could do something like this with Vanilla JS.

We add a "hidden/interim" element to the document with the text, grab it's width.

 const hiddenEl = document.createElement('span');
  hiddenEl.textContent = text;
  hiddenEl.style.visibility = 'hidden';
  document.body.appendChild(hiddenEl);

We could grab that the first time and cache it if we wanted.

Then we just figure out what the letter spacing needs to be based on the overall width minus the texts original width.

div.style.letterSpacing = `${(width - absoluteWidth) / text.length}px`;

function setLetterSpace(el) {
  const width = el.getBoundingClientRect().width;
  const text = el.textContent.trim();

  const hiddenEl = document.createElement('span');
  hiddenEl.textContent = text;
  hiddenEl.style.visibility = 'hidden';
  document.body.appendChild(hiddenEl);
  const absoluteWidth = hiddenEl.getBoundingClientRect().width;
  document.body.removeChild(hiddenEl)

  div.style.letterSpacing = `${(width - absoluteWidth) / text.length}px`;
}


const div = document.querySelector('div');
setLetterSpace(div);

window.addEventListener('resize', () => {
  setLetterSpace(div);
});
<div>Some text in here</div>
Loktar
  • 34,764
  • 7
  • 90
  • 104
  • This looks good in the snippet editor but I am unable to compile this. Can you do this in jQuery? – Junky Jul 24 '23 at 20:12
0

We can just make the span as wide as the div. and give the letter spacing as width/totalLetters.

But at very first we will also store the actual width of the letters because there are words too with spaces.

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
$(document).ready(function () {
var sizeOfAllLetters = $(".dynamic-text").width();
    function adjustLetterSpacing() {
        var containerWidth = $(".container").width();
        var textElement = $(".dynamic-text");
        var totalLetters = textElement.text().length;
        textElement.width(containerWidth);
        textElement.css("letter-spacing",(containerWidth-sizeOfAllLetters)/totalLetters);
        //console.log(containerWidth/totalLetters)
        }

    // Initial adjustment on page load
    adjustLetterSpacing();
    
    $(window).on("resize", adjustLetterSpacing);
});
</script>

<style>
.container {
  width: 1200px;
  /*margin-inline:auto;*/
  }

.dynamic-text {
    white-space: nowrap;
    /*margin-inline:auto;*/
    background:grey;

}
</style>

</head>
<body>
<div class="container">
  <span class="dynamic-text">Lorem ipsum dolor sit amet</span>
</div>
</body>
</html>
Thug Life
  • 87
  • 10
  • This does add letter-spacing to the element but it is greater than the container size of 1200px. It should be the width of the container. – Junky Jul 24 '23 at 20:10
  • I fixed that. It was taking extra size because I did not consider that the actual text will also take some space. We need to subtract that space from total space and then divide spacing in the remaining – Thug Life Jul 24 '23 at 20:21
  • The width of the text is still breaking the container and I don't see that you are using the sizeOfAllLetters variable. Could you add a code snippet? – Junky Jul 24 '23 at 20:56
  • Now I edited it. It will work now – Thug Life Jul 24 '23 at 21:07
  • Yes, thank you, it is working. – Junky Jul 25 '23 at 12:37