From 64edfe5c98037165c56d02d242598b65d18eb4a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Wed, 27 Sep 2023 18:28:02 +0200 Subject: [PATCH] Increase links and buttons contrast on focus The Web Content Accessibility Guidelines version 2.1 added a success criterion called Non-text Contrast [1], which mentions that the focus indicator must contrast with the background, and version 2.2 introduced a specific one regarding focus appearance [2]. According to that criterion, the focus indicator: * is at least as large as the area of a 2 CSS pixel thick perimeter of the unfocused component or sub-component * has a contrast ratio of at least 3:1 between the same pixels in the focused and unfocused states. Our current solution for highlighting elements on focus has a couple of issues: * It doesn't offer enough contrast against the default white background (1.6:1) * It offers even less contrast against other backgrounds, like the homepage banner or the featured proposals/debates Making the color of the outline darker would increase the contrast against these backgrounds, but it would reduce the contrast against other backgrounds like our default brand color. For this reason, most modern browsers use a special double outline with two different colors [3], and we're choosing to combine an outline and a box shadow to emulate it, using the brand color as the second color. However, this double-colored outline doesn't work so well when focusing on dark buttons surrounded by a light background, so instead we're using a triple outline, which works well on any color combination [4]. Since I feel that making the third outline 2px wide makes the overall outline too wide, I'm making the inner outline just 1px wide since that's enough to prevent edge cases. Note that Foundation adds a transition for the `box-shadow` property on `select` controls, which gets in the way of the focus we use on the language selector. So we're removing the transition. Also note that the box-shadow style didn't work properly with the box-shadow we added on the `:hover` status on cards, so we're changing the code in order to cover this case. Finally, note that the box-shadow isn't displayed properly on multiline links (in Chrome, not even with `box-decoration-break: clone`), like the ones in debates/proposals/polls/investments/processes titles, so we're changing the style of these links to `inline-block`. [1] https://www.w3.org/TR/WCAG21/#non-text-contrast [2] https://www.w3.org/TR/WCAG22/#focus-appearance [3] https://www.sarasoueidan.com/blog/focus-indicators/#examining-(current)-browser-focus-indicators-against-wcag-requirements [4] https://www.erikkroes.nl/blog/the-universal-focus-state/ --- app/assets/stylesheets/_consul_settings.scss | 6 +++- .../headings/group_switcher.scss | 2 +- app/assets/stylesheets/budgets/phases.scss | 2 +- app/assets/stylesheets/layout.scss | 13 +++---- .../stylesheets/layout/locale_switcher.scss | 4 ++- app/assets/stylesheets/legislation.scss | 1 + app/assets/stylesheets/mixins/links.scss | 35 +++++++++++++------ app/assets/stylesheets/mixins/uploads.scss | 2 +- app/assets/stylesheets/participation.scss | 4 ++- app/assets/stylesheets/sdg/help.scss | 2 +- .../sdg/related_list_selector.scss | 2 +- 11 files changed, 48 insertions(+), 25 deletions(-) diff --git a/app/assets/stylesheets/_consul_settings.scss b/app/assets/stylesheets/_consul_settings.scss index 150e9efdd..bbf168e92 100644 --- a/app/assets/stylesheets/_consul_settings.scss +++ b/app/assets/stylesheets/_consul_settings.scss @@ -115,7 +115,11 @@ $color-alert: #a94442 !default; $pdf-primary: #0300ff !default; $pdf-secondary: #ff9e00 !default; -$outline-focus: 3px solid #ffbf47 !default; +$focus-middle: #ffbf47 !default; +$focus-outer: $brand !default; +$focus-inner-width: 1px !default; +$focus-middle-width: 3px !default; +$focus-outer-width: 2px !default; $input-height: $line-height * 2 !default; diff --git a/app/assets/stylesheets/admin/budgets_wizard/headings/group_switcher.scss b/app/assets/stylesheets/admin/budgets_wizard/headings/group_switcher.scss index e0c4109f3..c873c0e69 100644 --- a/app/assets/stylesheets/admin/budgets_wizard/headings/group_switcher.scss +++ b/app/assets/stylesheets/admin/budgets_wizard/headings/group_switcher.scss @@ -42,8 +42,8 @@ &:focus, &:hover { @include brand-background; + @include no-outline; text-decoration: none; - outline: none; } } } diff --git a/app/assets/stylesheets/budgets/phases.scss b/app/assets/stylesheets/budgets/phases.scss index a3f95ef04..7c67897a6 100644 --- a/app/assets/stylesheets/budgets/phases.scss +++ b/app/assets/stylesheets/budgets/phases.scss @@ -82,7 +82,7 @@ } &:focus { - outline: none; + @include no-outline; } &[aria-selected="true"], diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index b2f589353..ea7bba8bc 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -102,20 +102,20 @@ button, [type="button"], [type="submit"] { &:focus { - outline: $outline-focus; + @include focus-outline; } &:focus-visible { - outline: $outline-focus; + @include focus-outline; } &:focus:not(:focus-visible) { - outline: none; + @include no-outline; } &:active, &:focus:active { - outline: $outline-focus; + @include focus-outline; } } @@ -1135,6 +1135,7 @@ form { .notification-link { @include text-colored-link; + display: inline-block; } &:hover { @@ -1994,7 +1995,7 @@ table { padding: $line-height / 2; z-index: 1; - &:hover { + &:hover:not(:focus-within) { box-shadow: 0 4px 6px 0 rgba(0, 0, 0, 0.15); } } @@ -2219,7 +2220,7 @@ table { } } - a:hover { + a:hover:not(:focus) { box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.2); text-decoration: none; diff --git a/app/assets/stylesheets/layout/locale_switcher.scss b/app/assets/stylesheets/layout/locale_switcher.scss index 5b2bc8076..c403d15cc 100644 --- a/app/assets/stylesheets/layout/locale_switcher.scss +++ b/app/assets/stylesheets/layout/locale_switcher.scss @@ -36,11 +36,13 @@ outline: none; padding-left: $line-height / 4; padding-right: calc(#{$line-height / 4} + 1em); + transition: none; width: auto; &:focus { + @include focus-outline; border: 0; - outline: $outline-focus; + transition: none; } option { diff --git a/app/assets/stylesheets/legislation.scss b/app/assets/stylesheets/legislation.scss index 699fe3417..6a9c728cf 100644 --- a/app/assets/stylesheets/legislation.scss +++ b/app/assets/stylesheets/legislation.scss @@ -57,6 +57,7 @@ h3 a { color: inherit; + display: inline-block; margin-bottom: 1rem; } } diff --git a/app/assets/stylesheets/mixins/links.scss b/app/assets/stylesheets/mixins/links.scss index 9163c627a..5a841c062 100644 --- a/app/assets/stylesheets/mixins/links.scss +++ b/app/assets/stylesheets/mixins/links.scss @@ -1,39 +1,52 @@ +@mixin focus-outline { + $total-width: $focus-inner-width + $focus-middle-width + $focus-outer-width; + + box-shadow: 0 0 0 $total-width $focus-outer; + outline: $focus-middle-width solid $focus-middle; + outline-offset: $focus-inner-width; +} + +@mixin no-outline { + box-shadow: none; + outline: none; +} + @mixin focus-outline-on-img { &:focus { - outline: none; + @include no-outline; img { - outline: $outline-focus; + @include focus-outline; } } &:focus-visible { - outline: none; + @include no-outline; img { - outline: $outline-focus; + @include focus-outline; } } &:focus:not(:focus-visible) { img { - outline: none; + @include no-outline; } } &:active { - outline: none; + @include no-outline; img { - outline: $outline-focus; + @include focus-outline; } } &:focus:active { - outline: none; + @include no-outline; img { - outline: $outline-focus; + @include focus-outline; } } } @@ -42,10 +55,10 @@ position: relative; &:focus-within { - outline: $outline-focus; + @include focus-outline; a:focus { - outline: none; + @include no-outline; } } diff --git a/app/assets/stylesheets/mixins/uploads.scss b/app/assets/stylesheets/mixins/uploads.scss index 692ec9b05..04db8ad91 100644 --- a/app/assets/stylesheets/mixins/uploads.scss +++ b/app/assets/stylesheets/mixins/uploads.scss @@ -22,7 +22,7 @@ } &:focus-within label { - outline: $outline-focus; + @include focus-outline; } } diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index 7b92ac831..21a68e186 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -464,6 +464,7 @@ a { color: inherit; + display: inline-block; } } @@ -1333,7 +1334,7 @@ font-size: rem-calc(24); } - &:hover { + &:hover:not(:focus-within) { box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.2); } } @@ -1596,6 +1597,7 @@ a { color: inherit; + display: inline-block; } } } diff --git a/app/assets/stylesheets/sdg/help.scss b/app/assets/stylesheets/sdg/help.scss index 0d9b94df1..32608ac62 100644 --- a/app/assets/stylesheets/sdg/help.scss +++ b/app/assets/stylesheets/sdg/help.scss @@ -7,7 +7,7 @@ li { &:focus { - outline: $outline-focus; + @include focus-outline; } } } diff --git a/app/assets/stylesheets/sdg/related_list_selector.scss b/app/assets/stylesheets/sdg/related_list_selector.scss index 08f3a2438..5a959e576 100644 --- a/app/assets/stylesheets/sdg/related_list_selector.scss +++ b/app/assets/stylesheets/sdg/related_list_selector.scss @@ -34,7 +34,7 @@ @include element-invisible; &:focus + label { - outline: $outline-focus; + @include focus-outline; } &:checked + label img {