textfill.js to remove jQuery (because I dislike jQuery).
In this article, I will be examining the following libraries…
- https://github.com/DanielHoffmann/jquery-bigtext/ as
- https://github.com/BrOrlandi/big-text.js as
- https://github.com/jquery-textfill/jquery-textfill as
- https://github.com/Jetroid/textfill.js as
- https://github.com/STRML/textFit as
- https://github.com/fazouane-marouane/fancy-textfill as
…for the following categories…
- Dependencies & Installation Issues
- Resize Correctness
- Content & Functionality
- Download Size
- Project Health
… and for each category, I will rate the libraries as ‘Exceptional’, ‘Pass’, or ‘Fail’. Or you can skip the exploration and skip straight to the conclusion.
Dependencies & Installation Issues
The names of these projects are pretty clear about their dependencies -
fancy-textfill-jquery all require jQuery to function. The rest require no dependencies. That said,
fancy-textfill-jquery has the sister script,
fancy-textfill.js, a version without jQuery. This gives
All studied packages are available to be used in browser or on NPM, with the exception of
textFit, which do not appear to be available on NPM. At the time of writing, trying to use
jquery-textfill in the browser can have problems due to poor management of exporting to module managers. This has been acknowledged (with a workaround) for
jquery-textfill doesn’t have problems when trying to include it alone, but it isn’t perfectly behaved and errors out if you use the
big-text.js workaround fix before including the
After installing all the projects, the first thing I was interested in was if these libraries produced the same font size values, and if not, how are those sizes different? Do some prefer to give integer font sizes, or do some give floating point sizes?. These libraries all do similar things, just with different implementations, so I was curious how that affected sizing. And if they were not consistent, I wanted to ask which values were ‘correct’?
I tested all libraries with two different scenarios: One where the limiting factor is the width (300x200 pixel container, contents ‘test’), and another where height was the limiting factor (300x100 pixel container, contents ‘test’). I found that they all produced similar results, but that there was inconsistency between them. I also think it’s important to note that all libraries tested gave integer font sizes, which was a little disappointing.
For the width experiment, I found that both
big-text.js produced font sizes of 124px,
textFit gave 125px, and both versions of
fancy-textfill gave 122px.
I think it is debatable about which of these font size values is correct, though I think 122px is completely wrong in all metrics, as there is a underflow of 7.12px, visible even to the eye! For this reason I think I will grade both versions of
fancy-textfill as ‘Fail’. 124px makes the span 2.34px smaller than the container, and 125px makes the inner span 0.05px bigger than the container (overflowing the container slighty). The perfect font-size that would fit with no underflow or overflow is somewhere between 124.98px and 124.99px.
Because 125px overflows the container, it is debatably ‘wrong’ - the goal of these libraries could be described as ‘make the text as big as possible without overflowing the container’. That said, the 125px is much closer to the perfect font-size. Therefore, the question of which value is the ‘correct value’ depends on if you think these libraries should give the ‘font size closest to the perfect value’ or ‘the biggest font size that fits inside with zero overflow’. I’ll let you decide.
Demonstration of the underflow of 122px and 124px (represented in yellow), and the overflow of the 125px (represented in red, but not visible because it is too small). Static Demo Here.
For the height experiment,
big-text.js gave a font size of 80px, whilst the rest gave
89px. The explanation for this is that the two BigText libaries have a
fontSizeFactor setting that defaults to
0.8 - this setting is intended to provide additional space for letters like ‘g’ and ‘Á’ which overflow the line. Changing that setting to
0.89 makes BigText take the same sizes as the other libraries, so I can only see this as a point in BigText’s favour, so I will grade it ‘Exceptional’ - and grade the remaining three as ‘Pass’.
P.S. I was curious if the
fontSizeFactor was preventing the BigText libraries from reaching 125px in the width experiment, so I set
0.89 again and retested, but the change had no effect. This makes sense, because width is the limiting factor, not height, and we don’t need extra vertical space for accentuated characters in that scenario.
Content & Functionality
In this section, I’d like to look at how the different libraries react to different content, and some of the functionality they have.
If we have a long string on content in a roughly square textbox, it probably doesn’t make sense for the library to resize our text to be a single line within the box; We probably want our library to insert linebreaks and resize the text too.
This is the default behaviour for most of the libraries, but
big-text.js do not support this, they only support manual linebreaks.
Sometimes, we may want to insert manual linebreaks (
<br />) into our text so that it appears on multiple lines.
This is supported by all libraries, with the exception of
fancy-textfill.js, which overflow.
(Note that only
fancy-textfill.js perform incorrectly - the difference between the rest is just based on their default settings.)
The opposite of Automatic Linebreaks - sometimes we may want to ensure that our text always remains on a single line.
All libraries support this! For
big-text.js, this is the only choice and nothing needs to be done. For
Sometimes, we might want to add multiple different elements inside our resizing element, and give them relative font-sizes. Or even include text-like content, like font-awesome icons.
This is supported by all libraries except for
fancy-textfill, where it causes an overflow.
I have written automated scripts to run a few simple performance tests on the libraries. You can try it to see if my results match with your system.
An argument could be made that average performance of execution with these optimisations is useful information, as we may repeatedly call these libraries in some circumstances (like when resizing the browser window), however I think the most important scenario to consider is that posed by experiments 1 and 2, as the font-size change for the first call is likely to be greater than any feature rescale in most scenarios (especially if the element is prominent on the page, and resize happens as part of page load). I’d also like to point out that in a realistic scenario, the performance increase from those Engine / Browser / OS optimisations that are seen in the final four experiments will be lessened as other code and processes will be executed between resizes, so the probability of a cache miss increases as more of our data is evicted, etc.
The experiments are as follows:
- Performance for single execution for a single word.
- Performance for singe execution for a multiline string.
- Average of performance for 100 executions of a single word, with randomisation.
- Average of performance for 100 executions of a single word, without randomisation.
- Average of performance for 100 executions of a multiline string, with randomisation.
- Average of performance for 100 executions of a multiline string, without randomisation.
Google Chrome, v69
Mozilla Firefox, v66
I obtained these results by rebooting my laptop before starting each test, to ensure that any caches were clear. I’m running this on a fairly old laptop so your results are likely faster, too.
It should be fairly obvious that the jQuery libraries suffer a big loss here, especially on Google Chrome, though
fancy-textfill-jquery only really had problems with the first execution on Chrome.
textFit also surprisingly has bad performance, despite not using jQuery.
textfill.js all have fairly good results.
textfill.js are both very consistently good, whilst
fancy-textfill.js can have slower ‘first run’ times but then sees huge benefits from caching/pipelining on repeat resizings.
Again, it’s worth noting that the design of this experiment was not perfect, and that because of browser / processor optimisations, the execution of one script may be affecting the performance of another.
big-text.js shares some common code with
jquery-bigtext, as does
fancy-textfill-jquery are nearly identical. The fact that the jQuery versions were run before the plain JS versions could effect the results here. As could the fact that
fancy-textfill.js is executed last, etc.
A goal I had for this experiment was create something that readers could execute in their own browser (for reproducibility / proof of undoctored and ubiased numbers), which limited the scope for experimental purity that could be achieved if I wasn’t limited to a single browser window. Perhaps in the future I will come back to this and create a bash script that spawns independent headless browser windows for each resize or something.
In the interests of creating a repeatable / refreshable “single first resize performance test”, I created the following pages, which indicates that the ‘real’ first run speeds might be higher than those from my table of results:
For this test, if a repository provides the minified file, that one is used, else it has been minified using JSCompress.
The libraries which depend on jQuery have been considered both with and without jQuery - some projects will already include jQuery as it is very prevalent, so incur no extra cost, whilst other projects would have to include jQuery to use the library.
|Size (library only)||Size (including jQuery 3.4.1)||Total Size|
Project Health is an important factor to consider when selecting a library to use - libraries which are not maintained could have unresolved bugs or security vulnerabilities (though that’s very unlikely for a text resizing library!), and won’t respond to changes in the browser/language ecosystem (important when your library heavily depends on browser APIs like these text resizing libraries!).
jquery-bigtext: Dead, formally replaced by
big-text.js: Alive, but with un-merged pull requests. No commits since March 2017.
jquery-textfill: Alive, but with un-merged pull requests. No commits since February 2018.
textfill.js: Alive; released this month.
textFit: Unclear. The maintainer says that the project is “done”, despite other users reporting bugs and un-merged pull requests. No commits since May 2016.
fancy-textfill-jquery: Alive, no issues nor pull requests. Recent commits within the last year.
To be able to more easily compare these libraries, let’s consider
★ to equal
✓ to equal
1 point, and
✗ to equal
0 points. Here’s a tabulation of the grades I gave, and what the resultant score become with that scoring system.
|Dependencies & Installation Issues||Resize Correctness||Content & Functionality||Performance||Download Size||Project Health||Total||Points|
|jquery-bigtext||✓||★||✗||✗||✗||✗||1x★, 1x✓, 4x✗||3|
|big-text.js||✗||★||✗||★||★||✓||3x★, 1x✓, 2x✗||7|
|jquery-textfill||✗||✓||✓||✗||✗||✓||1x★, 3x✓, 2x✗||5|
|textfill.js||✓||✓||✓||✓||★||★||2x★, 4x✓, 0x✗||8|
|textFit||✓||✓||✓||✗||★||✗||1x★, 3x✓, 2x✗||5|
|fancy-textfill-jquery||★||✗||✗||✓||✗||★||2x★, 1x✓, 3x✗||5|
|fancy-textfill.js||★||✗||✗||★||★||★||3x★, 1x✓, 2x✗||8|
The scores agree with my feelings, so I can safely say that I can recommend
textfill.js is the better library to choose if you really care about the pixel-perfectedness of the resize, or if you want to do complicated things with the text content of your inner element (which can just include a manually inserted line break (
fancy-textfill.js is a better choice if performance is your utmost concern, as it becomes significantly faster when resizing repeatedly.
If you can look past the lack of automatic newline inserting,
big-text.js also had a unique advantage in that it gives special compensation for accents and characters that underhang the line (and is really fast too!).