diff --git a/.claude/rules/formats/sass-theming.md b/.claude/rules/formats/sass-theming.md index 99f421dc775..5b27b016298 100644 --- a/.claude/rules/formats/sass-theming.md +++ b/.claude/rules/formats/sass-theming.md @@ -6,6 +6,7 @@ paths: - "src/format/reveal/format-reveal-theme*" - "src/format/dashboard/format-dashboard-shared*" - "src/resources/formats/**/*.scss" + - "src/resources/projects/**/*.scss" --- # Sass Theming @@ -22,3 +23,50 @@ background-color: var(--r-background-color, $body-bg); Read `llm-docs/sass-theming-architecture.md` for full compilation pipeline details. For the three-tier callout CSS architecture (Bootstrap, RevealJS, standalone HTML), see `llm-docs/callout-styling-html.md`. + +## Keyboard focus ring (Bootstrap formats) + +One rule in `_bootstrap-rules.scss` draws the focus ring for every focusable +element: `:focus-visible`. The `focus-ring` mixin in +`_bootstrap-mixins.scss` defines the ring. Do not add focus rules for one +control. A rule with a higher specificity replaces part of the ring on that +control. + +- The global rule has specificity (0,1,0) on purpose, so that author rules + such as `a:focus-visible` (0,1,1) win. Do not raise it. +- Bootstrap removes the outline with (0,2,0) rules (`.btn:focus-visible`, + `.nav-link:focus-visible`, `.form-control:focus`, ...). A second rule lists + these classes and includes the ring again. MathJax removes the outline on + `mjx-speech` at runtime, so `:root mjx-speech:focus-visible` (0,2,1) puts + it back. Add a rule only if Bootstrap or a bundled library removes the + outline. +- The inner tone is `box-shadow: var(--quarto-focus-ring-shadow)`. The + property is set on `:root`. An author can remove the inner tone with + `--quarto-focus-ring-shadow: none`. Use the property, not + `$focus-ring-inner-shadow`, in any rule that adds to the ring. + +- One exception is the search box. Its visible field is `.aa-Form`, which + holds a borderless `.aa-Input`. The form gets `@include focus-ring` when the + input has focus, and the input gets no ring. +- Another exception is pagination. Some Bootswatch themes (vapor, zephyr) + give `.page-link` a `box-shadow` with a higher specificity, so a + `(0,4,0)` rule includes the ring again. + +- The ring follows W3C technique C40. The outer color is an `outline` + (`$focus-ring-outline-width`, 2px). The inner color is a `box-shadow` that + fills the `outline-offset` (`$focus-ring-outline-offset`, 2px). Both are + public `!default` variables in `_bootstrap-variables.scss`. +- On a dark page (`$body-bg` has more contrast with white than with black), + the derived tones swap: white goes on the `outline`. The test is per + stylesheet, not per `light:`/`dark:` key. If a user sets + `$focus-ring-outer-color` or `$focus-ring-inner-color`, nothing swaps. +- The outer color is the `outline` because Bootswatch themes often set + `box-shadow` on controls, but rarely `outline`. Forced-colors mode also + keeps the `outline`. +- `_bootstrap-variables.scss` sets Bootstrap's focus halos to `none`. Do not + turn them on again. +- If an element must not show the ring, set both `outline: none` and + `box-shadow: none`. An example is `#quarto-document-content`, which gets + focus from the skip link. +- If a scroll container clips the ring, add `$focus-ring-extent` of padding + on that side. The TOC sidebars and the collapsed navbar menu are examples. diff --git a/news/changelog-1.11.md b/news/changelog-1.11.md index 63e16dd8fd2..d010245be08 100644 --- a/news/changelog-1.11.md +++ b/news/changelog-1.11.md @@ -24,6 +24,7 @@ All changes included in 1.11: - ([#14615](https://github.com/quarto-dev/quarto-cli/issues/14615)): Fix invalid `role="menu"` on the website navbar's collapse toggle button, flagged by axe-core (`aria-allowed-role`) and WAVE (`aria-role-mismatch`). - ([#12116](https://github.com/quarto-dev/quarto-cli/issues/12116), [#4935](https://github.com/quarto-dev/quarto-cli/issues/4935)): Website sidebar section toggles are now `