CSS · Lesson 35

CSS Attribute Selectors

9 phases  ·  Build: Project Overview

👋 Welcome to Lesson 35

So far in your CSS journey, you have selected elements using their tag name (p, div, img), their class (.menu-item), or their ID (#header). These are great · but what if you need to style elements based on something more specific, like:

  • All links that open in a new browser tab?
  • All text input fields (but not checkbox inputs or button inputs)?
  • All images whose file path ends in .png?
  • All elements whose class name starts with the word "btn"?

For situations like these, CSS gives you a powerful tool called attribute selectors. Instead of selecting elements by their tag or class name, attribute selectors let you target elements based on the attributes they carry · and even on the value of those attributes, or parts of those values.

In this lesson, you will learn:

  • What HTML attributes are and why they matter for CSS selection
  • How to use the six core CSS attribute selectors
  • The difference between exact-match and partial-match attribute selectors
  • How to combine attribute selectors with element type selectors
  • A critical real-world use case: styling form inputs by type
  • How to apply these selectors confidently in your own projects

By the end, you will be writing powerful, precise CSS rules that require zero extra classes or IDs in your HTML.


📚 9 phases🏗️ Project Overview🌐 GitHub Pages
Phase 1 of 9
Lesson Introduction

So far in your CSS journey, you have selected elements using their tag name (p, div, img), their class (.menu-item), or their ID (#header). These are great · but what if you need to style elements based on something more specific, like:

  • All links that open in a new browser tab?
  • All text input fields (but not checkbox inputs or button inputs)?
  • All images whose file path ends in .png?
  • All elements whose class name starts with the word "btn"?

For situations like these, CSS gives you a powerful tool called attribute selectors. Instead of selecting elements by their tag or class name, attribute selectors let you target elements based on the attributes they carry · and even on the value of those attributes, or parts of those values.

In this lesson, you will learn:

  • What HTML attributes are and why they matter for CSS selection
  • How to use the six core CSS attribute selectors
  • The difference between exact-match and partial-match attribute selectors
  • How to combine attribute selectors with element type selectors
  • A critical real-world use case: styling form inputs by type
  • How to apply these selectors confidently in your own projects

By the end, you will be writing powerful, precise CSS rules that require zero extra classes or IDs in your HTML.


✏️ Your Task
Practise what you just learned about Lesson Introduction. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 2 of 9
Prerequisite Concepts

What Is an HTML Attribute?

An attribute is extra information attached to an HTML element, written inside the opening tag. Attributes always come in name="value" pairs.

html
<!-- The word "href" is the attribute NAME. "https://example.com" is the VALUE. -->
<a href="https://example.com">Visit site</a>

<!-- "type" is the attribute. "text" is the value. -->
<input type="text" placeholder="Enter your name">

<!-- "target" is the attribute. "_blank" is the value. -->
<a href="page.html" target="_blank">Open in new tab</a>

<!-- "class" is the attribute. "btn-primary" is the value. -->
<button class="btn-primary">Submit</button>

<!-- "disabled" is an attribute with NO value — it is a "boolean" attribute. -->
<input type="text" disabled>

Every HTML element can carry one or more attributes. CSS attribute selectors let you use these attributes as selection criteria.

What Do Attribute Selectors Look Like?

All CSS attribute selectors use square brackets [ ] around the attribute condition. You place them after the tag name (or alone, to match any tag):

css
/* General pattern */
element[attribute]           /* Has the attribute */
element[attribute="value"]   /* Attribute equals exactly "value" */
element[attribute~="value"]  /* Attribute contains "value" as a whole word */
element[attribute|="value"]  /* Attribute equals "value" or starts with "value-" */
element[attribute^="value"]  /* Attribute starts with "value" */
element[attribute$="value"]  /* Attribute ends with "value" */
element[attribute*="value"]  /* Attribute contains "value" anywhere */

There are seven attribute selectors in total · four basic ones and three advanced ones. We will learn each one, one at a time.


✏️ Your Task
Practise what you just learned about Prerequisite Concepts. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 3 of 9
Section 1: The Basic Attribute Selectors

1.1 [attribute] · Select Elements That Have a Specific Attribute

What it does: Selects every element that has a particular attribute present, regardless of what the attribute's value is. Even elements with an empty attribute value will be selected.

Why it exists: Sometimes you just want to know whether an attribute exists on an element, not what its value is. For example, all <a> tags that have a target attribute · regardless of whether that target is _blank or _self or _parent.

Syntax:

css
element[attribute] {
  /* styles */
}

Real example from W3Schools · style all links that have a target attribute:

html
<!-- HTML: Three links, only two have target attribute -->
<a href="page1.html">Link without target</a>
<a href="page2.html" target="_blank">Link with target="_blank"</a>
<a href="page3.html" target="_self">Link with target="_self"</a>
css
/* CSS */
a[target] {
  background-color: yellow;
}

Expected Output:

code
Link without target        ← no yellow background (no target attribute)
Link with target="_blank"  ← YELLOW background (has target attribute)
Link with target="_self"   ← YELLOW background (has target attribute)

Line-by-line explanation:

  • a · We are targeting <a> (anchor/link) elements
  • [target] · But only those that have the target attribute
  • The first link has no target attribute at all, so it is NOT selected
  • The second and third both have target, so they ARE selected · regardless of the value

Thinking prompt: What if you wrote just [target] without the a in front? That would select any element that has a target attribute · not just links. You can omit the element type to cast a wider net.


Second example · select all inputs that have a placeholder attribute:

html
<!-- HTML -->
<input type="text" placeholder="Your name">
<input type="text">
<input type="email" placeholder="Your email">
<input type="submit" value="Submit">
css
/* CSS */
input[placeholder] {
  border: 2px solid green;
  padding: 5px;
}

Expected Output:

code
[ Your name  ] ← green border (has placeholder)
[            ] ← no green border (no placeholder)
[ Your email ] ← green border (has placeholder)
[ Submit     ] ← no green border (no placeholder)

1.2 [attribute="value"] · Select Elements with an Exact Attribute Value

What it does: Selects elements that have a specific attribute set to exactly the value you specify. The entire attribute value must match perfectly · not just part of it.

Why it exists: The previous selector finds all elements with an attribute. This one narrows it down to only those where the attribute has a specific exact value. The most common use: styling different types of form inputs differently.

Syntax:

css
element[attribute="value"] {
  /* styles */
}

Real example · style only links that open in a new tab:

html
<!-- HTML -->
<a href="home.html">Home</a>
<a href="docs.html" target="_blank">Documentation (new tab)</a>
<a href="about.html" target="_self">About (same tab)</a>
css
/* CSS */
a[target="_blank"] {
  background-color: yellow;
}

Expected Output:

code
Home                        ← no yellow (no target attribute)
Documentation (new tab)     ← YELLOW (target="_blank" exactly matches)
About (same tab)            ← no yellow (target="_self" does NOT equal "_blank")

Key point: target="_self" does NOT match [target="_blank"] because the value _self is not equal to _blank. This selector requires an exact, complete match.


Second example · the most famous practical use: styling form inputs by type:

html
<!-- HTML: A simple registration form -->
<form>
  <input type="text"     placeholder="Full name">
  <input type="email"    placeholder="Email address">
  <input type="password" placeholder="Password">
  <input type="checkbox">
  <label>Remember me</label>
  <input type="submit"   value="Register">
</form>
css
/* CSS: Style different input types differently — no class names needed! */
input[type="text"] {
  width: 200px;
  padding: 8px;
  background-color: lightyellow;
  border: 1px solid #aaa;
}

input[type="email"] {
  width: 200px;
  padding: 8px;
  background-color: lightblue;
  border: 1px solid blue;
}

input[type="password"] {
  width: 200px;
  padding: 8px;
  background-color: lightpink;
  border: 1px solid red;
}

input[type="submit"] {
  background-color: green;
  color: white;
  padding: 10px 20px;
  border: none;
  cursor: pointer;
}

Expected Output (visual):

code
[ Full name     ]   ← lightyellow background (type="text")
[ Email address ]   ← lightblue background  (type="email")
[ Password      ]   ← lightpink background  (type="password")
[ ] Remember me     ← default checkbox style (type="checkbox" has no special rule)
[ Register      ]   ← green button          (type="submit")

Real-world use: This technique is used constantly in web forms. Instead of adding class="text-input" or class="email-input" to every input element, attribute selectors let you target them based on what they already are.


1.3 [attribute~="value"] · Select Elements Whose Attribute Value Contains a Specific Whole Word

What it does: Selects elements where the attribute value is a space-separated list of words and the list contains the specified word. This is perfect for attributes that can hold multiple space-separated values · like the HTML class attribute or a title attribute with multiple words.

The key rule: The specified value must be a complete word in the list. It will NOT match partial words or words joined by hyphens.

Syntax:

css
element[attribute~="value"] {
  /* styles */
}

Real example · select elements whose title attribute contains the word "flower":

html
<!-- HTML -->
<p title="flower">Paragraph 1 — title is exactly "flower"</p>
<p title="summer flower">Paragraph 2 — title contains "flower" as a word</p>
<p title="flower new">Paragraph 3 — title starts with "flower"</p>
<p title="my-flower">Paragraph 4 — title is "my-flower" (hyphenated)</p>
<p title="flowers">Paragraph 5 — title is "flowers" (not the whole word "flower")</p>
css
/* CSS */
p[title~="flower"] {
  background-color: yellow;
}

Expected Output:

code
Paragraph 1  ← YELLOW (title="flower" — "flower" is the whole value)
Paragraph 2  ← YELLOW (title="summer flower" — "flower" is one of the space-separated words)
Paragraph 3  ← YELLOW (title="flower new" — "flower" is the first word)
Paragraph 4  ← no yellow (title="my-flower" — "flower" is not a standalone word, it is joined by a hyphen)
Paragraph 5  ← no yellow (title="flowers" — "flowers" ≠ "flower", it is a different word)

Important distinction: [title~="flower"] matches "flower" as a standalone word in a space-separated list. It does NOT match "my-flower" (hyphenated) or "flowers" (plural · a different word entirely). This behaviour is very similar to how the class selector .flower works.


Second example · the class attribute with multiple values:

html
<!-- HTML: Elements with multiple classes (space-separated) -->
<div class="card featured product">Featured Product Card</div>
<div class="card product">Regular Product Card</div>
<div class="card sidebar featured">Featured Sidebar Card</div>
<div class="widget featured">Featured Widget</div>
css
/* CSS: Select elements where class list contains the word "featured" */
[class~="featured"] {
  border: 3px solid gold;
  background-color: lightyellow;
}

Expected Output:

code
[ Featured Product Card  ]  ← gold border (class list contains "featured")
[ Regular Product Card   ]  ← no gold border (no "featured" in class list)
[ Featured Sidebar Card  ]  ← gold border (class list contains "featured")
[ Featured Widget        ]  ← gold border (class list contains "featured")

Thinking prompt: Notice that [class~="featured"] does exactly the same thing as the class selector .featured. This helps you understand how the ~= operator works · it matches whole words in a space-separated list.


1.4 [attribute|="value"] · Select Elements Whose Attribute Value Is Exactly the Value, or Starts with the Value Followed by a Hyphen

What it does: Selects elements where the attribute value is either:

  • Exactly the specified value (e.g., "top"), OR
  • The specified value followed immediately by a hyphen (-) (e.g., "top-text" or "top-section")

Why it exists: This selector was specifically designed for language codes, which use hyphen notation. For example, lang="en" (English), lang="en-US" (American English), lang="en-GB" (British English). The |= selector lets you match lang="en" AND lang="en-US" AND lang="en-GB" all at once with [lang|="en"].

The critical rule: The value must be a whole word · not a substring inside a longer word. "top-text" matches [class|="top"], but "topping" does NOT.

Syntax:

css
element[attribute|="value"] {
  /* styles */
}

Real example · select all elements whose class is "top" or starts with "top-":

html
<!-- HTML -->
<p class="top">Class is exactly "top"</p>
<p class="top-text">Class starts with "top-"</p>
<p class="top-section">Class starts with "top-"</p>
<p class="topper">Class starts with "top" but NOT followed by a hyphen</p>
<p class="my-top">Class contains "top" but doesn't START with it</p>
css
/* CSS */
[class|="top"] {
  background-color: yellow;
}

Expected Output:

code
Class is exactly "top"                           ← YELLOW (exact match)
Class starts with "top-"                         ← YELLOW ("top" + hyphen)
Class starts with "top-"                         ← YELLOW ("top" + hyphen)
Class starts with "top" but NOT followed by a hyphen  ← no yellow ("topper" has no hyphen after "top")
Class contains "top" but doesn't START with it   ← no yellow (doesn't start with "top")

Language code example · the original purpose of this selector:

html
<!-- HTML: paragraphs in different English variants -->
<p lang="en">Hello!</p>
<p lang="en-US">Howdy, y'all!</p>
<p lang="en-GB">Cheerio!</p>
<p lang="fr">Bonjour!</p>
css
/* CSS: Select all English language paragraphs (any variant) */
p[lang|="en"] {
  font-style: italic;
  color: navy;
}

Expected Output:

code
Hello!         ← navy italic (lang="en" — exact match)
Howdy, y'all!  ← navy italic (lang="en-US" — "en" + hyphen)
Cheerio!       ← navy italic (lang="en-GB" — "en" + hyphen)
Bonjour!       ← normal style (lang="fr" — not "en" or "en-*")

✏️ Your Task
Practise what you just learned about : The Basic Attribute Selectors. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 4 of 9
Section 2: The Advanced Attribute Selectors (Partial-Value Matching)

The first four selectors all require either exact matches or whole-word matches. The next three are more flexible · they match any part of the attribute value. These are called partial-value matching selectors or substring selectors.

Quick analogy: Think of these like the "search and find" functions in a text editor. ^= is like searching from the start of a word. $= is like searching the end. *= is like searching anywhere in the text.


2.1 [attribute^="value"] · Attribute Value Starts With the Specified Value

What it does: Selects elements where the attribute value begins with the specified string. Unlike |=, the value does NOT need to be a whole word · it can be any starting substring.

Syntax:

css
element[attribute^="value"] {
  /* styles */
}

Real example · select all elements whose class value starts with "top":

html
<!-- HTML -->
<p class="top">Exactly "top"</p>
<p class="top-text">Starts with "top-"</p>
<p class="topper">Starts with "top" (no hyphen needed!)</p>
<p class="my-top-class">Contains "top" but doesn't START with it</p>
<p class="bottom-top">Ends with "top", doesn't start with it</p>
css
/* CSS */
[class^="top"] {
  background-color: yellow;
}

Expected Output:

code
Exactly "top"                          ← YELLOW (starts with "top")
Starts with "top-"                     ← YELLOW (starts with "top")
Starts with "top" (no hyphen needed!)  ← YELLOW (starts with "top")
Contains "top" but doesn't START with it  ← no yellow (starts with "my", not "top")
Ends with "top", doesn't start with it    ← no yellow (starts with "bottom")

Compare with |=: The key difference is that ^="top" matches "topper" (starts with "top" even without a hyphen), while |="top" would NOT match "topper" (requires "top" to be a whole word). The ^= operator is purely about string position · is this text at the very beginning?


Practical use · style all external links (those whose href starts with "https"):

html
<!-- HTML -->
<a href="https://google.com">Google (external)</a>
<a href="https://github.com">GitHub (external)</a>
<a href="about.html">About page (internal)</a>
<a href="contact.html">Contact page (internal)</a>
css
/* CSS: Mark all external links with a special colour */
a[href^="https"] {
  color: green;
  font-weight: bold;
}

Expected Output:

code
Google (external)      ← GREEN + bold (href starts with "https")
GitHub (external)      ← GREEN + bold (href starts with "https")
About page (internal)  ← normal (href starts with "about", not "https")
Contact page (internal) ← normal (href starts with "contact", not "https")

Real-world use: Many websites use a[href^="https"] or a[href^="http"] to automatically style external links differently from internal ones · adding an external link icon, a different colour, or an underline style.


2.2 [attribute$="value"] · Attribute Value Ends With the Specified Value

What it does: Selects elements where the attribute value ends with the specified string. Again, it does not need to be a whole word · any ending substring works.

Syntax:

css
element[attribute$="value"] {
  /* styles */
}

Real example · select elements whose class ends with "test":

html
<!-- HTML -->
<p class="unit-test">Ends with "test"</p>
<p class="integration-test">Ends with "test"</p>
<p class="testing">Contains "test" but ends with "ing"</p>
<p class="protest">Ends with "test" but is "protest"</p>
<p class="best">Ends with "est" not "test"</p>
css
/* CSS */
[class$="test"] {
  background-color: yellow;
}

Expected Output:

code
Ends with "test"               ← YELLOW (class ends with "test")
Ends with "test"               ← YELLOW (class ends with "test")
Contains "test" but ends with "ing" ← no yellow (ends with "ing")
Ends with "test" but is "protest"  ← YELLOW (ends with "test")
Ends with "est" not "test"         ← no yellow (ends with "est" not "test")

Practical use · style all PDF links differently from other links:

html
<!-- HTML -->
<a href="report-2024.pdf">Annual Report (PDF)</a>
<a href="brochure.pdf">Company Brochure (PDF)</a>
<a href="terms.html">Terms of Service</a>
<a href="contact.html">Contact Us</a>
css
/* CSS: Highlight all links ending in .pdf */
a[href$=".pdf"] {
  color: darkred;
  font-weight: bold;
  text-decoration: underline;
}

/* Optional: Add a small PDF label after each PDF link */
a[href$=".pdf"]::after {
  content: " [PDF]";
  font-size: 0.8em;
  color: grey;
}

Expected Output:

code
Annual Report (PDF) [PDF]      ← dark red, bold (href ends with ".pdf")
Company Brochure (PDF) [PDF]   ← dark red, bold (href ends with ".pdf")
Terms of Service               ← normal style (href ends with ".html")
Contact Us                     ← normal style (href ends with ".html")

Real-world use: The $= selector is incredibly useful for automatically distinguishing file types in navigation links · PDF downloads, ZIP archives, external documents · without adding any extra classes.


2.3 [attribute*="value"] · Attribute Value Contains the Specified Value Anywhere

What it does: Selects elements where the attribute value contains the specified string anywhere · at the beginning, middle, or end. It does not need to be a whole word.

Syntax:

css
element[attribute*="value"] {
  /* styles */
}

Real example · select elements whose class contains "te" anywhere:

html
<!-- HTML -->
<p class="unite">Contains "te" inside</p>
<p class="internet">Contains "te" inside</p>
<p class="technology">Contains "te" at start</p>
<p class="rate">Contains "te" at end</p>
<p class="testing">Contains "te" at start</p>
<p class="box">Contains no "te"</p>
css
/* CSS */
[class*="te"] {
  background-color: yellow;
}

Expected Output:

code
unite       ← YELLOW ("te" is inside "unite")
internet    ← YELLOW ("te" is inside "internet")
technology  ← YELLOW ("te" is at the start)
rate        ← YELLOW ("te" is at the end)
testing     ← YELLOW ("te" is at the start)
box         ← no yellow (no "te" anywhere in "box")

Practical use · style all links pointing to any Google property:

html
<!-- HTML -->
<a href="https://google.com">Google Search</a>
<a href="https://maps.google.com">Google Maps</a>
<a href="https://docs.google.com/document">Google Docs</a>
<a href="https://github.com">GitHub (not Google)</a>
<a href="https://youtube.com">YouTube</a>
css
/* CSS: Style any link that contains "google" anywhere in the href */
a[href*="google"] {
  color: #4285F4;   /* Google's blue colour */
  font-weight: bold;
}

Expected Output:

code
Google Search    ← Google blue + bold ("google" in "google.com")
Google Maps      ← Google blue + bold ("google" in "maps.google.com")
Google Docs      ← Google blue + bold ("google" in "docs.google.com")
GitHub (not Google) ← normal (no "google" in "github.com")
YouTube          ← normal (no "google" in "youtube.com")

✏️ Your Task
Practise what you just learned about : The Advanced Attribute Selectors (Partial-Value Matching). Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 5 of 9
Section 3: Complete Reference Table

Here is a summary of all seven attribute selectors in one place:

SelectorWhat It MatchesExample
[attr]Elements that have the attribute (any value)a[target] · all links with a target attribute
[attr="val"]Attribute value is exactly "val"input[type="text"] · only text inputs
[attr~="val"]Attribute is a space-separated list containing whole word "val"[title~="flower"] · title contains "flower" as a word
`[attr\="val"]`Attribute is exactly "val" or starts with "val-" (hyphen)`[lang\="en"]` · English language variants
[attr^="val"]Attribute value starts with "val"[class^="btn"] · classes beginning with "btn"
[attr$="val"]Attribute value ends with "val"a[href$=".pdf"] · links to PDF files
[attr*="val"]Attribute value contains "val" anywhere[class*="icon"] · any class containing "icon"

Memory trick: Think of the operators as:

  • ~= → word in a ~list (tilde = list/wave/many)
  • |= → value or "value|hyphen" (pipe = divider, like a hyphen)
  • ^=^top / starts (caret points UP · to the beginning)
  • $= → en$ / ends (dollar sign closes things · the end)
  • =\ = wildcard = anywhere (asterisk = "anything goes")

✏️ Your Task
Practise what you just learned about : Complete Reference Table. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 6 of 9
Section 4: Combining Attribute Selectors

Combining with an Element Type

You can always narrow an attribute selector by placing a tag name in front of it. This targets only elements of that type that also match the attribute condition.

css
/* Any element with target attribute */
[target] { color: red; }

/* Only <a> elements with a target attribute */
a[target] { color: red; }

/* Only <input> elements with type="text" */
input[type="text"] { background: yellow; }

/* Any element with class containing "icon" */
[class*="icon"] { width: 24px; }

/* Only <img> elements whose src ends with ".png" */
img[src$=".png"] { border: 2px solid blue; }

Combining Multiple Attribute Selectors

You can chain multiple attribute selectors together to create very precise rules. Just write them one after another with no space between them:

css
/* Select input elements that are BOTH type="text" AND have a placeholder attribute */
input[type="text"][placeholder] {
  border: 2px solid green;
}
html
<!-- HTML -->
<input type="text" placeholder="Your name">  ← GREEN border (both match)
<input type="text">                          ← no green (no placeholder)
<input type="email" placeholder="Email">     ← no green (type is "email" not "text")

Another multi-selector example · style only HTTPS links that also open in a new tab:

html
<!-- HTML -->
<a href="https://google.com" target="_blank">Google (HTTPS + new tab)</a>
<a href="https://github.com">GitHub (HTTPS only)</a>
<a href="http://oldsite.com" target="_blank">Old site (new tab, not HTTPS)</a>
<a href="about.html">About (internal)</a>
css
/* CSS: Only links that are BOTH https AND open in a new tab */
a[href^="https"][target="_blank"] {
  color: green;
  font-weight: bold;
}

Expected Output:

code
Google (HTTPS + new tab)    ← GREEN + bold (both conditions met)
GitHub (HTTPS only)         ← normal (target attribute missing)
Old site (new tab, not HTTPS) ← normal (href doesn't start with "https")
About (internal)            ← normal (neither condition met)

✏️ Your Task
Practise what you just learned about : Combining Attribute Selectors. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 7 of 9
Section 5: Styling Forms with Attribute Selectors · A Practical Deep Dive

One of the most common and important real-world uses of attribute selectors is styling HTML forms. Forms contain many different <input> types · text, email, password, checkbox, radio, range, file, submit, and more. Without attribute selectors, you would need a separate class for each type. With attribute selectors, you can target them precisely using what they already have.

Complete Styled Form Example

html
<!-- HTML: A full registration form -->
<form class="registration-form">
  <label>Full Name:</label>
  <input type="text" placeholder="Enter your full name">

  <label>Email:</label>
  <input type="email" placeholder="Enter your email">

  <label>Password:</label>
  <input type="password" placeholder="Create a password">

  <label>Age:</label>
  <input type="number" placeholder="Your age" min="18" max="120">

  <label>
    <input type="checkbox"> I agree to the terms
  </label>

  <input type="reset" value="Clear Form">
  <input type="submit" value="Create Account">
</form>
css
/* CSS: Style each input type differently using attribute selectors */

/* Base styles for all text-like inputs */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"] {
  width: 280px;
  padding: 10px 12px;
  margin-bottom: 12px;
  border-radius: 4px;
  font-size: 1em;
  display: block;
}

/* Text input — soft yellow */
input[type="text"] {
  background-color: #fffde7;
  border: 1px solid #f9a825;
}

/* Email input — soft blue */
input[type="email"] {
  background-color: #e3f2fd;
  border: 1px solid #1565c0;
}

/* Password input — soft red */
input[type="password"] {
  background-color: #fce4ec;
  border: 1px solid #c62828;
}

/* Number input — soft green */
input[type="number"] {
  background-color: #e8f5e9;
  border: 1px solid #2e7d32;
}

/* Checkbox — slightly larger */
input[type="checkbox"] {
  width: 18px;
  height: 18px;
  cursor: pointer;
}

/* Reset button — grey */
input[type="reset"] {
  background-color: #9e9e9e;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  margin-right: 10px;
}

/* Submit button — green */
input[type="submit"] {
  background-color: #2e7d32;
  color: white;
  padding: 10px 25px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-weight: bold;
}

input[type="submit"]:hover {
  background-color: #1b5e20;
}

Expected Output:

code
Full Name: [ __________________ ]  ← yellow background, orange border
Email:     [ __________________ ]  ← blue background, blue border
Password:  [ __________________ ]  ← pink background, red border
Age:       [ __________________ ]  ← green background, green border
[ ] I agree to the terms           ← slightly larger checkbox
[ Clear Form ]  [ Create Account ] ← grey / green buttons

Real-world insight: Notice there are zero class attributes on any of the input elements! All the styling is done purely through attribute selectors. This is clean, readable HTML and clean, maintainable CSS. Many professional CSS frameworks use this exact pattern for form styling.


✏️ Your Task
Practise what you just learned about : Styling Forms with Attribute Selectors · A Practical Deep Dive. Open your editor, type the examples above by hand, modify them, and observe what changes.
Phase 8 of 9
Section 6: Guided Practice Exercises
🎯 Your Challenge

Exercise 1: Warm-Up · Target by Attribute Presence

Objective: Use the [attribute] selector to identify required form fields.

Scenario: You have a form where some fields are marked as required. You want to give all required inputs a red left border to signal to users that these fields must be filled in.

Starter HTML:

html
<form>
  <input type="text" placeholder="Full name" required>
  <input type="text" placeholder="Nickname">
  <input type="email" placeholder="Email" required>
  <input type="tel" placeholder="Phone number">
  <input type="submit" value="Submit">
</form>

Your task: Write a CSS rule using [required] to give all required inputs:

  • A 3px solid red left border
  • A light red background: #fff5f5
  • 8px padding

Expected Output:

code
[ Full name  ] ← red left border + light red bg (has required)
[ Nickname   ] ← default border (no required)
[ Email      ] ← red left border + light red bg (has required)
[ Phone      ] ← default border (no required)
[ Submit     ] ← default (no required)

Self-check Questions:

  • Does the submit button get the red border? Why or why not?
  • What would happen if you changed [required] to input[required]? Would anything look different?
  • Add required to the phone number input · does it automatically get the red border?

Exercise 2: Exact Match · Style Link Destinations

Objective: Use [attribute="value"] to differentiate where links go.

Scenario: A news website navigation has links that either stay on the same page or open a new tab. You want all "new tab" links to have a distinct colour.

HTML to work with:

html
<nav>
  <a href="home.html">Home</a>
  <a href="about.html" target="_self">About</a>
  <a href="https://twitter.com" target="_blank">Twitter</a>
  <a href="https://facebook.com" target="_blank">Facebook</a>
  <a href="contact.html">Contact</a>
</nav>

Your task: Write a CSS rule that:

  • Targets all <a> elements with target="_blank"
  • Sets their colour to #e65100 (orange)
  • Sets font-weight: bold

Expected Output:

code
Home     ← default colour (no target attribute)
About    ← default colour (target="_self", not "_blank")
Twitter  ← ORANGE + bold (target="_blank")
Facebook ← ORANGE + bold (target="_blank")
Contact  ← default colour (no target attribute)

Exercise 3: Partial Match · File Type Indicators

Objective: Use $= to automatically style links by file type.

Scenario: A school resources page has links to different file types. You want each file type to look visually different so students know what they are downloading before clicking.

HTML:

html
<ul>
  <li><a href="chapter1.pdf">Chapter 1 Notes</a></li>
  <li><a href="worksheet.pdf">Worksheet</a></li>
  <li><a href="slides.pptx">Presentation Slides</a></li>
  <li><a href="data.xlsx">Grade Data</a></li>
  <li><a href="home.html">Go to Homepage</a></li>
</ul>

Your task:

  • Style links ending in .pdfcolor: darkred
  • Style links ending in .pptxcolor: darkorange
  • Style links ending in .xlsxcolor: darkgreen
  • All styled links should also have font-weight: bold

Expected Output:

code
Chapter 1 Notes      ← DARK RED + bold (.pdf)
Worksheet            ← DARK RED + bold (.pdf)
Presentation Slides  ← DARK ORANGE + bold (.pptx)
Grade Data           ← DARK GREEN + bold (.xlsx)
Go to Homepage       ← normal (it's a .html file)

What-If Challenge: Add this rule too:

css
a[href$=".pdf"]::after {
  content: " 📄";
}

What does it add after every PDF link? Why is ::after useful here?


Exercise 4: Contains Selector · Icon Classes

Objective: Use *= to target elements that belong to a broad category.

Scenario: Your icon library uses class names like icon-home, icon-user, icon-settings, icon-bell. You want all icon elements to share the same base size without touching the HTML.

HTML:

html
<span class="icon-home">🏠</span>
<span class="icon-user">👤</span>
<span class="btn-primary">Submit</span>
<span class="icon-settings">⚙️</span>
<span class="icon-bell">🔔</span>
<span class="label-warning">Warning!</span>

Your task: Write ONE CSS rule using [class*="icon"] that gives all icon elements:

  • font-size: 24px
  • margin: 0 8px
  • cursor: pointer

Expected Output:

code
🏠  👤  Submit  ⚙️  🔔  Warning!
↑ ↑ styled   ↑ ↑   ↑ not styled

(The "Submit" button and "Warning!" label are NOT targeted because their class does not contain "icon".)


Phase 9 of 9
Section 8: Common Beginner Mistakes

Mistake 1: Forgetting the Square Brackets

The Problem:

css
/* WRONG — this is NOT an attribute selector */
input type="text" {
  background: yellow;
}

The Fix:

css
/* CORRECT — always wrap in square brackets */
input[type="text"] {
  background: yellow;
}

Mistake 2: Using = When You Need ~= (or vice versa)

The Problem:

css
/* WRONG — if title="summer flower", this WON'T match because
   "summer flower" is not exactly equal to "flower" */
p[title="flower"] { color: red; }

The Fix:

css
/* CORRECT — use ~= to match "flower" as a whole word within the value */
p[title~="flower"] { color: red; }

Mistake 3: Confusing ^= (starts with) and |= (starts with hyphen variant)

Both match values that start with a specific string, but they work differently:

css
/* |= "top" matches: "top" exactly OR "top-anything" (hyphen required!) */
/* DOES NOT match "topper" */
[class|="top"] { background: yellow; }

/* ^= "top" matches: anything that STARTS with "top" — "top", "topper", "top-text", all match */
[class^="top"] { background: yellow; }

Rule of thumb: If you need to match language codes or hyphenated naming conventions, use |=. For everything else (just "starts with"), use ^=.


Mistake 4: Thinking *= Requires Whole Words

The misconception: Some beginners think [class*="te"] only matches if "te" is a whole word.

The truth: *= matches any substring, including partial words:

css
/* This matches: "rate", "internet", "technology", "unite", "testing"
   — because ALL of them contain "te" as a substring, even inside other words */
[class*="te"] { background: yellow; }

If you want whole words only, use ~= instead.


Mistake 5: Putting a Space Between the Tag and the Bracket

The Problem:

css
/* WRONG — the space means "a descendant with [target]",
   NOT "an <a> that has [target]" */
a [target] { color: red; }

The Fix:

css
/* CORRECT — no space means the <a> itself has the target attribute */
a[target] { color: red; }

Critical rule: a[target] (no space) = select <a> elements that HAVE a target attribute. a [target] (with space) = select any element with target that is a DESCENDANT of an <a> element. These are completely different!


Mistake 6: Forgetting That Attribute Selectors Are Case-Sensitive by Default

css
/* This will NOT match href="HTTPS://google.com" (uppercase HTTPS) */
a[href^="https"] { color: green; }

/* Use the 'i' flag for case-insensitive matching */
a[href^="https" i] { color: green; }

The i flag makes the value comparison case-insensitive. It is supported in all modern browsers.


✏️ Your Task
Practise what you just learned about : Common Beginner Mistakes. Open your editor, type the examples above by hand, modify them, and observe what changes.
🏗️ Build It — Mini Project
Project Overview

In this project, you will build a complete resource directory page that uses only attribute selectors to apply all its link and input styling · no class attributes needed on the elements being styled.

Project Overview

You are building a resources page for a web development course. The page has:

  • A search bar and filter input
  • Navigation links (some external, some internal)
  • A file download list with mixed file types
  • A contact form with multiple input types

All styling will be achieved using attribute selectors.


Stage 1 · HTML

starter.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Course Resources</title>
  <link rel="stylesheet" href="resources.css">
</head>
<body>

  <header>
    <h1>Web Development Resources</h1>
    <!-- Search bar — has a placeholder and type="search" -->
    <input type="search" placeholder="Search resources...">
  </header>

  <!-- Navigation: mix of internal and external links -->
  <nav>
    <a href="index.html">Home</a>
    <a href="lessons.html">Lessons</a>
    <a href="https://developer.mozilla.org" target="_blank">MDN Docs</a>
    <a href="https://css-tricks.com" target="_blank">CSS-Tricks</a>
    <a href="contact.html">Contact</a>
  </nav>

  <!-- Downloads: mix of file types -->
  <section class="downloads">
    <h2>Downloads</h2>
    <ul>
      <li><a href="css-cheatsheet.pdf">CSS Cheat Sheet</a></li>
      <li><a href="html-reference.pdf">HTML Reference Guide</a></li>
      <li><a href="project-template.zip">Starter Project Template</a></li>
      <li><a href="grade-tracker.xlsx">Grade Tracker</a></li>
      <li><a href="lesson-slides.pptx">Lesson Slides</a></li>
      <li><a href="extra-notes.html">Extra Notes</a></li>
    </ul>
  </section>

  <!-- Contact form: multiple input types -->
  <section class="contact">
    <h2>Contact Instructor</h2>
    <form>
      <input type="text"     placeholder="Your name"    required>
      <input type="email"    placeholder="Your email"   required>
      <input type="tel"      placeholder="Phone (optional)">
      <input type="number"   placeholder="Student ID"   required>
      <textarea placeholder="Your message..." rows="4"></textarea>
      <div>
        <input type="checkbox" id="notify">
        <label for="notify">Notify me by email</label>
      </div>
      <input type="reset"  value="Clear">
      <input type="submit" value="Send Message">
    </form>
  </section>

</body>
</html>

Lesson 35 complete! 🎉

You covered: