Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fractional balancing; simplification #3

Open
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

jamiemccarthy
Copy link

Summary

These are the changes that Vox Media has used for text-balancer. This version is approximately what's been running on vox.com for some time now.

We'd like to thank you for open-sourcing this library, and submit these changes back upstream for your consideration.

The main change is that there's a new argument to apply only a fraction of the maximum change. On vox.com, we determine how much each headline can be squeezed, and then only squeeze it half that much. We find this to be a visually appealing tradeoff. This new argument is optional and backwards-compatible.

Fractional squeezing

Here is a crude animation to show the effect of different fractional values. 0.00 is the same as not enabling text-balancer at all; 1.00 is the same as text-balancer without this PR applied.

vox-balanced-headlines

Other changes

This PR also proposes a performance improvement and simplification: the removal of textElementIsMultipleLines. It's a good idea, but in my testing, running this function took about the same time as simply running squeezeContainer, so removing it should make things run slightly faster. For details, see the commit message on 6f2b7a7.

As an additional performance enhancement, this tweaks the beginning and end of the recursive function to not run quite as long. Squeezing beyond 50% is never necessary because in the only case where it's possible (single line) there is no visual difference. So we start at 50% instead of 0%. And halting the loop once the range is down to 5 pixels saves another couple of iterations at a small cost in accuracy.

Finally, this PR adds a check before trying to squeeze an element, to make sure that its text is left-aligned. The algorithm could be changed to work with center- and right-aligned divs, but as written, its results would look pretty ugly on them. For now, the algorithm should only be applied to those aligned left. It's a simple getComputedStyle check, which I think is pretty compatible, though this 2010 comment suggests there's a workaround for an MSIE incompatibility. I don't know how well this works with IE. (Hat tip to @bceskavich for help with this.)

Manipulating the DOM to determine element height is a clever idea, but
it's a premature optimization:

(1) it's additional complexity,

(2) the 10 pixel fudge factor leaves its behavior on small text
questionable,

(3) this implementation doesn't work when a div's html starts with tags
instead of text, because the first split() word ends up nonvisible so
firstWord.offsetHeight is zero, and

(4) it's faster to simply try squeezing and see what happens. In my
rudimentary testing, headlineIsMultipleLines ran in 2.66ms, but simply
running squeezeContainer completed in 2.73ms, so it's making things
slower. My numbers may not be super accurate, but they would have to be
very far off for my conclusion to be backwards.
Function renamed to "squeezeContainerLeft" in anticipation of adding
compatibility with centered and right-aligned elements at a later time.
The +1's were gradually shifting the range to the right with each binary
subdivision. No real harm but also not correct.
@mbeswetherick
Copy link
Contributor

@jamiemccarthy hey. this looks really cool! Thanks for working on this. We're gonna look into this sucker but I really like your idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants