See the suggestion by @muan at https://github.com/whatwg/html/pull/3499#issuecomment-544745912:
<h1>GitHub</h1> <h2>jsdom/jsdom</h2> <div> <article headinglevelstart="3"> <h1>jsdom</h1> <h2>Basic usage</h2> <h2>Customizing jsdom</h2> <h3>Simple options</h3> ... </article> </div>
cc @whatwg/a11y
Reading through the other thread, I'd prefer this approach of an opt in instead of just overwriting heading levels.
The only question I have is what is the expectation for something like:
<h1>GitHub</h1>
<h2>jsdom/jsdom</h2>
<div>
<article headinglevelstart="5">
<h1>jsdom</h1>
<h2>Basic usage</h2>
<h2>Customizing jsdom</h2>
<h3>Simple options</h3>
...
</article>
</div>
Expose h5, h6, h7 instead? h7 obviously being the outlier here.
Quickly looking at some of the different exposed levels from the platform mappings / trees exposed by browsers, a level 7 _should_ work, but JAWS and NVDA range from getting a little tripped up at times, to JAWS with Firefox just not exposing the levels beyond 6 at all, instead reverting to level 2 or the default level of the heading element used.
Again, it seems the screen readers would need to be updated to account for heading levels beyond 6. Unfortunately, that also means that anyone using an older screen reader, even with a newer browser, may well not get optimal output.
This would solve all my problems with hN tags: user/plugin generated content in templates and template partial that use hN tags. The template including any of the above can just tell it where to start.
If an author can identify what value needs to be set in headinglevelstart, then it stands to reason the author can increment that in their own code for each descendant heading instead of offloading that burden to the user agent.
Pseudo-code with structure borrowed from above:
<h1>GitHub</h1>
<h2>jsdom/jsdom</h2>
<div>
<article>
<h{1 + $headinglevelstart}>jsdom</h{1 + $headinglevelstart}>
<h{2 + $headinglevelstart}>Basic usage</h{2 + $headinglevelstart}>
<h{3 + $headinglevelstart}>Customizing jsdom</h{3 + $headinglevelstart}>
<h{3 + $headinglevelstart}>Simple options</h{3 + $headinglevelstart}>
...
</article>
</div>
In other words, the headinglevelstart attribute on its own does not seem to offer anything a developer cannot do now.
For example, in this Codepen example from 2016 I use data-level to do seemingly exactly what this attribute proposes (though I would prefer a server-side solution over client-side or in the UA).
Though neither approach prevents an author from choosing a value that renders as <h7> or above, completely nullifying the benefit for many screen reader users (see @scottaohara's comment above).
@Aardrian wrote:
If an author can identify what value needs to be set in headinglevelstart, then it stands to reason the author can increment that in their own code for each descendant heading instead of offloading that burden to the user agent.>
The priority of constituencies puts users and authors before implementors, and this seems to be one of the times when that prioritisation is needed. Authors struggle with heading levels as it is, and this has an impact on users. If we ask authors to take on handling more, I'm afraid things will only get harder for authors and worse for users.
If the UA does the work, it has other advantages too:
On this last note, would it be possible to extend the capability of the start attribute, instead of minting a new headinglevelstart attribute?
Would it be possible to extend the capability of the start attribute
I like how short the "start" attribute is but if it only contains a number in it, it isn't as clear what it is doing as it is on ordered lists.
If you have <article start="h3"> though, that is pretty clear what the intention is.
If an author can identify what value needs to be set in
headinglevelstart, then it stands to reason the author can increment that in their own code for each descendant heading instead of offloading that burden to the user agent.
In fairness, from a development point of view, using headinglevelstart would not require potential reprocessing of content. Assuming in the example above the actual <article> content comes from somewhere else (stored like that in a database, coming from a third-party via an API call), the author can simply define the template
<h1>GitHub</h1>
<h2>jsdom/jsdom</h2>
<div>
<article headinglevelstart="3">
{INSERT THE STUFF HERE}
</article>
</div>
without having to server-side re-munge the content to reprocess all heading levels appropriately. Otherwise, particularly for third-party stuff, they'd have to always proxy content and do, in naive terms, do a find/replace of any heading elements (either native <hx> ones or ARIA-based headings and their aria-level="x") to bump their number.
@LJWatson, to your point about the Priority of Constituencies, I feel that pushing the logic to the UA creates a black box that will make it easier for developers to ignore, resulting in a generally worse experience for users. And I also want a better experience for users (over authors).
@patrickhlauke, that is a good point (and also made by @LJWatson). And yes, the client-side processing is potentially more burden for users than broken / opaque headings.
Perhaps something similar to the code/approach I posted above could be the basis for a polyfill (though it still won't help current SRs).
This mostly addresses what I was interested in in this comment a while ago - though, it still seems to me we could probably just figure that out with simply a marker attribute rather than an explicit level, and that would be better for authors. Still, this very much seems like progress and worth doing if that's not plausible.
@aardrian
If an author can identify what value needs to be set in headinglevelstart, then it stands to reason the author can increment that in their own code for each descendant heading instead of offloading that burden to the user agent.
That is simple for simple cases but it gets more complicated quickly.
The approach you outlined works fine within a single template file whose content is all under the control of the author (but, in that limited context, so does just using h-tags, which are also easier to read).
Here is where it hurts:
When a template includes another template the counter needs to be both threaded through the template and used by the child templates as well. Many templating languages support this, though not all make it super pleasant, but it's not of much use unless the entire project agrees upon the convention. That's easy on greenfield projects but legacy code requires more work or when there's a "parent theme" and you end up needing to modify all of its templates even if you're making no other changes. On hosted platforms the choice of templating language is usually fixed so whether this can be done at all can be out of one's hands.
Sometimes html comes from a blackbox plugin. This is no one's favorite but it happens distressingly often. The generated html can be parsed and its headers shifted by walking the AST allowing it to be re-rendered correctly, but this is fairly complicated and slow so it's unlikely to happen and probably needs to be fixed up on the client side with some javascript.
If the platform had the concept of the heading level baked into its core and took care of threading it through templates and plugins, all of which agreed to use this feature, this wouldn't be as much of an effort. To my knowledge, there is no such platform or at least it is not among the most commonly used. Even if all the popular ones added it today it would take quite a while for it to see widespread use and for legacy code bases to get on board even if their platform now supported it.
That still leaves user-generated content. If it's stored in some non-html source or some IR that can make it easy to generate starting at whatever level is necessary (assuming it's an option: it usually is not). Often it's stored in html that was created by some kind of WYSIWYG editor. If every instance of the user generated content starts at, say, h2, you could configure the header to not allow creating h1 tags. If this is a legacy project or a project going under redesign that means going through the database and parsing all the entries and shifting the headings. Not pleasant but it's a one time thing. If you're trying to use the content where the starting header is different in different contexts you're back to fixing it up on the fly.
(I haven't looked into it too deeply yet, but it seems like wordpress's gutenberg would have many of these problems simultaneously).
None of this is insurmountable but it's enough to surmount that it doesn't seem to ever get surmounted.
Having an attribute may mean occasionally having to add a div to hang it off of but the outlining solutions could also mean having to insert an extraneous tag and generally one of greater semantic weight and its less explicit that those tags are necessary to maintain the correct document outline. An attribute would also make it easier to fix up a legacy codebase with just a few simple edits.
Another thing I like about having an attribute is that it could possibly have extra modes in the future like "none" to mean "ignore any headings in this subtree" (useful for teasers whose teased body should not be contributing to the document outline) or something to mean "this came from an editor apply a slower algorithm to shift the headings so that are no gaps like h3 to h6 with no intervening h5".
@jimmyfrasche, I feel bad that my response is so brief as to seem dismissive, but I understand your points and agree with many. After my last comment I am not pushing my model anymore as I made my case (and nobody seems down with it). But I still think a polyfill may be helpful.
Most helpful comment
@Aardrian wrote:
The priority of constituencies puts users and authors before implementors, and this seems to be one of the times when that prioritisation is needed. Authors struggle with heading levels as it is, and this has an impact on users. If we ask authors to take on handling more, I'm afraid things will only get harder for authors and worse for users.
If the UA does the work, it has other advantages too:
On this last note, would it be possible to extend the capability of the
startattribute, instead of minting a newheadinglevelstartattribute?