Justif: Knuth-Plass justification and microtypography for the web

63 points by lyall 11 hours ago on lobsters | 17 comments

swannodette | 6 hours ago

p0llard | 3 hours ago

The post is not about vibecoding, so does it really need the vibecoding tag?

I’m not very interested in reading stories about people using LLMs, so I would like to be able to filter them out, but in practice the tag seems to be slapped on posts where there is even a suspicion [1] coding assistants may have been used, even if that has nothing to do with the substance of the post.

[1] of course in this case it’s incontrovertible, but I have seen it on posts about projects just because the project accepts contributors using coding assistants.

atmosx | 3 hours ago

Lobster-1: "Hey, they developed a drug that cures cancer!"

Lobster-2: "Yeah… but they used AlphaFold, CRISPR and ...(drumroll)... Fable."

Lobster-1: "OMG! that’s unacceptable. For the sake of human kind lets just throw everything away and go back to spending 40 years manually drawing proteins with colored pencils on a board!!!!!"

vbernat | 9 hours ago

The result looks really nice. You go even further than TeX (unless you use the microtype package). Such typesetting should be done directly by the browser. Some browsers implements text-wrap: pretty but it's limited to a few lines (6?).

chrismorgan | 9 hours ago

text-wrap: pretty spec makes it clear it’s purely a hint, with no defined behaviour:

Specifies the UA should bias for better layout over speed, and is expected to consider multiple lines when making break decisions. Otherwise equivalent to ‘auto’.

The user agent may among other things attempt to avoid excessively short last lines, similarly to ‘avoid-orphans’, but it should also improve the layout in additional ways. The precise set of improvements is user agent dependent, and may include things such as: reducing the variation in length between lines; avoiding typographic rivers; prioritizing different classes of soft wrap opportunities, hyphenation opportunities, or justification opportunities; avoiding hyphenation on too many consecutive lines…

As I recall it, it only made it into the spec once different browsers said they’d do different things with it, in order to avoid tying it down too much. (Remember how Web SQL was killed off because the fact that implementers were always going to use SQLite leaked through? Similar deal.)

I live in hope that text-wrap: pretty will one day be noop, because they apply it all to text-wrap: auto. Also that https://bugzilla.mozilla.org/show_bug.cgi?id=630181 will eventually happen.

(Such hints are not a new thing. will-change is an optimisation hint for last-generation browsers; by the time they specified it, Firefox mostly didn’t need it any more, and some next-generation engines can’t benefit from it at all, I think. I wish they’d stuck with the transformZ(0) hack, which made it clear it was a hack… as it was, will-change was promptly abused something awful.)

matklad | 6 hours ago

There’s a real implementation of pretty in Safari these days, but it is buggy in combination with justify:

https://matklad.github.io/2026/02/14/justifying-text-wrap-pretty.html

[OP] lyall | 6 hours ago

Yes! I remember seeing your post on here a few months ago. It probably contributed to me thinking about this issue and deciding to take a swing at it.

It's maddening that the combination of pretty and justify doesn't work nicely in WebKit. Justified text is precisely when we need the best text wrapping algorithm! But I'm just happy the issue is getting worked on in the browsers, if slowly.

[OP] lyall | 9 hours ago

Agreed. In an ideal world this library shouldn't have to exist.

You can play around with the text-wrap: pretty toggle in the demo to see how your browser handles it. I recommend trying some different browsers, because it's surprising how differently Blink vs WebKit vs Gecko handle it.

chrismorgan | 9 hours ago

I have long felt that hanging punctuation is overdone. If you notice it, it’s too much: and it’s almost always noticeable on in particular, where it should hang less than half as much. Actually, I like the fact that a start-of-paragraph essentially serves as a little text-indent.

The subtler effect of “protrusion” turned on but “hang punctuation” off feels tolerable (though I’d still prefer it off in most cases).

Too much of these sorts of things depends on the specific font. In my chosen serif (Equity), an “f,” at end of line looks wrong with this adjustment, because kerning has already tucked the comma under the f, so now the top of the f is protruding out of the line. Related, I wonder what it’d be like if serif fonts put the tail/spur beyond the character advance so that it would hang; that feels a more worthy thing to hang than most punctuation.

On tracking: letter-spacing is risky because it interacts poorly with ligation. Either ligation happens first and you end up with “T h i s   i s   fi n e!”, or non-zero letter-spacing disables ligation and you get the f colliding with the dot of the i. (You’ll generally get the latter, but it depends a little on script and font and explicitly-enabled OpenType features, which can easily be done accidentally.)

[OP] lyall | 9 hours ago

I personally like the look of hanging punctuation, but it's a configurable option of course :)

Re: tracking, you're right that ligatures make it a bit fraught. But I think the default limits of ±3% make it look acceptable. You can check the end of the first paragraph of the "Type Specimen" sample for a sequence that contains the fl, fi, and ffi ligatures. Naturally the 3% limit is configurable as well!

gerikson | 4 hours ago

Hanging punctuation might explain something I’ve often observed and gotten mad about: on some Swedish sites, an initial right double quote mark is sometimes left alone at the end of the preceding line.

Swedish uses right double quote marks only - both in the beginning and end of the quoted text.

For a long time I’ve wondered if there’s a way to let a browser know that a specific text is in another language/locale and it would automatically handle quote marks , decimals etc.

heftig | an hour ago

This is what the lang attribute is for. It at least affects automatic hyphenation.

I’ll be a spoilsport and point out that the examples use artificially narrow line widths to make the improvement more obvious. The usual advice is that a line of text should be about as wide as two lowercase alphabets, or ~60 characters.

gerikson | 4 hours ago

Weren’t old newspaper columns about the length shown in the example? Not that that is something to emulate nowadays.

gcupc | 3 hours ago

You can widen the columns to see how they compare with realistic text column widths. It's much less dramatic, but still obvious. At 36em lines, the stats still look very good compared to the default.

brian | 3 hours ago

This is tagged vibecoding because the author in a comment on another site mentioned the used an LLM to author this? And the link isn’t about LLMs or Vibecoding?

Seems like the tag is just a witch hunt at this point or that’s the impression that I get. I could be wrong.

bitshift | 49 minutes ago

A more charitable interpretation is that the tag serves two different roles, and that stories frequently get tagged as a trigger warning (which causes confusion and seems overly aggressive because the more obvious use of the tag is to say, this story is about vibecoding).

Having a tag with two different purposes is not my ideal world. But in general, I'm in favor of trigger warnings and I support folks exercising their freedom to filter out stuff they don't want to see—the tag is confusing but at least tags don't penalize the author.