w3c / wcag

Web Content Accessibility Guidelines
https://w3c.github.io/wcag/guidelines/22/
Other
1.13k stars 257 forks source link

Do skeleton loaders fall under “inactive” exemption of 1.4.11 Non-Text Contrast? #2048

Closed mra11yx closed 6 months ago

mra11yx commented 3 years ago

I’ve been involved in a discussion around whether skeleton loaders need to meet the contrast requirements of 1.4.11 Non-Text Contrast. On the one hand, they seem to fall squarely within the definition of “inactive user interface components.” However, on the other hand, they convey a specific, distinct, “content is here but not yet loaded” state, which is in line with Adrian Roselli’s take in More Accessible Skeletons. Hoping to get some clarification here.

mraccess77 commented 3 years ago

They appear to be communicating something using limited contrast (without another mechanism) - the presence of future content - but this is an area that is not clear in the current guidelines. It is analogous to disabled controls using contrast - an issue which WCAG 3.0 should take up and one where the low vision task force will likely provide informative guidance.

scottaohara commented 3 years ago

generally they're not 'inactive components' as that's referring to things like disabled form controls. Skeleton loaders are typically graphics / styled divs that convey a loading state of various types of content. I'd consider these to be "graphical objects" as they are visually-minimal representations of content, but not content themselves, that are meant to indicate a loading state for said content.

def of 'user interface component' per the 'inactive component' reference:

a part of the content that is perceived by users as a single control for a distinct function

patrickhlauke commented 3 years ago

even simple inactive components like a <button disabled>...</button> do convey information that "there's some functionality that you may have at some point, but not just now", so even for those the exemption is a bit...rubbish to be honest. but applying the same logic as for those, i'd say yes those skeletal structures can be seen as exempt, but as best practice i'd have some contrasty-enough indication that there's something there

patrickhlauke commented 3 years ago

to @scottaohara's point about the normative definition of user interface component, it gets blurry if the skeleton placeholder structure also contains dummy controls for instance that are, at that point, inactive...so don't think it's a super-useful distinction. i'm still a bit on the fence, but my gut feeling is exempt the skeleton for being a large inactive "component" of sorts, but as best practice still make sure that there's something visible there.

scottaohara commented 3 years ago

@patrickhlauke would you say that a loading spinner to indicate a loading state would not need to meet contrast then? these skeleton states are essentially the same thing. If there's no other non-failing 'loading' text or indicator, i don't think this is really a best practice alone.

mraccess77 commented 3 years ago

I agree @patrickhlauke I think the assumption for disabled controls was that they would be things not needed for the task and always disabled for a particular workflow. Unfortunately I don't think people realized how much information they actually communicate and that people without contrast issue rely on that information to make decisions about their actions. Disabled controls today are often just a temporary state until you do something else.

I also find that people miss categorize not selected or not currently active but still interactive under this exemption - which in my opinion is a issue. Something that is inactive but actionable is not exempt. Example, the alarm times on the Apple watch which are not set but can be tapped to be turned on.

mraccess77 commented 3 years ago

Loading spinners would need to have sufficient contrast.

scottaohara commented 3 years ago

so then why not skeletons which are performing the same function @mraccess77 ?

patrickhlauke commented 3 years ago

@patrickhlauke would you say that a loading spinner to indicate a loading state would not need to meet contrast then? these skeleton states are essentially the same thing. If there's no other non-failing 'loading' text or indicator, i don't think this is really a best practice alone.

perhaps thin-slicing, but the spinner/loader is a "thing" in its own right, which appears and then disappears, while the placeholder skeleton is replaced/turns into actual content and interactive components (links, buttons). but yes, it's a wobbly distinction, admittedly.

mraccess77 commented 3 years ago

@scottaohara I haven't said that they aren't covered - they are communicating something as I indicated. It's just not clear in the guidance we have today. Inactive buttons that are interactive or at some point can become interactive should also need to meet the requirements for contrast. So we'd end up with skeletons that have contrast but inactive buttons that don't require it - where inactive controls might actually be more necessary to operation.

scottaohara commented 3 years ago

thanks for clarifying @mraccess77, i think i misunderstood one of your previous comments which seemed to read to me that you didn't think skeletons needed to pass contrast. i understand your point now.

re: patrick

but yes, it's a wobbly distinction, admittedly.

agreed. it does seem wobbly to say one type of content loading indicator needs to meet contrast, but another type does not. i think that's a problem.

bruce-usab commented 3 years ago

I just want to add a plus one to these observations from @mraccess77 as they comport to my memory:

