🌞

Advanced CSS Techniques

Master powerful selectors, pseudo-elements, CSS counters, and specificity management to write sophisticated, maintainable stylesheets

Modern Complex Selectors

CSS has evolved with powerful new selectors that make targeting elements easier and more maintainable. Let's explore :is(), :where(), and :not().

The :is() Selector

The :is() selector simplifies complex selector lists. Instead of repeating selectors, you can group them together. It's a huge time-saver!

Heading in Section

Heading in Article

/* Without :is() - repetitive */
section h4,
article h4,
aside h4 {
  color: #2563eb;
  font-weight: 700;
}

/* With :is() - clean and maintainable */
:is(section, article, aside) h4 {
  color: #2563eb;
  font-weight: 700;
}

The :where() Selector

The :where() selector works like :is() but with zero specificity. This makes it perfect for base styles that you want to easily override.

/* :where() has zero specificity - easy to override */
:where(a) {
  color: #64748b;
  text-decoration: none;
}

/* Simple class selector wins */
.link-special {
  color: #7c3aed;
  font-weight: 600;
}

The :not() Selector

The :not() selector is your exclusion tool. Style everything except certain elements - incredibly powerful for edge cases.

/* Style all buttons except .primary */
button:not(.primary) {
  background: #f1f5f9;
  color: #334155;
  border: 1px solid #cbd5e1;
}

button.primary {
  background: #2563eb;
  color: white;
  border: none;
}

💡 Specificity Tip

:is() takes the specificity of its most specific argument, while :where() always has zero specificity. Use :where() for reusable base styles and :is() when you need more control.

Pseudo-elements Deep Dive

Pseudo-elements let you style specific parts of an element or add decorative content without extra HTML. They're your secret weapon for clean, semantic markup.

::before and ::after

These are the workhorses of pseudo-elements. Create decorative elements, badges, tooltips, and more - all with CSS.

New Pro Beta
.badge::before {
  content: '★ ';
  opacity: 0.7;
}

.badge::after {
  content: ' ★';
  opacity: 0.7;
}

/* Badges with icons - no extra HTML needed! */

::first-letter and ::first-line

Style the first letter or line of text differently - perfect for drop caps, magazine-style layouts, and typographic effects.

Once upon a time, in a web far, far away, there lived a developer who discovered the magic of CSS pseudo-elements. With just a few lines of code, entire design systems came to life, creating beautiful typography without touching a single line of HTML.

.dropcap-text::first-letter {
  font-size: 3.5em;
  font-weight: 700;
  float: left;
  line-height: 0.9;
  margin: 0.1em 0.15em 0 0;
  color: #2563eb;
}

.dropcap-text::first-line {
  font-variant: small-caps;
  font-weight: 600;
  color: #475569;
}

::selection

Style the appearance of selected text. A small touch that can significantly improve your site's personality.

Try selecting this text - notice the custom selection color! This works on any text element and can match your brand colors.

::selection {
  background: #2563eb;
  color: white;
}

/* Firefox */
::-moz-selection {
  background: #2563eb;
  color: white;
}

CSS Counters

CSS counters let you create automatic numbering without JavaScript. They're perfect for step-by-step guides, nested lists, and numbered sections.

Basic Counter

Create numbered items that update automatically when you add or remove elements. No manual renumbering required!

Set up your project structure
Install dependencies
Configure your build tools
Write your first component
Test and deploy
.counter-demo {
  counter-reset: step;
}

.step-item::before {
  counter-increment: step;
  content: 'Step ' counter(step) ': ';
  font-weight: 700;
  color: #2563eb;
}

Nested Counters

Counters can be nested to create hierarchical numbering like 1.1, 1.2, 2.1, etc. Great for documentation and specifications.

Introduction
Overview
Prerequisites
Setup
Installation
Configuration
Advanced Topics
Optimization
.nested-counter-demo {
  counter-reset: section;
}

.section-item {
  counter-reset: subsection;
  counter-increment: section;
}

.section-item::before {
  content: counter(section) '. ';
  font-weight: 700;
}

