Basic Selectors and Specificity

Module 5: CSS Fundamentals - Lecture 3

Introduction to CSS Selectors

CSS selectors are patterns used to select and style HTML elements. They are the bridge between your HTML document and your style rules—telling the browser which elements should receive which styles.

Think of selectors as address labels on packages. Just as you might address a package to "All Residents" (universal selector), a specific person (element selector), everyone in a certain neighborhood (class selector), or someone with a unique ID (ID selector), CSS selectors target elements with varying levels of precision.

Types of Basic CSS Selectors

graph TD A[CSS Selectors] --> B[Universal] A --> C[Type/Element] A --> D[Class] A --> E[ID] A --> F[Attribute] style B fill:#e6f7ff style C fill:#e6f7ff style D fill:#e6f7ff style E fill:#e6f7ff style F fill:#e6f7ff

Let's explore each type of selector, its syntax, use cases, and examples.

1. Universal Selector (*)

The universal selector matches any element of any type and is denoted by an asterisk (*).

CSS

/* Selects ALL elements on the page */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

Explanation

This rule applies a CSS reset to all elements, removing default margins and padding, and setting the box-sizing to border-box.

Common Use Cases:

  • CSS resets to normalize browser defaults
  • Setting global box-sizing behavior
  • Debugging (e.g., * { border: 1px solid red; })

Analogy: The universal selector is like sending a company-wide memo that applies to everyone.

Caution

While convenient, the universal selector can impact performance when used extensively, as it applies to every element. Use it judiciously for truly global styles.

2. Type/Element Selectors

Type selectors target elements based on their HTML tag name.

CSS

/* Selects all paragraph elements */
p {
  line-height: 1.6;
  margin-bottom: 1em;
}

/* Selects all heading level 2 elements */
h2 {
  font-size: 1.5em;
  margin-top: 1em;
}

/* Selects all anchor elements */
a {
  color: #0066cc;
  text-decoration: none;
}

Explanation

These rules apply styles to all elements of the specified type, regardless of their position in the document or any attributes they might have.

Common Use Cases:

  • Setting base styles for text elements (paragraphs, headings)
  • Defining consistent styles for interactive elements (links, buttons)
  • Normalizing browser-default styles for elements

HTML Example:

<h2>Product Features</h2>
<p>Our product includes amazing features.</p>
<p>Learn more <a href="features.html">here</a>.</p>

Analogy: Type selectors are like addressing all people with a specific job title in an organization.

3. Class Selectors (.classname)

Class selectors target elements that have a specific class attribute value, prefixed with a period (.).

HTML

<div class="card">
  <h2 class="card-title">Product Name</h2>
  <p class="card-description">Product description here.</p>
  <button class="btn primary">Add to Cart</button>
</div>

<div class="card featured">
  <h2 class="card-title">Featured Product</h2>
  <p class="card-description">This is our featured product.</p>
  <button class="btn primary">Add to Cart</button>
</div>

CSS

/* Targets elements with class="card" */
.card {
  border: 1px solid #ddd;
  border-radius: 4px;
  padding: 1rem;
  margin-bottom: 1rem;
}

/* Targets elements with class="featured" */
.featured {
  background-color: #fffbcc;
  border-color: #e6c700;
}

/* Targets elements with class="card-title" */
.card-title {
  margin-top: 0;
  color: #333;
}

/* Targets elements with class="btn" */
.btn {
  padding: 0.5em 1em;
  border-radius: 4px;
  border: none;
  cursor: pointer;
}

/* Targets elements with class="primary" */
.primary {
  background-color: #0066cc;
  color: white;
}

/* Targets elements with BOTH class="btn" AND class="primary" */
.btn.primary {
  font-weight: bold;
}

Explanation

Class selectors are incredibly versatile and widely used in modern CSS development. They allow for:

  • Multiple elements to share the same styling
  • Single elements to have multiple classes (space-separated in the class attribute)
  • Reusable styling components across different element types

Note: In the example above, .btn.primary (no space) targets elements that have both classes. This is different from .btn .primary (with space) which would target elements with class="primary" that are descendants of elements with class="btn".

Common Use Cases:

  • Component-based design systems (cards, buttons, forms)
  • State indicators (active, disabled, featured)
  • Layout patterns (grid, flex-container)
  • Utility classes (text-center, margin-large)

Analogy: Class selectors are like addressing people by the groups they belong to, such as "all marketing team members" or "all project leaders."

