← Back to Blog

The Ultimate Guide to CSS & JavaScript Selectors

From Beginner to Advanced: Master DOM targeting for styling, manipulation, and A/B testing

Selectors are one of the most fundamental concepts in front-end development. They determine which elements you target whether for styling with CSS or manipulation with JavaScript.

This guide starts with the basics and gradually moves into advanced patterns you can use in real projects, including A/B testing scripts, dynamic DOM manipulation, and powerful attribute-based selections.

1. What Are Selectors?

Selectors are patterns used to target elements in the DOM.

CSS selectors: decide what to style.
JavaScript selectors: decide what to read, change, move, clone, hide, or remove.

JavaScript uses:

const element = document.querySelector("selector");
const elements = document.querySelectorAll("selector");

2. Basic Selectors

2.1 Element Selector

/* CSS */
p { color: #333; }
// JavaScript
const paragraphs = document.querySelectorAll("p");

2.2 Class Selector

/* CSS */
.card { border-radius: 8px; }
// JavaScript
const card = document.querySelector(".card");

2.3 ID Selector

/* CSS */
#hero { height: 400px; }
// JavaScript
const hero = document.querySelector("#hero");

2.4 Universal Selector

/* CSS */
* { box-sizing: border-box; }

3. Combining Selectors

3.1 Comma Selector (Multiple)

h1, h2, h3 { font-family: sans-serif; }

3.2 Descendant Selector

nav ul li a { color: black; }

3.3 Direct Child Selector

.container > p { margin-bottom: 20px; }

3.4 Adjacent Sibling Selector

h2 + p { margin-top: -10px; }

3.5 General Sibling Selector

h2 ~ p { color: grey; }

4. Attribute Selectors

4.1 Equals

input[type="email"] { border: 2px solid blue; }

4.2 Contains (*=)

a[href*="product"] { color: green; }

4.3 Starts With (^=)

a[href^="/collections"] { font-weight: bold; }

4.4 Ends With ($=)

img[src$=".svg"] { width: 40px; }

5. CSS Pseudo-Classes

5.1 :hover

button:hover { opacity: 0.7; }

5.2 nth-child

ul li:nth-child(2) { color: red; }

5.3 :not()

.button:not(.primary) { background: #efefef; }

6. JavaScript Selector Patterns

6.1 Excluding disabled buttons

document.querySelectorAll("button:not([disabled])");

6.2 Selecting inside a container

document.querySelector(".product-card .price");

6.3 Using data attributes

document.querySelector('[data-variant="A"]');

6.4 Using closest()

element.closest(".container");

7. Advanced CSS Selectors

7.1 :has() - Parent Selector

.card:has(img) { border: 2px solid green; }

7.2 :is() - Matches Any

:is(h1, h2, h3) { color: #222; }

7.3 Conditional styles with :has()

.product-card:has(.discount) .price { color: red; }

8. Advanced JavaScript Techniques

8.1 Deep targeting

document.querySelector(".menu li:nth-child(3) a");

8.2 MutationObserver for dynamic pages

const observer = new MutationObserver(() => {
  const el = document.querySelector(".dynamic-content");
  if (el) console.log("Loaded!");
});
observer.observe(document.body, { 
  childList: true, 
  subtree: true 
});

9. Real-World Examples

9.1 Style external links

a[href^="http"]:not([href*="yourwebsite.com"]) { 
  color: orange; 
}

9.2 Select product cards with discount

document.querySelectorAll('.product-card:has(.discount)');

9.3 A/B Test: Move an element

const delivery = document.querySelector(".delivery-estimate");
const priceBox = document.querySelector(".price-wrapper");

if (delivery && priceBox) { 
  priceBox.prepend(delivery); 
}

10. Handling Dynamic Classes

Modern frameworks like Tailwind, React, or CSS Modules often generate dynamic or utility-heavy class names (e.g., .css-1a2b3c or .flex.p-4.bg-red-500). These are unreliable for A/B testing because they can change on the next build.

The Golden Rule: Never rely on a class that looks like a random string or a long list of utility classes. Look for stable attributes instead.

10.1 Target by Text Content

If an element has unique text (like a button label), use XPath or a custom helper.

// Find button with text "Add to Cart"
const btn = Array.from(document.querySelectorAll('button'))
  .find(el => el.textContent.trim() === 'Add to Cart');

10.2 Target by Attribute

Look for stable attributes like href, name, id, or aria-label.

// Unreliable
document.querySelector('.btn-primary-123');

// Reliable
document.querySelector('a[href="/checkout"]');
document.querySelector('button[aria-label="Close menu"]');

10.3 Target by Relationship

Find a stable parent or sibling and navigate from there.

// Find the stable header, then get the first button inside it
document.querySelector('header#main-nav button');

11. Best Practices

  • Prefer classes over IDs for styling
  • Keep selectors short and readable
  • Use data attributes for JavaScript hooks
  • Avoid over-nesting (max 3 levels)
  • Use modern selectors like :has() and :is()
  • Test selector performance on large DOMs
  • Use semantic HTML to reduce selector complexity

Need Help with A/B Testing?

Let's optimize your website together using advanced selector techniques.