Skip to content

fix(cdk/a11y): make cdk-high-contrast work w/ emulated view encapsulation #18152

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

Merged
merged 3 commits into from
Jan 29, 2020

Conversation

jelbourn
Copy link
Member

Say you have this in your component:

.some-element {
  @include cdk-high-contrast() {
    border: 1px solid white;
  }
}

With this change, this will output:

.cdk-high-contrast-active .some-element,
.cdk-high-contrast-active :host .some-element {
  border: 1px solid white;
}

Here, .cdk-high-contrast-active .some-element will apply in places
where encapsulation is turned off, and .cdk-high-contrast-active :host .some-element will apply in cases where encapsulation is emulated.
Neither will work in Shadow DOM (which we don't officially support).
AFAIK, Shadow DOM would need to use :host-content(), which we could
consider adding if we get an additional request.

This adds a few more bytes, but high-contrast styles tend to be pretty
limited.

Fixes #18147

@jelbourn jelbourn added P2 The issue is important to a large percentage of users, with a workaround target: major This PR is targeted for the next major release labels Jan 11, 2020
@jelbourn jelbourn added this to the 9.0.0 milestone Jan 11, 2020
@jelbourn jelbourn requested a review from devversion as a code owner January 11, 2020 00:06
@googlebot googlebot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Jan 11, 2020
@jelbourn jelbourn requested a review from crisbeto January 11, 2020 00:09
@@ -35,7 +35,8 @@
// context. We address this by nesting the selector context under .cdk-high-contrast.
@at-root {
$selector-context: #{&};
.cdk-high-contrast-#{$target} {
.cdk-high-contrast-#{$target},
.cdk-high-contrast-#{$target} :host {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested it out and this breaks the high contrast styles for Edge and IE for unencapsulated components. The problem is that when encapsulation is disabled, Angular leaves the :host in place which IE/Edge don't support and causes the entire selector to be invalidated. It can be worked around by outputting a separate selector, but it means that we generate double the amount of CSS:

.cdk-high-contrast-#{$target} {
  @content;
}

.cdk-high-contrast-#{$target} :host {
  @content;
}

We could also add another parameter to the mixin that allows the consumer to tell us whether the styles are encapsulated and we can output the correct styles based on it. By default it can output both.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd definitely prefer to add a parameter to toggle this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see- I was assuming IE would ignore a pseudo-class it didn't recognize. I pushed an update that adds a param, defaulting to emitting both styles for maximum compatibility.

Copy link

@biolauri biolauri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the quick PR & fix for (my|the) issue! 🙇

/// * `on` - works for `Emulated`, `Native`, and `ShadowDom`
/// * `off` - works for `None`
/// * `both` - works for all encapsulation modes by emitting the CSS twice (default).
@mixin cdk-high-contrast($target: active, $encapsulation: 'both') {
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 sure the both value makes sense since encapsulation is either on or off.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would you do instead? I want the mixin to "just work" by default, even if it is emitting extra styles.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the thing that's throwing me off is that it's called both which sounds like it can have more than one style encapsulations at the same time. Maybe can make it on | off | undefined and output both styles if it's emitted? Another approach could be to match the naming from Angular.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your point, but I think, both is fine here, because with this option, the mixin supports both general states of view/style encapsulation. So it's rather an option of which policies are supported.
Matching the naming from Angular would be complicated, as AFAIK there's no explicit naming from Angular which addresses Emulated, Native, and ShadowDom together.

undefined is not a restricted value in Sass, so null would be the way to go. But I'm feeling that both fits better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about 'any'?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, that works too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to any

Copy link
Member

@crisbeto crisbeto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but the CI is failing. It looks like not all references to both were updated.

@jelbourn
Copy link
Member Author

That's what I get for using the in-browser editor

jelbourn and others added 3 commits January 28, 2020 10:06
…tion

Say you have this in your component:
```scss
.some-element {
  @include cdk-high-contrast() {
    border: 1px solid white;
  }
}
```

With this change, this will output:
```scss
.cdk-high-contrast-active .some-element,
.cdk-high-contrast-active :host .some-element {
  border: 1px solid white;
}
```

Here, `.cdk-high-contrast-active .some-element` will apply in places
where encapsulation is turned off, and `.cdk-high-contrast-active :host
.some-element` will apply in cases where encapsulation is emulated.
Neither will work in Shadow DOM (which we don't officially support).
AFAIK, Shadow DOM would need to use `:host-content()`, which we could
consider adding if we get an additional request.

This adds a few more bytes, but high-contrast styles tend to be pretty
limited.
@jelbourn jelbourn added the action: merge The PR is ready for merge by the caretaker label Jan 28, 2020
@jelbourn jelbourn merged commit ea17135 into angular:master Jan 29, 2020
jelbourn added a commit that referenced this pull request Jan 29, 2020
…tion (#18152)

* fix(cdk/a11y): make cdk-high-contrast work w/ emulated view encapsulation

Say you have this in your component:
```scss
.some-element {
  @include cdk-high-contrast() {
    border: 1px solid white;
  }
}
```

With this change, this will output:
```scss
.cdk-high-contrast-active .some-element,
.cdk-high-contrast-active :host .some-element {
  border: 1px solid white;
}
```

Here, `.cdk-high-contrast-active .some-element` will apply in places
where encapsulation is turned off, and `.cdk-high-contrast-active :host
.some-element` will apply in cases where encapsulation is emulated.
Neither will work in Shadow DOM (which we don't officially support).
AFAIK, Shadow DOM would need to use `:host-content()`, which we could
consider adding if we get an additional request.

This adds a few more bytes, but high-contrast styles tend to be pretty
limited.

(cherry picked from commit ea17135)
yifange pushed a commit to yifange/components that referenced this pull request Jan 30, 2020
…tion (angular#18152)

* fix(cdk/a11y): make cdk-high-contrast work w/ emulated view encapsulation

Say you have this in your component:
```scss
.some-element {
  @include cdk-high-contrast() {
    border: 1px solid white;
  }
}
```

With this change, this will output:
```scss
.cdk-high-contrast-active .some-element,
.cdk-high-contrast-active :host .some-element {
  border: 1px solid white;
}
```

Here, `.cdk-high-contrast-active .some-element` will apply in places
where encapsulation is turned off, and `.cdk-high-contrast-active :host
.some-element` will apply in cases where encapsulation is emulated.
Neither will work in Shadow DOM (which we don't officially support).
AFAIK, Shadow DOM would need to use `:host-content()`, which we could
consider adding if we get an additional request.

This adds a few more bytes, but high-contrast styles tend to be pretty
limited.
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Feb 29, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement P2 The issue is important to a large percentage of users, with a workaround target: major This PR is targeted for the next major release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

cdk-high-contrast mixin not working anymore without :host selector
4 participants