4. ID Selectors (#idname)

ID selectors target a single element with a specific id attribute value, prefixed with a hash (#).

HTML

<header id="main-header">
  <h1>Website Title</h1>
  <nav id="primary-navigation">
    <!-- Navigation items -->
  </nav>
</header>

<main id="content">
  <article id="featured-post">
    <h2>Featured Article</h2>
    <p>Article content here...</p>
  </article>
</main>

<footer id="main-footer">
  <p>© 2025 My Website</p>
</footer>

CSS

/* Targets the element with id="main-header" */
#main-header {
  background-color: #333;
  color: white;
  padding: 1rem;
}

/* Targets the element with id="primary-navigation" */
#primary-navigation {
  display: flex;
  justify-content: space-between;
}

/* Targets the element with id="featured-post" */
#featured-post {
  border-left: 4px solid #0066cc;
  padding-left: 1rem;
}

Explanation

ID selectors have some key characteristics that distinguish them from class selectors:

  • IDs must be unique within a document (only one element can have a specific ID)
  • An element can only have one ID (unlike classes, where multiple classes can be applied)
  • IDs have much higher specificity than classes (more on this later)
  • IDs can be targeted with fragment identifiers in URLs (e.g., example.com/page.html#section1)

Common Use Cases:

  • Unique page sections (header, main content, footer)
  • JavaScript hooks (though data attributes are often preferred nowadays)
  • Anchor navigation targets (jump to specific sections)
  • Styling singleton elements that appear only once on a page

Analogy: ID selectors are like addressing someone by their unique employee ID number or social security number—they identify exactly one individual.

Best Practice

While IDs are powerful, many modern CSS methodologies avoid using them for styling due to their high specificity. Instead, they prefer classes for more maintainable and modular CSS. Save IDs primarily for JavaScript hooks and anchor links.

5. Attribute Selectors

Attribute selectors target elements based on the presence or value of their attributes. They use square brackets notation.

CSS

/* Selects all elements with the "type" attribute */
[type] {
  margin-bottom: 1rem;
}

/* Selects elements where type="text" exactly */
[type="text"] {
  border: 1px solid #ccc;
  padding: 0.5rem;
}

/* Selects elements whose class attribute contains "btn" */
[class*="btn"] {
  cursor: pointer;
}

/* Selects elements with href attributes starting with "https" */
[href^="https"] {
  color: green;
}

/* Selects elements with src attributes ending in ".jpg" */
[src$=".jpg"] {
  border: 2px solid #ddd;
}

/* Case-insensitive matching with "i" flag */
[lang="en" i] {
  font-family: 'Arial', sans-serif;
}

Explanation

Attribute selectors provide powerful ways to target elements based on their attributes and attribute values, with several matching operators:

  • [attr] - Elements with the attribute, regardless of value
  • [attr="value"] - Elements with exact attribute value
  • [attr*="value"] - Elements with attribute containing value anywhere
  • [attr^="value"] - Elements with attribute starting with value
  • [attr$="value"] - Elements with attribute ending with value
  • [attr~="value"] - Elements with attribute containing value as a space-separated word
  • [attr|="value"] - Elements with attribute being exactly "value" or starting with "value-"

HTML Example:

<input type="text" placeholder="Your name">
<input type="email" placeholder="Your email">
<a href="https://example.com">Secure Link</a>
<a href="http://example.org">Regular Link</a>
<img src="photo.jpg" alt="Photo">
<div lang="en-US">English content</div>

Common Use Cases:

  • Form elements styling (by input type)
  • Link styling (by protocol or domain)
  • Language-specific styling
  • Media styling (by file extension)
  • Data-attribute-based styling (modern approach for JavaScript hooks)

Analogy: Attribute selectors are like searching for people in a database based on specific characteristics or properties they possess.

Practical Example: Custom Form Styling

/* Style all required inputs */
[required] {
  border-left: 3px solid #cc0000;
}

/* Style inputs by type */
[type="checkbox"], [type="radio"] {
  margin-right: 0.5rem;
}

/* Style download links */
[href$=".pdf"], [href$=".doc"], [href$=".zip"] {
  padding-left: 20px;
  background-repeat: no-repeat;
  background-position: left center;
  background-size: 16px 16px;
}

[href$=".pdf"] {
  background-image: url('pdf-icon.svg');
}

/* Target elements with data attributes (modern approach) */
[data-status="active"] {
  background-color: #e6ffe6;
}

[data-status="pending"] {
  background-color: #fff9e6;
}

[data-status="inactive"] {
  background-color: #f9f9f9;
  color: #999;
}

Combining Selectors

Selectors can be combined to create more targeted and powerful patterns:

1. Descendant Combinator (space)

/* Targets <p> elements inside .article */
.article p {
  font-size: 1rem;
}

Matches elements that are descendants (at any nesting level) of the first element.

2. Child Combinator (>)

/* Targets <li> elements that are direct children of .nav */
.nav > li {
  display: inline-block;
}

Matches elements that are direct children (immediate descendants) of the first element.

3. Adjacent Sibling Combinator (+)

/* Targets <p> elements immediately after <h2> */
h2 + p {
  font-weight: bold;
}

Matches the second element only if it immediately follows the first element and they share the same parent.

4. General Sibling Combinator (~)

/* Targets all <p> elements after <h2> within the same parent */
h2 ~ p {
  color: #666;
}

Matches all instances of the second element that follow (not necessarily immediately) the first element and share the same parent.

5. Multiple Selectors (comma)

/* Targets <h1>, <h2>, and <h3> elements */
h1, h2, h3 {
  font-family: 'Georgia', serif;
}

Applies the same styles to multiple selectors at once, creating a selector group.

Selector Combination Visualization

div.container header section footer h1 h2 p p Descendant: .container p selects both paragraph elements Child: section > p selects only the paragraph under section Adjacent Sibling: h2 + p selects paragraph after h2 Group: h1, h2 selects both heading elements

CSS Specificity

Specificity determines which CSS rule applies when multiple rules could style the same element. It's a weight assigned to each selector, with more specific selectors overriding less specific ones.

Think of specificity as a scoring system in a competition. The selector with the highest score wins and gets to apply its styles.

Specificity Hierarchy (lowest to highest)

  1. Type selectors and pseudo-elements (e.g., h1, ::before)
  2. Class selectors, attribute selectors, and pseudo-classes (e.g., .example, [type="text"], :hover)
  3. ID selectors (e.g., #header)
  4. Inline styles using the style attribute (style="color: red;")
  5. !important declaration (overrides everything else)
graph TD A[Specificity Hierarchy] --> B[Type selectors, pseudo-elements] A --> C[Class selectors, attribute selectors, pseudo-classes] A --> D[ID selectors] A --> E[Inline styles] A --> F[!important] style B fill:#e6f7ff style C fill:#fff7e6 style D fill:#fff1f0 style E fill:#f6ffed style F fill:#fff2e8 B --> B1[0-0-1] C --> C1[0-1-0] D --> D1[1-0-0] E --> E1[1-0-0-0] F --> F1[∞]

Calculating Specificity

Specificity is typically represented as four values: a-b-c-d

Specificity Examples

Selector Specificity Value Explanation
p 0-0-0-1 One type selector
p.intro 0-0-1-1 One type selector + one class selector
.container p.intro 0-0-2-1 One type selector + two class selectors
#header .nav 0-1-1-0 One ID selector + one class selector
#header .nav li.active 0-1-2-1 One ID + two classes + one type
style="color: red;" 1-0-0-0 Inline style
p { color: red !important; } !important declaration

When comparing specificity, you compare from left to right. A single ID selector (0-1-0-0) will always override any number of class selectors (0-0-n-0), no matter how many there are.

Specificity Examples

HTML

<div id="container">
  <p class="text">This is a paragraph with a class.</p>
  <p class="text highlight">This is a highlighted paragraph.</p>
  <p id="special" class="text">This is a special paragraph.</p>
</div>

CSS

/* Specificity: 0-0-0-1 */
p {
  color: black;
  font-size: 16px;
}

/* Specificity: 0-0-1-0 */
.text {
  color: blue;
}

/* Specificity: 0-0-2-0 */
.text.highlight {
  color: orange;
}

/* Specificity: 0-1-0-1 */
#container p {
  color: green;
}

/* Specificity: 0-1-1-0 */
#special.text {
  color: red;
}

