Skip to content

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

Open
wants to merge 38 commits into
base: develop
Choose a base branch
from
Open

Conversation

Jym77
Copy link
Collaborator

@Jym77 Jym77 commented Sep 21, 2020

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):

  • N/A

Need for Final Call:
This will require a 2 weeks Final Call (new rule)


Pull Request Etiquette

When creating PR:

  • Make sure you're requesting to pull a branch (right side) to the develop branch (left side).

After creating PR:

  • Add yourself (and co-authors) as "Assignees" for PR.
  • Add label to indicate if it's a Rule, Definition or Chore.
  • Link the PR to any issue it solves. This will be done automatically by referencing the issue at the top of this comment in the indicated place.
  • Optionally request feedback from anyone in particular by assigning them as "Reviewers".

When merging a PR:

  • Close any issue that the PR resolves. This will happen automatically upon merging if the PR was correctly linked to the issue, e.g. by referencing the issue at the top of this comment.

How to Review And Approve

  • Go to the “Files changed” tab
  • Here you will have the option to leave comments on different lines.
  • Once the review is completed, find the “Review changes” button in the top right, select “Approve” (if you are really confident in the rule) or "Request changes" and click “Submit review”.
  • Make sure to also review the proposed Final Call period. In case of disagreement, the longer period wins.

@Jym77 Jym77 self-assigned this Nov 13, 2020
@Jym77 Jym77 added reviewers wanted Rule Use this label for a new rule that does not exist already labels Nov 18, 2020
@Jym77 Jym77 marked this pull request as ready for review November 18, 2020 14:13
@Jym77 Jym77 dismissed WilcoFiers’s stale review November 27, 2020 12:01

Explained intention

@Jym77 Jym77 requested a review from WilcoFiers November 27, 2020 12:01

## 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:
Copy link
Member

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?

Copy link
Collaborator Author

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.

Copy link
Member

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:
Copy link
Member

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.

Copy link
Collaborator Author

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 😅

  1. 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.

  2. 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.

  3. 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 and hover 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 the visited 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.

Copy link
Member

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?

Copy link
Collaborator Author

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.

Copy link
Contributor

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.

Copy link
Collaborator

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.

@Jym77 Jym77 dismissed WilcoFiers’s stale review November 30, 2020 10:56

Furthering discussion (it's a tough point…)

@Jym77 Jym77 requested a review from WilcoFiers November 30, 2020 10:56

## 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:
Copy link
Member

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:
Copy link
Member

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?

@Jym77 Jym77 added the Blocked Blocked by another PR/Issue label Dec 22, 2020
@kasperisager kasperisager removed their request for review December 23, 2020 11:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Blocked Blocked by another PR/Issue Rule Use this label for a new rule that does not exist already
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants