Selectors in CSS

Selectors in CSS are patterns used to choose which HTML elements should receive a style rule. If CSS declarations are the instructions, selectors are the address system. A selector tells the browser, “apply these styles to this element, this class, this state, this relationship, or this group of elements.” Without selectors, CSS would not know where each visual rule belongs.

Learning selectors properly is important because most CSS problems are not caused by unknown properties. They are caused by rules targeting the wrong element, rules being too broad, rules being too specific, or rules being overridden by another selector. A clean selector strategy makes a stylesheet easier to read, debug, and maintain.

Basic Selector Syntax

A CSS selector appears before the declaration block. The selector chooses the target, and the declarations inside curly braces define the styles for that target.

selector {
  property: value;
}
p {
  color: #333333;
  line-height: 1.6;
}

In this example, the selector is p. It targets all paragraph elements in the document. Every matching paragraph receives the color and line height unless another CSS rule overrides those values later.

Element Selectors

An element selector targets HTML elements by tag name. It is useful for setting broad default styles for common elements such as headings, paragraphs, lists, tables, buttons, and images.

h1 {
  font-size: 40px;
}

p {
  margin-bottom: 16px;
}

Element selectors are simple and readable, but they affect every matching element. That is useful for global defaults, but risky for component-specific styling. For example, styling every button on a site may be fine for a reset, but a real design usually needs classes for different button variants.

Class Selectors

A class selector starts with a dot. It targets elements that have a matching class attribute. Class selectors are the most common selectors in real projects because classes are reusable and flexible.

.card {
  padding: 24px;
  border: 1px solid #dddddd;
  border-radius: 8px;
}
<article class="card">
  <h2>CSS Selectors</h2>
  <p>This article card uses a reusable class.</p>
</article>

The class card can be added to many elements. This makes the visual pattern reusable. A class name should describe the role or component clearly enough that another developer can understand why it exists.

ID Selectors

An ID selector starts with a hash symbol. It targets an element with a matching id attribute. IDs should be unique within a page. Because ID selectors have high specificity, they can be harder to override later.

#main-title {
  color: navy;
}

ID selectors are valid, but they are not usually the best default choice for styling. Classes are more reusable and easier to override. IDs are often better reserved for document anchors, JavaScript hooks, form labels, and unique page sections.

SelectorExampleTargets
Element selectorpAll paragraph elements
Class selector.cardElements with class card
ID selector#main-titleThe element with ID main-title
Universal selector*All elements
Grouping selectorh1, h2Both h1 and h2 elements

Universal Selector

The universal selector uses an asterisk and targets every element. It is often used in resets and box-sizing rules.

* {
  box-sizing: border-box;
}

This rule changes how width and height are calculated for all elements. It is common because it makes sizing boxes more predictable. However, the universal selector should be used carefully because it can apply to many elements at once.

Grouping Selectors

Grouping selectors let multiple selectors share the same declarations. Separate selectors with commas.

h1,
h2,
h3 {
  color: #111160;
  line-height: 1.2;
}

The comma matters. Without commas, the selector describes a descendant relationship instead of a group. This is one of the easiest mistakes to make when writing selector lists.

Descendant and Child Selectors

A descendant selector uses a space between selectors. It targets elements inside another element, no matter how deeply nested. A child selector uses the > symbol and targets only direct children.

.article p {
  line-height: 1.7;
}

.menu > li {
  display: inline-block;
}

The selector .article p targets all paragraphs inside an element with the class article. The selector .menu > li targets only list items that are direct children of .menu. If a list item is nested deeper inside another list, it will not match the child selector.

Sibling Selectors

CSS can also target elements based on sibling relationships. The adjacent sibling selector uses + and targets the next matching sibling. The general sibling selector uses ~ and targets matching siblings that come later.

h2 + p {
  margin-top: 0;
}

h2 ~ p {
  color: #333333;
}

Sibling selectors are useful when spacing depends on document flow. For example, you may want the first paragraph after a heading to have less top margin, without creating a special class for that paragraph.

Attribute Selectors

Attribute selectors target elements based on attributes and attribute values. They are useful for forms, links, accessibility states, data attributes, and special HTML patterns.

input[type="email"] {
  border-color: blue;
}

a[target="_blank"] {
  text-decoration-style: dotted;
}

The first rule targets email inputs. The second rule targets links that open in a new tab or window. Attribute selectors can also match values that start with, end with, or contain certain text.

Pseudo-Classes

Pseudo-classes target a special state or position of an element. They start with a single colon. Common examples include :hover, :focus, :first-child, :last-child, and :nth-child().

a:hover {
  color: crimson;
}

input:focus {
  outline: 2px solid blue;
}

li:nth-child(odd) {
  background-color: #f5f5f5;
}

Pseudo-classes are important for interaction and structure. Hover styles help users understand clickable elements. Focus styles are important for keyboard navigation and accessibility. Structural pseudo-classes help style repeated elements without adding extra classes to every item.

Pseudo-Elements

Pseudo-elements target a specific part of an element or create generated visual content. They usually use double colons. Common examples are ::before, ::after, ::first-line, and ::first-letter.

.note::before {
  content: "Note: ";
  font-weight: bold;
}

Pseudo-elements are often used for decorative markers, icons, labels, and small visual additions. They should not replace important HTML content because generated content may not behave like real document content in every context.

Specificity and Selectors

Selectors also affect specificity. Specificity is one part of how the browser decides which rule wins when multiple rules target the same element. ID selectors are stronger than class selectors. Class selectors are stronger than element selectors. Inline styles are stronger than normal stylesheet rules.

SelectorSpecificity Tendency
pLow
.textMedium
#mainHigh
style attributeVery high
!importantOverrides normal cascade rules

High specificity is not always better. A stylesheet full of very specific selectors becomes hard to override. Prefer simple class-based selectors for components, and use higher specificity only when it is genuinely needed.

Good Selector Practices

  • Use class selectors for reusable components.
  • Use element selectors for broad defaults, not detailed component styling.
  • Avoid styling with IDs unless there is a strong reason.
  • Keep selectors as short as the design allows.
  • Avoid depending too much on deep HTML nesting.
  • Use pseudo-classes for states such as hover, focus, and checked.
  • Use developer tools to see which selector is winning.

Good selectors describe intent without becoming fragile. A selector like .product-card can survive small HTML changes. A selector like main section div article div h2 can break as soon as the structure changes.

Debugging CSS Selectors

When a selector does not work, do not guess blindly. Open browser developer tools, inspect the element, and check the Styles panel. It shows which rules match the selected element, which declarations are active, and which declarations are crossed out. If your selector does not appear there, it probably does not match the HTML or the stylesheet did not load.

If the selector appears but the style is crossed out, another rule is winning. In that case, compare specificity and source order. Sometimes the fix is not to make the selector stronger. The better fix may be to remove an unnecessary competing rule or use a clearer class name. Constantly increasing specificity creates a stylesheet that becomes harder to maintain.

Selector Performance and Maintainability

Modern browsers are fast at matching selectors, so beginner CSS rarely has selector performance problems. Maintainability matters more. A simple selector that clearly communicates purpose is usually better than a clever selector that depends on a fragile chain of elements. For example, .pricing-card is clearer than .page-content section:nth-child(3) article.

Use relationship selectors when the relationship itself is meaningful. Use class selectors when you are styling a reusable component. Use pseudo-classes when styling states. This keeps selectors connected to design intent instead of accidental HTML structure.

Combining Selector Types

Selectors can be combined when an element must meet more than one condition. For example, button.primary targets button elements that also have the class primary. The selector .card.featured targets elements that have both classes. This is useful for variants because you can keep the base component style separate from the special version.

.button {
  padding: 12px 20px;
}

.button.primary {
  background-color: #111160;
  color: white;
}

This pattern keeps the CSS modular. The base button rule controls shared button styling, while the combined selector controls only the primary version.

Combined selectors should still stay understandable. If a selector needs several classes, states, and parent relationships to work, it may be a sign that the component needs clearer class names or simpler HTML structure.

Selectors in CSS FAQ

Which CSS selector should beginners use most?

Class selectors are usually the best default for reusable styling because they are flexible, readable, and easier to override than IDs.

Are ID selectors bad in CSS?

ID selectors are not invalid, but they have high specificity. Use them carefully because they can make later style overrides harder.

What is the difference between .card p and .cardp?

The selector .card p targets paragraph elements inside an element with class card. The selector .cardp targets elements with the class cardp.

Why is my selector not working?

The selector may not match the HTML, another rule may override it, the stylesheet may not be loaded, or the selector may contain a spacing or punctuation mistake.


Continue learning CSS in order
Follow the topic sequence with the previous and next lesson.