resize font to fit in a div (on one line)

Viewed 130040

There have been similar questions asked, but the solutions do mesh with what I'm trying to do. Basically, I have an article with a title (<h1>). I don't want to control the length of the title, but I also don't want the title to appear on multiple lines. Is there a way with css or jQuery to resize text based on the width of a <div> tag?

I know what I would do with pseudocode if I could detect the overlap of the text to the edge of the <div>:

var fontize = $("#title").css("font-size");
var i = /*remove unit from integer*/
while( /*text overlaps div*/ ){
    $("#title").css("font-size", --i+"pt");
}

If there's a CSS attribute I can set that would be even nicer, but I can't seem to find one (overflow wouldn't work in this situation).

15 Answers

I had a similar issue, which made me write my own plugin for this. Have a look at jquery-quickfit (which is quite similar to Robert Koritnik's solution, which I really like).

In order to prevent the headline to span multiple lines, just add a css style of:

white-space:nowrap;

to the element.

After including jquery and quickfit in the header. You can trigger quickfit with:

$('h1').quickfit();

It meassures and calculates a size invariant meassure for each letter of the text to fit and uses this to calculate the next best font-size which fits the text into the container.

The calculations are cached, which makes it very fast when dealing having to fit multiple text or having to fit a text multiple times, like e.g., on window resize (there is almost no performance penalty on resize).

Demo for a similar situation as yours

Further documentation, examples and source code are on the project page.

You can accomplish this in css under certain circumstances, but it is brittle and context-dependent.

css font-sizes can accept relative sizes to the screen. IF the containing element for your header is sized relative to the screen size, you can accomplish this by simply setting font-size: 3vw or an appropriate size so that the text fits on one-line. If the screen is resized, the text will follow suit. Note that the width will depend on the exact text contents, and if you add characters to text that used to fit on a single line, you may need to adjust your font-size.

See this fiddle: https://jsfiddle.net/mguk8v27/

You can do this with JS but it's actually pretty complicated to craft a generic solution. The way line heights affect element height is not straightforward, and there are a lot of other pitfalls to consider. I made an NPM package, @tvanc/lineclamp, for doing exactly what you want. I honestly don't know of a more robust solution.

It's relatively fast because it narrows down the possible font sizes more efficiently than just iterating over each font size one by one to find the largest working font size. Instead it starts at the max, then tries halfway between that and the lower bound. So with a max of 100 and a min of 1, it would try 100. Then 50. Then 75. And so on. (Binary search)

This lets you (relatively) performantly get a font-size adjusted to two decimal places to very precisely fit within the prescribed number of lines.

For the effect you want the code might look like this

import LineClamp from "@tvanc/lineclamp"
const element = document.getElementById("#long-marketing-title")

// "soft clamp" means resize the text to fit. "hard clamp" means trim the text to fit
const clamp = new LineClamp(element, { useSoftClamp: true })

clamp
  .apply() // Apply the clamp
  .watch() // Automatically reclamp when the layout changes
Related