fit-to-width.js is a tiny JavaScript library for fitting text into text containers in a typographically sensitive way, using standard CSS. Its user-facing function, ftw_fit(), takes a set of elements, and automatically adjusts a variable font’s width (wdth
) axis, as well as adjustments of letter-spacing and word-spacing, attempting to fill each element with the text that it contains. By default, it adjusts the width axis via CSS font-variation-settings
, then resorts to a horizontal scale using CSS transform
. In general, a sequence of operations can be specified, each performed to the best of its ability before proceeding to the next operation if an optimal result has not yet been reached.
For efficiency it uses a binary search algorithm to converge quickly on a good result. Typically it performs only 8 or so tests to arrive at an ideal solution for the width axis setting, even though there are thousands of possible values.
There is one user-facing function, ftw_fit().
To try out the library:
-
Create a page with
<div>
elements containing text you want to fit to width. -
Set these
<div>
elements in a variable font with a Width axis. -
Style these
<div>
elements to have a specific width, e.g.width: 600px
. -
Include the
fit-to-width.js
script at the top of your web page like this:
<script src="fit-to-width.js"></script>
-
Assign the class “ftw” to the HTML elements you want to process.
-
When your page and fonts are loaded, call
ftw_fit(".ftw")
. -
or try this CodePen
In the table, the first column shows various possible typographic adjustments we can try in order to adjust width. The CSS column shows how we adjust this with CSS. The third column shows the method name we use in fit-to-width.js. The fourth column shows whether or not this adjustment is implemented in fit-to-width.js.
Adjustment | CSS | Method | Implemented |
---|---|---|---|
tracking | letter-spacing |
letter-spacing | ✓ |
font width | font-stretch |
font-stretch | ✓ |
font width | font-variation-settings: 'wdth' <nnn> |
font-variation-settings:wdth | ✓ |
font size | font-size |
||
word spacing | word-spacing |
word-spacing | ✓ |
enable ligatures | font-feature-settings: 'dlig' <0/1>, 'liga' <0/1> |
ligatures | ~ |
horizontal scale | transform:scale(<scale-factor>,1) ) |
transform | ✓ |
By default ftw_fit() uses the following methods in this order:
font-variation-settings:wdth
transform
Note: Chrome has not implemented CSS font-stretch
for variable fonts, so by default we use the font-variation-settings:wdth
method instead. This low-level property does not inherit other axis settings, and so other axes revert to default if you are not careful. See below for how to use the axes
property to set other axes.
This method was first presented in Resize textbox with variable fonts (aka Fit-to-Width) on the Axis-Praxis blog, November 2016.
ftw_fit (<elements>, [<operations>], [<targetWidth>] ])
The required first parameter, elements, specifies the DOM elements we should process. We can specify these elements in several ways:
-
A string, e.g. “.ftw”, is used as a selector to obtain all elements matching
document.querySelectorAll(<string>)
. The example will get all elements of class “ftw”. This is similar to element selection in jQuery. -
A single element, e.g. the return value from
document.getElementById("myId")
. -
Multiple elements, e.g. the return value from
document.getElementsByClassName("myClass")
. Return values from jQuery’s$("...")
selection mechanism will also work.
The optional operations
parameter is used to customize the sequence of operations of ftw_fit().
Default is ["font-variation-settings:wdth", "transform"]
Each operation has a method name, which is one of:
font-stretch
font-variation-settings:wdth
word-spacing
letter-spacing
transform
ligatures
Each of these can be specified simply, just using a string. To use font-stretch, then letter-spacing, the operations
parameter is ["font-stretch", "letter-spacing"]
. Each method can also be specified with various other parameters: min, max, maxDiff, maxIterations, axes.
This ftw_fit() method ideally would use CSS font-stretch
, which is specified as the standard method of adjusting width in variable fonts. Browsers implementing the property inherit just the wdth
axis setting, so weight applied using other CSS will also be respected.
There are two significant disadvantages in using CSS font-stretch now, however:
-
Although CSS
font-stretch
is working in Safari it is not supported in Chrome (2018-06), so cross-platform code must use CSSfont-variation-settings
. Thefont-variation-settings:wdth
method is implemented in ftw_fit() for this purpose. -
CSS font-stretch uses % units, where 100% is normal width, 50% is a notional half-width, and 200% is a notional double width font. According to the OpenType specification, these values are supposed to come directly from
wdth
axis coordinates. Unfortunately, many existing variable fonts usewdth
axis values which do not make sense as percentages; the range 0 to 1000 is common, and negative values are also seen. Such non-compliant values are not handled well by browsers. Default min and max for ftw_fit() are 0.00001 and 32767.99998. Note that values offont-stretch
<= 0 are invalid.
This ftw_fit() method uses the low-level CSS font-variation-settings
property. It works on all browser platforms where variable fonts are supported. Care must be taken because it overrides axis settings made elsewhere, for example an initial or inherited wght
axis setting. See the axes
method property for a way to specify other axes. Default min and max are -32768 and 32767.99998 (the extremes of the Fixed 16.16 representation).
This ftw_fit() method uses CSS word-spacing
to make the text fit the container. Default min and max are -0.2 and 20.
This ftw_fit() method uses CSS letter-spacing
to make the text fit the container. Default min and max are -0.05 and 1.
This ftw_fit() method uses CSS transform:scale(n,1)
, where n
is the scale by which the element must be stretched (>1) or squashed (<1) to fit the container. There are no other properties.
Not ready for use. This method always applies font-variation-settings:'dlig' 1,'liga' 1
. The idea is that we should turn on ligatures if we hope for a narrower setting.
min
is the minimum value to be used in the binary search. If you don’t wantwdth
axis values below a certain value, specify it here. If you know the minimum width axis value, specify it here to save a few iterations.max
is the maximum value to be used in the binary search. If you don’t wantwdth
axis values above a certain value, specify it here. If you know the maximum width axis value, specify it here to save a few iterations.maxDiff
is the largest difference, measured in px units, from the targetWidth that we accept before proceeding to the next operation. Default is 1.maxIterations
is the number of tests we perform before giving up. Default is 50.axes
(used only in thefont-variation-settings:wdth
method) specifies axis locations other thanwdth
. These get appended to thefont-variation-settings
CSS. For example, if you want to run ftw_fit() while keepingwght
at 788 andopsz
at 36, then specifyaxes:"'wght' 788, 'opsz' 36"
. You might usegetComputedStyle()
to find current weight, in order to use an inherited or initial weight of the element.
["font-variation-settings:wdth", "transform"]
(default, so you can omit it if you want this)[{method:"font-stretch",min: 0.61998, max: 1.3}]
(setting min and max to the min and max of the font’s weight axis helps it converge more quickly)[{method:"font-variation-settings:wdth", axes:"'wght' 280, 'opsz' 22"}]
(keepwght
axis at 280 andopsz
axis at 22 while adjusting thewdth
axis)
The optional targetWidth
parameter is used to set a pixel width for the element. Default is to use the current width of the elements.
Be careful not to apply ftw_fit()
on elements of auto
width.
Returns an object which has properties:
elapsedTime
: the total time in msoperations
: the operations used to adjust elements
<style>
.ftw {
font-family: Gimlet-Roman;
font-size: 72px;
width: 400px;
}
</style>
<div class="ftw">
Here is
</div>
<div class="ftw">
Here is more
</div>
<div class="ftw">
Here is yet more text
</div>
<script>
ftw_fit(".ftw");
</script>
<style>
.myftwclass {
width: 600px;
}
</style>
<div class="myftwclass">
Here is a more advanced example
</div>
<script>
ftw_fit(".myftwclass", [{method:"font-variation-settings:wdth", min: 0.6, max: 600},"letter-spacing","transform"]);
</script>
This will first attempt to fit using font-variation-settings, then try letter-spacing, then finally (if those still have not fit the text) transform.
Performance is good since it uses binary search on font-stretch
and letter-spacing
. Iterations are limited to 50, in case the algorithm fails to converge. The alrogithm typically converges in 7 to 9 iterations.
-
Sometimes the font is not ready in time for a container’s
clientWidth
to be measured, even when document.fonts.ready has resolved to true. Reloading the page or adding a 2 ms timeout seems to solve the problem, but a solution is needed. This appears to be a bug since the CSS spec states “The ready promise is only fulfilled after layout operations complete” -
Currently (2018-06) only Safari supports
font-stretch
. You must use thefont-variation-settings:wdth
method for Chrome. -
Unfortunately, in many browsers letter-spacing is added to glyphs even when a glyph is last on a line. This is typographically incorrect and the CSS specification is clear: “Letter-spacing must not be applied at the beginning or at the end of a line”.
-
Glyph sidebearings mean that lines of large font-size or large font-width do not align precisely with lines of small font-size or large font-width. It could be a good idea to add customization for this, but it would probably have to be tuned for each font.
-
On macOS, system variable fonts (Skia and SF) when specified by
font-family
, do not properly clamp axis values to their minimum and maximum. Awdth
axis setting of -32768 is valid in CSS, but it reverts to default width in Skia. To use system Skia and SF, be sure to specify axis extrema, as inftw_fit(".ftw", [{method: "font-variation-settings:wdth", min: 0.61998, max: 1.3}])
.
-
FitText, a jQuery plugin by Paravel that adjusts CSS font-size to make text fit a given width.
-
FitText.js, a tiny JavaScript library by Jeremy Keith that does the same thing as FitText but without the jQuery dependency.
-
Fitty by Bram Stein.
-
typeset by Bram Stein, the TeX line breaking algorithm in JavaScript. This scales each line horizontally by a different amount to reduce whitespace caused by justification.
-
Font-To-Width is a small JavaScript library by Nick Sherman and Chris Lewis that takes advantage of large type families to fit pieces of text snugly within their containers.
-
Fitting Text to a Container is a list of various text-fitting tricks, compiled by CSS Tricks’ Chris Coyier.