Code snippets
How to Add Custom CSS to an A/B Test
★★★ Technical level 3 of 3
Written by Neil Webley · Last updated
Add scoped, responsive and accessible CSS to an A/B test without affecting unrelated pages, controls or experiments.
Quick answer
Add CSS to an A/B test with a uniquely identified stylesheet, scope every selector to the tested component or variant, and keep accessibility and responsive behaviour intact. Remove or replace only that stylesheet when cleanup is needed.
How can CSS be added to an A/B test?
For a small experiment, JavaScript can create a style element in the page head. A named stylesheet is preferable to writing many inline styles because it keeps the change inspectable, supports media queries and pseudo-classes, and can be removed cleanly.
var style = document.createElement('style');
style.id = 'experiment-pricing-layout';
style.textContent = '.pricing-card__cta { font-weight: 700; }';
document.head.appendChild(style);
Before inserting, check whether the ID already exists. Experiment code may be evaluated again after SPA navigation, and duplicate style elements make debugging and cleanup harder.
How to scope A/B test CSS safely
Use the narrowest stable ancestor that identifies the tested experience. Avoid broad selectors such as button, h2 or .container; they can change unrelated checkout, consent or account interfaces.
.pricing-experiment .pricing-card__cta {
background: #14532d;
color: #fff;
}
If practical, add an experiment class to the component and write all CSS beneath it. This creates a clear boundary and makes rollback as simple as removing the class and stylesheet.
Prefer selectors based on stable IDs, component classes or controlled data-* attributes. Deep nth-child chains are fragile when content order changes. Avoid !important unless you have inspected the site's cascade and genuinely need it.
Add CSS in a FreeCROTool hand-coded test
The Add Style code snippet uses cro_tests.addCSS(id, css):
window.cro_tests.addCSS(
'testCSS_--testID--',
[
'.pricing-experiment .pricing-card__cta {',
' background: #14532d;',
' color: #fff;',
'}',
'.pricing-experiment .pricing-card__cta:focus-visible {',
' outline: 3px solid #f59e0b;',
' outline-offset: 3px;',
'}'
].join('\n')
);
addCSS creates the style when absent and updates the same element when called again, so the ID makes it idempotent. --testID-- is case-sensitive and is replaced during publishing. Use the same ID with removeCSS. See the helper reference and safe CSS removal guide.
Preserve responsive and accessible behaviour
- Test all site breakpoints and content lengths.
- Do not remove visible keyboard focus.
- Check text and control contrast in every state.
-
Respect
prefers-reduced-motionfor new animation. - Avoid fixed heights that clip translated, zoomed or user-generated content.
- Reserve image and component dimensions to reduce layout shift.
- Do not visually reorder content in a way that disagrees with keyboard or reading order.
@media (prefers-reduced-motion: reduce) {
.pricing-experiment .pricing-card {
transition: none;
}
}
Before publishing experiment CSS
- Inspect which elements each selector matches on tested and untested pages.
- Confirm control does not receive variant-only styles.
- Navigate through SPA routes and check styles are not duplicated.
- Test hover, focus, active, disabled, loading and error states.
- Check mobile orientation, zoom and long text.
- Remove the stylesheet and confirm the original page is restored.
If CSS arrives after the original component paints, use the targeted approach in How to Prevent Page Flicker in an A/B Test.