Is it possible to control tabindex with CSS and if yes, which browsers support it and on which elements?
EDIT
I should say, my goal is to catch keydown events on a div. I saw this page http://www.quirksmode.org/js/events/keys.html# that tests keyboard events and it shows that the only way keydown fires on anything other than document and body or some kind of form element or link is to have tabindex declared on it. But I read on W3C site:
The following elements support the
tabindex attribute: A, AREA, BUTTON,
INPUT, OBJECT, SELECT, and TEXTAREA.
So I am a little confused, what to do in order to be standarts compliant and make my use case work?
EDIT2
My whole use case is a div with a lot of content with an artificial scroll bar. I am able to scroll it with mouse events but no luck with the keyboard so far.
Update 2017
As pointed out by #Wallop in the comments, the nav-index property was dropped from the spec in 2015 due to "lack of implementation interest".
Take a look at the nav-index property introduced by W3C in CSS3-UI.
This property has exactly the same behavior as a tabindex and is applicable to any element.
The ‘nav-index’ property is an input-method-neutral way of specifying the sequential navigation order (also known as "tabbing order").
This property is a replacement for the HTML4/XHTML1 attribute ‘tabindex’
Being probably the best standards-compliant solution for the use case, nav-index is interpreted only by Opera so far (as of June 2012) and is also marked as "Feature at risk" by W3C, therefore may be dropped any time.
Alternative cross-browser solutions are:
non-standards-compliant: set the tabindex attribute on a DIV. This will work in all common browsers.
standards-compliant: replace DIV by an anchor element (A) without a href attribute set, style it with display: block and add the tabindex attribute.
With respect to BoltClock´s point, I agree that the tabbing order is very logical (both the text selection order and tabbing order are closely related to the sequence in which elements are aranged in the document). On the other hand, CSS has a wider purpose today. It can manipulate not just the content of a document (content property) but also the behavior when and if events are to be fired: i.e. using pointer-events, display or z-index the pointer event's order will change. If these are very basic CSS properties, why you should not be able to influence KeyBoardEvents, too?
This is a bit old but now there are css options like -moz-user-focus. I'm sure there is a webkit equivalent.
https://developer.mozilla.org/en-US/docs/CSS/-moz-user-focus
user-focus is the standard cross browser attribute.
Related
Background: I am trying to fix two annoyances in the appearance of the audio element in Chrome and while attempting to do so I came across two issues I would like to understand better. This is about Chrome 89 on MacOS. I nicely manage to style inside the audio element, using pseudo selectors. Finding out about the names of the pseudo selectors works nicely when looking inside of the shadow dom with the dom inspector. For example, the following two rules work exactly as expected:
::-webkit-media-controls-timeline {background-color:pink;}
audio::-webkit-media-controls-time-remaining-display {background-color:lightgrey;}
Question: However, two things do not work as expected and I want to understand why.
Problem 1: Styling the first letter in the remaining-display div does not work. The following rule is not effective.
audio::-webkit-media-controls-time-remaining-display:first-letter {color:white;}
This is astonishing, since the browser dispplays this
<style>div:first-letter {color:red;}</style> ... <div>e xample</div>
as expected. Why would I be unable to style the first letter? (The idea of this is to get rid of the most annoying leading / symbol in the remaining time display).
Problem 2:
Why would I be unable to style an element with a different pseudo attribute in a different part of the shadow DOM. More precisely the following rule is not effective:
::-internal-track-segment-highlight-before {background-color: blue;}
I see no difference to the other case above where the color styling worked. (The idea of this is to increase the too small contrast between two parts of the track segment.)
Add on: I managed to improved the contrast a bit using
audio::-webkit-media-controls-timeline {-webkit-filter: brightness(2.5);}
but the issue remains why the one method worked and the other did not work.
You are using Chrome, with "Show user agent shadow DOM" turned on
There are 2 types of shadowDOM
let's call it "userland" shadowDOM,
the (open or closed) shadowDOM created by a (3rd party developer) Custom Element/Web Component
This type is available since the W3C Web Components standard was implemented
"user-agent" shadowDOM created by each Browser (Vendor),
implementing input , audio , video, select etc. tags
but each Browser can have a different implementation.
This shadowDOM content can only be accessed if the Browser vendor has enabled access. (with shadowParts or related tech)
And in general it can not be accessed.
WebKit does have some pseudo selectors to change some settings
See: Is it possible to style html5 audio tag?
But they are not CSS selectors that get you full access to shadowDOM by creating complex selectors.
Some Font and Styling settings do cascade into shadowDOM only to have a consistent style in the whole page.
See: https://lamplightdev.com/blog/2019/03/26/why-is-my-web-component-inheriting-styles/
So that is why your color:red works, and :first-letter doesn't
That is why filter works; and background-color doesn't
alternative
https://github.com/dascritch/cpu-audio is a decent Web Component replacing the standard <audio> tag, that gets you styling in all browsers
Note the notation: (open) not (user-agent)
video::-webkit-media-controls-timeline {
background-color: blue !important;
}
work better for highter contrast.
(tested in video tag)
I'm trying to find a list of elements that are tabbable.
Adding tab-index to elements make them tabbable.
Some elements are tabbable by default like <input>.
Is there a list of these elements that are tabbable by default?
And optionally, why are they tabbable by deault?
The easiest way to find answers to such questions is by looking at the spec
I believe the list you are looking for is:
a elements that have an href attribute
link elements that have an href attribute
button elements
input elements whose type attribute are not in the Hidden state
select elements
textarea elements
Editing hosts
Browsing context containers
To answer your optional question: they are "tabbable" by default for usability issues. If you follow the principals of making a good, user friendly app, it should allow for a consistent navigation and discoverability among other things.
So, by making them "tabbable", in the order they appear in code, the default behavior is to allow the user to complete a form from top to bottom, with minimal clicks and moving around, this making the "thinking process" about what should be filled next unnecessary
https://allyjs.io/data-tables/focusable.html is probably the most comprehensive list I've ever found. Not only does it go over what is "expected" by the spec but also how all major browsers actually behave.
At https://www.w3schools.com/tags/att_global_tabindex.asp, it talks about the tabindex attribute in HTML 4.01, and how only certain elements could enter the tab order through the tabindex attribute.
Those elements were: <a>, <area>, <button>, <input>, <object>, <select>, and <textarea>.
I've been working with tab stuff for a few months now, and that list seems to fit with I've noticed as naturally tabbable.
According to the Mozilla Doc, the value none for the CSS attribute display does the following:
Turns off the display of an element (it has no effect on layout); all descendant elements also have their display turned off. The document is rendered as though the element did not exist.
I know this means I can't see the element. Since the element has no effect on the layout, it appears as if it does not exist.
My question is: does it still exist in the layout (it still responds to user events)? Or does it not exist in the layout at all (therefore not just appearance)?
Just to clarify:
I know the element still exists in the DOM. I'm asking if interaction with the view can still affect the state of that element. For example, if I click where a hidden element would have existed, does that still trigger an event?
I'm asking because I know you can target hidden elements in CSS like so:
input[type="checkbox"] {
display: none;
}
input[type="checkbox"]:checked + otherElement {
...
}
Some event must be firing or else the second CSS selector would not work.
Can someone explain this?
For example, if I click where a hidden element would have existed,
does that still trigger an event?
There is no such thing as "click where a hidden element would have existed".
For example, if a brick was not used in building a house, you can't touch it by touching the line between two other bricks, even if it could have been there otherwise.
So there are no user-caused events that apply to an invisible object not included in the layout.
However I am pretty sure it would still produce other events, for example ones reported by MutationObserver. I would expect events dispatched by dispatchEvent to work as well, though I hadn't tested this.
You cannot affect the state of an element that is display: none by interacting directly with the element, because that element is not rendered. However you can still affect its state by interacting with other elements that fire events that in turn change the state of that element via the DOM.
Some event must be firing or else the second CSS selector would not work.
Can someone explain this?
States and events are completely different. Events do not need to have fired for the state of an element to change, and when an element changes its state it does not necessarily fire any events. Selectors never operate on events; they are always state-based.
In your example, if the input element was already checked via the checked attribute, then the DOM loads with that element in that state to begin with, and no events would be fired, and it would still allow otherElement to match the selector immediately. Furthermore, it would continue to match that selector, until something happens that causes the input to become unchecked (or in CSS selector terms, :not(:checked)).
See my answer to this other question for a little more explanation on states vs events in CSS.
It will have no effect on your layout, as if it didn't exist, but the content is still present in the HTML DOM. The CSS attribute display:none is just that - a CSS attribute, and it does not modify your HTML content.
You can still perform javascript functions on the element.
I have an HTML page, with multiple hidden elements that become visible only under certain circumstances.
When I set the focus on the page wrapper (to read all the content), Windows Narrator reads all the elements, even the hidden ones.
I have tried using aria-hidden="true", CSS display: none, HTML5 hidden attribute, all are completely ignored. So far, the only mechanism that I found that works is to remove this elements from the DOM, before setting the focus on the wrapper. But it's not an ideal solution.
apply role="presentation" tabindex="-1" to your elements that have aria-hidden applied.
Just fought with the same thing, and found out that if there's an element with role="main" without explicit aria-label/aria-labelledby defined, its whole content, including all the hidden elements, is added to MSAA and UIA trees which is then read out by the Narrator. Adding an explicit aria property solves the issue - but apparently also stops the Narrator from starting to read the main content automatically.
The good thing is that AccChecker warns about these problems. Apparently better to follow its advice even though it would be nice to have that automatic reading of content.
Apparently this isn't an issue anymore on MS Edge! Hurray! If the element is hidden with CSS display:none then it doesn't read it's content.
So I was able to get my page working just fine with the NDVA screen reader, however, when testing in JAWS, it tabs to the span, but doesn't read the text.
<span tabindex="0" title="whatever">whatever</span>
UPDATE:
What I am trying to achieve is a I have a few elements which expand/collapse certain sections of the site I'm building. These functional elements, however are not links.
Reponse to #discojoe (thanks for the response)
Adding a TABINDEX="0" attribute will insert the SPAN/DIV element into tabbing list in natural order (whereas by default, they're usually not added to the tabbing list). This allows screen readers to tab to that element, and is working just fine. Specifically, my problems is JAWS will just tab to that element, it just doesn't read it.
I agree, using TABINDEX="n" (where n > 0) is a bad thing which messes with the natural order of the tabbing list, and I am not doing that.
Also, you can use TABINDEX="-1" to remove an element from the tabbing list if it's placed in there by default (example an A or INPUT tag).
I have already tried using tags, however, when user hits enter on this link (to trigger the onclick event), it does something (not quite reloading, but kinda re-initializing) to the page which delays the animation associated with that element. I find that to be a bad experience to both normal and disabled users.
using the # tag in the A tag adds the hash tag to the page title in IE.
Additionally, using A tags makes the screen reader read out "LINK" before/after each element, and since they're not actually links, I feel this is negative impact on accessibility.
I would first want to know why you are using a span element and not a standard a href element? What is it you are wanting to achieve? It may help if you can provide more context\code.
I've just tried this and am getting the same issue; whilst I can arrow through the document and have a span read out to me, I cannot then tab to it and have it read out.
Using something instead like
Whatever
works fine.
There are additional problems around using the tabindex attribute, specifally for keyboard users. On a page that users the tabindex attribute, the tab focus order will first of all go through all of the elements with tabindex specified, and then run through all the elements without it, in source code order.
A good general rule is to either use tabindex for all keyboard accessible elements, or for none of them, to get around this problem.
I realise in this case, you are likely using tabindex to just provide keyboard accessibility for this one item, so this issue may be irrelavant if you use the a href approach mentioned, but I wanted to mention it for completeness
First of all, reading "link" before such elements does not impact accessibility in a negative way, I'd say, it's quite opposite: you warn the user that he/she can click the element in such a manner.
Here you have a couple options:
Use quite a lot of ARIA: add the link role to your span elements, properly code your expanding/collapsing menus (with corresponding ARIA roles and states).
Use <a href="#" as suggested by #discojoe but add event.preventDefault() (in jQuery) or return false; (in vanilla) so the page would not reinitialize.
If you need more suggestions, please post some code or a link to your page.
Use anchor tag for screen reading simple text related works. You can simply do :-
<a href="javascript:void(0);" title="What you want to be read by jaws></a>
That's it. I tested it with JAWS.