Archive for the ‘Processing Model’ Category
Thursday, March 17th, 2022
In the last year or so, my main task was to tackle some of the "specification technical debt" that had been accumulating over a few years, specifically at the crossroads of Fetch, performance APIs, and the HTML Standard.
Monkey patching and hand waving
When starting this work, the behaviors of some of the features relating to web performance were specified in the form of "monkey patching" — describing how another spec needs to be modified rather than modifying it; or "hand waving" — describing the expected behavior of a feature in general or vague terms.
These ways of specifying have an advantage at early stages of specification, and allow moving fast without requiring consensus prematurely.
However, as the specs mature and become widely used, these practices accumulate and come with a few costs.
Interoperability
Some details and flows may be too vaguely defined in the hand-waved description or monkey-patch. This, in turn, creates interoperability issues — one browser vendor may interpret a loosely defined phrase in some way, and another vendor in a different way.
Example: Resource Timing specified that loading images should result in a resource timing entry. However, it was not specified (or tested) whether those entries should be added before or after the image's load
event.
Bugs and security flaws
When having to spell out all the details of a previously loose spec, sometimes bugs and security/privacy flaws emerge. This has happened as part of this work more than once, for example in w3c/resource-timing#260: Resource Timing was exposing some of its properties for cross-origin resources, and by specifying it more rigorously we found that some properties that were exposed should actually be hidden.
The role of web platform tests
Of course, writing a few words into a standard doesn't fix interoperability issues or security flaws — it requires the two other pillars, tests and implementations. A big part of this debt-paying work involves adding missing coverage to web platform tests, and posting implementation bugs.
Work done so far
Work in progress
Retroactive consensus
Some of the features in question are already shipped, and vendors took liberties to interpret them in different ways. This raises a challenge of achieving retroactive consensus. Vendors might have good reasons to do things differently, but the differences make it difficult for web developers to write interoperable code. In the area of performance APIs, interoperability issues mean that performance measurements or hints might create different results across browsers.
Because the feature is already shipped, achieving consensus retroactively means that browser vendors would have to go back to their implementations and change things, which apart from the work involved could potentially make things suboptimal for some existing cases. Is interoperability worth it? That's a good question and the answer is dynamic.
A current example of this is the attempts to specify prefetch. It is a relatively old feature that is implemented differently across browsers and those two facts make it difficult to spec after the fact. Another bigger example is the discussion about navigation start time being the zero point, which is a cross-origin information leak, but where fixing it would have big implications.
What's next
The technical debt in the fetch/HTML/performance crossroads is a little smaller than before, but still far from being paid. Apart from the in-progress pull requests, some of the remaining debt is tracked here.
How you could help
Apart from the retroactive consensus challenge, an additional challenge is involving more people in the conversation. You can help by reading the issues in progress, forming opinions, finding flaws, posting what you find, proactively becoming involved. If you're not part of the conversation already and are curious, follow the links in this post, read, ask questions, and make suggestions. We'd love to hear from you!
Posted in Processing Model | Comments Off on Retro-specifying fetch/performance
Wednesday, October 16th, 2019
Focus behavior in HTML had been under-specified for the past few years, and it was also quite confusing due to a variety of subtle differences between focusing methods, UA-specific behaviors, relation to the tabindex
attribute, relations to shadow DOM, etc.
A few months ago Domenic filed a meta-bug that contains a list of things to fix so that we would have a good foundation for further additions to focus-related stuff, and to hopefully make focus in HTML make sense to browser engineers and web authors!
Types of focus
You may know that you can focus on stuff by clicking on them, tabbing, or calling focus()
on it — but did you know that things might be focusable with one method but not with others? Domenic and Mu-An made a giant interactive list of HTML elements to showcase how they react to different methods of focusing, and can be tested from various browsers to show the difference between them.
To reflect the varying behaviors of focus in various UAs in the spec, we classified focusability into three types: “programmatically focusable”, “click focusable”, and “sequentially focusable”.
If an element is programmatically focusable, it will get focused when calling the focus()
method on it or when putting an autofocus
attribute on the element. In all platforms, all elements that are either click focusable or sequentially focusable are also programmatically focusable, so “programmatically focusable” is interchangeable with “focusable”.
If an element is click focusable, the element will get focused when it’s clicked. This has the same set of elements as “programmatically focusable” in most UAs/platforms. A notable exception is Safari where non-editable form controls (checkboxes, etc.) are not click focusable by default.
If an element is sequentially focusable, the element can be focused through “tabbing” — in most UAs this means pressing Tab/Shift+Tab (and in Safari, Option+Tab too!).
Previously the spec didn’t clearly differentiate “programmatically focusable” and “sequentially focusable”, didn’t even mention “click focusable”, and used the “tabindex focus flag” concept which was slightly confusing due to its relations with the tabindex attribute. So we updated it in this PR.
tabindex
As you may know already, built-in elements like <button>
, <input>
, <a>
, etc. all have a “default” focus behavior — they are focusable (or not) by default. When the tabIndex
property getter is run on an element whose tabindex
attribute is not explicitly set already, it will return 0 sometimes and -1 other times. Previously, the spec said to return 0 if the element is “focusable” by default (which type of focusable?), and -1 otherwise. But this wasn’t implemented anywhere, because of possible differences in which elements are focusable by default in various UAs. So now the spec actually checks if the tag name is one of the tag names included in a pre-defined list. This is quite awkward, but at least it’s interoperable! (PR is here.)
Now, what is the use of tabindex
exactly? You can make an element focusable by setting its tabindex
attribute to an integer. This will set the tabindex value, and thus impact the focusability of the element. If the integer is non-negative, the element is also sequentially focusable. You can’t, however, make an element not focusable at all through this attribute — there is no value you can set the tabindex attribute to on a <button>
that will stop it from being focusable.
You can also modify the order of elements traversed with sequential navigation/tabbing — elements with a positive tabindex value will be traversed first, in ascending order (and in tree order in case of a tie), and then elements with a tabindex value of zero (or unspecified but the element is sequentially focusable by default), in tree order.
autofocus
The autofocus
content attribute is useful if you want to set focus on a form control element on page load. However, it had some issues such as:
- The
autofocus
attribute was available only for some form control elements, and unavailable for other focusable elements like <summary>
, <div contenteditable="true">
, and <span tabindex="0">
.
- The behavior with an autofocused element in a page accessed with a fragment identifier (e.g. https://example.com/#foo) was not interoperable.
- What should happen if there are multiple autofocused elements, and one of them is not focusable?
The HTML specification and the SVG specification were updated to resolve these issues by changes 1, 2, and 3. Now the autofocus
content attribute and the autofocus
IDL attribute are available on all HTML and SVG elements. The autofocus
content attribute is not processed if its document has a fragment identifier, or has a focused element. If an autofocus element is not focusable, the element is skipped and another autofocus element is handled.
Shadow DOM and delegatesFocus
All of the previously mentioned concepts were already specced in the HTML spec in some way, albeit a bit unclear, not reflecting the actual behavior, etc. Focus behavior with shadow DOM, though, had not been upstreamed from the old Shadow DOM spec at all, so this part of the effort took the most time overall. Since some parts of the Shadow DOM spec on focus were unclear and needed more explanation, we also took a look at how it’s implemented in Blink to get the exact behavior down, and discussed with other browser vendors and web developers on whether we want to keep the implemented behavior or not in some cases.
Sequential focus navigation got some significant additions (PR) with Shadow DOM. We now have a concept of “tabindex-ordered focus navigation scope”, “focus navigation scope owners”, etc. Essentially, elements are put in different focus navigation scopes, where those that belong to the same shadow tree/root, or are slotted to the same slot, are put in the same focus navigation scope. The tabindex order explained earlier now only applies to elements in the same scope, and then finally we flatten all of the scopes to get the final sequential focus navigation order.
A new concept added (PR 1, 2) by Shadow DOM is “delegates focus”, which is used when you want attempts to focus on a shadow host to not focus on the host itself, and instead delegate the focus to within the shadow tree (like <input type="date">
!). In Blink, this delegation uses the sequential focus navigation order, but we think it is a bit weird and started a discussion on how this should actually work — finally changing the delegation to respect the protocol of whatever the focusing method is originally used. (That is, use sequential order if we used tabbing, otherwise use flat-tree order and respect click focusability if needed.)
We also added the DocumentOrShadowRoot
’s activeElement
property (PR). And we updated the :focus
selector (PR), which will now match on shadow hosts if the focused element is a shadow-including inclusive descendant of it. (This is actually different than the behavior in Blink, and is a result of discussion in TPAC — where we also discussed “delegates focus”.)
The future, and outro
Now that we have a good-enough spec for focus, we have a good foundation for future additions to focus. One new relevant proposal is “custom element default focusability”. As we’ve mentioned, built-in elements have a “default” focus behavior — even though they don’t have a tabindex value explicitly, they are still focusable (or not). When you’re making custom elements, though, currently there is no way to make them focusable by default, without setting the tabindex attribute. The proposal listed various ways this might be solved, and it was talked about in TPAC with a relatively positive response from various parties. Do check it out if you’re interested!
In summary, focus was and is still quite complex to understand. But, at least now there’s a clear source of truth for it, and the browser vendors are working to make it interoperable — implementing new changes to the spec as soon as they can. There are still lots of focus-related things that need to be specced (we’ve heard people mention focusin
/focusout
, more CSS selectors, etc.), so if you’re intrigued by this post, know that you can also contribute to fix more things like these!
Having an old and mostly confusing focus spec, different types of focus, and multiple uses for tabindex
made things quite complicated when starting out. However, one of the trickiest parts of focus, in my opinion, is the fact that what is focusable/click focusable/sequentially focusable might differ in different UAs, and it might be dynamic as well! (E.g. in Safari what’s sequentially focusable changes if you hold down the Option key!) This means we need to make sure the spec is written to allow for differences, but is still, um, specific enough to make things not too ambiguous.
Overall, we’re happy with the result of this effort. We’d like to thank all the parties involved that participated in various ways: experimenting, reviewing spec PRs, implementing the changes, commenting/participating in discussions, etc. Special thanks to Kent Tamura (who wrote some parts of this post and did the autofocus
specs) and Domenic Denicola (who kickstarted this whole effort, reviewed all the PRs, and suggested + reviewed this post).
Now we can focus on other parts of HTML Standard...
Posted in Browser API, DOM, Forms, Processing Model | 2 Comments »
Wednesday, April 13th, 2016
One thing we’ve been meaning to do more of is tell our blog readers more about new features we’ve been working on across WHATWG standards. We have quite a backlog of exciting things that have happened, and I’ve been nominated to start off by telling you the story of <script type="module">
.
JavaScript modules have a long history. They were originally slated to be finalized in early 2015 (as part of the “ES2015” revision of the JavaScript specification), but as the deadline drew closer, it became clear that although the syntax was ready, the semantics of how modules load each other were still up in the air. This is a hard problem anyway, as it involves extensive integration between the JavaScript engine and its “host environment”—which could be either a web browser, or something else, like Node.js.
The compromise that was reached was to have the JavaScript specification specify the syntax of modules, but without any way to actually run them. The host environment, via a hook called HostResolveImportedModule, would be responsible for resolving module specifiers (the "x"
in import x from "x"
) into module instances, by executing the modules and fetching their dependencies. And so a year went by with JavaScript modules not being truly implementable in web browsers, as while their syntax was specified, their semantics were not yet.
In the epic whatwg/html#433 pull request, we worked on specifying these missing semantics. This involved a lot of deep changes to the script execution pipeline, to better integrate with the modern JavaScript spec. The WHATWG community had to discuss subtle issues like how cross-origin module scripts were fetched, or how/whether the async
, defer
, and charset
attributes applied. The end result can be seen in a number of places in the HTML Standard, most notably in the definition of the script
element and the scripting processing model sections. At the request of the Edge team, we also added support for worker modules, which you can see in the section on creating workers. (This soon made it over to the service workers spec as well!) To wrap things up, we included some examples: a couple for <script type="module">
, and one for module workers.
Of course, specifying a feature is not the end; it also needs to be implemented! Right now there is active implementation work happening in all four major rendering engines, which (for the open source engines) you can follow in these bugs:
And there's more work to do on the spec side, too! There's ongoing discussion of how to add more advanced dynamic module-loading APIs, from something simple like a promise-returning self.importModule
, all the way up to the experimental ideas being prototyped in the whatwg/loader repository.
We hope you find the addition of JavaScript modules to the HTML Standard as exciting as we do. And we'll be back to tell you more about other recent important changes to the world of WHATWG standards soon!
Posted in Elements, Processing Model, WHATWG | 5 Comments »
Wednesday, July 8th, 2009
The HTML5 parsing algorithm is meant to demystify HTML parsing and
make it uniform across implementations in a backwards-compatible way.
The algorithm has had “in the lab” testing, but so far it hasn’t
been tested inside a browser by a large number of people. You
can help change that now!
A while ago, an implementation of the HTML5 parsing algorithm
landed on mozilla-central
preffed off. Anyone who is testing Firefox nightly builds can now opt
to turn on the HTML5 parser and test it.
How to Participate?
First, this isn’t release-quality software. Testing the HTML5
parser carries all the same risks as testing a nightly build in
general, and then some. It may crash, it may corrupt your Firefox
profile, etc. If you aren’t comfortable with taking the risks
associated with running nighly builds, you shouldn’t participate.
If you are still comfortable with testing, download a trunk
nightly
build, run it, navigate to about:config
and flip the
preference named html5.enable
to true
. This
makes Gecko use the HTML5 parser when loading pages into the content
area and when setting innerHTML
. The HTML5 parser is not
used for HTML embedded in feeds, Netscape bookmark import, View
Source, etc., yet.
The html5.enable
preference doesn’t require a
restart to take effect. It takes effect the next time you load a
page.
What to Test?
The main thing is getting the HTML5 parser exposed to a wide range
of real Web content that people browse. This may turn up crashes or
compatibility problems.
So the way to help is to use nightly builds with the HTML5 parser
for browsing as usual. If you see no difference, things are going
well! If you see a page misbehaving—or, worse, crashing—with the
HTML5 parser turned on but not with it turned off, please report the
problem.
Reporting Bugs
Please file bugs in the
“Core” product under “HTML: Parser” component with “[HTML5]
” at the start of the summary.
Known Problems
First and foremost, please refer to the list
of known bugs.
However, I’d like to highlight a particular issue: Support for
comments ending with --!>
is in the spec, but the
patch
hasn’t landed, yet. Support for similar endings of
pseudo-comment escapes within script
element content is
not in
the spec yet. The practical effect is that the rest of the page
may end up being swallowed up inside a comment or a script
element.
Another issue is that the new parser doesn’t yet inhibit
document.write()
in places where it shouldn’t be
allowed per spec but where the old parser allowed it.
Is There Anything New?
So what’s fun if success is that you notice no change? There are
important technical things under the hood—like TCP packet
boundaries not affecting the parse result and there never being
unnotified nodes in the tree when the event loop spins—but you
aren’t supposed to notice.
However, there is a major new visible feature, too. With the HTML5
parser, you can use SVG and MathML in text/html
pages.
This means that you can:
And yes, you can even put SVG inside MathML <annotation-xml>
or MathML inside <foreignObject>
. The mixing
you’ve seen in XML is now supported in HTML, too.
If you aren’t concerned with taking the steps to make things
degrade nicely in browsers that don’t support SVG and MathML in
HTML, you can simply copy and paste XML output from your favorite SVG
or MathML editor into your HTML source as long as the editor doesn’t
use namespace prefixes for elements and uses the prefix xlink
for XLink attributes.
If you don’t use the XML empty element syntax and you put you
SVG text nodes in CDATA sections, the page will degrade gracefully in
older HTML browser so that the image simply disappears but the rest
of the page is intact. You can even put a fallback bitmap as <img>
inside <desc>
. Unfortunately, there isn’t a
similar technique for MathML, though if you want to develop one, I
suggest experimenting with the <annotation>
as
your <desc>
-like container.
There are known issues with matching camelCase names with
Selectors
or getElementByTagName
,
though.
Posted in Browsers, Processing Model, Syntax | 8 Comments »
Monday, May 25th, 2009
Version 1.2.1 of the Validator.nu HTML Parser is now available. It fixes an incompatibility with the DOM implementation of the latest Xerces.
Posted in DOM, Processing Model, Syntax | Comments Off on Validator.nu HTML Parser 1.2.1