I think the assumption for disabled controls was that they would be things not needed for the task and always disabled for a particular workflow. Unfortunately I don't think people realized how much information they actually communicate and that people without contrast issue rely on that information to make decisions about their actions. Disabled controls today are often just a temporary state until you do something else.

Even with the benefit of hindsight, I do not have good ideas for what we could/should be doing differently. Conveying visually that a control is not available is important, and controls being grayed out is a paradigm that is quite old. My recollection, and someone please correct me if I am making this up, is that for a significant period of time, this sort of disabled / unavailable state was something which was either readily exposed by screen reading software, or it worked just as well for the unavailable controls to be invisible to screen reading software.

I agree that the current status quo, where the presence of a not-yet-but-soon button is quite important to convey, is not something we should be content to keep tolerating just because it is technically conforming. But I am not clear as to what are considered best practices, and if there is consensus around techniques which provide a good user experience for everyone.

The archetype example, a form trying to convey that a required field is missing -- before hitting the submit button -- is a nice feature (at least theoretically) for everyone, including people with disabilities. But the form being incomplete might only be indicated by the submit button being grayed out. Which might be fine when the form is just a search button or an email field. For longer forms, this UI convention is terrible for most users, including people with disabilities. Significantly, it is pretty easy to make the case that this sort of UI behavior disproportionally impacts people with cognitive difficulties and/or people who are using assistive technology. This means that this problematic UI behavior is in the scope/domain of something WCAG might address.

Have we hit upon SC worthy phrasing for capturing this particular real-world problem? Are best practice alternatives to grayed-out controls documented? I am not convinced that skeleton loaders need to be low contrast to convey their place-holder status. But there are other examples where I am not creative enough to suggest what might be the required behavior.

alastc commented 3 years ago

I'm assuming skeletons are the placeholders that appear on sites using (things like) React that appear before the full content kicks in?

I don't think that falls under the definition of user-interface component as it isn't functional. I.e. you can't click it or tab to it and activate anything. Therefore I don't think it falls under that bullet of 1.4.11.

You could consider it "Parts of graphics required to understand the content", i.e. to understand it is loading, in which case you'd check that some aspects of it have contrast so that you can understand it is loading.

What that would be might vary case to case, but for example the outline could have reasonable contrast whilst having low-contrast placeholder backgrounds inside.

mraccess77 commented 3 years ago

The group was looking at a universal visual pattern (perhaps an icon) that may communicate disabled) that could be used. In many cases as you describe it's not even helpful as providing supports with error message/instruction help users more with successful form completion. So it might be a proposal to not allow them in certain situations and in other situations use x or y if you are going to use them.

aardrian commented 3 years ago

