Techniques - the Experience Cloud specialty

Techniques, tips, and tricks

The Salesforce-grade patterns that survive release upgrades, plus the debugging moves that find the real problem in minutes instead of hours. These are tuned for Experience Cloud's worst-case churn - which is exactly why the same discipline holds up on any site you style.

Scope everything, always

Anchor every rule to one wrapper so your CSS cannot leak into Experience Builder chrome or other components:

/* Aura sites */
.siteforceContentArea .slds-button_brand { background: #235789; }

/* LWR sites */
.comm-page .slds-button_brand { background: #235789; }

/* A single Lightning component, e.g. an OmniScript */
.vlocity-omniscript .slds-input { border-radius: 6px; }

Never write rules against body, html, or the universal selector on a portal. The one exception to broad scoping: a component stylesheet attached as a static resource already loads inside the component context, so its selectors can start from the component's own classes directly.

Tokens first, CSS second

Set brand colors, radius, and spacing through the Lightning Design System Design Tokens field before writing CSS. Tokens flow into places your selectors cannot reach (LWR shadow DOM, component internals), survive DOM changes between releases, and keep your CSS file small. Then use the stylesheet for the things tokens cannot express: layout, specific component shapes, and Safari coverage.

Precision targeting with your own names

Many Lightning components render with stable attributes that carry a name you chose, not a churned class. OmniScript elements expose a data-omni-key with the element name from the designer; FlexCard elements carry data-style-id and data-test-id. These are the most precise stable handles you have:

/* One specific field, by its element name */
[data-omni-key="CustomerFirstName"] .slds-input {
  font-weight: 600;
}

/* One FlexCard element */
[data-test-id="NewQuote"] .vlocity-btn {
  min-width: 160px;
}

Because the attribute value is your own element name, it changes only when you rename the element. This beats any class-chain guesswork.

Beating inline styles

Some component designers (FlexCard and OmniScript among them) write per-element choices as inline styles - icon fills, label colors, element backgrounds. Resolution order:

  1. First choice: change it in the designer. The style stays with the component definition and deploys with it.
  2. Second choice: a narrow !important override, scoped to one element via data attributes, never a blanket rule:
[data-test-id="NewQuote"] .btnLabel {
  color: #235789 !important;
}

Before reaching for !important at all, try winning on specificity: a scoped selector with two classes beats most stylesheet rules without the maintenance tax.

Debugging workflow

  1. Inspect the element and read the Computed pane in devtools. For any property, expand it to see every rule that tried to set it and which one won, with the file each came from. If the winner came from a style attribute, it is designer inline styling.
  2. Check which document you are in. If the inspector shows an iframe (dashboards) your CSS will never reach it.
  3. Test selectors live before shipping: the OmniStyler extension's Test selector action outlines every element your exact selector reaches before you commit the rule.
  4. Force states: devtools can pin :hover and :focus so you can style them without chasing the mouse.
  5. Check Safari separately: design tokens are not supported there, so confirm the stylesheet alone carries your brand.
  6. Measure before optimizing: the Network tab shows your static resource loading, and the Performance pane shows where layout and recalculation time actually goes.

Versioning and deployment hygiene

  • Upload stylesheet static resources with cache control Public, otherwise guest users may not receive them.
  • Keep one stable resource name (the component references it by name) and let the resource body change; Salesforce serves static resources with versioned URLs, so updates propagate without renaming.
  • Keep the source CSS in version control or export it from OmniStyler as JSON, so rollback is a re-upload, not a reconstruction.
  • Sandbox first, always. Test the Builder preview, the published page, a guest user, authenticated users, and a phone-width viewport.
  • Re-test after each Salesforce release. Three times a year the runtime can shift markup; your scoped, stable-class selectors will usually survive, but verify.

Performance: keep the styling cheap

  • Keep the generated CSS lean. Disable component blocks you are not using (OmniStyler's component toggles exist for this) and stay well under 50 KB.
  • Avoid universal selectors and long descendant chains inside the scope; they force wide style recalculation on every DOM change, and interactive components re-render elements as users type.
  • Prefer class and attribute selectors over :nth-child positional logic, which breaks when conditional views insert or remove elements.

Accessibility holds the brand together

Visual polish is worthless if it locks people out. The non-negotiables that survive every release:

  • Keep text contrast at 4.5:1 or better; check it before shipping, not after the complaint.
  • Never remove focus outlines, and never hide slds-assistive-text - both are accessibility plumbing the runtime relies on.
  • Don't restyle state classes like slds-hide or slds-show; component logic toggles them, and overriding their display breaks behavior.