whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
8.03k stars 2.62k forks source link

Is it possible to allow `<a>` elements to nest within each other in the future? #8541

Open LIXiangChen opened 1 year ago

LIXiangChen commented 1 year ago

It's a very common layout / requirement, as shown in these pictures: the entire area of each item is clickable, and there are other links within the area. This layout can be seen on many websites, currently, it takes some tricks to achieve. So, why not just allow <a> elements to nest within each other in the standard specification?

pic

microsoft

apple

brennanyoung commented 1 year ago

For accessibility reasons at least, this is a bad idea. A link has distinct semantics. It navigates. If a link contains links, and their destination differs, which one should have higher precedence? What is obvious to you is not obvious to me.

Yes, people put links inside links routinely, and may never notice their error if they don't validate their code.

Luckily user agents (i.e. browsers) now handle invalid markup in a consistent way, so nested links always behave the same way, but actually permitting nested links in the spec would require some hard choices, possibly new attributes, and whatever is chosen will most likely cause a lot of unexpected side effects on sites where those validation errors are currently handled 'safely' and consistently.

Have you inspected the DOM that Microsoft and Apple have used in the examples you posted? Do they nest the links or do something else? I just hopped over to Apple's site and found that the the two subordinate links are not nested inside the "primary" link in the DOM. They used some clever CSS to make it seem that way to sighted, pointing-device users.

So, you can make a clickable "card" which has other clickable elements visually placed on top with CSS, but your DOM should keep the larger and smaller links separate. Something like:

<article id="mycard" aria-labelledby="mycardmainlinktitle">
<a href="thewholethinglink.html" id="mycardmainlinktitle">the title of the card</a>
<img src="cardThumbnail.png" alt="imgdesc here" />
<p>the brief</p>
<a href="subordinateURL1.html">Foo</a>
<a href="subordinateURL2.html">Bar</a>
</article>

and then style it such that the first link extends the full width and height of its parent, with the subordinate links placed on top with something like position:relative;. <a> is an inline element by default, which means that width and height are ignored, so you'll need to change the display value to something that permits setting width and height, like block or inline-block. This would achieve the exact layout you are looking for, while keeping the links themselves distinct, accessible and valid. Apple's implementation is a bit more robust, but otherwise quite similar.

My example also repurposes the link title text as the heading for the article, but an explicit heading tag would also be fine, and in many cases would be better. I chose this because I assume that the "primary" link text would also be the most obvious accessible name for the card as a whole, at least in the Microsoft and Apple examples you included. The image could be a background image if you prefer, but if the image is more than decorative, make sure there is a text alternative.

Suggest closing this issue as wont fix, because the use case can be handled with HTML as-is

LIXiangChen commented 1 year ago

@brennanyoung It seems that there is some misunderstanding, I didn't say that the code of these websites is nested <a> in another <a>, I know they used other ways to achieve this visual effect, such as placing an <a> that fills the parent element at the bottom level, or use JS, these are what I called "tricks" in the original post.

What I mean is, this kind of visual effect (layout) is a very common requirement, but because the current standard does not support nesting of <a> elements, so people can only achieve it through these "tricks".

So the question is, are these "tricks" really better than allowing nesting of <a> elements?

Here are two examples. The first is what the code might look like if nested <a> elements were allowed by the standard:

<a href="product.html">
    <img src="thumb.png">
    <p>The brief</p>
    <a href="buy.html">Buy</a>
    <a href="product.html">Learn more</a>
</a>

The second is the code commonly used by websites to achieve the same visual effect:

(You know, people wrote this, not that they like it. If the first example can be supported by UAs, they definitely prefer that).

<section>                                     // position: relative;
    <a href="product.html"></a>               // position: absolute;
    <div>                                     // position: relative;
        <img src="thumb.png">
        <p>The brief</p>
        <a href="buy.html">Buy</a>
        <a href="product.html">Learn more</a>
    </div>
</section>

In terms of readability, whether it is human or software, the first one is obviously better than the second one. As for the accessibility you mentioned, I'm sure the second one is also not likely to be better than the first one (not to mention that it needs to use absolute positioning, which is a disaster in many cases).

If the HTML standard isn't going to serve some broad requirements, where is it headed?

brennanyoung commented 1 year ago

Whether it's obviously better is a matter of opinion, and not an opinion that I share.

I would agree that your first snippet of markup has a more obvious mapping to the exact layout you are going for, but layout is a presentation matter, and the second snippet of markup is semantically clearer to me, so this really is a CSS concern.

But ok, let's say nested <a> is allowed. Let's say you're blind, partially sighted, dyslexic or similar, you've hit the product link with your AT (screen reader or braille device). The expected behavior is to be informed of the semantic role, which in this case would be "link" or something like it. You might also get a state announcement like "visited/unvisited". Additionally, you can expect the name of the thing, typically a concatenation of the text nodes inside, (there are many other influences on accessible name calculation, which I will skip for now).

So, which text nodes inside the primary link should be announced as the accessible name for the link? All? Some? Should the subordinate links get announced, or suppressed? What if they too have links inside?