My opinion in the linked post is clear (because it's my post) — I think these generally constitute a 1.4.11 failure. They are using visuals to convey a state, and that state is busy, not disabled, not inactive. IMO, these are not analogous. There is content there yet to be disabled.

I have sat in on tests with users, along with having matching anecdotal experience, where lower vision users, users offset from the ideal viewing angle of the screen, and users in sunlight or experiencing reflections from office lights, have not seen the skeletons. They have proceeded to scroll and click and tap around the screen in frustration as the browser loads and then parses ("hydrates") the content. In some cases they have accidentally activated a control just as it appears while they pressing down, starting the whole process over.

Those users would all have benefited from higher contrast skeletons.

Regardless, the discussion Scott, Jonathan, Patrick, et al are having related to how they conform to current definitions is a good one.

clarkepaul commented 2 years ago

Maybe I missed it somewhere, but I think skeletons are primarily about holding space, so layouts aren't shifting as much during page loads (Cumulative Layout Shift). Then they provide a secondary benefit of indicating placement for content—pages are becoming more gradual experiences as more important content is prioritized. Often skeletons don't have a 1-1 relationship with the content that replaces them. e.g. 6 skeleton tiles are possibly replaced by 16 items, so I find it hard to see each skeleton as an exact replacement for a loading indicator (although maybe as a collective they do if implemented in that way?).

Not that my comments solve any of the above concerns. I came here looking for an indication of which contrast was appropriate, as 3:1 seems way over the top, but think they do need to be visible enough to see. As there's no appropriate standard for these as yet (just my opinion), they are being forced into specs that are not the right fit.

bruce-usab commented 2 years ago

@clarkepaul – I am overdue with my commitment to LVTF for writing some ideas for possible approaches, and I welcome your thought on what you think a reasonable approach. Please keep in mind that people with low vision should be able to use the skeleton loader, and hence my belief that 3:1 contrast ration is not unreasonable. What about using a strong bright/garish color, one not used elsewhere in the product UI, for the skeleton loader? For example, I think a skeleton using cyan would be useable, yet clearly conveys draft.

patrickhlauke commented 2 years ago

What about using a strong bright/garish color, one not used elsewhere in the product UI, for the skeleton loader

you'll likely get pushback on that, not just from designers/design-minded folks, but also from users complaining that things look initially "broken". i think a slightly more sedate approach will work better (e.g. just making a spinner/icon/three-dot loading animation in the middle of it reach 3:1)

bruce-usab commented 2 years ago

Thanks @patrickhlauke as I agree that not looking broken is essential, but I am trying to visualize approaches which convey in progress while maintaining good contrast.

Your spinner/icon/three-dot loading animation (with good contrast) is sufficient for conformance to 1.4.11 — but I do not believe it results in the skeleton loader being generally usable by someone with low vision.

aardrian commented 2 years ago

@clarkepaul

…I think skeletons are primarily about holding space, so layouts aren't shifting as much during page loads […] Often skeletons don't have a 1-1 relationship with the content that replaces them. e.g. 6 skeleton tiles are possibly replaced by 16 items, so I find it hard to see each skeleton as an exact replacement for a loading indicator

That is some of the challenge with skeletons I have seen. A big thing in the middle of the page indicating content will soon appear is a signal for users to pause interactions. A skeleton that at first glance looks like content and implies the layout is set is a signal that users can start to interact — especially with already-loaded content (nav, footer, sidebar, etc) that may still shift when the remaining content comes in.

This is not hypothetical. I have seen this catch users in testing.

As you note, though, that is outside the scope of the 1.4.11 question at hand.

clarkepaul commented 2 years ago

If 3:1 becomes the advised contrast ratio, then I think that pattern will be avoided altogether. Probably worth exploring other patterns which might gel well with skeletons that can provide the right contrast, like a loading line, animated border, or something that is relatively minimal but still noticeable to provide adequate contrast. I would think the contrast of the skeleton still needs to be adequate, say nothing lighter than 1.16:1 (#eee) against white? (I haven't put this into a design to test properly though).

toplizard commented 2 years ago

Could any loader (skeleton, spinners and what ever...) would fall under the category "status message" (https://www.w3.org/WAI/WCAG21/Understanding/status-messages#dfn-status-message) - change of content, not context? The spinner/skeleton tells a user with good visual and cognitive ability that something is happening (mostly because of a previous action). To make it accessible we also need to tell assistive technology that something is happening, and we do that by using role="status". To enhance the visual presentation of a spinner or a loader a visual text could be added. "Loading content...".

But I must say, the first rule of loaders is not to use them at all, first optimise the code, from from both the BE and FE so that content can be fetched faster and loaded incrementally.

aardrian commented 2 years ago

The spinner/skeleton tells a user with good visual and cognitive ability that something is happening (mostly because of a previous action). To make it accessible we also need to tell assistive technology that something is happening, and we do that by using role="status".

To your first point, this issue is for users who have reduced vision.

To your second point, the only AT that roles affect (today) are screen readers. While not all screen reader users are blind, the role still does not affect the contrast issue for non-SR low-vision users. Adding a role will not automatically make it accessible.

As for adding visible text, that is an option that arguably negates the need for the graphic to have sufficient contrast. At 4.5:1 for normal-sized text (versus 3:1 for non-text contrast), it is also then out of scope for this issue as it is governed by SC 1.4.3.

bruce-usab commented 2 years ago

If 3:1 becomes the advised contrast ratio, then I think that pattern will be avoided altogether.

Why is that a problem? I am predisposed to the idea that if some feature cannot be made accessible, then skip the feature.

That said, WCAG has exceptions for essential and I think that is okay too.

I am currently of the opinion that if (1) a developer wants to include a skeleton loader but (2) can't abide a 3:1 contrast ratio (maybe because the results do not visually convey the place-holder nature), then (3) it is incumbent upon the developer to figure out something that works well for end-users with low vision.

WCAG allows for conforming alternative versions (so it could just be a setting preference), but a better approach would be something that works well for everyone (including users with low vision). I am not sure what that would be, but a clever developer might come up with something. The developer would be taking a risk, but implementing regulation probably allows for good approaches which are not, strictly speaking, conforming. (The U.S. ADA and 508 term is Equivalent Facilitation.

mbgower commented 2 years ago

To summarize the discussion:

  1. skeletons convey meaning (loading)
  2. most skeletons fail contrast
  3. skeletons are analogous to a loading icon, but are positioned in place of content that will become active; as such it is unclear whether or not they are representations of inactive components
  4. to the degree they convey meaning, they should be accessible, both programmatically and via non-text contrast; but this line of thought enters into the classic debate on how much information is conveyed by inactive controls which currently get a Get Out of Jail Free card
  5. there seems to be general consensus that a skeleton that has some representation that meets 3:1 is desireable

Sounds like an area to try to tackle for Silver. Or, put another way, sounds like this is one of the things that should be tackled in the 'in between time' where we try to improve SCs while transitioning them to whatever 3.0's structure becomes. I think (hope) that is intended as a major portion of the next charter period.

One thing I'll throw in, specifically about point 3, is if skeletons aren't inactive, what state do they represent? Is there, or should there be a 'loading' state? Would that solve at least this problem (ie., they're not inactive, they're loading, and therefore are not exempt)?

mstewartgallus commented 1 year ago

Skeletons are not supposed to be loading screens.

If anything they are more like fancy animations than disabled buttons IMO.

Arbitrary but I guess if it's longer than 3 seconds it's a loader and if it's less it's an animation?

Could adjust the skeleton if loading takes too long to make things clearer?

I didn't test but something like

// Hide WCAG conforming contrast from our designer
.skeleton {
  animation: 0s linear 3s contrast;
}
@keyframes contrast {
  from {
     color: #eee ;
  }

  to {
    color: black ;
  }
}

You'd also need to think about reduced motion of course

gerald-fullam-kr commented 1 year ago

One thing I'll throw in, specifically about point 3, is if skeletons aren't inactive, what state do they represent? Is there, or should there be a 'loading' state? Would that solve at least this problem (ie., they're not inactive, they're loading, and therefore are not exempt)?

Although "loading" is not directly listed under the definition of state in the 1.4.11 Understanding document, it is mentioned as a state under the Testing Principles in the 1.4.11 Understanding document.

(emphasis mine)

Testing Principles A summary of the high-level process for finding and assessing non-text graphics on a web page:

  • Identify each user-interface component (link, button, form control) on the page and:
    • Identify the visual (non-text) indicators of the component that are required to identify that a control exists, and indicate the current state. In the default (on page load) state, test the contrast ratio against the adjacent colors.

Regardless, despite the lack of clarity in "the letter of the law" (in a manner of speaking), there is abundant clarity in "the spirit of the law" as described under the Intent in the 1.4.11 Understanding document:

The intent of this Success Criterion is to ensure that active user interface components (i.e., controls) and meaningful graphics are distinguishable by people with moderately low vision. The requirements and rationale are similar to those for large text in 1.4.3 Contrast (Minimum).

Low contrast controls are more difficult to perceive, and may be completely missed by people with a visual impairment. Similarly, if a graphic is needed to understand the content or functionality of the webpage then it should be perceivable by people with low vision or other impairments without the need for contrast-enhancing assistive technology.

This is all I need to know to believe that this guideline applies to skeleton loaders.

piofinn commented 1 year ago

I agree with @gerald-fullam-kr that skeleton loaders probably meet the intent of the 1.4.11 Success Criterion. Specifically (emphasis mine),

[…] if a graphic is needed to understand the content or functionality of the webpage then it should be perceivable […]

This is assuming the skeleton loader is needed to understand that content is loading. In that case it conveys functionality in showing that the page is performing a load of content. If there is another indication of this then that skeleton loader would not fall under the 1.4.11 criterion in my opinion. In that case the the skeleton loader falls back to a placeholder role (that it has even if also indicating loading).

I would suggest that much of the confusion about what to make of skeleton loaders in an accessibility context is this duality of roles. From a UX design standpoint the utility of a skeleton loader over a traditional spinner/loading bar is to suggest (conceptually) what content will appear, with the added benefit of minimizing layout shift on load. However, when it is the only indication of loading it also takes on the responsibility of conveying application state, which has different implications.

I don't know enough about the definitions of states in WCAG to make a definitive statement here, but my general understanding is that a state is only a useful distinction if it one of several states of the same entity. So the question, in my eyes, then becomes "is the skeleton the same entity as what it represents?" If not, then does it really have a state? It is either there or it is not. If anything it represents the state of (part of) the application, as stated above, and should probably have a role dependent on that. The closest WCAG material I could find regarding that is a wiki page on Notification of Loading/Busy

fstrr commented 6 months ago

This issue is labelled as a discussion, so we’re moving this to Discussions. There doesn’t seem to be an update to make to the documentation, but if that changes, we can move it back to the issues list.