Skip to content

Soften the tab label hover colour so it is not the active colour - #303

Open
dchaudhari7177 wants to merge 1 commit into
executablebooks:mainfrom
dchaudhari7177:fix/tabs-label-hover-not-active-colour
Open

Soften the tab label hover colour so it is not the active colour#303
dchaudhari7177 wants to merge 1 commit into
executablebooks:mainfrom
dchaudhari7177:fix/tabs-label-hover-not-active-colour

Conversation

@dchaudhari7177

Copy link
Copy Markdown

Closes #301.

Confirmed at 4f66f32

style/design.toml lines 29-30 carried the same literal:

["--sd-color-tabs-label-active", "hsla(231, 99%, 66%, 1)"],
["--sd-color-tabs-label-hover",  "hsla(231, 99%, 66%, 1)"],

and style/tabs.css:28 applies the hover token to the unselected label:

.sd-tab-set > input:not(:checked) + label:hover {
  color: var(--sd-color-tabs-label-hover);
  border-color: var(--sd-color-tabs-underline-hover);
}

So a hovered unselected tab rendered in exactly the selected tab's colour, leaving underline saturation as the only remaining cue — which is the "two active tabs" reading described in the issue.

The suggested 0.62 ratio does not transfer to the label

The issue proposes muting the label with the same ratio the hover underline uses. I measured it before adopting it, and it inverts the problem:

over white
label-inactive hsl(0, 0%, 66%) 2.38:1
hsla(231,99%,66%,0.62)rgb(148,164,254) 2.33:1 ← the suggested value

Those are the same colour to the eye — 1.02:1 between them. It would swap the collision with active for a collision with inactive, and lose the hover affordance completely. Alpha also composites against whatever is behind the label, so it behaves differently on a dark background, whereas the underline can afford that because it sits on a known surface.

What this uses instead

A solid lighter form of the active hue, hsla(231, 99%, 72%, 1), positioned between the two neighbours it must stay distinct from:

token value vs white
--sd-color-tabs-label-inactive hsl(0, 0%, 66%) 2.38:1
--sd-color-tabs-label-hover hsla(231, 99%, 72%, 1) 3.21:1
--sd-color-tabs-label-active hsla(231, 99%, 66%, 1) 4.26:1

It is near-equidistant from both (1.35:1 against inactive, 1.33:1 against active), so hover is unmistakably an affordance and unmistakably not selected.

Generated CSS

Regenerated with python tools/generate_css.py. The diff in sphinx-design.min.css is a single character-level change6672 in the tabs-label-hover value — which I verified with a difflib.SequenceMatcher opcode dump rather than eyeballing the minified line.

Full suite: 173 passed, 100 skipped. (tests/test_snippets.py needs pytest-regressions; without it those cases error on a missing file_regression fixture on a clean tree too.)

One thing worth your call

design.toml is a flat name/value list, so this is a static literal. The semantic colours already have a nicer story — the generator emits a color-mix(in srgb, black 15%, var(--sd-color-<name>)) line after the static value so downstream overrides propagate to the hover shade. A theme that overrides --sd-color-tabs-label-active with its brand colour will not get a matching hover here; it still has to override -label-hover too, exactly as today.

Deriving it as color-mix(in srgb, var(--sd-color-tabs-label-active) ~70%, var(--sd-color-tabs-label-inactive)) would fix that class of problem for every theme at once, but it needs the generator to emit a second declaration for a non-[[colors]] token, which felt like a bigger change than this bug warrants. Happy to do it in this PR if you'd prefer that shape.

style/design.toml gave --sd-color-tabs-label-hover the identical literal to
--sd-color-tabs-label-active, while the hover underline was already softened
(--sd-color-tabs-underline-hover, 0.62 alpha). tabs.css:28 applies the hover token
to input:not(:checked) + label:hover, so hovering an unselected tab rendered its
label in exactly the selected tab's colour and underline saturation became the only
cue to which tab was open. On a site theming these tokens with a strong brand
colour that reads as two active tabs.

The issue suggests reusing the underline's 0.62 ratio on the label. Measured, that
does not work: hsla(231,99%,66%,0.62) composites over white to rgb(148,164,254),
2.33:1, which is indistinguishable from --sd-color-tabs-label-inactive at 2.38:1
(1.02:1 between them). It would trade one collision for the opposite one and lose
the hover affordance entirely. Alpha also composites against whatever sits behind
the label, so it behaves differently on a dark background.

Used a solid lighter form of the active hue instead, hsla(231, 99%, 72%, 1), which
lands between the two neighbours it has to stay distinct from - contrast against
white:

  label-inactive  hsl(0, 0%, 66%)        2.38:1
  label-hover     hsla(231,99%,72%,1)    3.21:1   (1.35:1 vs inactive, 1.33:1 vs active)
  label-active    hsla(231,99%,66%,1)    4.26:1

Near-equidistant from both, so hover is clearly an affordance and clearly not
selected.

Regenerated sphinx-design.min.css with tools/generate_css.py; the generated diff is
a single character-level change, '66' -> '72' in the tabs-label-hover value.

Full suite: 173 passed, 100 skipped.

Closes executablebooks#301
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tabs: hovering an unselected tab shows the full active label colour

1 participant