Odd CSS syntax. [class^='icon-'], [class*=' icon-']

Learn odd css syntax. [class^='icon-'], [class*=' icon-'] with practical examples, diagrams, and best practices. Covers css, syntax, css-selectors development techniques with visual explanations.

Demystifying CSS Attribute Selectors: [class^='icon-'] and [class*=' icon-']

Hero image for Odd CSS syntax. [class^='icon-'], [class*=' icon-']

Explore the powerful and often misunderstood CSS attribute selectors [class^='icon-'] and [class*=' icon-']. Learn how they target elements based on class names, their use cases, and best practices for effective styling.

CSS attribute selectors provide a flexible way to style elements based on the presence or value of their attributes. Among these, [attribute^=value] (starts with) and [attribute*=value] (contains substring) are particularly useful for targeting elements with specific class naming conventions. This article delves into two common patterns: [class^='icon-'] and [class*=' icon-'], explaining their distinct behaviors and practical applications in modern web development.

Understanding [class^='icon-']

The [attribute^=value] selector targets elements where the specified attribute's value begins with the given string. When applied to the class attribute as [class^='icon-'], it selects any element whose class attribute value starts with icon-. This is incredibly useful for styling elements that follow a strict naming convention, such as a set of icons where all icon classes begin with a common prefix.

/* Selects elements with classes like 'icon-home', 'icon-user', 'icon-settings' */
[class^='icon-'] {
  display: inline-block;
  width: 24px;
  height: 24px;
  background-size: contain;
  background-repeat: no-repeat;
  vertical-align: middle;
}

Basic styling for elements whose class attribute starts with 'icon-'

This selector is precise. It will match <i class="icon-home"></i> but not <i class="my-icon-home"></i>. It's ideal for scenarios where you control the class naming and want to apply base styles to a group of related components.

Understanding [class*=' icon-']

The [attribute*=value] selector targets elements where the specified attribute's value contains the given string as a substring. When used as [class*=' icon-'], it selects elements whose class attribute value contains the substring icon-. Notice the leading space in icon-. This space is crucial because it ensures that the selector matches a full class name, not just a part of a longer class name.

/* Selects elements with classes like 'btn icon-add', 'item icon-delete', 'icon-edit' */
/* Note: It will also match 'icon-edit' because ' icon-edit' contains ' icon-' */
[class*=' icon-'] {
  padding-left: 30px; /* Make space for the icon */
  position: relative;
}

[class*=' icon-']::before {
  content: '';
  position: absolute;
  left: 5px;
  top: 50%;
  transform: translateY(-50%);
  width: 20px;
  height: 20px;
  background-image: url('/path/to/default-icon.svg');
  background-size: contain;
}

Styling elements that contain a class name starting with 'icon-' anywhere in their class list

Without the leading space, [class*='icon-'] would match <i class="my-icon-home"></i> because my-icon-home contains icon-. By including the space, [class*=' icon-'] effectively targets class names that are preceded by a space (meaning they are not the first class in the list) or are the first class if the class attribute itself starts with icon- (e.g., <div class="icon-settings">). This makes it more robust for targeting specific class tokens within a space-separated list.

Comparison and Use Cases

While both selectors deal with class names, their application differs based on the specificity and context required. [class^='icon-'] is best for strict prefix matching, often used for base styles of a component family. [class*=' icon-'] (with the leading space) is more flexible, allowing you to target elements that have a specific class name anywhere in their class attribute list, making it suitable for utility classes or modifiers that can be combined with other classes.

flowchart TD
    A[Element with class attribute] --> B{Does 'class' value start with 'icon-'?}
    B -- Yes --> C["Matched by [class^='icon-']"]
    B -- No --> D{Does 'class' value contain ' icon-'?}
    D -- Yes --> E["Matched by [class*=' icon-']"]
    D -- No --> F[Not Matched]

Decision flow for CSS attribute selectors

Consider the following HTML examples to solidify your understanding:

<div class="icon-home">Home Icon</div>
<span class="button icon-add">Add Button</span>
<p class="text-content my-icon-paragraph">Paragraph</p>
<a class="link icon-external">External Link</a>

Example HTML structure

/* Matches: <div class="icon-home">, <a class="link icon-external"> (because 'icon-external' starts with 'icon-') */
[class^='icon-'] {
  border: 1px solid blue;
}

/* Matches: <span class="button icon-add">, <a class="link icon-external"> (because ' icon-external' contains ' icon-') */
/* Also matches <div class="icon-home"> because 'icon-home' contains ' icon-' (implicitly at the start) */
[class*=' icon-'] {
  background-color: lightyellow;
}

/* Does NOT match <p class="text-content my-icon-paragraph"> for either selector */

CSS rules demonstrating the effect of each selector on the HTML