-
Notifications
You must be signed in to change notification settings - Fork 75
New rule: "Color contrast for widget" #1455
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
base: develop
Are you sure you want to change the base?
Conversation
|
||
## Applicability | ||
|
||
This rule applies to triplet of an HTML element, a character in a [text node][], and a set of [widget pseudo-classes][] for which all the following are true: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're not giving the relationship between the element and the text node. Why not apply this to any visible text node that is a descendant of a widget?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get it.
The ancestor condition is giving that relationship.
I felt it was a bit easier to explicitly mention the element here as it allows easier references to it in the conditions below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh I see... okay I find that confusing.
|
||
## Applicability | ||
|
||
This rule applies to triplet of an HTML element, a character in a [text node][], and a set of [widget pseudo-classes][] for which all the following are true: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused what this list of peuso-classes has to do with it. Are you saying that the rule applies to the element in each possible state that would match the pseudo element. E.g. I don't just test the button in its current state, but in any possible state?
That seems odd. Why would I test the invalid state of a button? Buttons generally aren't invalid at all. Similarly, why would i test the required state of an optional form field? That's even assuming those styles don't change with scripts, which when it comes to widgets is fairly common place. I don't think we should try to fake the state here, we should actually test the element in the states it can be in; but only in the states it can actually be in. That way it also doesn't matter if you've used ARIA to match states, or native pseudo-classes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point, and that is definitely the main difficulty of that rule 😅
-
I think that only checking in the current state is not going to be enough. Essentially, on a given web page we'll only ever check one (combination of) state. For example, a link would be tested when matching
:link
if it's the current state, but won't be tested when matching:visited
. If only testing the current state, I say this rule could be merge with the non-widget contrast rule and just check every text node in its current state. So, I do feel that the goal of having a separate rule is to be able to check if various states and be explicit about it. -
I agree that checking all states allowed on a given widget is pointless. As you say, there is no need to check the required state of an optional field.
-
My idea was to check each (combination of) states a given widget (inside a page) can be in, possibly with interactions with the page. This is similar to what is done in the "inline link is distinguishable" rule where the link needs to pass both when
:link
and when:visited
, and where some of the checks need to be done when the link is:hover
or:focus
. This kind of states manipulation doesn't seem to be problematic in the "inline link" rule. Granted, it's not merged yet, but nobody raised objections about this at the rule level (it might still prove problematic at the implementations level, but that is a different issue).So, I tried by putting the set of pseudo-classes in Applicability. As I understand it, a
<a href="#">Foo</a>
would be applicable with sets {:link
}, {:visited
}, {:link
,:focus
} and {:visited
,focus
} (:active
andhover
are explicitly excluded) and would thus create 4 test targets. A<input required>
would not be applicable for any set that contains:optional
because such a combination of element and set would never match the matching condition.I felt that trying to put the pseudo-classes in Expectation was harder than in Applicability because of the huge variations that different kinds of widgets can match. For the "inline link" rule, there is only one kind of widgets targeted, so it's easy to list the pseudo-classes that matter. Here, it would be impractical to try and list them (depending on widget kind), and I felt that "the contrast must be good in each set of pseudo-classes that the element can match" was more imprecise than putting it in the Applicability 🤷
I also agree that this won't work for "pure ARIA/JS" widgets. E.g., a
<span class="link" role="link" onclick="this.class='visited'; history.push(…)>
will not match any pseudo class and will only be applicable with the empty state, so the rule doesn't check what happens in thevisited
class. I didn't find a correct way to make it checkable 😞 Something like "after any kind of interaction" seems impractical due to the universal quantification. We could try and list the possible interactions (clicking, focusing, entering or deleting text, …) but I'm afraid there are many and there are going to depend on the kind of widget, making this extremely difficult to write and read… So I felt it was easier to have a partial rule. Obviously, such kind of "JS widgets" are a bad idea and semantic HTML should be used. Doesn't mean they don't exist, unfortunately…
Obviously, this is kinda new (as only "inline link is playing with pseudo-classes iirc), so I'm open for discussion both on the goal of the rule (current state or all possible ones) and the way to reach it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sold on testing hover and focus states in the inline links either, although I'm far less concerned about that case. Inline links tend not to have hover / focus effects outside CSS. If they do, it might be some kind of tooltip or preview thing that pops out, which doesn't change the link, it just reveals a bit of additional content.
That logic doesn't hold when you extend it to all widgets, anywhere in the page. Lots of widgets have scripted effects. You may very well be right that the way to test this is not to have the rule attempt to discover state, but to just test whatever state the page is in, in which case extending the existing contrast rule is probably better. We didn't want to make that call at the time, and I'm not ready to give up on testing state... but I don't applying pseudo-styles is the way to do it, not for this rule.
Maybe we should put this on the agenda for next week's CG call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am afraid of the can of worms we risk opening if we want to test widgets in various states without referring to CSS pseudo-classes or other solid reference.
Let's take the example of a link, ideally the rule should check its contrast whether it's been visited or not, and whether it's focused or not. If we can't rely on the pseudo-classes, we need to define what it means for a link to be visited. This might be doable, but it already some amount of non-trivial work.
And then we need to consider an input field and define what it mean for the placeholder to be shown, or for the field to be not empty, or for the field to be valid / invalid, …
And then for options, we need to define what it means to be selected or not, …
Already at that point, we'll essentially need to redefine all the CSS pseudo-classes in our own terms.
Then, we need to try and wrap it up in a rule (or break into many individual rules) as in "if the test target is a link, …; if it is an input field, …; …" which would then be completely unreadable.
That's why I chose to restrict the rule to the pseudo-classes. I couldn't find a good way to do it otherwise. I'm of course open to suggestions, my approach might be bad.
Of course, I am aware that it won't test as much as we'd ideally want, but I think this is OK because every failure of the rule will still be a clear failure of the SC. This does extend the color contrast rule, maybe not as much as we'd like, but still brings value.
Maybe we should put this on the agenda for next week's CG call?
Yes, more brains on the question is definitely a good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Backing up a bit, I've yet to realise the problem in assuming that CSS pseudo classes aren't representative of the various interaction states of any given widget. Take something like :focus
, for example: While one could certainly toggle an .is-focused
class on a widget on focus and blur, the widget would still be expected to match :focus
while the .is-focused
class is present on the widget. Similar arguments exists for :hover
, :active
, and others.
It's true that no CSS pseudo class is representative of something like "a tab that is currently expanded in a tab list", but I also don't think catering to that should be within scope of this rule. If you know that your tab is presented differently when expanded, just expand it and evaluate the rule again, making sure that the covered interaction states have proper contrast as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One possible solution, although not ideal, is to further limit the number of pseudo-classes to user action pseudo-classes. The trouble is that the rule wouldn't catch :link
and :visited
which are common/important.
Furthering discussion (it's a tough point…)
|
||
## Applicability | ||
|
||
This rule applies to triplet of an HTML element, a character in a [text node][], and a set of [widget pseudo-classes][] for which all the following are true: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh I see... okay I find that confusing.
|
||
## Applicability | ||
|
||
This rule applies to triplet of an HTML element, a character in a [text node][], and a set of [widget pseudo-classes][] for which all the following are true: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sold on testing hover and focus states in the inline links either, although I'm far less concerned about that case. Inline links tend not to have hover / focus effects outside CSS. If they do, it might be some kind of tooltip or preview thing that pops out, which doesn't change the link, it just reveals a bit of additional content.
That logic doesn't hold when you extend it to all widgets, anywhere in the page. Lots of widgets have scripted effects. You may very well be right that the way to test this is not to have the rule attempt to discover state, but to just test whatever state the page is in, in which case extending the existing contrast rule is probably better. We didn't want to make that call at the time, and I'm not ready to give up on testing state... but I don't applying pseudo-styles is the way to do it, not for this rule.
Maybe we should put this on the agenda for next week's CG call?
Trying to draft a color contrast for widget by matching pseudo-classes.
Blocked: waiting for decision on how to handle states in rules
Closes issue(s):
Need for Final Call:
This will require a 2 weeks Final Call (new rule)
Pull Request Etiquette
When creating PR:
develop
branch (left side).After creating PR:
Rule
,Definition
orChore
.When merging a PR:
How to Review And Approve