-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Suggestion: adding an option to render a more accessible anchor link #82
Comments
Edit (2021-03-01): TLDREdit 2: you know you fucked up your TLDR when the TLDR is that long.
My proposition so far: Offer an Make the header anchor Solved:
Hey Nicolas! Thanks a lot, this is awesome! I really want this plugin to be accessible by default. As you pointed out this would be a breaking change, but I'm comfortable changing the DOM structure on a major version. There's a couple points that I want to discuss before going on with this change; Rendering without CSSThis "requires" some CSS for an "acceptable" result. To illustrate this, I'll quote David's comment on your article:
I wouldn't have thought about this, but this reminds me that there's all sorts of tools that could consume the HTML and embed parts of it somewhere else without applying CSS. As you responded, this could be mitigated using inline CSS instead of a class, but some RSS readers or similar software might strip or just ignore inline CSS. This also applies to search engines, which might not be ideal? Right now the default behaviour is not ideal for screen reader users. Do I prefer it to be not ideal for RSS readers users, and (to some extent) search engine users instead? I would rather not have to answer to that question, ideally nobody should find the default behaviour "pas terrible". I like the idea of having the title itself be the anchor, but this is probably too uncommon of a practice to be the default, and as pointed out, it comes to the expense of being able to easily select parts of the title, or for what it's worth, being able to include other links in the title. → Even though the Alt text contentWhile there's a lot of details about the chosen structure in Amber's article, there's no explanation on why the text "Section titled <TITLE>" was chosen. I have no experience with using screen readers and I'm more than happy to trust people who are more knowledgeable than me on the subject, that being said I would love to learn what's the reasoning behind this text. My uneducated guess would have been to name it "Link to this section" because I assume that if I was using a screen reader, I wouldn't want to be read the whole title twice every time? And maybe as a screen reader user I wouldn't even want to hear a header anchor after every title in the page, but that's my next question. We also have to keep in mind that this plugin is not locale-aware, so I can't hardcode a string like "Section titled" in the source. I can make this an option but then the accessible version can't be the default which somewhat makes me sad. Are headers anchors important enough to justify interrupting the content flow?Even though marking focusable elements as As a screen reader user, is it more important to have the header anchor text presented after every title to have the option to copy it, or is it more important to keep the content meaningful, where the anchor link could be considered a distraction the majority of the time? I originally mimicked GitHub's behaviour upon the assumption that it was more important for screen reader users to have the content read uninterrupted by anchor links since they're not useful the vast majority of the time. This was later questioned then removed. But as you show in this issue, this was not enough. Again I understand why accessibility best practices and tools recommend as a general rule to not hide focusable elements, but I would prefer to have the opinion of regular screen reader users about the particular case of header anchors before taking a decision on this. Visually hidden side effectsThere's other details to be careful about, for example (I'm on Firefox) on Amber's article if I triple click on a title and copy it, my clipboard contains:
Or on the one named "Contents", if double click on "Contents" and copy the text, it yields:
This seems to be related to the fact the ConclusionI was really excited when I saw that issue and both blog posts, as I imagined a bulletproof way to have accessible header anchors, and my first reaction was "fantastic, let's make this the default". However while digging into the technical implications of this change and considering other use cases and aspects (RSS, search engines, internationalization), I'm left with the usual conclusion that "there's no silver bullet", and that we need to make choices – which I would rather avoid as I try to keep this plugin as unopinionated as possible (but at that point even keeping the current behaviour would be an opinionated choice). At the end of the day I'm leaning towards the permalink element being described by an const md = require('markdown-it')()
const anchor = require('markdown-it-anchor')
md.use(anchor, {
renderPermalink: anchor.accessiblePermalink(title => `Section titled ${title}`)
}) As for the default behaviour I'm considering, if that makes any sense at all, making the anchors The reasoning for that is that it's probably better to have no anchor for screen readers than a bad anchor (like it's the case now), but giving (and encouraging) the option to use the I'll end a long answer by a short question: what do you think? |
Wow, that's a very detailed answer indeed! 😅 And I must say that everything you say is right, there are multiple caveats I didn't anticipate, so it needs much more thoughts to get it right. For the CSS use case, on my site I removed the anchor link from the feed, users are much less likely to share a link to a feed item anyway. But I guess we can't simply say Markdown-it(-anchors) to generate two versions depending on the way it's used. For the SEO, I agree it's not great to have the anchor link text inlined like you show… 🥲 Regarding anchor link text, you can't use just "Link to this section" because screen reader users often ask for the list of links in the page (they also ask for the list of headings), and they would get multiple times the same "Link to this section". Overall, I think you're conclusion and suggestion is the good one, but I'm not an accessibility expert, so I will ask for advice on Twitter first, before we can continue: https://twitter.com/nhoizey/status/1366476887992729601 |
Another side-effect, activating the Reader mode on Firefox: The extra-space between the title and the content is not ideal and might be confusing. In the future, Text Fragments might save us a couple of headaches :) |
Hello there. 👋
If I’m not mistaken, this was done following a conversation Amber and I had. I would encourage people not to read too much into it. I don’t think there was such a significant decision behind it. We just thought it was adequate content. I don’t pretend it’s the best solution either. Ultimately, this content could be anything, as long as it’s different from title to title.
I am not a screen-reader user, so do not quote me on this, but I would say the content being correctly and semantically marked up is the most important. According to a WebAim survey from 2014, two-thirds of screen-reader users scan headings as the first step of trying to find information on a long web page, so this should stay clean and intact above all.
There is no silver bullet, and you probably won’t even have a consensus from screen-reader users, especially when their experience and habits vary based on their browser and assistive technology of choice. What’s important is to come to a solution that makes it possible for people to link to a specific title of an article, without it being a chore.
This might be unwise.
I would personally not sweat the SEO topic too much. Ultimately, this is the role of search engine to discern what is relevant content and what is a scam, and anchor links will most likely not being reported as illegitimate content. I think this is a non-issue. If I had to build that feature from scratch, I would mark up headings like this: <h2 id="this-is-a-heading">
This is a heading
</h2>
<a href="#this-is-a-heading">
<!-- Visual # or any other decorative character/icon of choice -->
<span aria-hidden="true">#</span>
<!-- Link accessible name, that is unique to every heading -->
<span class="sr-only">Link to “This is a heading”</span>
</a> Listing links or headings through the VoiceOver rotor look nice:
Absence of CSS also looks alright, all things considered: I think from an implementation standpoint, you could default to “Link to …”. To be on the safe side, you could apply // English (default)
assistiveText: (heading) => `Link to “${heading)”`,
// German
assistiveText: (heading) => `Link zum Titel „${heading)“`,
// French
assistiveText: (heading) => `Lien vers le titre « ${heading) »`,
// Dutch
assistiveText: (heading) => `Link naar “${heading)”` Honestly making the entire headings links is also a fine option in my opinion. Then we don’t have to mess around all this stuff at all. What you see is what you get. |
That's unfortunate, but not as much as the other issues… can we say it's a Reader mode issue? 😅
I did mention Text Fragment in my article lead, indeed! 👍 But they currently don't work on short texts (lack of "context", I think), so often not on headings… 😭 |
Hey! Thanks for picking up on this 🙂 With no CSS, the anchor links do indeed show up as follows, either on a website or in an RSS reader: I am not a huge fan of how this looks, however I am happy with how the anchor links are expressed in a screen reader "headings" and "links" list, as depicted by Kitty above. I can understand that this may not be desirable for everyone, though. |
I still prefer to make the headers links themselves, rather than a separate link for the following reasons:
MDN uses this approach (without an anchor icon): https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attributes And it's what we put in the Web Almanac (but with an anchor icon on desktop on hover/focus, but no anchor on mobile where there's less space): https://almanac.httparchive.org/en/2020/accessibility#ease-of-reading |
Downside with that though is that it’s harder to select the heading text if you want to copy just the heading text but I’m thinking that’s less likely then wanting to copy the link itself from the URL bar after clicking on it (or by right clicking on desktop/hard pushing on mobile). |
Yep @bazzadp, I remember now that I didn't want the heading text to be hard to copy. But I can't now think of a good reason for that. I think the way MDN and the Web Almanac go about it is a good one. I also like how the heading is underlined and the icon shows up on hover/focus on Web Almanac. This is a great opportunity to edit my post once again with a link to and explanation of this discussion. I love that the discussion popped up. I also wonder if there will be a decision about the most sensible way for |
I came up with a solution that mimics the "behavior" of the heading/anchor in @ambrwlsn's article but based on MDN's markup: https://codepen.io/thierry/full/qBqYmgw |
That's very, very clever! The reason Voice-Over does not announce the hash, is you only have this on h2:hover a::before,
h2:focus-within a::before {
display: block;
} The latest version of CSS introduces the ability to set alt text (including blank to remove it from the accessibility tree) by adding a h2 a::before {
content: "#";
content: "#" / ''; Looks like this currently also works with text like here, and not just images which is a nice added bonus. Note you need both lines on this as support is pretty poor unfortunately and browsers (like Safari) that don't recognise this The downsides of the solution are that I'm not loving the double tab on mobile (though that could be fixed by removing the hover style completely and just displaying this all the time), and the click area is notable smaller (especially a problem on mobile), which is the same issue it was previously, but is something I think the full header-version like MDN uses solves. I'm really not convinced the ability to select header text only is a real issue and in the rare occasion you want to do this you can work around it by selecting either side of the header. To be honest, I still prefer the full header links. But do appreciate the cleverness of this solution none-the-less! |
Duh! Of course! How did I miss that? Thank you!
I'm now wrapping the rules inside
As far as I know this is not an issue on mobile, so there is even more reason to use Note that it is possible to select text inside links via I'll try using a background image instead of a character and see the advantages of it. Thanks a lot for the feedback! |
So happy to see all that activity and discussions on this issue! Thanks everybody for contributing. 😻
Thanks for the explanation, that makes a lot of sense now!
That's fair, I didn't think about that. That makes the RSS thing a non-issue at that point, and it seems like a good practice to omit the header anchors from RSS feeds anyways. Thanks a lot for asking for external feedback on Twitter, that brought a lot of value to this issue. 🙏
Wow I didn't realize the extent of the issue with
Thanks for testing in different contexts! I agree that the rendering without CSS or in RSS feeds may not be ideal for everyone, but the screen reader experience is definitely great in your example. At the end of the day, the alt text "leaking" in places where we usually wouldn't expect it to be is the "cost" for having a proper translation experience on a screen reader, and it's only a small visual inconvenience (as @KittyGiraudel pointed out, it's not a SEO issue as the content itself is legitimate, it's just a visual redundancy when displayed in SERPs and RSS feeds).
That's a solid solution. As @bazzadp pointed out we can use The I'm gonna give this idea a bit more thinking but I like where this is going.
Wow, I didn't know that, just confirmed this works on my Linux setup as well! Tradeoffs
How markdown-it-anchor should handle this
I kept reasoning about this issue with the objective to find a default At that point, since it appears that no one solution can satisfy every user of markdown-it-anchor, I believe that markdown-it-anchor shouldn't provide a default as far as how permalinks are rendered, which allows me to keep this library unopinionated. By having no default (instead of changing the markup of the default option), I also make sure that if users upgrade the library to the next major version without changing their code, it will not silently change the way their site renders, it will just fail to compile, which I think can save some trouble. My suggestion after this discussion is to remove the That being said, with backwards compatibility in mind, I might deprecate the current default instead. This would ensure that new users are provided with the accessible choices in the documentation, but existing users who would upgrade to a new version wouldn't have to change their code right away, they would instead see a deprecation warning if they use the legacy default renderer. In code, this would look like: const md = require('markdown-it')()
const anchor = require('markdown-it-anchor')
md.use(anchor, {
renderPermalink: anchor.permalink.ohMyGoshWeNeedToNameAllOfThoseNow(permalinkOptions)
}) And for the list of built-in renderers (naming suggestions more than welcome): // The one originally discussed
anchor.permalink.linkAfterHeader({
assistiveText: title => `Permalink to ${title}`, // Required except if `style` is `aria-describedby`
style: 'visually-hidden', // Could also be `aria-label` or `aria-describedby`
visuallyHiddenClass: 'sr-only' // Required if `style` is `visually-hidden`,
symbol: '¶' // Currently `permalinkSymbol`
})
// MDN / Web Almanac style
anchor.permalink.headerLink({
symbol: null, // If set, include a `aria-hidden` `span` inside the link with this symbol for styling purpose
symbolClass: 'permalink-symbol', // Allows to give a class to the `span`
space: true, // Currently `permalinkSpace`
placement: 'after' // Currently `permalingBefore`
})
// Aliases
anchor.permalink.mdn
anchor.permalink.httpArchive
anchor.permalink.webAlmanac
// GitHub style
anchor.permalink.ariaHidden({
symbol: '¶', // Currently `permalinkSymbol`
space: true, // Currently `permalinkSpace`
placement: 'after' // Currently `permalingBefore`
})
// Aliased as
anchor.permalink.github I'll probably rename If this sounds like a good solution to everybody, I'll go on with implementing and documenting those changes (I might tweak a bit the API as I give this more thinking but it should be close to what I proposed above). As for the Other detailsEven if I want to keep this mostly backwards compatible, there's one thing I want to break, which is not requiring This will slightly improve the new experience as we'll be able to do And at that point I can also check whether the I'd love to hear your feedback below, and based on it, I can free up some time in the next couple of weeks to make this change happen. ❤️ |
Yep! That's exactly what I have on the new version I am working on. The original Pen was just a "proof of concept" to see if Now I have something that works the way I want based on the following markdown:
As far as I know this should be fine regarding localization ( I think that markup (associated with CSS) addresses many of the issues listed in this thread apart of course the fact that it prevents including links inside the heading. :-( I'm writing an article about this, that's why I'm not sharing my new Pen here yet. |
@valeriangalliat that's a great overview of all pros and cons! 👍 Your suggestion to provide multiple functions to chose from is interesting, even if I would love everyone to agree on one single solution. I'm not sure it's useful to have aliases with And I think we can wait for @thierryk's next iteration, even if I do have some (rare) headings containing links in my contents: https://nicolas-hoizey.com/articles/2004/08/04/les-transferts-de-gros-fichiers-simplifies/#dropload |
I was inspired by the Demo as JSFiddle and did this online "tool" to help get the proper slug for an easy copy/paste (better experience using keyboard only). |
@thierryk for safe slugs, I always use https://github.com/sindresorhus/slugify (But that's not the topic of this issue… 😅) |
Little late here, but when I was implementing the Web Almanac/MDN pattern (whole header is the link) on my own site, I noticed that the headers didn't appear at all in Safari’s Reader View. 😢 I fussed around and figured out that some additional markup around the text content will make them show up again, but it feels sorta gross: <h2 id="introduction">
<a href="#introduction">
<span>
Introduction
</span>
</a>
</h2> I wrote up my findings here: https://www.leereamsnyder.com/blog/making-headings-with-links-show-up-in-safari-reader |
Thanks for raising that @leereamsnyder . That definitely didn't use to happen when I first implemented that for the Web Almanac (I have screenshots to prove it! 😀). But yeah confirm it does happen now which sucks 😞 BTW one less icky way of getting round it is swapping round the headers and links:
More test cases here: https://www.tunetheweb.com/experiments/heading-links/ And raised this as a bug with WebKit team: https://bugs.webkit.org/show_bug.cgi?id=225609 |
FWIW, I found an issue with that construct: CodePen Home |
I've read this great post about accessible anchor links, and I've managed to write a
renderPermalink
function formarkdown-it-anchor
that generates the accessible HTML:https://nicolas-hoizey.com/articles/2021/02/25/accessible-anchor-links-with-markdown-it-and-eleventy/
Unfortunately, I think this can't be a "simple" PR to change the default
renderPermalink
function, as it changes the HTML structure, and would probably broke visual rendering of every current user.I see two options:
renderPermalink
function and release a major version with breaking changerenderPermalink
function only intentionallyFirst option would enhance accessibility for everyone, but I'm not sure people really pay attention to the major version of a breaking change, so feedback would probably be pretty negative.
What do you think?
The text was updated successfully, but these errors were encountered: