COMMAND REFERENCE

fxcss audit

bash
fxcss audit
fxcss audit --patch fix.diff     # write the confident fixes as a patch
fxcss audit --strict             # exit non-zero if a selector needs attention
fxcss audit --strict-vars        # …or if a custom property override is dead

Upgrading a theme after Firefox moved on. inspect answers the question one selector at a time; audit does the whole theme at once. It walks every id and class your CSS mentions, resolves each against a running Firefox, and shows what to change — with the real line from your file and the replacement applied:

example
  14 selectors need attention

  RENAMED  #urlbar-background  →  .urlbar-background
           same name, now a class rather than an id

    chrome/parts/headerbar-urlbar.css:52
    - #urlbar-background {
    + .urlbar-background {

  SIMILAR  #appMenu-fullscreen-button  →  #appMenu-fullscreen-button2  (a guess, not applied)
           no exact match; closest live name is #appMenu-fullscreen-button2

    chrome/parts/icons.css:198
      #appMenu-fullscreen-button {

These examples come from findings in a long-running theme. The …-button2 pattern is how Firefox has been versioning app-menu controls, and it breaks menu styling silently.

Findings are grouped as follows:

meaning
RENAMED The same name exists, but as a class instead of an id, or the reverse. The suggestion is exact.
SIMILAR No exact counterpart, but a close name exists. Usually a Firefox suffix change, or a typo in your CSS.
offscreen Not in any state the live audit produced, but present in the markup this Firefox ships — a dialog, another platform's chrome. Healthy, and the report says which file carries it.
unresolved Nothing close. Listed separately with --all and not counted as a problem — normally an element that only appears in a state fxcss cannot reach, not one that was removed.

That last distinction is the point. Reporting every unmatched selector as broken would be noise; a theme legitimately styles things that only exist in private windows, on other platforms, or inside popups.

Suggestions are inferred from the live browser, not from a hardcoded list of Firefox versions, so they keep working for releases that came out after this tool did.

--patch writes a unified diff of the RENAMED findings only — the ones where the replacement is certain. If a replacement would repeat another selector in the same rule, that occurrence is left out of the patch and the report asks you to remove the redundant selector manually. Other safe occurrences are still patched. Review the diff, then git apply. SIMILAR findings are deliberately excluded: they are usually right, but "usually" is not good enough to rewrite your CSS unattended.

Custom properties die differently

A selector that stops matching is only half of how a theme goes stale. The other half is a custom property Firefox stops reading: the override keeps parsing, keeps resolving, and paints nothing — --in-content-page-background did exactly that, and a theme's dialog body silently rendered white under its dark palettes for months.

When fxcss can find this Firefox's omni.ja archives (it can, for every packaged build), the audit reads the shipped chrome directly and separates three cases a live probe cannot tell apart:

  • set and read by Firefox — a working override, counted quietly;
  • SET, NEVER READ — this Firefox still declares the name but no rule or script consumes it any more, so the override changes nothing;
  • DEFINED ONLY — the shipped chrome neither declares nor reads the name, with the closest consumed name suggested when there is one (--panel-background → --panel-background-color).

Reading the shipped sources also covers documents the live audit cannot open — dialogs, DevTools, in-content pages — and replaces the second, unthemed Firefox launch the probe needed.

A name you keep deliberately — for an ESR that still reads it, say — gets an inline pragma rather than a CI flag nobody finds later:

css
--in-content-page-background: var(--gnome-menu-background) !important; /* fxcss-keep: ESR 140 reads it */

--strict-vars turns dead and stale overrides into a non-zero exit for CI; fxcss-keep lines are exempt.

Unused and unreachable code

audit also reports housekeeping, in its own section, separate from breakage:

  • Stylesheets nothing imports. Files under chrome/ unreachable by following @import from userChrome.css. Sheets in a custom/ or optional/ folder are excluded — being opt-in is the point of those.
  • Custom properties used but never set, where an unthemed Firefox does not provide them either. These are usually typos: the var() silently falls back.
  • Custom properties set but read nowhere. Reported cautiously — setting --arrowpanel-background exists precisely so Firefox's own rules pick it up, so this section excludes every name an unthemed Firefox resolves.

The audit reads Firefox's shipped sources where available. Otherwise it uses a second, unthemed browser to distinguish theme-defined properties from those Firefox provides.

Pass --no-unused to skip the section.

Use --strict to fail on actionable selector findings and --strict-vars for dead custom properties. Unreachable stylesheet reports remain advisory; /* fxcss-keep */ marks deliberate property overrides.