/* Specificity: 0-0-1-1 with !important */
p.text {
  color: purple !important;
}

Result Explanation

  • First paragraph: Would be purple due to p.text with !important (overrides everything)
  • Second paragraph: Would be purple due to p.text with !important (overrides everything)
  • Third paragraph: Would be purple due to p.text with !important (overrides everything)

Without the !important declaration:

  • First paragraph: Would be green due to #container p (ID selector wins over class)
  • Second paragraph: Would be orange due to .text.highlight (two classes have higher specificity than #container p because the ID is not directly targeting the element)
  • Third paragraph: Would be red due to #special.text (ID + class has highest specificity)

The Cascade

When several rules have equal specificity, the last one declared in the CSS will take precedence. This is part of what makes CSS "cascading."

/* This rule is applied first */
.button {
  background-color: blue;
}

/* This rule, with equal specificity but defined later, 
   will override the previous one */
.button {
  background-color: green;
}

The full order of precedence in CSS is:

  1. Origin and importance: User agent (browser defaults) → User styles → Author styles → Author styles with !important → User styles with !important
  2. Specificity: As detailed above
  3. Order of appearance: Last declaration wins when specificity is equal

Best Practices

Selector Best Practices

Specificity Best Practices

Modern CSS Methodologies

Several methodologies have emerged to manage selector complexity and specificity:

BEM (Block Element Modifier)

BEM uses a naming convention to create component-based architecture:

/* Block component */
.card {}

/* Element that depends on the block */
.card__title {}
.card__image {}

/* Modifier that changes the style of the block */
.card--featured {}
.card--compact {}

BEM provides a clear component structure and keeps specificity consistently low.

SMACSS (Scalable and Modular Architecture for CSS)

SMACSS categorizes CSS rules into several types:

  • Base rules (element selectors)
  • Layout rules (.l-header, .l-grid)
  • Module rules (.navbar, .btn)
  • State rules (.is-active, .is-hidden)
  • Theme rules (.theme-dark, .theme-holiday)

Utility-First CSS

Frameworks like Tailwind CSS use small, single-purpose utility classes:

<div class="bg-white rounded shadow p-4 mb-6">
  <h2 class="text-xl font-bold text-gray-800 mb-2">Card Title</h2>
  <p class="text-gray-600">Card content here...</p>
</div>

This approach avoids specificity issues by using only class selectors with consistent specificity.

Real-World Applications

E-commerce Product Card

Here's how selectors and specificity might apply in a real-world component:

HTML

<div class="product-card" data-category="electronics">
  <span class="product-badge new">New!</span>
  <img class="product-image" src="laptop.jpg" alt="Laptop">
  <div class="product-info">
    <h3 class="product-title">Ultra Slim Laptop</h3>
    <p class="product-price">$999</p>
    <div class="product-rating">
      <span class="star filled"></span>
      <span class="star filled"></span>
      <span class="star filled"></span>
      <span class="star half-filled"></span>
      <span class="star"></span>
    </div>
    <button class="btn-primary">Add to Cart</button>
  </div>
</div>

CSS

/* Base component styling with class selector */
.product-card {
  border: 1px solid #eaeaea;
  border-radius: 8px;
  padding: 1rem;
  position: relative;
  transition: transform 0.3s ease;
}

/* Element selector with attribute selector */
.product-card[data-category="electronics"] {
  border-color: #0066cc;
}

/* Descendent selector for nested elements */
.product-card .product-title {
  font-size: 1.25rem;
  margin-top: 0.5rem;
}

/* Class selector for specific element */
.product-badge {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  padding: 0.25rem 0.5rem;
  border-radius: 4px;
  font-size: 0.75rem;
  font-weight: bold;
}

/* Multiple selector matching for variants */
.product-badge.new {
  background-color: #22c55e;
  color: white;
}

/* Adjacent sibling selector */
.product-rating + button {
  margin-top: 1rem;
}

/* Pseudo-class for interactive states */
.btn-primary:hover {
  background-color: #0055aa;
}

/* Combination of attribute and pseudo-class selectors */
[class*="btn-"]:focus {
  outline: 2px solid #0066cc;
  outline-offset: 2px;
}

Practice Exercise

Selector Mastery Challenge

Task: Create a basic blog post layout and style it using a variety of selectors.

Exercise Steps:

  1. Create an HTML structure with:
    • Article container with an ID
    • Article title (h1) and subtitle (h2)
    • Author information section with name and publication date
    • Several paragraphs of content, with the first paragraph marked as an introduction
    • A blockquote somewhere in the middle
    • A list of related articles at the bottom
    • Share buttons with different social media platforms
  2. Style the article using at least one of each:
    • Universal selector
    • Type/element selector
    • Class selector
    • ID selector
    • Attribute selector
    • Descendant combinator
    • Child combinator
    • Adjacent sibling combinator
  3. Create a specificity conflict and resolve it in three different ways:
    • By increasing selector specificity
    • By reordering CSS rules
    • By using !important (just for demonstration)
  4. Add comments to your CSS explaining the specificity of each selector and why you chose that selector for each element

Bonus challenge: Implement a "dark mode" variant of your article using an additional class on the body element and demonstrate how specificity affects the theme switch.

Conclusion

Understanding CSS selectors and specificity is foundational to becoming proficient with CSS. These concepts impact how you structure both your HTML and CSS files, and how styles are applied to your web pages.

Remember these key takeaways:

As you build more complex projects, these concepts will become increasingly important. Thoughtful use of selectors and understanding of specificity helps create CSS that is both powerful and maintainable.

Additional Resources