1

I know this question is asked multiple times, yet mine is different. I noticed that with the pure JavaScript solution, there is a need to resize the screen, while mine has absolutely nothing to do with resizing a screen.

What I have is a container div with some text in it. All texts have a certain font-size, but I want to change the font-size whenever the text gets a certain length.

I have seen this solution on SO: Resize font depending on string length

Yet, this absolutely looks horrible in pure JavaScript and it's a post of three years ago. There surely must be a better (shorter, better) solution for this. I have read about the CSS solutions, but as I said: I am not using a certain viewport and I don't want to. I just want to change the font-size when it's too long.

I have made a JSFiddle to illustrate the problem:

https://jsfiddle.net/tpx71aqL/

<div class="test">
Blablabla
</div>

<div class="test">
Blablabla12124e121211asdasasas
</div>

PS: I can't use jQuery and don't want to use ellipsis.

Siyah
  • 2,852
  • 5
  • 37
  • 63
  • What about using ellipsis to solve the problem of text escaping containers? I created an implementation of it using your example [here](https://jsfiddle.net/Obsidian_Age/db9fco3j/). – Obsidian Age Jan 13 '17 at 00:25
  • Well, the problem with that is, is that you can't see the whole text anymore... I don't want to ellipse it. – Siyah Jan 13 '17 at 00:32
  • Wrap your text in an element, reduce the size of the text until the wrapper and the parent element are equal width or the wrapper is ever so slightly smaller. – kontur Jan 18 '17 at 13:40

3 Answers3

3

An idea for this solution is actually really simple. Check out my codepen here.

Using a simple while loop which checks clientWidth against scrollWidth which you can learn more about here, we use the javascript .style.fontSize = "smaller" which decreases the font size by 1 unit. This works well when we don't know what unit is assigned in the CSS. You can read more about it here.

Hope this helps.

document.onreadystatechange = () => {
  if (document.readyState === 'complete') {
    var container = document.getElementById("test");
    while (container.scrollWidth > container.clientWidth) {
      container.style.fontSize = "smaller";
    }
  }
};
.test {
  width: 200px;
  border: 1px solid black;
  font-size: 16px;
}
<div class="test">
Blablabla
</div>

<div class="test" id="test">
Blablabla12124e121211asdasasas
</div>
Community
  • 1
  • 1
Matthew Brent
  • 1,366
  • 11
  • 23
  • Hi Matthew, thanks for the swift and nice response. Is there any other way I could do this? I am getting "cannot read property" errors, while I know it should work. I have even set a script above my HTML in the HTML file, yet it doesn't seem to be working for me. Should I use it as a function or wrap it up in an onload or something? – Siyah Jan 13 '17 at 09:49
  • Well that could be a number of things...first off it will need to be bound to some kind of function. It would probably need to be when the document is ready and all sub resources are loaded, i'll add this in to the answer. – Matthew Brent Jan 13 '17 at 13:12
  • its hard to say without looking at your live code. After wrapping it in the ready function, do try troubleshooting by using `alert()` or `console.log` to view the `clientWidth` and `scrollWidth` to make sure something is returning. – Matthew Brent Jan 13 '17 at 13:16
  • Thanks mate... you've helped me out. Appreciated! – Siyah Jan 13 '17 at 17:53
  • Using `smaller` like that might not be what you want, instead extract the current font size and then reduce it. For all we know the current value could already be `x-small`, which would then make the font bigger when applying `smaller`. – kontur Jan 18 '17 at 13:39
  • Actually that's incorrect smaller makes the font size one relative increment smaller. According to mdn [here](https://developer.mozilla.org/en/docs/Web/CSS/font-size) – Matthew Brent Jan 19 '17 at 02:02
3

This fiddle shows what I suggested in my comment. You extract the current width of the text wrapper and reduce font size until you have a wrapper the same size or slightly smaller than the parent.

var fit = document.getElementById("fit"),
    wrap = document.getElementById("wrap"),
    step = 0.5,
    currentSize;

while (fit.offsetWidth < wrap.offsetWidth) {
    currentSize = parseFloat(window.getComputedStyle(wrap, null).getPropertyValue('font-size'));
    wrap.style.fontSize = (currentSize - step) + "px";
}

Note the getComputedStyle to really get the calculated size.

You could improve this by making the reduction step smarter, instead of just going down a step again and again; for example calculate how far a 1px reduction approximated the wrapper width to the parent width and adjust step size accordingly.

Also this does assume that the text indeed needs scaling down, no scaling up - the same idea applies.

kontur
  • 4,934
  • 2
  • 36
  • 62
  • Thanks man, but it keeps saying that "wrap" and "fit" are NULL. So they can't be found in the HTML, while they are there! – Siyah Jan 18 '17 at 17:44
  • I'm referencing the html from the fiddle example. You have to adjust your code accordingly, the id's are just examples. Does the fiddle work for you, and if not, what browser and OS are you on? – kontur Jan 18 '17 at 18:04
  • I have used the exact same HTML and JS as in your fiddle, so that's certainly not the problem. I tested it in Chrome on a MacBook. I think the problem is because it's not wrapped in a function or something. All other code in the same JS file are working fine, yet this one doesn't. – Siyah Jan 18 '17 at 18:06
  • Yes, so you want to have that javascript referenced at the end of the page, when your html has loaded already, maybe even only after a document ready event. I am providing you with the essential core for how to scale the text, it needs some implementation. The fiddle does run correctly for you, yes? – kontur Jan 18 '17 at 18:08
  • Yes, the fiddle runs correctly. Thanks. I have upvoted you – Siyah Jan 18 '17 at 18:10
  • Okay ;) Well, compared to your originally posted JS this is very much less code and cleaner. Have fun implementing this to your setup. – kontur Jan 18 '17 at 18:11
0

I needed something similar and I ended up doing something like this:

var elem = document.getElementById("test");
elem.style.fontSize = 30 - elem.innerHTML.length / 6 + 'px';

The idea is to set the max size and reduce it based on the length of the string.

Not fancy or sophisticated but worked for me.

Vassilis
  • 2,801
  • 1
  • 20
  • 16