a11y.css icon indicating copy to clipboard operation
a11y.css copied to clipboard

[webextension] — Focus order visualizer

Open ffoodd opened this issue 4 years ago • 8 comments

Not sure it's easy nor doable but I'd want to give this a try:

JavaScript

  1. list focusable elements,
  2. log them in proper order,
  3. get their respective coordinates,
  4. set on html tag two custom properties for each element (say, --1-x and --1-y, etc.),
  5. probably set a data-* attribute on each element, with their respective order as value.

CSS

If you had a look to chaarts, you might have guessed what I'm trying to do.

Using clip-path and a polygon() value with enough points (hardcoded arbitrary value, or generated via JavaScript?) directly on the html element, we should be able to draw a line between each element and to display their order thanks to the data-attribute and a pseudo-element.

Any thought?

It will probably be hard on perf, so any thought welcome.

Resources

javascript: (function () {
    try {
        var s = document.createElement('style');
        var b = document.getElementsByTagName('body').item(0);
        var counter = 0;
        s.innerHTML = '.FocusOrder{position:absolute;border:.1rem solid #00f;border-radius:50%;background:#00f;color:#fff;padding:.25rem .5rem;font-family:\'Segoe UI\',-apple-system,BlinkMacSystemFont,Roboto,Oxygen-Sans,Ubuntu,Cantarell,\'Helvetica Neue\',sans-serif;text-align:center;min-width:1rem;line-height:1;box-shadow:.2rem .2rem .2rem rgba(0,0,0,.5);margin-left:-.5rem;margin-top:-.75rem}';
        document.getElementsByTagName('head').item(0).appendChild(s);
        for (var e = document.querySelectorAll("a[href], area[href], input:not([disabled]), button:not([disabled]), select:not([disabled]), textarea:not([disabled]), iframe, object, embed, summary, [tabindex]:not([tabindex='-1']), [contenteditable=true], video[controls], audio[controls]"), t = 0; t < e.length; t++) ! function (t) {
            var rect = e[t].getBoundingClientRect();
            if(rect.top != 0 && rect.left != 0) {
                var sp = document.createElement('span');
                sp.classList.add('FocusOrder');
                sp.innerText = ++counter;
                sp.setAttribute('style',`top:${rect.top}px;left:${rect.left}px`);
                b.appendChild(sp);
            }
        }(t)
    } catch (e) {
        console.log(e)
    }
})()

ffoodd avatar Jan 07 '20 08:01 ffoodd

My bookmarklet code is just a basis to show how focus is ordered on a page but it lacks a few things:

  1. Elements that are not displayed have no tooltip (if top and left are not computed, they are "0")
  2. This is static, so if the page moves tooltips will go awry. The right thing to do should be a ::before for every focusable element, plus relative position as a minimum, I guess.

notabene avatar Apr 28 '20 08:04 notabene

BTW I'm writing an article on the bookmarklet I wrote, but to be clear most of my code comes directly from @aardrian (giving credit where credit's due as early as possible).

notabene avatar Apr 28 '20 10:04 notabene

There might be something you can use from my reading order visualizer: https://adrianroselli.com/2019/04/reading-order-bookmarklet.html

I found I could not throw the numbers into a page using ::before or ::after since that often broke site styles. That is why all my numbers live at the end of the DOM and are absolutely positioned.

aardrian avatar Apr 28 '20 11:04 aardrian

BTW I'm writing an article on the bookmarklet I wrote, but to be clear most of my code comes directly from @aardrian (giving credit where credit's due as early as possible).

Here: https://nota-bene.org/Focus-order-bookmarklet

notabene avatar Apr 28 '20 11:04 notabene

Newcomer: @KittyGiraudel came up with a micro-lib to list focusable elements. I guess this selector is comprehensive, or will be at some point. :)

ffoodd avatar Feb 16 '21 13:02 ffoodd

  • Needs object, embed, summary.
  • I like the addition of checking for inert, but until it is supported it might give false positives (negatives?).
  • I also like checking for non-negative tabindex.
  • audio and video might need to check for the controls attribute.
  • contenteditable is a good addition too, even if it makes me queasy.

aardrian avatar Feb 17 '21 03:02 aardrian

@ffoodd Thank you for the shoutout. :) @aardrian Thanks for sharing your thoughts. I have a few further questions/comments:

  • I’ve discovered that only the first <summary> element within a <details> element should be focusable. I also read that a <details> element without a <summary> element should be focusable, but that cannot be represented with a CSS selector so I’ll omit it.

  • Good catch on the controls attribute of the <audio> and <video> elements. I issued a fix.

  • The <embed> and <object> elements do not appear to be focusable by default and I cannot find much literature around them. Do you have any further information to share? From focus-trap/tabbable:

    The tabbability of <iframe>s, <embed>s, <object>s, <summary>s, and <svg>s is inconsistent across browsers, so if you need an accurate read on one of these elements you should try giving it a tabindex. (You'll also need to pay attention to the focusable attribute on SVGs in IE & Edge.) But you also might not be able to get an accurate read — so you should avoid relying on it.

KittyGiraudel avatar Feb 17 '21 11:02 KittyGiraudel

Support for summary in focusable-selectors is coming in this PR: https://github.com/KittyGiraudel/focusable-selectors/pull/9

KittyGiraudel avatar Jul 27 '22 10:07 KittyGiraudel