mirror of
https://github.com/twbs/bootstrap.git
synced 2024-12-01 13:24:25 +01:00
Focus ring helper and utilities (#33125)
* Add global variables for box-shadow focus rings * Update instances of -btn-focus-box-shadow to use -ring-box-shadow, unless it's for buttons or inputs * fix variable name * Add CSS variables for global focus styling, document it * Move to CSS vars section * Update scss/_nav.scss Co-authored-by: Gaël Poupard <ffoodd@users.noreply.github.com> * Helper and utils * Fix bundlewatch * Change 'Focus ring' in sidebar so that the page can be visible * Minor typo fix * fix merge * Revamp some more, improve docs Co-authored-by: Gaël Poupard <ffoodd@users.noreply.github.com> Co-authored-by: Julien Déramond <juderamond@gmail.com> Co-authored-by: Patrick H. Lauke <redux@splintered.co.uk>
This commit is contained in:
parent
1a043b55bc
commit
9e17b2b34c
@ -18,11 +18,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./dist/css/bootstrap-utilities.css",
|
"path": "./dist/css/bootstrap-utilities.css",
|
||||||
"maxSize": "10.5 kB"
|
"maxSize": "10.75 kB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./dist/css/bootstrap-utilities.min.css",
|
"path": "./dist/css/bootstrap-utilities.min.css",
|
||||||
"maxSize": "9.75 kB"
|
"maxSize": "10.0 kB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./dist/css/bootstrap.css",
|
"path": "./dist/css/bootstrap.css",
|
||||||
@ -30,7 +30,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./dist/css/bootstrap.min.css",
|
"path": "./dist/css/bootstrap.min.css",
|
||||||
"maxSize": "29.25 kB"
|
"maxSize": "29.5 kB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./dist/js/bootstrap.bundle.js",
|
"path": "./dist/js/bootstrap.bundle.js",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
@import "helpers/clearfix";
|
@import "helpers/clearfix";
|
||||||
@import "helpers/color-bg";
|
@import "helpers/color-bg";
|
||||||
@import "helpers/colored-links";
|
@import "helpers/colored-links";
|
||||||
|
@import "helpers/focus-ring";
|
||||||
@import "helpers/ratio";
|
@import "helpers/ratio";
|
||||||
@import "helpers/position";
|
@import "helpers/position";
|
||||||
@import "helpers/stacks";
|
@import "helpers/stacks";
|
||||||
|
@ -38,6 +38,11 @@
|
|||||||
text-decoration: if($link-hover-decoration == underline, none, null);
|
text-decoration: if($link-hover-decoration == underline, none, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: 0;
|
||||||
|
box-shadow: $nav-link-focus-box-shadow;
|
||||||
|
}
|
||||||
|
|
||||||
// Disabled state lightens text
|
// Disabled state lightens text
|
||||||
&.disabled {
|
&.disabled {
|
||||||
color: var(--#{$prefix}nav-link-disabled-color);
|
color: var(--#{$prefix}nav-link-disabled-color);
|
||||||
|
@ -127,6 +127,15 @@
|
|||||||
@each $name, $value in $grid-breakpoints {
|
@each $name, $value in $grid-breakpoints {
|
||||||
--#{$prefix}breakpoint-#{$name}: #{$value};
|
--#{$prefix}breakpoint-#{$name}: #{$value};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Focus styles
|
||||||
|
// scss-docs-start root-focus-variables
|
||||||
|
--#{$prefix}focus-ring-width: #{$focus-ring-width};
|
||||||
|
--#{$prefix}focus-ring-opacity: #{$focus-ring-opacity};
|
||||||
|
--#{$prefix}focus-ring-color: #{$focus-ring-color};
|
||||||
|
// By default, there is no `--bs-focus-ring-x`, `--bs-focus-ring-y`, or `--bs-focus-ring-blur`, but we provide CSS variables with fallbacks to initial `0` values
|
||||||
|
--#{$prefix}focus-ring-box-shadow: var(--#{$prefix}focus-ring-x, 0) var(--#{$prefix}focus-ring-y, 0) var(--#{$prefix}focus-ring-blur, 0) var(--#{$prefix}focus-ring-width) var(--#{$prefix}focus-ring-color);
|
||||||
|
// scss-docs-end root-focus-variables
|
||||||
}
|
}
|
||||||
|
|
||||||
@if $enable-dark-mode {
|
@if $enable-dark-mode {
|
||||||
|
@ -84,6 +84,14 @@ $utilities: map-merge(
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
// scss-docs-end utils-shadow
|
// scss-docs-end utils-shadow
|
||||||
|
// scss-docs-start utils-focus-ring
|
||||||
|
"focus-ring": (
|
||||||
|
css-var: true,
|
||||||
|
css-variable-name: focus-ring-color,
|
||||||
|
class: focus-ring,
|
||||||
|
values: map-loop($theme-colors-rgb, rgba-css-var, "$key", "focus-ring")
|
||||||
|
),
|
||||||
|
// scss-docs-end utils-focus-ring
|
||||||
// scss-docs-start utils-position
|
// scss-docs-start utils-position
|
||||||
"position": (
|
"position": (
|
||||||
property: position,
|
property: position,
|
||||||
|
@ -549,6 +549,14 @@ $box-shadow-inset: inset 0 1px 2px rgba(var(--#{$prefix}body-color-rg
|
|||||||
$component-active-color: $white !default;
|
$component-active-color: $white !default;
|
||||||
$component-active-bg: $primary !default;
|
$component-active-bg: $primary !default;
|
||||||
|
|
||||||
|
// scss-docs-start focus-ring-variables
|
||||||
|
$focus-ring-width: .25rem !default;
|
||||||
|
$focus-ring-opacity: .25 !default;
|
||||||
|
$focus-ring-color: rgba($primary, $focus-ring-opacity) !default;
|
||||||
|
$focus-ring-blur: 0 !default;
|
||||||
|
$focus-ring-box-shadow: 0 0 $focus-ring-blur $focus-ring-width $focus-ring-color !default;
|
||||||
|
// scss-docs-end focus-ring-variables
|
||||||
|
|
||||||
// scss-docs-start caret-variables
|
// scss-docs-start caret-variables
|
||||||
$caret-width: .3em !default;
|
$caret-width: .3em !default;
|
||||||
$caret-vertical-align: $caret-width * .85 !default;
|
$caret-vertical-align: $caret-width * .85 !default;
|
||||||
@ -761,11 +769,11 @@ $input-btn-font-family: null !default;
|
|||||||
$input-btn-font-size: $font-size-base !default;
|
$input-btn-font-size: $font-size-base !default;
|
||||||
$input-btn-line-height: $line-height-base !default;
|
$input-btn-line-height: $line-height-base !default;
|
||||||
|
|
||||||
$input-btn-focus-width: .25rem !default;
|
$input-btn-focus-width: $focus-ring-width !default;
|
||||||
$input-btn-focus-color-opacity: .25 !default;
|
$input-btn-focus-color-opacity: $focus-ring-opacity !default;
|
||||||
$input-btn-focus-color: rgba($component-active-bg, $input-btn-focus-color-opacity) !default;
|
$input-btn-focus-color: $focus-ring-color !default;
|
||||||
$input-btn-focus-blur: 0 !default;
|
$input-btn-focus-blur: $focus-ring-blur !default;
|
||||||
$input-btn-focus-box-shadow: 0 0 $input-btn-focus-blur $input-btn-focus-width $input-btn-focus-color !default;
|
$input-btn-focus-box-shadow: $focus-ring-box-shadow !default;
|
||||||
|
|
||||||
$input-btn-padding-y-sm: .25rem !default;
|
$input-btn-padding-y-sm: .25rem !default;
|
||||||
$input-btn-padding-x-sm: .5rem !default;
|
$input-btn-padding-x-sm: .5rem !default;
|
||||||
@ -918,7 +926,7 @@ $form-check-input-border: var(--#{$prefix}border-width) solid va
|
|||||||
$form-check-input-border-radius: .25em !default;
|
$form-check-input-border-radius: .25em !default;
|
||||||
$form-check-radio-border-radius: 50% !default;
|
$form-check-radio-border-radius: 50% !default;
|
||||||
$form-check-input-focus-border: $input-focus-border-color !default;
|
$form-check-input-focus-border: $input-focus-border-color !default;
|
||||||
$form-check-input-focus-box-shadow: $input-btn-focus-box-shadow !default;
|
$form-check-input-focus-box-shadow: $focus-ring-box-shadow !default;
|
||||||
|
|
||||||
$form-check-input-checked-color: $component-active-color !default;
|
$form-check-input-checked-color: $component-active-color !default;
|
||||||
$form-check-input-checked-bg-color: $component-active-bg !default;
|
$form-check-input-checked-bg-color: $component-active-bg !default;
|
||||||
@ -1124,6 +1132,8 @@ $nav-link-color: var(--#{$prefix}link-color) !default;
|
|||||||
$nav-link-hover-color: var(--#{$prefix}link-hover-color) !default;
|
$nav-link-hover-color: var(--#{$prefix}link-hover-color) !default;
|
||||||
$nav-link-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out !default;
|
$nav-link-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out !default;
|
||||||
$nav-link-disabled-color: var(--#{$prefix}secondary-color) !default;
|
$nav-link-disabled-color: var(--#{$prefix}secondary-color) !default;
|
||||||
|
$nav-link-disabled-color: $gray-600 !default;
|
||||||
|
$nav-link-focus-box-shadow: $focus-ring-box-shadow !default;
|
||||||
|
|
||||||
$nav-tabs-border-color: var(--#{$prefix}border-color) !default;
|
$nav-tabs-border-color: var(--#{$prefix}border-color) !default;
|
||||||
$nav-tabs-border-width: var(--#{$prefix}border-width) !default;
|
$nav-tabs-border-width: var(--#{$prefix}border-width) !default;
|
||||||
@ -1265,7 +1275,7 @@ $pagination-border-color: var(--#{$prefix}border-color) !default;
|
|||||||
|
|
||||||
$pagination-focus-color: var(--#{$prefix}link-hover-color) !default;
|
$pagination-focus-color: var(--#{$prefix}link-hover-color) !default;
|
||||||
$pagination-focus-bg: var(--#{$prefix}secondary-bg) !default;
|
$pagination-focus-bg: var(--#{$prefix}secondary-bg) !default;
|
||||||
$pagination-focus-box-shadow: $input-btn-focus-box-shadow !default;
|
$pagination-focus-box-shadow: $focus-ring-box-shadow !default;
|
||||||
$pagination-focus-outline: 0 !default;
|
$pagination-focus-outline: 0 !default;
|
||||||
|
|
||||||
$pagination-hover-color: var(--#{$prefix}link-hover-color) !default;
|
$pagination-hover-color: var(--#{$prefix}link-hover-color) !default;
|
||||||
@ -1665,8 +1675,9 @@ $btn-close-height: $btn-close-width !default;
|
|||||||
$btn-close-padding-x: .25em !default;
|
$btn-close-padding-x: .25em !default;
|
||||||
$btn-close-padding-y: $btn-close-padding-x !default;
|
$btn-close-padding-y: $btn-close-padding-x !default;
|
||||||
$btn-close-color: $black !default;
|
$btn-close-color: $black !default;
|
||||||
$btn-close-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$btn-close-color}'><path d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/></svg>") !default;
|
|
||||||
$btn-close-focus-shadow: $input-btn-focus-box-shadow !default;
|
$btn-close-focus-shadow: $input-btn-focus-box-shadow !default;
|
||||||
|
$btn-close-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$btn-close-color}'><path d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/></svg>") !default;
|
||||||
|
$btn-close-focus-shadow: $focus-ring-box-shadow !default;
|
||||||
$btn-close-opacity: .5 !default;
|
$btn-close-opacity: .5 !default;
|
||||||
$btn-close-hover-opacity: .75 !default;
|
$btn-close-hover-opacity: .75 !default;
|
||||||
$btn-close-focus-opacity: 1 !default;
|
$btn-close-focus-opacity: 1 !default;
|
||||||
|
5
scss/helpers/_focus-ring.scss
Normal file
5
scss/helpers/_focus-ring.scss
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.focus-ring:focus {
|
||||||
|
outline: 0;
|
||||||
|
// By default, there is no `--bs-focus-ring-x`, `--bs-focus-ring-y`, or `--bs-focus-ring-blur`, but we provide CSS variables with fallbacks to initial `0` values
|
||||||
|
box-shadow: var(--#{$prefix}focus-ring-x, 0) var(--#{$prefix}focus-ring-y, 0) var(--#{$prefix}focus-ring-blur, 0) var(--#{$prefix}focus-ring-width) var(--#{$prefix}focus-ring-color);
|
||||||
|
}
|
@ -397,3 +397,8 @@
|
|||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.focused {
|
||||||
|
outline: 0;
|
||||||
|
box-shadow: var(--#{$variable-prefix}focus-ring-offset), var(--#{$variable-prefix}focus-ring-x, 0) var(--#{$variable-prefix}focus-ring-y, 0) var(--#{$variable-prefix}focus-ring-blur) var(--#{$variable-prefix}focus-ring-width) var(--#{$variable-prefix}focus-ring-color);
|
||||||
|
}
|
||||||
|
@ -74,6 +74,20 @@ a {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Focus variables
|
||||||
|
|
||||||
|
{{< added-in "5.3.0" >}}
|
||||||
|
|
||||||
|
Bootstrap provides custom `:focus` styles using a combination of Sass and CSS variables that can be optionally added to specific components and elements. We do not yet globally override all `:focus` styles.
|
||||||
|
|
||||||
|
In our Sass, we set default values that can be customized before compiling.
|
||||||
|
|
||||||
|
{{< scss-docs name="focus-ring-variables" file="scss/_variables.scss" >}}
|
||||||
|
|
||||||
|
Those variables are then reassigned to `:root` level CSS variables that can be customized in real-time, including with options for `x` and `y` offsets (which default to their fallback value of `0`).
|
||||||
|
|
||||||
|
{{< scss-docs name="root-focus-variables" file="scss/_root.scss" >}}
|
||||||
|
|
||||||
## Grid breakpoints
|
## Grid breakpoints
|
||||||
|
|
||||||
While we include our grid breakpoints as CSS variables (except for `xs`), be aware that **CSS variables do not work in media queries**. This is by design in the CSS spec for variables, but may change in coming years with support for `env()` variables. Check out [this Stack Overflow answer](https://stackoverflow.com/a/47212942) for some helpful links. In the meantime, you can use these variables in other CSS situations, as well as in your JavaScript.
|
While we include our grid breakpoints as CSS variables (except for `xs`), be aware that **CSS variables do not work in media queries**. This is by design in the CSS spec for variables, but may change in coming years with support for `env()` variables. Check out [this Stack Overflow answer](https://stackoverflow.com/a/47212942) for some helpful links. In the meantime, you can use these variables in other CSS situations, as well as in your JavaScript.
|
||||||
|
60
site/content/docs/5.3/helpers/focus-ring.md
Normal file
60
site/content/docs/5.3/helpers/focus-ring.md
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
layout: docs
|
||||||
|
title: Focus ring
|
||||||
|
description: Utility classes that allows you to add and modify custom focus ring styles to elements and components.
|
||||||
|
group: helpers
|
||||||
|
toc: true
|
||||||
|
added: "5.3"
|
||||||
|
---
|
||||||
|
|
||||||
|
The `.focus-ring` helper removes the default `outline` on `:focus`, replacing it with a `box-shadow` that can be more broadly customized. The new shadow is made up of a series of CSS variables, inherited from the `:root` level, that can be modified for any element or component.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Click into the example below and press <kbd>Tab</kbd> to see the focus ring in action.
|
||||||
|
|
||||||
|
{{< example >}}
|
||||||
|
<a href="#" class="d-inline-flex focus-ring py-1 px-2 text-decoration-none border rounded-2">
|
||||||
|
Custom focus ring
|
||||||
|
</a>
|
||||||
|
{{< /example >}}
|
||||||
|
|
||||||
|
## Customize
|
||||||
|
|
||||||
|
Modify the styling of a focus ring with our CSS variables, Sass variables, utilities, or custom styles.
|
||||||
|
|
||||||
|
### CSS variables
|
||||||
|
|
||||||
|
Modify the `--bs-focus-ring-*` CSS variables as needed to change the default appearance.
|
||||||
|
|
||||||
|
{{< example >}}
|
||||||
|
<a href="#" class="d-inline-flex focus-ring py-1 px-2 text-decoration-none border rounded-2" style="--bs-focus-ring-color: rgba(var(--bs-success-rgb), .25)">
|
||||||
|
Green focus ring
|
||||||
|
</a>
|
||||||
|
{{< /example >}}
|
||||||
|
|
||||||
|
`.focus-ring` sets styles via global CSS variables that can be overridden on any parent element, as shown above. These variables are generated from their Sass variable counterparts.
|
||||||
|
|
||||||
|
{{< scss-docs name="root-focus-variables" file="scss/_root.scss" >}}
|
||||||
|
|
||||||
|
### Sass
|
||||||
|
|
||||||
|
Customize the focus ring Sass variables to modify all usage of the focus ring styles across your Bootstrap-powered project.
|
||||||
|
|
||||||
|
{{< scss-docs name="focus-ring-variables" file="scss/_variables.scss" >}}
|
||||||
|
|
||||||
|
### Utilities
|
||||||
|
|
||||||
|
In addition to `.focus-ring`, we have several `.focus-ring-*` utilities to modify the helper class defaults. Modify the color with any of our [theme colors]({{< docsref "/customize/color#theme-colors" >}}). Note that the light and dark variants may not be visible on all background colors given current color mode support.
|
||||||
|
|
||||||
|
{{< example >}}
|
||||||
|
{{< focus-ring.inline >}}
|
||||||
|
{{- range (index $.Site.Data "theme-colors") }}
|
||||||
|
<p><a href="#" class="d-inline-flex focus-ring focus-ring-{{ .name }} py-1 px-2 text-decoration-none border rounded-2">{{ title .name }} focus</a></p>
|
||||||
|
{{- end -}}
|
||||||
|
{{< /focus-ring.inline >}}
|
||||||
|
{{< /example >}}
|
||||||
|
|
||||||
|
Focus ring utilities are declared in our utilities API in `scss/_utilities.scss`. [Learn how to use the utilities API.]({{< docsref "/utilities/api#using-the-api" >}})
|
||||||
|
|
||||||
|
{{< scss-docs name="utils-focus-ring" file="scss/_utilities.scss" >}}
|
@ -104,6 +104,7 @@
|
|||||||
- title: Clearfix
|
- title: Clearfix
|
||||||
- title: Color & background
|
- title: Color & background
|
||||||
- title: Colored links
|
- title: Colored links
|
||||||
|
- title: Focus ring
|
||||||
- title: Position
|
- title: Position
|
||||||
- title: Ratio
|
- title: Ratio
|
||||||
- title: Stacks
|
- title: Stacks
|
||||||
|
Loading…
Reference in New Issue
Block a user