A look at advanced CSS selectors. Ways to target elements by attributes, relationships, and state with more precision than basic class and ID selectors. They help you write cleaner CSS with less markup.
Why advanced selectors matter
Advanced selectors go beyond element types, classes, and IDs. They let you target elements based on attributes, parent-child relationships, and sibling order – often removing the need for extra classes in your HTML.
Attribute selectors
Target elements based on their attributes and values.
Example – attribute match
input[type="text"] {
border-color: blue;
}
Targets all <input> elements with type="text" and gives them a blue border.
Example – starts with
a[href^="https"] {
background-color: green;
}
Targets <a> elements whose href starts with https.
Child selectors
Target direct children of a specified element.
Example – child combinator
ul > li {
color: red;
}
Only <li> elements that are direct children of <ul> are selected – not nested lists deeper down.
Adjacent sibling selector
Targets an element immediately following another specified element.
Example
h1 + p {
font-size: 18px;
}
Only a <p> that directly follows an <h1> is selected.
General sibling selector
Like the adjacent sibling selector, but matches any following sibling, not just the next one.
Example
h1 ~ p {
color: blue;
}
All <p> elements that are siblings of an <h1>, regardless of position among siblings.
Pseudo-class selectors
Target elements in a specific state.
Example – :nth-child()
li:nth-child(odd) {
background-color: grey;
}
Targets odd-numbered <li> elements.
Example – :not()
div:not(.highlight) {
opacity: 0.5;
}
Targets all <div> elements that do not have the class highlight.
Pseudo-element selectors
Target specific parts of an element.
Example – ::first-letter
p::first-letter {
font-size: 2em;
}
Targets the first letter of every <p> element.
Combining selectors
Chain selectors for very specific targeting:
Example
header nav ul li:first-child a {
font-weight: bold;
}
Targets the first link in a list inside a <nav> within a <header>.
Specificity
More specific selectors override less specific ones. A long chained selector beats a single class – which is why it pays not to over-specify.
Use cases
- Styling forms: Attribute selectors for different input types.
- Styling lists: Child and pseudo-class selectors for specific items.
- Dynamic content: Sibling selectors to style elements based on what comes before them.
Best practices
- Do not over-specify: Keep selectors as simple as you can.
- Watch performance: Very complex selectors can slow rendering on large pages.
- Think about maintenance: If you cannot read the selector in six months, simplify it.
Advanced selectors reduce clutter in your HTML and make CSS more expressive. Pick one or two – attribute selectors and :nth-child() are good starting points – and use them on a real page before reaching for another class.