.subsection-item::before {
  counter-increment: subsection;
  content: counter(section) '.' counter(subsection) ' ';
  font-weight: 600;
  color: #7c3aed;
}

Attribute Selectors

Target elements based on their attributes and attribute values. These selectors are incredibly powerful for styling forms, links, and dynamic content.

Basic Attribute Selectors

Match elements that have specific attributes, or attributes with specific values.

/* Style all inputs with type attribute */
input[type] {
  padding: 8px 12px;
  border: 2px solid #cbd5e1;
  border-radius: 6px;
}

/* Specific type values */
input[type="email"] {
  border-color: #2563eb;
}

input[type="password"] {
  border-color: #7c3aed;
}

/* Elements with disabled attribute */
button[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

Advanced Attribute Matching

Use powerful operators to match attribute values partially - perfect for styling external links, file types, or data attributes.

/* Starts with https:// */
a[href^="https://"]::after {
  content: ' ↗';
  font-size: 0.85em;
}

/* Ends with .pdf */
a[href$=".pdf"]::before {
  content: '📄 ';
}

/* Contains 'image' */
a[href*="image"]::before {
  content: '🖼️ ';
}

/* Matches word in space-separated list */
[class~="special"] {
  background: #fef3c7;
}

💡 Attribute Selector Operators

^= starts with, $= ends with, *= contains, ~= word match, |= starts with (dash-separated). These operators make attribute selectors incredibly flexible!

Combinators & Relationship Selectors

Combinators let you select elements based on their relationship to other elements. Master these and you'll write cleaner, more maintainable CSS.

Descendant Combinator (space)

Selects all descendants, no matter how deeply nested. The most common combinator you'll use.

Styled paragraph

Nested styled paragraph

/* Space = descendant combinator */
.descendant-demo p {
  color: #2563eb;
  font-weight: 600;
}

/* Matches ALL paragraphs inside, no matter how nested */

Child Combinator (>)

Selects only direct children, not deeper descendants. Great for precise targeting.

Direct child (styled)

Grandchild (not styled)

Direct child (styled)

/* > = child combinator */
.child-demo > p {
  color: #7c3aed;
  font-weight: 600;
}

/* Only matches DIRECT children, not grandchildren */

Adjacent Sibling (+) and General Sibling (~)

Select elements based on their sibling relationships. Perfect for spacing, alternating styles, and contextual design.

Heading

First paragraph (adjacent to h4)

Second paragraph (general sibling)

Third paragraph (general sibling)

/* + = adjacent sibling (immediately follows) */
h4 + p {
  font-weight: 700;
  color: #2563eb;
}

/* ~ = general sibling (any following sibling) */
h4 ~ p {
  margin-left: 16px;
  border-left: 3px solid #cbd5e1;
  padding-left: 16px;
}

Understanding & Managing Specificity

Specificity determines which CSS rules win when multiple rules target the same element. Master it to avoid !important hell.

Specificity Hierarchy

CSS specificity is calculated based on four categories (inline, IDs, classes, elements). Understanding this hierarchy is crucial.

1000 Inline Styles
100 IDs
10 Classes, Attributes, Pseudo-classes
1 Elements, Pseudo-elements
/* Specificity: 1 (one element) */
p { color: gray; }

/* Specificity: 10 (one class) */
.text { color: blue; }

/* Specificity: 100 (one ID) */
#special { color: red; }

/* Specificity: 11 (one class + one element) */
div.text { color: green; }

/* Specificity: 111 (one ID + one class + one element) */
div#special.text { color: purple; }

Specificity Best Practices

Keep specificity low and consistent. Use classes over IDs, avoid nesting too deeply, and reserve !important for truly exceptional cases.

💡 Specificity Tips

1. Prefer classes over IDs for styling
2. Keep selector chains short (2-3 levels max)
3. Use :where() for zero-specificity base styles
4. Avoid !important unless absolutely necessary
5. Organize CSS from low to high specificity

✅ Good

.button { }
.button-primary { }
.button-large { }

❌ Avoid

#header div.nav ul li a.button { }
.button { color: blue !important; }