A CSS audit can mean several different things. One team wants to remove unused declarations. Another wants to fix specificity. A third wants to know whether the codebase still needs the workarounds it collected over the last eight years. If you do not define the question first, the report becomes a long list of facts with no clear decision attached.

This guide focuses on a modernization audit: finding custom HTML, CSS, and JavaScript that the browser can now handle natively. It is a practical way to modernize a website without treating old code as automatically bad.

Define what the CSS audit will answer

Write the audit question in one sentence. For example: "Which public-page workarounds can we replace with well-supported HTML and CSS without changing behavior?" That sentence sets useful boundaries.

  • Choose the page or user journey you will inspect.
  • List the browsers and assistive technology combinations the team supports.
  • Decide whether the audit covers CSS architecture, unused code, performance, or only modern replacements.
  • Record states that require authentication or business data and cannot be reached from a public page.

Keep the promise narrow. A modernization scan is not a full accessibility, performance, security, or design-system audit. Those reviews need different evidence.

Inspect the rendered page, not only the CSS files

Static source tells you what code exists. It does not tell you which code controls the interface a visitor can see. A class called .modal might be a real dialog, a non-modal panel, or a dead style left behind after a redesign. The rendered page gives the code context.

Open the target in a fresh browser profile and exercise safe, reversible interactions:

  • Scroll through the whole page so lazy content and scroll-linked behavior can appear.
  • Open menus, disclosures, dialogs, filters, and tooltips.
  • Use the keyboard, not only the pointer.
  • Check narrow and wide layouts.
  • Respect reduced-motion and dark-mode preferences.

Do not submit forms, follow destructive actions, or click controls whose result is unclear. The point is to observe states, not to test a production site's tolerance for automation.

Capture the code that drives each behavior

A recommendation needs a chain of evidence. Save the trigger, the element whose state changes, the relevant styles, and the script that connects them. A DOM mutation by itself is not enough. It may show that a panel became visible, but not how or why.

For each candidate, record:

  • The visible component and where it appears on the page
  • The control that opens, closes, selects, or updates it
  • The DOM attributes and classes before and after interaction
  • The CSS rules responsible for layout, state, and motion
  • The readable JavaScript that drives the same behavior

Minified bundles can be useful evidence, but they are easy to overread. If you cannot connect a snippet to the observed component, lower your confidence or leave the candidate out.

Look for canonical replacement patterns

A defined pattern catalog keeps the review repeatable. It also prevents the audit from turning every unusual class name into a recommendation. Useful starting categories include:

  • Scripted disclosures that match <details> and <summary>
  • Custom modal shells that match <dialog>
  • Non-modal floating panels that match the Popover API
  • Parent state classes that only mirror a selector relationship expressible with :has()
  • Viewport-dependent components that would be clearer with container queries
  • Scroll or entry effects that CSS can own while preserving reduced-motion behavior

A match is a candidate, not a verdict. A custom dropdown may carry search, virtualized options, analytics, and product rules that a native popover does not replace. Describe the boundary instead of pretending the new API deletes everything.

Check browser support against the real audience

Modern CSS is not a single compatibility level. <dialog> is widely available. The Popover API is newer. A recently shipped CSS feature may work across current browsers but miss older devices still present in your analytics.

Use Web Platform Baseline to understand cross-browser availability, then compare the feature with your Browserslist target and traffic. Finally, test the failure mode. A missing transition is often acceptable. A control that cannot open is not.

  • Does unsupported CSS get ignored without hiding content?
  • Can @supports isolate the enhancement?
  • Does the native element preserve the keyboard and focus behavior users rely on?
  • Will the team need a polyfill, and is that still simpler than the current code?

Write findings that someone can act on

A useful finding should let a developer understand the opportunity in one pass. Keep the structure consistent:

  1. Current implementation: the relevant HTML, CSS, and readable JavaScript.
  2. Possible replacement: the native feature and a small code example.
  3. Why it may help: the specific custom behavior or workaround it could remove.
  4. Found in: the component name and selectors that connect the finding to the page.
  5. To verify: the behavior that must remain intact before the team ships the change.

Current implementation

<div class="profile-menu" hidden>...</div>

trigger.addEventListener("click", toggleMenu);
document.addEventListener("click", closeOutside);
document.addEventListener("keydown", closeOnEscape);

Possible replacement

<button popovertarget="profile-menu">
  Profile
</button>

<div id="profile-menu" popover>
  ...
</div>

The final note might say: "Verify focus movement, outside-click behavior, Escape dismissal, positioning, and analytics before deleting the current listeners." That sentence changes the recommendation from a code sample into a migration task.

Run a separate pass for mechanical CSS quick wins

Behavioral findings need interaction evidence. Some CSS improvements can be matched directly in stylesheets and reviewed separately:

  • Percentage-padding boxes that can use aspect-ratio
  • top: 50% plus transforms used only for centering
  • 100vh layouts that should use dynamic or small viewport units
  • Paired left and right spacing that can use logical properties
  • Resolution media queries that can use image-set()
  • Negative decorative layers that need isolation: isolate

Keep the original values in the recommendation. A quick win should be a small rewrite, not a redesign disguised as cleanup.

Automate the search, not the decision

Automation is good at collecting stylesheets, observing DOM changes, and matching known syntax. It is less good at deciding whether two interactions are equivalent. A scanner should require evidence for a supported pattern and prefer a missed finding over a broad guess.

That is how CSS Radar is built. It renders one public page in Chrome, explores safe interactions, checks a fixed catalog, and rejects leads that do not have enough evidence. The report gives you a possible replacement and a review checklist. It does not patch production code for you.

The outcome of a good audit is not more findings. It is a shorter list of changes a team can understand, test, and either accept or reject.

Primary references