In CSS, how do the selectors `.card.featured`, `.card .featured`, and `.card, .featured` differ in what they match?
answer
- punctuation carries the meaning
- no separator means one element
- whitespace is not decoration
- comma builds independent selectors
- an element is not its own descendant
basics
~20 sWritten together, .card.featured matches one element carrying both classes. With a space, .card .featured matches a .featured element inside a .card. With a comma, .card, .featured is a selector list: two independent selectors sharing one declaration block.
solid answer
~40 sThey are three different things separated only by punctuation. `.card.featured` is a single compound selector: no separator means both simple selectors must match the *same* element, so it matches `<div class="card featured">` and nothing else. `.card .featured` has whitespace, which is the descendant combinator, so it matches a `.featured` element anywhere inside a `.card` — two different elements. `.card, .featured` is a selector list: the comma separates independent selectors that happen to share one declaration block, so the rule applies to every `.card` and every `.featured` regardless of any relationship between them. The trap in interviews is the space, because it is invisible punctuation with real meaning — accidentally typing `.btn .primary` when you meant `.btn.primary` is one of the most common CSS bugs there is.
code
html · 7 lines<style>
.card.featured { outline: 2px solid gold; } /* one element, both classes */
.card .featured { background: #eee; } /* .featured inside .card */
.card, .featured { padding: 1rem; } /* every .card AND every .featured */
</style>
<div class="card featured">both classes on one element</div>
<div class="card"><span class="featured">nested</span></div>go deeper
Be able to look at a class selector and say instantly whether the space is there, and state which elements each of the three forms matches in a small piece of markup.
Explain that a compound requires one element to satisfy every part while whitespace introduces a second element, and know that one invalid selector drops the entire comma-separated rule.
Demonstrate debugging instinct: when a correctly spelled rule never applies, show that you check for an accidental descendant space and for a poisoned selector list before suspecting anything deeper.
Own the conventions that make these mistakes rare — lint rules and review habits around selector lists and depth limits are cheaper than debugging invisible whitespace across a large stylesheet.
## Three kinds of punctuation, three meanings CSS selector syntax packs a lot of meaning into characters that are easy to skim past. Between two class selectors there are three possibilities, and each builds a structurally different query. ### No separator: a compound selector `.card.featured` is one *compound selector*. A compound selector is a run of simple selectors — type, class, ID, attribute, pseudo-class — written with nothing between them, and **every part must match the same element**. Order within the compound does not matter, so `.featured.card` is equivalent, with one syntactic rule: if a type selector is present it must come first, so you write `a.btn[target]`, never `.btn a`-style reordering. ```css .card.featured { border-color: gold; } ``` ```html <div class="card featured">matched</div> <div class="card">not matched</div> <div class="featured">not matched</div> ``` The same principle applies across selector kinds: `input[type="checkbox"]`, `li.active`, `#main.dark` are all compounds requiring one element to satisfy every part. ### Whitespace: the descendant combinator `.card .featured` inserts a combinator, so the selector now describes **two** elements and a relationship between them: a `.featured` element with a `.card` ancestor at any depth. The element that actually receives the declarations is the rightmost one, `.featured`. ```html <div class="card"><span class="featured">matched</span></div> <div class="card featured">not matched</div> ``` Note the second line carefully: an element cannot be its own descendant, so a single element carrying both classes is matched by the compound but *not* by the descendant selector. This is the exact pair interviewers use to check whether you read whitespace as syntax. ### Comma: a selector list `.card, .featured` is a *selector list* (the specification's term; "grouping" in older material). The comma does not create any relationship. It is shorthand for writing the same declaration block twice: ```css .card, .featured { padding: 1rem; } /* identical in effect to */ .card { padding: 1rem; } .featured { padding: 1rem; } ``` Each selector in the list is matched and weighted independently — the list itself contributes nothing. ## The invalid-selector rule There is one behaviour of selector lists that surprises people and shows up in real bugs. If **any** selector in a comma-separated list is invalid or unrecognised by the browser, the *whole rule* is dropped, including the parts the browser understood perfectly well: ```css /* one unknown pseudo-class poisons the entire rule */ .button, .link:some-unsupported-thing { color: red; } ``` Neither `.button` nor the link gets `color: red` in a browser that does not know that pseudo-class. This is why a single experimental or vendor-specific selector must be given its own rule rather than being folded into a shared list — a habit worth keeping even though the selectors involved change over time. ## Compounds and combinators together Real selectors mix all three. `.card.featured > .title, .card.archived > .title` is a list of two selectors, each of which chains a compound (`.card.featured`) to another compound (`.title`) with the child combinator. When reading such a selector aloud, split on commas first, then read each selector right to left. ## Why the space bug is so common The compound/descendant distinction is invisible in a diff view, produces no error, and silently changes which elements a rule reaches — usually to *none*, because the intended element carries both classes rather than nesting them. Symptoms are a rule that appears in the stylesheet, is spelled correctly, and simply never applies. When a class-based rule mysteriously does nothing, checking for an accidental space between the two class selectors is one of the fastest things to rule out. The reverse mistake also happens: writing `.modal.close` when the close button is a child, so the rule silently targets a nonexistent element that is both a modal and a close button. ## Reading habit Before committing to an answer, tokenise the selector out loud: "class card, *no space*, class featured — same element" versus "class card, *space*, class featured — one inside the other" versus "class card, *comma*, class featured — two separate rules". Saying the punctuation aloud is what stops the mistake.
- What happens if one selector in a comma-separated list is invalid?The entire rule is discarded, not just the offending selector. If a browser cannot parse `.button, .link:some-unknown-thing { color: red }`, then `.button` loses the declaration too. That is why an experimental or browser-specific selector should be given its own rule rather than folded into a shared list.
- Does the order of simple selectors inside a compound change what it matches?No — `.card.featured` and `.featured.card` match exactly the same elements, since every part of a compound must match the same element. There is one syntactic constraint: a type selector, if present, must be written first, so `a.btn` is valid and `.btn` followed by `a` in the same compound is not.
- Why can `.card .featured` fail to match an element that has both classes?Because the whitespace demands two distinct elements: a `.featured` element with a `.card` *ancestor*. An element is never its own ancestor or descendant, so `<div class="card featured">` satisfies the compound `.card.featured` but not the descendant selector. This is the classic accidental-space bug.
saying these in an interview costs you the question
- Treating `.a.b` and `.a .b` as interchangeable
- Saying the comma means "and" rather than a selector list
- Claiming `.a .b` matches an element with both classes
- Thinking an invalid selector in a list is skipped harmlessly
- Believing compound order changes what is matched