The power of CSS attribute selectors
Tags: css
Published: 2021-11-30 15:19:31

Besides the obvious utility of selecting elements with an exactly matching data attribute, there are a lot more things we can achieve with CSS attribute selectors.
In general, the attribute selector can target *any* attribute that's attached to an HTML element. By default, the selector is case sensitive and has a lower specificity than id's and classes.

Here's an attribute selector in its simplest form, selecting every anchor element that has an `href` attribute — regardless of the actual href URL:   

```css
a[href] {
    /* ... */
}
```

If we want it to be more specific about which `href` to target, we can explicitly pass the URL to the attribute selector like this

```css
a[href="https://specific-url.com"] {
    /* ... */
}
```

One of the latest <a href="https://www.w3.org/TR/selectors-4/#attribute-case" target="_blank">specs changes</a> introduced a new flag for attribute selectors, which allows us to make the matching case insensitive, by adding an `i` after our selector. This is <a href="https://caniuse.com/?search=attribute%20case" target="_blank">fairly well supported</a> and works across all modern browsers, except IE11.
```css
a[href="https://specific-url.com" i] {
    /* matches <a href="https://SpEciFic-url.com"></a> ... */
}
```


## Special types of attribute selectors
Besides matching an attribute with an existing attribute or a specific value, we can use other types of attribute selectors to achieve partial matching on the
value of an attribute. These selectors can also be combined to match very specific elements.

### CSS attribute contains
Using the wildcard operator `*` we can match any element that has an attribute containing the given string in any form.
That means the example below would match the exact string `value` but also `something value something` as well as `somethingvaluesomething`.
```css
[data-attribute*="value"] {
  /* ... */
}
```


### CSS attribute starts with
If we want to look for an attribute whose value **starts** with a given string, we can use the `^` operator lie below.
In that case, we'd only match `value something` and `valuesomething` but not `something value`.
```css
[data-attribute^="value"] {
  /* ... */
}
```

### CSS attribute ends with
Conversely to looking for matched at the start, we can also look at the very end of an attribute's value by useing the `$` operator.
We'd match `something value` but not `value something`. This is especially interesting because we know that files always have a certain extension and by passing
the full name into a data-attribute, we'd be able to match elemenets that represent PDF documents like this `a[href$="pdf"]`.
```css
[data-attribute$="value"] {
  /* ... */
}
```

### CSS attribute is in space-separated or dash-separated lists
There are two selectors that allow us to specifically look for matches inside lists, where one is only matching when the value is dash-separated `|` and the other operator
matches everything inside a space-separated list `~`. Especially the space separation can also be achieved with other operators mentioned above.

```css

[data-attribute~="value"] {
  /* matches eg. <li data-years="thor value loki">...</li> */
}

[data-attribute|="value"] {
  /* matches eg. <li data-years="value-2021">...</li> */
}
```

## Combining attribute selectors
Of course, we can also use multiple attribute selectors simultaneously to select specific elements. This can be especially handy when the HTML
provides us with enough info to create different styles only through our attributes. Let's say we want to give icons to every file download link
on a site and a special icon to PDFs. We can combine the contains and ends with selectors to select all files and then specifically find all PDFs.

```css
a[href*="/downloads"] {
    /* file is in /downloads directory */
}

a[href*="/downloads"][href$="pdf"] {
    /* file is in /downloads directory */
    /* AND ends with pdf */
}
```

## Negating the attribute selector with :not
All the attribute selectors above can also be combined with the CSS `:not` selector, so we could also take our example above and find all files
that are inside the downloads directory but are specifically *not* PDF files.
```css
a[href*="/downloads"]:not([href$="pdf"]) {
    /* file is in /downloads directory */
    /* AND ends NOT with pdf */
}
```

## Using attribute selectors in Javascript
Just like using regular class and id selectors, we can also utilize all of the above selectors when writing JavaScript to select DOM elements.
```javascript
let team = document.querySelector('img[src*="team"]');
```