CSS Variants
How CSS variants are injected, how to find stable selectors, and the patterns you'll reuse — plus the escape hatches when your theme fights back.
CSS is the workhorse variant type in Split Test Pro — most of your experiments will be CSS-only. This guide covers the mechanics (so you know what’s happening), how to write selectors that don’t break, and the patterns you’ll reuse across tests.
How CSS Injection Works
When a visitor lands on a page that matches an experiment’s targeting:
- The script determines which variant they’re assigned to.
- It adds a
<style data-splittestpro-experiment="css">element with the variant’s CSS to the page’s<head>. - The browser applies the rules along with the rest of the stylesheet cascade.
When that happens depends on the visit. On a visitor’s first page view, the script applies the CSS once the experiment configuration arrives from Split Test Pro, so a slow connection can show the original page for a moment. On later page views it applies the CSS synchronously, as the script loads, from a copy of the configuration cached in the browser (refreshed in the background and kept for up to 24 hours). A preview never uses the cache, so you always see your latest saved edits.
Because the style is appended to <head> after the theme’s existing stylesheets, your variant has higher specificity by position when other things are equal. For more stubborn styles, you’ll need to escalate (see “When the theme fights back” below).
Inline or Load from URL instead
The CSS tab gives you two ways to provide the stylesheet:
- Inline — write the CSS in the editor. Best for most variants.
- Load from URL instead — turn on the switch and the editor is replaced by a URL field (placeholder
https://cdn.example.com/styles.css; the field has no visible label). The script adds the file as a<link rel="stylesheet">in<head>.
The URL must be an absolute https:// address; anything else is refused when you save. If the file fails to load, the script removes the tag again and leaves the page as it was — the variant simply shows no change. Under the field, the tab reminds you: Applied to this variant only.
Finding the Right Selector
The most important skill in CSS-based testing is identifying a selector that:
- Targets exactly the element you want to change.
- Stays stable as the page is updated by your platform.
- Doesn’t accidentally hit other elements with the same class or tag.
The DevTools workflow
Open the page and inspect the element
Visit the page in Chrome or Firefox. Right-click the element you want to change and choose Inspect (F12). The Elements panel highlights the node.
Read the classes and IDs
Look at the highlighted node’s class and id attributes. You’re looking for selectors that scream “this specific element,” not “any element of this rough shape.” Prefer in roughly this order:
- IDs like
#add-to-cart(most specific, usually unique on a page). - BEM-style class names like
product-form__cart-buttonorcta--primary(descriptive, usually stable). - Data attributes like
[data-testid="add-to-cart"](often added intentionally for QA — very stable).
Test it in the console
In the DevTools Console tab, run:
document.querySelectorAll("#add-to-cart")Replace the selector with yours. The result should be exactly the elements you want to change — no more, no less. If it returns 12 elements when you wanted 1, your selector is too broad.
Selectors to avoid
- Position-based like
.products > div:nth-child(3). Re-orderings break it. - Generic tags like
buttonorh1. Almost always hits more than you want. - Auto-generated class names like
.css-1a2b3c4from CSS-in-JS frameworks. Regenerated on every build. - Whitespace-collapsed compound classes like
.btn.btn-primary.large.checkoutwhere any one is fragile. Pick the most specific stable class.
Patterns You’ll Actually Use
These are the patterns that show up in test after test. Copy and adapt.
Change a button’s color
#add-to-cart,
[data-testid="add-to-cart"],
.btn--primary {
background-color: #f5620a !important;
border-color: #f5620a !important;
color: #ffffff !important;
}
The comma-separated selector list is a defensive move — it catches the same button under whatever class name your theme actually uses.
Make a button bigger
.btn--primary {
padding: 18px 36px !important;
font-size: 18px !important;
font-weight: 700 !important;
letter-spacing: 0.02em !important;
}
Test a headline
.product__title,
h1.product-hero__heading {
font-size: 2.5rem !important;
font-weight: 700 !important;
line-height: 1.15 !important;
margin-bottom: 0.75rem !important;
}
You can’t change the text content of a headline with CSS — only its appearance. For copy changes, use a JS variant.
Hide an element
Removing UI is often a winning experiment. Try removing a promotional banner, a secondary CTA, or a trust badge:
.announcement-bar,
.promo-banner,
.featured-collection--secondary {
display: none !important;
}
Move an element via flex order
When the parent is a flex container, you can reorder children without touching markup:
.product-form {
display: flex !important;
flex-direction: column !important;
}
.product-form__description {
order: -1 !important;
}
Swap an image via background
You can’t change an <img> src with CSS alone. The workaround is to hide the original and show a different image as a background on its parent:
.product-hero__image img {
opacity: 0 !important;
}
.product-hero__image {
background-image: url("https://your-cdn.com/alternative-hero.jpg") !important;
background-size: contain !important;
background-repeat: no-repeat !important;
background-position: center !important;
min-height: 400px !important;
}
For Shopify, host the image on your store’s cdn.shopify.com URL or in your theme’s assets. For HTML, any reachable HTTPS URL works.
Test a mobile-only change
Wrap the variant in a media query:
@media (max-width: 768px) {
.btn--primary {
width: 100% !important;
padding: 16px !important;
}
}
You can also use device targeting at the experiment level — the trade-off is that device targeting gives you cleaner segmented results, while a media query lets you test responsive changes in a single experiment.
When the Theme Fights Back
If your CSS isn’t applying, the theme’s existing rule is more specific than yours. There’s a hierarchy of escape hatches, listed least to most aggressive — try them in order.
1. Add !important
Almost always sufficient:
.btn { background: orange !important; }
!important overrides any non-!important rule regardless of specificity. Use it freely in variant CSS — variant CSS is short-lived and tightly scoped, which is exactly when !important is appropriate.
2. Increase specificity by adding a parent
/* Before */
.btn { background: orange !important; }
/* More specific */
.product-form .btn--primary { background: orange !important; }
3. Repeat the class name
A trick that’s syntactically valid and bumps specificity without changing what’s matched:
.btn.btn { background: orange !important; }
.btn.btn.btn { background: orange !important; }
Each repetition adds a class-level specificity point. Reach for this only when even !important is being beaten by a style="..." inline attribute.
4. Set inline styles via JavaScript
If even repeated !important is being overridden (usually because of a style="..." attribute set by JavaScript on the page), you’ve hit CSS’s ceiling. Use a JS variant instead — it can directly manipulate element.style or remove the offending inline attribute.
Testing Your CSS Before Launching
Don’t wait for the experiment to find out the variant doesn’t render. Validate it ahead of time:
Apply your CSS in DevTools
Open the live target page. In DevTools, click the + in the Styles panel to add a new rule. Paste your variant CSS. The page updates instantly — confirm it looks right.
Check responsive
Toggle DevTools’ device emulator (Ctrl+Shift+M / Cmd+Shift+M). Cycle through mobile, tablet, desktop. The variant should look intentional at every size, not just where you authored it.
Paste into the CSS tab
Once you’re happy, paste the exact same CSS into the CSS tab of the Variants step. What you see in DevTools is what your visitors will see.
Next Steps
- Pair your CSS with logic when needed: JavaScript Variants.
- Build a library of selectors you can reuse: Selector Cookbook.
- See your variant rendered before launch: Screenshots and Preview.