CSS Variants
How CSS injection works in Split Test Pro, how to find stable selectors, and the patterns you'll actually reach for — buttons, typography, hide/show, image swap, and the specificity 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 creates a
<style data-splittestpro-experiment="css">element with the variant’s CSS. - It appends the style element to the page’s
<head>, synchronously, before the page paints. - The browser applies the rules along with the rest of the stylesheet cascade.
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).
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 variant editor
Once you’re happy, paste the exact same CSS into Split Test Pro’s variant editor. 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.
Ready to start testing?
Install Split Test Pro and run your first experiment today.