How would the nesting be represented in the AT "links" view, or the output of document.links if at all?

Should we assume that nesting expresses some kind of semantic relationship between the primary and secondary links? If so, what (exactly) is that relationship? Can that relationship be modified, extended or disabled by authors? How would those modifications be expressed clearly?

In the most general, abstract case, what would <a> inside <a> actually mean? That the inner link goes to a section of the resource indicated by the outer one? That would make sense, but it would be very fragile. Maybe the inner links could be #fragment indicators of the URI indicated by the outer one. Or maybe not. Maybe they're just links. Potentially with an arbitrarily complex tree of links inside.

Why would it be important to specify the <a> inside <a> semantic relationship? Well, let's say you've visited all the subordinate links but not the primary one. What would the "visited" state of the primary link be? Something like a "mixed" checkbox value perhaps? Visited, unvisited and... some visited. The questions will come thick and fast. These are the ones that occur to me here and now.

Then, let's say you steer your screen reader to the (inner) product link and let's assume we have an extra paragraph in there, after the product link. You steer your screen reader further to that second paragraph, leaving the product link. Some ATs might announce "Leaving Link" (but which one?) And then, should the subsequent paragraph be announced as a paragraph? Would you remember that you were actually still inside the primary link? It gets messy very quickly.

There are a lot of unanswered questions that complicate a situation where simplicity is called for. Agreeing on a new but unambiguous spec for something so fundamental to HTML as <a> is likely to take many years. (It's unrealistic to expect otherwise.) Not to say this is impossible, but frankly there are more pressing priorities.

I fear that simply allowing nested <a> elements would create far more problems than it solves. Even if all the questions above could be answered, I would expect an extra burden on memory which is only supported by visual cues which are not available to all users. Consider that reducing cognitive load is usually an important usability consideration, and especially so for AT users. Complex hierarchies are notoriously difficult to maintain, cognitively speaking.

But there may well be other ways that this kind of GUI could be made easier to style, while sticking to the important markup fundamentals which are well-supported and predictable. I've never been a confident user of position:relative, which always seems rather fragile. I used to teach CSS and HTML to novices, and position:relative was always an uphill struggle, even with the best students. It always feels like a hack, scarcely better than using tables for layout. This (I would argue) is where the dog is buried.

The marvellous work on flex and grid gives me hope that some elegant and clear CSS modules might one day be cooked up to handle the layering/offset cases that position:relative "handles" in such a counter-intuitive way.

LIXiangChen commented 1 year ago

@brennanyoung I've got your point. Changing the specification of <a> will definitely create a lot of issues to solve, I think this is probably because <a> was originally only used for inline text, and did not consider such a complicated layout.

I don't quite agree with the accessibility part though. You see, on each group in this layout, there must be at least one link within it that has the same URL as the whole-area-link, which in the above example is the "Learn more". So we can prevent the screen reader in some way to get the whole-area-link (parent <a>) - may be done through some HTML attribute - just like the parent <a> is not a link but a <div>, then the screen reader will only get the "Buy" and "Learn more" links, and there will be no trouble.

And under the implementations of the current standard, the accessibility is not perfect. For sites like the second example code, the whole-area-link is often without any text or hints, which is not helpful for screen reader.

There is also a similar layout but different coding style, which does not use an <a> that fills the entire parent, but sets multiple elements as links to maximize the clickable area. As shown, there are four <a> used here, all pointing to the same URL, which may confuse users of screen reader even more (and search engines' bot).

2

https://fonts.adobe.com/fonts

Speaking of SEO, in the first sample code, each group is a small environment, which has independent title, brief, picture, all of which are wrapped by a parent <a>, the semantics are pretty clear for search engines (if standardized). But the second sample code obviously does not have such a role.

If changing the specification of <a> is not feasible, maybe introducing a new element or a new attribute can satisfy the requirement? I don't know how this work carried out, but anyway, I just wanted to let you guys know that this kind of requirement exists, maybe it's worth considering when revising the standard.

excitedbox commented 1 year ago

I agree with the sentiment, but not with the solution. Any time devs have to use hacks or tricks to make something work, it means there is a limitation or missing functionality or even flaw in the system. We have all seen ul, li, ol, etc. used by frameworks to fill in for missing features. There are entire frameworks like AlpineJS based around exploiting hacks to accomplish their goals.

Nesting is not a good solution, and I would rather see a different solution. Maybe adding a link/destination attribute to tags instead of having to use an for all links. If you could use:

<div dest="url1"><img dest="url2"><h1 dest="url3">title</h1><p dest="url4">some text</p></div>

Or something of the sort, it would be clear what the link is without nesting. tags should only be used for text that is in the middle of a line of text which requires a link, and therefore shouldn't have nested tags.

So to summarize, I think we need to allow more tags to have a link attribute assigned instead of using more tags. There should also be more attention paid to places where tricks and workarounds have become commonplace, and find better standardized solutions.

LIXiangChen commented 1 year ago

@excitedbox Thank you for understanding this need. A link attribute that works on most elements would be great. I also agree that, should discover those widely used tricks/hacks and improve/standardized them.