Attribute Selectors
Learn to select elements based on the presence or value of their HTML attributes, including partial-match variants for prefixes, suffixes, substrings, and word lists.
Sometimes class and ID selectors aren't precise enough — you want to target elements based on an attribute they carry, like every <input> of type="email", every link pointing to an external site, or every image whose filename ends in .png. Attribute selectors, written in square brackets, give you this power without needing extra classes in your HTML.
Presence and exact match
[attr] matches any element that has the given attribute at all, regardless of its value. [attr="value"] narrows that to elements where the attribute's value is an exact match. These are the simplest and most common forms — for example, [disabled] matches any disabled form control, and [type="submit"] matches only submit buttons.
Substring matching operators
CSS also provides operators for partial matches, which behave similarly to simple pattern matching:
• [attr^="value"] — attribute value STARTS WITH value (e.g. [href^="https"] matches secure links) • [attr$="value"] — attribute value ENDS WITH value (e.g. [src$=".png"] matches PNG images) • [attr*="value"] — attribute value CONTAINS value anywhere (e.g. [class*="col-"] matches any class containing 'col-')
Word-list and language-style matching
Two more specialized operators handle space- or hyphen-separated values:
• [attr~="value"] — matches if value is one whole word within a whitespace-separated list (e.g. class="btn primary large" is matched by [class~="primary"], but NOT by [class~="prim"]) • [attr|="value"] — matches if the attribute value is exactly value, or starts with value immediately followed by a hyphen (e.g. [lang|="en"] matches lang="en" and lang="en-US", but not lang="english")
Case sensitivity
By default, attribute value matching is case-sensitive for most HTML attributes in HTML documents (behavior can vary by attribute). You can force case-insensitive matching by adding an i right before the closing bracket, e.g. [href$=".PDF" i], which matches .pdf, .PDF, .Pdf, and so on.
Attribute selector forms
[attr] { } /* has the attribute at all */
[attr="value"] { } /* exact value match */
[attr^="value"] { } /* starts with */
[attr$="value"] { } /* ends with */
[attr*="value"] { } /* contains substring */
[attr~="value"] { } /* exact word in whitespace-separated list */
[attr|="value"] { } /* exact value, or value followed by hyphen */
[attr="value" i] { } /* case-insensitive match */Code Examples
Selects any <input> element that has the required attribute present (regardless of its value), highlighting required form fields.
a[href^="https"] targets only the first link, since its href attribute value starts with 'https'. CSS: a[href^="https"] { color: green; } a[href^="http://"] { color: gray; } img[src$=".png"] matches only diagram.png because its src value ends with '.png'. CSS: img[src$=".png"] { border: 2px solid orange; }
[class*="col-"] matches both div A and div B (their class attribute contains the substring 'col-' somewhere). [class~="primary"] matches only div A, because 'primary' must appear as a whole, separate word — div C's class is the single word 'primary-outline', which does NOT equal the word 'primary'. CSS: [class*="col-"] { display: inline-block; } [class~="primary"] { font-weight: bold; }
input[required] {
border-color: crimson;
}<a href="https://example.com">Secure</a>
<a href="http://example.com">Not secure</a><img src="photo.jpg" alt="cat">
<img src="diagram.png" alt="chart">
<img src="icon.svg" alt="menu"><div class="col-4 primary">A</div>
<div class="col-8">B</div>
<div class="primary-outline">C</div>Important Rules
[attr] checks presence only; [attr="value"] checks an exact value.
^= starts with, $= ends with, *= contains anywhere.
~= matches a whole word in a space-separated list; |= matches an exact value or a hyphen-prefixed value (handy for language codes).
Add a trailing i inside the brackets for case-insensitive matching.
Where this shows up in real code
Attribute selectors are heavily used for styling forms by input type (input[type="checkbox"]), flagging external or downloadable links (a[href^="http"]:not([href*="yoursite.com"]), a[download]), and targeting elements generated by frameworks that don't let you easily add custom classes.
[class*="primary"] { font-weight: bold; } <!-- unintentionally also matches class="primary-outline" and class="not-primary-color" -->
[class~="primary"] { font-weight: bold; } <!-- matches only an exact whole-word "primary" in the class list -->
*= matches any substring occurrence, which can accidentally match unrelated classes that merely contain the same letters. ~= is safer when you specifically mean 'this exact class name, among possibly several'.
[Predict the Output] Given the CSS rule a[href^="mailto"] { color: purple; }, which link(s) below will be styled purple? <a href="mailto:[email protected]">Email us</a> <a href="/contact">Contact page</a> <a href="tel:mailto123">Weird number</a> A. All three links B. Only the first link (mailto:[email protected]) C. Only the third link, because it contains 'mailto' in the value D. None of the links
B. Only the first link (mailto:[email protected]) — ^= matches values that START WITH the given string. Only the first link's href begins with 'mailto'. The third link's href starts with 'tel:', so even though it contains the substring 'mailto' later on, ^= does not match it (that would require *=).
Write a selector that targets any <a> element whose href attribute ends in '.pdf', and give it a small paperclip-style left padding of 20px.
a[href$=".pdf"] { padding-left: 20px; } Use the $= (ends with) operator.