This thread shows that it's a widely required feature:
https://twitter.com/sindresorhus/status/979363460411609091
Example of a workaround: Open https://tobireif.com/ and (eg using dev tools responsive mode) resize the page down to 250px width while watching the text "Welcome".
This requires performing layout in a loop, which we generally have avoided. Requiring a round-trip through JS is valuable because authors are more likely to realize it has a large perf cost
In the JS at https://tobireif.com/ I perform two passes - that's plenty for a good-enough result, and it doesn't impact perf in any noticeable way (the text-fitting is only done once in addition to the first main run). That could be a great option for browser implementers as well, and it shows that supporting such a CSS feature is very feasible.
If this were a feature, I think it'd be best if it was a CSS function. (similar to calc
or minmax
)
Something like font-size: fit(8px, 48px);
where 8px
is the minimum font-size and 48px
is the maximum font-size.
I think using a function, other than being useful for minimum and maximum sizes, relays the gravity of using the feature since surely it'll have _some_ performance issues in extreme cases.
I'd love to see this in CSS!
Great suggestions!
A lower limit and an upper limit both make sense.
Instead of font-size: fit(8px, 48px)
it might be better to name it eg font-size: fit-width(8px, 48px)
.
Changing font-stretch, especially using variable fonts, is another way to fit text into parent. Or compression during justification . So if there is a css property that instructs layout engine to fit, it should allow different methods and so likely be separate from font-size.
And this kind of functionality may not only be on line operation. It may be useful for more advanced functionality, like optimal paragraph layout, line clamping, or simple ellipsis.
Changing font-stretch, especially using variable fonts, is another way to fit text into parent. Or compression during justification . So if there is a css property that instructs layout engine to fit, it should allow different methods and so likely be separate from font-size.
True! (also eg letter-spacing)
And this kind of functionality may not only be on line operation. It may be useful for more advanced functionality, like optimal paragraph layout, line clamping, or simple ellipsis.
Let's start simple 😀 If we're asking for too much we might not get anything. The basic simple use case of fitting one line of text (eg a heading) into its responsive parent is so common that a solution for that would cover a lot (and more could get added/specd later).
Yes it's feasible to implement the functionality using JS, and yes there are workarounds, and I think there even is a lib, but it sure would be very handy to be able to simply write one single line of CSS instead.
My implementation in the source of https://tobireif.com/ is more than 50 lines of JS - if people could instead write a single line of CSS then that would save a lot of typing.
By the way @litherum : If the implementation is smart enough, perhaps one pass would be sufficient → no loop / double-pass.
Perhaps the syntax could look like this:
fit-width: font-size(20px, 100px);
fit-width: letter-spacing(-0.1em, 1.5em);
md5-438b4904c42da8e95edaa8e2ab7d8952
fit-width: any-text-width-affecting-property(min, max);
The sizing/fitting should honour the (potential) padding of the container.
Using a small number of passes is unlikely to work in the general case, because if we get it wrong, the text will overflow its container and wrap, which would be catastrophic. Any generalized implementation would have to iterate until the algorithm converges. Such an algorithm would be a great way to make a browser hang.
If you do want to provide this widely requested feature - perhaps you could try it out 😀If your algorithm is smart regarding calculating the estimated target value, it will not need many passes, and it might need only one or two passes. For all and any cases.
Such an algorithm would be a great way to make a browser hang.
When you try it out, and limit the maximum number of passes to 2 == no browser hang at all, and if your algo can estimate the correct value pretty well, then there's a good chance that the result will be sufficiently good. You'd have to try it out though.
If you do not want to provide that feature no matter what, and thus do not want to create a quick "beta" implementation for seeing what's feasible, then there's not much reason to continue the discussion. In that case please close the ticket.
I did create a quick implementation using JS and found that it works sufficiently well using only two passes. The code is at https://tobireif.com/ -> source -> "var topLevelHeadings". It's just a quick (but good enough for that case) implementation - I'm 100% sure that you could come up with a much better (and generally applicable) algo 😀
Here's another JS implementation:
http://fittextjs.com/
https://github.com/davatron5000/FitText.js
None of the above implementations causes any noticeable performance issue. And: The latter is a general lib.
As for your own site, the type inside your headers is simple enough that you'd have performance gains in just using vw inside a breakpoint, reducing 50 lines of runtime js to possible 4 lines of css.
I'd prefer CSS that's based on the parent element width, not on the viewport width. (Because generally the element width might change without the viewport changing.)
The feature is a (very popular) wish - the specification of that feature (including all relevant details) would be up to the CSS WG.
(Oh, and if that feature would be only feasible to spec/implement for a defined set of simple types of cases, I'm sure that simple feature would be widely appreciated as well 😀 The syntax still could be fit-width: any-text-width-affecting-property(min-value, max-value)
, I think.)
If and when there will be an ew unit ("element width", as in EQCSS), and if and when there will be clamp() , then the functionality in this feature wish ticket here could be expressed sufficiently succinct, eg:
font-size: clamp(30ew, 20px, 80px);
Where are you getting 30
in the 30ew
? Are you matching that to the length of the string in the element? Or is 1ew
just 1% of the elements width, meaning a 100px
wide element would set its font-size to 30px
?
Here's the definition of ew
, eh
, emin
, and emax
from jsincss-element-units:
switch(unit) {
case 'ew':
return tag.offsetWidth / 100 * number + 'px'
case 'eh':
return tag.offsetHeight / 100 * number + 'px'
case 'emin':
return Math.min(tag.offsetWidth, tag.offsetHeight) / 100 * number + 'px'
case 'emax':
return Math.max(tag.offsetWidth, tag.offsetHeight) / 100 * number + 'px'
}
I was thinking of isolating just these tests into their own package (and maybe the element query tests from jsincss-element-query) so other plugin builders could more easily re-use the same tests in their plugins.
Yeah, it'd not be the real deal where the implementation figures out the value required for making the text fit its container. It'd just be a pragmatic way to get the feature with just one line of CSS.
(And yes, 30ew means 30% of the element width. The exact number is just an example, it could be eg 45.5ew .)
(I was replying to @jonjohnjohnson , just so there's no misunderstanding @tomhodgins 😀)
Ideally we could state in CSS "always fit this word/line of text inside its parent (by auto-adjusting the property "foo" eg font-size or letter-spacing), no matter what font is used".
Most helpful comment
If this were a feature, I think it'd be best if it was a CSS function. (similar to
calc
orminmax
)Something like
font-size: fit(8px, 48px);
where8px
is the minimum font-size and48px
is the maximum font-size.I think using a function, other than being useful for minimum and maximum sizes, relays the gravity of using the feature since surely it'll have _some_ performance issues in extreme cases.
I'd love to see this in CSS!