I've been wondering for some time now whether CSS should have a formal semantics to help implementations, and for posteriority (eg. not leaving behind a mess of specs making it infeasible to implement browsers from scratch/specs for generations to come).
For an example of what I'm after, see [1], which is using attribute grammars/logic grammars for a small fragment of CSS box layout, and is one of the precious few attempts of a formal semantics for CSS.
There are a bunch more interesting ones that folks often haven't heard of, like ex (relative to the height of an x) or ch (relative to the width of a 0)
These kind of complexities is why, as much as I would love it to, the web as it is cannot compete with the performance of native apps.
What is in native a simple number (maybe two) is dozens of pages of specifications - which result in insane amount of work to deduce the value of a simple variable.
Layout and rendering is probably even worse in this regard.
On the contrary, when native apps support styling (e.g. through React Native), it's invariably very slow compared to all the optimizations that have gone into browsers. They generally can't compete with the decades of optimization that have gone into the Web platform.
Sure, cascading of certain properties can be complex. But the compressed in-memory style representation, style sharing optimizations, parallel restyling, etc. more than make up for this. Each one of these is at least a 2x speedup on its own. Every single implementation of native app styling that I've seen hasn't even begun to implement any of these optimizations.
I don't know if you're aware of this, but you're making a different comparison than GP:
GP: a simple way to set font size, say, in pixels vs CSS styling
You: native support for CSS styling vs browser CSS styling
Of course browsers are faster with the latter, due to the reasons you mentioned. But they cannot hope to be able to optimise as much and as easily as the former approach (in principle that is, I cannot say anything about whether or not they actually do).
So I'd say you're both right by virtue of not debating the same thing.
PS: When are the fast SVGs demo'd in Servo a long time ago coming to Firefox? :)
To expand on this, CSS totally supports the basic performance of styling native apps provided you use features with the ergonomics of styling native apps (i.e. inline styles).
It's when one wants to be able to better declare what the styles will be that you have performance implications, and as pcwalton says these are worse for native styling frameworks since they don't have much optimization work put into them.
(Also, wrt the original comment, all this font-size handling isn't particularly a perf issue. There are other minor font perf issues, but this isn't one)
The full HTML and CSS spec is large, complicated, and full of corner cases, and thus a lot harder to optimise. The point GP is making is that a simpler framework is much easier to maintain and optimise because it has much less to worry about (again, in principle).
I think the key difference is this part of your earlier reply:
> when native apps support styling
.. when the implicit statement Illnyar was comparing CSS to a framework that doesn't support styling, or at least much simpler styling.
I'm not hating on browsers, HTML or CSS here - they're amazing technologies. But these are two different points being made.
Can you explain, specifically, how the code path for setting a specific numeric font size via inline style is slower than, say, setting the same attribute on an NSMutableAttributedString? (I know of one way in which it is slower, but it has nothing to do with anything discussed in this article and is fixable via work-in-progress specs.)
With native apps, you can either use the raw style modification methods or a comparatively slow third-party style system of your choosing. With the Web, you can either use inline styles (akin to the raw style modification) or a slower, but still relatively fast style system. I don't see any advantage for native apps here.
Why do you keep arguing something that I'm not even disagreeing with? And why are you not even engaging with my earlier statement that you're arguing a different thing altogether. If I'm wrong about that, then just explain to me why instead of trying to convince me of something I'm already agreeing with.
I mean, you're the expert working on Servo here, so you're better equipped to answer the other claim that you're ignoring: is a simpler spec than HTML and CSS be easier to optimise, yes or no?
You are wrong about that, and he did explain. He is talking about the same thing. That was the purpose of his comment about inline styles. (If it was unclear I can answer any more specific questions you have)
What native frameworks let you do is assign inline styling to mostly leaf nodes, plus some extremely generic overall theming functionality.
This is both possible and fast in CSS. This is not where CSS is complicated.
Comparing apples to apples, they're simple specs.
You're saying "But they cannot hope to be able to optimise as much and as easily as the former approach (in principle that is, I cannot say anything about whether or not they actually do)." -- this is incorrect. Setting inline style on leaf nodes is very fast and not a performance issue especially if you solely rely on inline style. The main reason I can think it would be a perf issue is that in CSS this will have to re-parse (whereas in native you can set these things without string ops), but that is fixable (typed CSSOM is probably going to happen). But aside from that, it's a simple computation followed by setting something on a struct. Not really a problem. You can't really optimize it further, aside from the typed CSSOM thing I mentioned (which has nothing to do with complexity).
CSS gets complicated when it attempts provides more power than these native frameworks, however the associated perf issues crop up when you try to use these features. If you use CSS restricted to the feature set of basic native frameworks, these complexities will not affect you much.
pcwalton made an additional point on top of that that if you want to compare apples to apples here, you get frameworks with that level of power (e.g. React Native) on the other side, which don't have as many optimizations.
That was my reaction to the article as well. The amount of work being done here for Servo (and which has been done in other browsers) is hugely impressive, but this problem feels a little artificial — we could have build the same web that we have today with half these options and not even have lost much in terms of ergonomics.
I wonder if some kind of "Expedient CSS" might be possible as a way forward. Site developers could opt themselves in with a comment tag and promise to use only a subset of CSS features and only simple cascades (maybe none) in return for better rendering performance. A little like what's been done for JavaScript with asm.js.
If you are writing a Web application, you can always just use the one number and skip the complexity. A lot of work is poured into browser engines to make them render the simple cases as quickly as possible, while allowing for rich styling grammar for use by people writing documents.
I'm always amazed by how performant complex CSS can be. Really complicated pages render in a few hundred ms, even though so much complicated computation is happening under the hood. Browser developers are true wizards.
> A lot of the web platform has hidden complexities like this, and it's always fun to encounter more of them.
"fun" is an odd choice of words here; (╯°□°)╯︵ ┻━┻ seems more apt.
also, what's the future of MathML? what's the point of continuing to support a standard that Chrome has decided not to implement? it means 50% of web users won't see MathML, so web authors will never bother writing it.
Well, from my point of view it's less work to implement it than it is to argue removal from Gecko (which could happen, but it would take a while). Stylo must have Gecko parity, whether it's by adding more features to stylo or unshipping features from Gecko. We've done the latter in some cases for nonstandard stuff folks no longer use.
I don't really know what the future of MathML is. Some folks seem to still use it, though less often on web pages.
Thanks. Also, does Servo incur any overhead from Stylo having to implement legacy or Gecko-parity features (eg -moz prefixes, etc)? Or does Servo not use Stylo directly? Same question for other Quantum components.
Stylo is the project name for taking Servo's CSS system and hooking it up to Gecko.
We conditionally compile out unsupported stuff. There is some complexity in shared code introduced but very little of it is anything but a complication of the abstractions (not an actual behavior-level change which can have a perf impact).
So for example the weird cascading behavior exists when you compile pure servo (because that's a core functionality of font-size, which servo does implement), but servo doesn't have to deal with the mathml stuff or text-zoom. Servo has some no-op code for text-zoom that lets shared code be written cleaner, but it compiles out.
Please, please, please, don't take MathML away from us. Even though we are few in number, we want to be able to put mathematics on the Web. I'm sad Chrome and IE chose not to implement support for MathML.
It's baffling just how complex CSS became over the years. I wonder, is the extra work involved for all the relative tracking something to consider for website performance?
It's baffling just how complex CSS became over the years
Well, except for calc(), these cases seems to come all from CSS 1.
Interestingly, the font-size section mentioned how a font may be sized in a VR environment. I remember VRML, but didn't know there were plans to apply CSS to VR back then!
Even before CSS 1... Initially CSS tried to emulate what was available in "presentational HTML" available at the time. The absolute and relative font sizes were introduced by the FONT-element and BASEFONT-element, and the BIG and SMALL elements.
Re: perf tips for authors: I don't think so, the tracking is pretty central to fundamental features of fonts (i.e. the default font size)
I guess using absolute font sizes as close to the top of the DOM tree as possible will help a tiny bit. But it also means that folks with custom default font size settings wont have the settings get respected.
I think this has a pretty minor perf impact overall as well.
I wrote a free responsive website editor (named "RocketCake"), and was surprised how complex CSS and these HTML rules are to implement, although I only needed not all of them. When I told my fellow programmers, they didn't believe me. I'll send them a link to this. Nice article!
> What this effectively means is that you need to keep track of two separate computed font size values. There’s one value that is used to actually determine the font size used for the text, and one value that is used whenever the style system needs to know the font-size (e.g. to compute an em unit.)
As someone who actually sets minimum font size, and to a healthy 14px at that... Does anyone know the actual reason behind this? It would probably go a long way to helping layouts not break all the time with my minimum font.
I don't, and I'm pretty baffled that it does affect em units for text-zoom (despite the two having very similar purposes).
Perhaps the difference is that with min font sizes everything gets clamped, which can make two objects of different sizes get the same size if they used em units (if em units affect things). Which is both good and bad, depending on the intent. (Whereas with text-zoom everything is nicely scaled so it's less of a problem).
text-zoom isn't a web feature, it's only a feature Firefox/Gecko has.
Servo doesn't implement it either, only Stylo (the confluence of Servo's style system and Gecko). In Servo mode all the code for text-zoom becomes a no-op.
Yes, SVG text will not zoom if you text zoom. SVG is fundamentally a absolutely-position image, not a laid out document. The concept of text-only zoom makes sense for documents, but not for images, where the position of the text is far more important.
(This won't affect `<img>` embedded SVG anyway, however it is possible to embed SVG directly within HTML via `<svg>`, which is where this matters.)
Ah, thanks for the clarification. I missed that part. That makes absolute sense. :)
> The concept of text-only zoom makes sense for documents, but not for images, where the position of the text is far more important.
> SVG is fundamentally a absolutely-position image, not a laid out document.
svt text is a fundament of svg that is incompatible with absolute-positioning. The OS's font stack might render px-sized mono-spaced font text at width x, or it might render it at x+7.
> “monospace fonts tend to be wider, so the default font size (medium) is scaled so that they have similar widths”
> “the base size depends on the font family and the language … Default system fonts are often really ugly for non-Latin- using scripts.”
‘often’, ‘tend to be’: I am worried. I think it’s a really bad idea to deflect default behavior based on such assumptions, certainly when the deviations are a blind process triggered by proxies (like language tags and some vaguely statistical rules-of-thumb for dealing with generic font family names). That is: without even looking at the actual design and metrics of the actual font involved.¹
What happens if the monospaced font in case has a normal x-height and/or an advance-width equal to that of its serif counterpart? What if the CJK and Devanagari fonts have characters drawn already ‘big on the body’?² Then such hard-coded default moonshot-fixes which try to cater for the lowest common denominator will make things needlessly hard to debug and force the designer still to ad-hoc size-adjust font per font, but now also trying to fix the browser’s ‘fixes’. (Too bad: any `normalize.css` wont help…³)
And yet, all of the needed data is available in the font file. There’s even a dedicated CSS property for dealing with fonts’ varying metrics: `font-size-adjust`.⁴ Not that browser makers care to implement⁵, but since the OP’s post concerns Firefox (which does support `font-size-adjust`, but the article does not discuss it) I wonder: is it a matter of performance that retrieving the actual font metadata and metrics is left out of the equation? Surely, the fact that local font files, base64 data-URI embedded or externally hosted ones can be used, makes implementation all but trivial…
At Textus.io⁶ we’re going great lengths to solve typographic issues such as these. Point in case: for each font we read out the `xHeight` value, then calculate the actual font-size relative to the font’s UPM (unitsPerEm), so we have consistent apparent font-sizes, c.q. aspect ratios.
I think it all boils down to a separation of concerns: proportion and interrelated sizes (ascender, caps, descender, x heights, stem width, etc.) are up to the discretion of the font designer, overall aspect size is the business of the typesetter (css stylesheet author), and the browser ought always draw consistently, regardless of generic font family name, language and/or Unicode code range.
> I am worried ... really bad idea ... will make things needlessly hard to debug
It has worked this way since the days of Netscape Navigator[1], though, so it's not a change or a new idea. It's just keeping things the way they've always been. (Nowadays, in Firefox, the corresponding settings are under Preferences -> Content -> Fonts & Colors -> Advanced.)
That Netscape screenshot only shows users have always been able to specify their own font preferences for three generic font families (serif, sans-serif, mono), along with a respective font-size. I’m not objecting to that: in fact, it’s a Good Thing that users are able to take control.
But taking control also means dealing with inconsistencies myself. If I were so bold as to set Impact as my default serif font, then I would also set a considerably smaller font-size to make up for the huge x-height. The thing is: if it would bother me, I, as an end-user, could do so, thanks to the browser’s interface exposing to me the needed controls.
It’s a whole different thing when browsers would start changing default behavior based on ‘common’ properties in ‘most’ fonts, without inspecting the real features of the actual fonts they render. Different, because if it would bother me, as a web developer, I couldn’t do anything about it, because the browser, while deviating from standard defaults, would not offer me the required controls, i.e. would render my CSS rules differently based on opinionated variables I cannot know.
That screenshot is from Netscape 6—a Gecko-based Netscape release without “Navigator” in the name. The mechanism mostly survives in Gecko today except for the Latin unification (previously split to Western, Central European, etc.).
> And yet, all of the needed data is available in the font file. There’s even a dedicated CSS property for dealing with fonts’ varying metrics: `font-size-adjust`
These are web features from before CSS existed.
The whole font sizing thing comes from how `<font size=x>` used to behave. When CSS came it only complicated this. font-size-adjust is pretty new.
And once the web starts behaving a certain way it's kind of hard to "fix".
(Also, just to mention, all of this complexity would still have to exist even if the monospace thing wasn't a problem, to support user configured font sizes)
> I wonder: is it a matter of performance that retrieving the actual font metadata and metrics is left out of the equation?
I think there is a nontrivial perf impact, yes. We've had to do some locking to make font metrics (for ex and ch) work in Stylo, for example, and while we've optimized it it still makes us lose out on parallelism a bit.
I believe I’ve come across allegations that the metrics encoded in the font (xHeight and unitsPerEm, by the sound of it) are fairly hit-and-miss. Any comments on that?
Sure. Badly produced fonts (those you can find on the cheap), tend to have faulty metrics: i.e. the designer did not change the default ones of the font design app (Glyphs, FontLab, FontForge, &c.) they are using so as to match the actual outlines of the glyphs they drew.
E.g. the font’s metrics tell: xHeight=500 and UPM=1024, so we may assume the aspect ratio is 0.48. But then we look at the outlines and see the designer drew the upper most top node of the x at the 600 coordinate on the Y-axis. So, in fact, the actual aspect ratio is 0.59, and thus the metrics are useless indeed…
But again: should we then _assume_ to be always dealing with badly produced fonts? Or could we just expect font metrics to tell the truth? For if we won’t, then we’re totally lost, and will make things even worse for professionally produced fonts, which do honor the specs.
(As for non-Latin scripts: it’s indeed up to the discretion of the font designer how to draw the height of, say, CJK characters or the size of the teeth in Arabic, but always _relative to the xHeight_ as stated in the font’s metadata, so the font behaves consistent with the specs.)
At Textus.io, we therefor rely on the font’s built-in metrics metadata, for now. But since we are obsessed with fool-proof typography, we are indeed considering to look at the actual coordinates of the outlines instead…
I do not expect browsers to do deal with inconsistent font metrics, though. As a developer, I instead want to rely on browsers behaving consistent, being assured they won’t ‘fix’ things I already fixed, for then the outcome will be totally unpredictable. That’s why we have standards and specs after all, haven’t we?
> But again: should we then _assume_ to be always dealing with badly produced fonts?
A major theme of the web platform is to assume the worst, because the worst is actually often not uncommon.
Another major theme is backwards compatibility. You've mentioned a fix that would break all previous sites relying on this behavior. Fixes that require a clean-slate redo of the web just won't work.
Note that these are mostly user configurable settings (although it's only the default font size that can be configured, not the other absolute and relative values)
I've been wondering for some time now whether CSS should have a formal semantics to help implementations, and for posteriority (eg. not leaving behind a mess of specs making it infeasible to implement browsers from scratch/specs for generations to come).
For an example of what I'm after, see [1], which is using attribute grammars/logic grammars for a small fragment of CSS box layout, and is one of the precious few attempts of a formal semantics for CSS.
[1]: https://lmeyerov.github.io/projects/pbrowser/pubfiles/extend...