Files
dickloads/PICO_CSS.md

3.3 KiB

Pico CSS — Gotchas & Notes

[role=button] clobbers --pico-color

Pico's stylesheet includes this rule:

[role=button], [type=button], button, ... {
  --pico-color: var(--pico-primary-inverse);
  ...
}

In light mode, --pico-primary-inverse is #fff. This means any element with role="button" will have white text by default, regardless of its background. Children inherit this, making text invisible on white/light card backgrounds.

Fix: On the element itself, reset the variable and set an explicit color:

.your-element {
  --pico-color: initial;
  color: var(--pico-contrast); /* #181c25 light / #dfe3eb dark — always legible */
}

Alternative: Remove role="button" and use tabindex="0" + keyboard handlers only, avoiding the Pico button rule entirely. Only do this if button semantics aren't needed for accessibility.

Plain buttons disappear on hover in light/Dan mode

Pico's button hover rule sets --pico-color: var(--pico-primary-inverse) (i.e. #fff) on hover, making the text white. If your button has a transparent or white background — e.g. a "plain" / ghost-style button — the text becomes invisible.

This affects any <button> element, not just [role=button]. The plain class (or similar resets) strips Pico's background/border, but does not prevent Pico from overriding the text color on hover.

Symptom: button text vanishes on hover in light or Dan mode, visible in dark mode (where the background is already dark).

Fix: Use !important on hover to override Pico's specificity, and also explicitly reset the background so you're sure nothing sneaks in:

.my-plain-button:not(:disabled):hover {
  color: var(--pico-color) !important;
  background: transparent;
}

Or, if you want a specific non-body text color on hover:

.my-plain-button:not(:disabled):hover {
  color: var(--pico-contrast) !important; /* always legible */
  background: transparent;
}

Do not rely on Pico's hover cascade for plain/ghost buttons — always override explicitly.

Palette overrides must be scoped to light mode

Pico defines its palette twice: once for light (:root:not([data-theme=dark])) and once for dark (@media (prefers-color-scheme: dark) + [data-theme=dark]). If you override Pico vars at bare :root, you'll clobber the dark mode values.

Wrong:

:root {
  --pico-color: #2C2C2C; /* kills dark mode */
}

Correct:

@media (prefers-color-scheme: light) {
  :root:not([data-theme]) { --pico-color: #2C2C2C; }
}
[data-theme=light] { --pico-color: #2C2C2C; }

Theme toggling pattern

Set data-theme="light" or data-theme="dark" on <html>. Pico reads this attribute for its palette selectors. Persist to localStorage. Read OS preference (prefers-color-scheme) on first visit when no stored value exists.

--pico-card-background-color in light mode

In light mode, Pico sets:

--pico-card-background-color: var(--pico-background-color)  →  #fff

If you want custom card backgrounds, override --pico-card-background-color directly (scoped to light mode only — see above).

CSS variables that Pico does NOT define

  • --color-label (app-defined) — must be set for both light and dark explicitly
  • Any --shadow-* vars — define at :root (theme-neutral)