Elements hardcode a hex color that exactly equals an existing global variable. Zero visual change to fix; the fix replaces the hex with var(--name). You can pick a different variable in the fix dialog — picking a non-identical color switches the fix to review tier.
Rule reference
Every one of the 33 checks Bricks Health can raise — why it matters and what to do. Rule codes are stable across releases: ignore-lists, score config and support conversations all reference them.
Severity → penalty points: critical 10 · major 5 · minor 1. Each rule's contribution to a category is capped (a pattern repeated 74× is one decision, not 74 problems), points are density-normalized on larger sites so the issue rate is what's scored — criticals stay full-weight at any size — and the total feeds a diminishing-returns curve, so fixing issues always visibly moves the score.
Design, class and performance checks cover every Bricks page and every reusable template (headers, footers, section templates) — and classes or variables used only inside a template or a component count as in-use. Responsive checks measure rendered pages only.
Design
Colors, spacing and typography consistency.
A hardcoded color is visually indistinguishable from an existing token (RGB distance ≤ 12) — usually an accidental near-duplicate like #FEF5E0 next to a #FEF5E3 token. Fixing consolidates on the token but shifts the rendered color by a hair, so it is a review-tier fix.
A hex color that matches no variable. Repeated values are strong candidates for a design token. The fix turns the color into a new global variable — or lets you assign an existing one — and swaps every usage on the page to it (creating a new variable is a zero-visual-change refactor). Only *literal* hex values are flagged: a color picked through a variable or palette swatch emits var(--name), which is the design system in use, and is never counted as hardcoded.
Most sides of a padding/margin sit exactly on a spacing token while one or two drift off by 1–2px (24/24/24/26 next to a 24px token) — usually a typo. The fix sets all sides to the token.
Odd pixel values (not divisible by 2) that match no spacing token — 13px, 37px. They accumulate into visual noise; snap them to the grid manually.
Literal font sizes set per-element instead of via theme styles or classes. Sizes referencing tokens (font-size: var(--text-xl)) are the typography scale being used and are never flagged.
Two global variables hold the same color value. Consolidate on one.
Classes
Reusable styling instead of copy-paste.
Three or more same-type elements share ≥75% of their per-element style declarations. Elements that declare different font sizes never group, whatever else they share. Elements styled through Theme Styles presets (a button set to "Primary") do not count — that is the design system working. Groups whose members already share a global class are never flagged — that reuse already exists. The fix extracts the shared declarations into a new global class, attaches it to every element in the group and strips the duplicates, so future changes become one edit.
Two or more global classes have byte-identical settings. Edits to one silently miss the others; merge them. When three or more match, the finding shows a count and lists the class names in its description rather than sprawling them across the title. BEM-structured classes are excluded — element/modifier classes and component roots are deliberately scoped per component, so identical styling is coincidental and merging would couple unrelated components.
A class no element uses. Delete it, or keep it deliberately for upcoming work.
A class used by exactly one element. Sometimes intentional structure; often a reuse plan that never happened. Safe to leave — or fold the styling onto the element and drop the class. Two shapes are excluded, because single use is by design: BEM element/modifier classes (block__element, block--modifier), and component roots — a class (.card) that a family of BEM descendants (.card__title) hangs off. Framework/library templates are built almost entirely from these. Unused (zero-use) classes are still reported.
Element-level custom CSS. Invisible to the design system; prefer a class.
Two classes on the same element set the same property to different values, so the result depends on class order. Split the shared properties or drop one. Not flagged: element-level custom CSS (two custom-CSS blocks compose rather than override), and a BEM base plus its own modifier/element (.grid + .grid--horizontal), where the descendant is meant to win.
Performance
Lean structure, right-sized media, lightweight fonts and icons.
An element's type is not registered with Bricks — its provider plugin is missing or deactivated — so it renders nothing for visitors while the builder shows a "PHP class does not exist" placeholder. Reactivate the plugin that registers the element type, or remove the orphaned elements.
A component instance whose component definition no longer exists — the component was deleted or never imported, so the instance renders nothing for visitors (just like a missing element). Re-create or re-import the component, or delete the empty instances from the page. Manual: the plugin will not guess whether you meant to remove that content.
The source upload is far larger than it ever renders. When responsive results are available, the finding measures how wide the image actually displays at each of your breakpoints and recommends a source size (displayed width × 2 for retina, capped at the original) — so you know exactly what to export. Background and URL-inserted images matter most, since those bypass WordPress’s srcset.
An image referenced by URL only — no attachment, so no width/height attributes and layout shift on load. The fix links the URL to its media-library attachment when one exists locally.
An element sits 7+ wrappers deep. Flatten pass-through wrappers. Required list semantics (ul/ol/li) are discounted from the count — a card grid built correctly as ul > li > card can’t be flattened, so those levels don’t count and what’s flagged is genuine wrapper depth.
Divs/blocks whose only child is another wrapper (canonical section > container pairs are excluded). Each is DOM weight with no layout role.
Wrappers with no child elements: editing leftovers, or spacer cells used to offset a layout (better done with spacing/grid than empty markup). A childless wrapper carrying a background image is excluded — it renders a photo, so it is not empty.
Autoplaying media (video/audio elements, background video) competes with critical content for bandwidth and is an accessibility concern. The bare autoplay key is not counted on sliders/carousels, where it means auto-advancing slides.
An unbounded query loop (posts_per_page: -1) scales render time with content growth until the page times out — flagged critical. A *finite* cap is good practice: posts_per_page is a maximum, not the actual count (a loop set to 30 renders however many posts exist, up to 30), so a sensible bound is never flagged. Only a very high finite cap (≥100) with no pagination earns a gentle nudge.
Your site pulls icons from more than one library — Font Awesome, Ionicons, Themify. Bricks loads a separate webfont for every family a page uses (Font Awesome alone is ~1MB of font files), so mixing two or three multiplies that download for a handful of glyphs. The finding lists every family in use and where each is placed. Standardize on one library — or swap the odd icons out and drop the extra font entirely.
One or more Google Fonts are in use while Bricks’ Disable Google Fonts switch is off, so every visitor’s browser connects to Google before your text can render — an extra third-party request chain that delays first paint, and an IP disclosure to Google that EU courts have treated as a GDPR violation. Families are matched against the same list Bricks itself loads from. Host the fonts locally (upload them as Bricks custom fonts or use a local-fonts plugin), point your typography at the local versions, then enable *Bricks → Settings → General → Disable Google Fonts*. The finding clears the moment the switch is on.
More than three distinct webfont families are used across your pages, templates, theme styles, classes and components. Each family — and every weight of it — is another download before text settles; most designs need two (one for headings, one for body). Consolidate on fewer families and trim unused weights. Locally-hosted custom fonts and system stacks (system-ui, Arial…) don’t count.
Tokens defined but never referenced in your Bricks content. Adopt them (the Design tab shows where hardcoded values duplicate them) or delete them — the one-click fix re-checks usage and removes only the still-unreferenced ones. Variables organized into a category (e.g. a framework’s synced palette) count as kept-by-intent and are never flagged. It can’t see external or child-theme code, so keep any tokens you use there.
Responsive
Measured in real rendered pages per breakpoint, not from data.
The page scrolls sideways at this breakpoint — the classic broken-on-mobile symptom.
An element extends past the viewport edge. Fixed widths and missing max-width: 100% are the usual causes. Each finding shows the exact overflow — e.g. *“extends 37px past the right edge — spans 0→412px in a 375px viewport”* — so it’s checkable, and sub-pixel spills under 4px (invisible to the eye) are ignored.
An image extends past the viewport edge. Usually a missing max-width: 100% on the image.
Text needs more room than its container provides.
The element sits entirely outside the visible area — visitors never see it.
A flex/grid gap over 100px at this breakpoint usually reads as a mistake.
Interactive elements below ~44px are hard to tap. Measured only at sub-800px viewports.