Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
🎨 Days 1–6 – CSS Foundations  ·  Day 05

Day 5: Advanced Selectors, Specificity & Cascade

⏱ 90 min📶 Intermediate🎯 100% self-study
Day 5 / 20

✅ Today you will learn

  • Combinators: descendant, child, sibling
  • Attribute selectors and :not(), :is(), :has()
  • Pseudo-classes: :hover, :focus-visible, :nth-child, :checked
  • Pseudo-elements: ::before, ::after, ::placeholder, ::marker
  • Cascade, specificity, inheritance – debugging “my CSS doesn’t work”

🏢 In the real world

The most common message a CSS developer gets: “I changed the colour in style.css but nothing happens.” Nine times out of ten the rule is fine – another, more specific rule wins. Once you can read specificity, you fix these bugs in 30 seconds instead of adding !important everywhere.

Combinators

HTML + CSS
<style>
.menu a      { color: #264de4; }               /* descendant: any <a> inside .menu  */
.menu > li   { border-bottom: 1px solid #e5e7eb; } /* child: only direct <li>         */
h3 + p       { font-weight: 600; }             /* adjacent sibling: the p right after h3 */
h3 ~ small   { color: #9ca3af; }               /* general sibling: any later small  */
</style>

<ul class="menu">
  <li><a href="#">Home</a></li>
  <li><a href="#">Sweets</a>
    <ul><li><a href="#">Dry sweets</a></li></ul>
  </li>
</ul>
<h3>Kaju Katli</h3>
<p>This first paragraph is bold (h3 + p).</p>
<p>The second is normal.</p>
<small>Prices include GST (h3 ~ small)</small>
▶  Descendant, child (>), adjacent (+) and general sibling (~)

Attribute selectors and logical pseudo-classes

HTML + CSS
<style>
a[href^="https"]::after   { content: " ↗"; }          /* starts with  */
a[href$=".pdf"]           { color: #b91c1c; }         /* ends with    */
a[href^="tel:"]           { font-weight: 700; color: #15803d; }
input[type="email"]       { border: 2px solid #264de4; }
li:not(:last-child)       { margin-bottom: 6px; }
:is(h4, h5) span          { color: #c2410c; }
.card:has(img)            { border: 2px solid #f59e0b; padding: 6px; }
</style>

<p><a href="https://maps.google.com">Find us on Maps</a> · <a href="menu.pdf">Download menu</a> · <a href="tel:+919829012345">Call now</a></p>
<input type="email" placeholder="you@example.com">
<ul><li>One</li><li>Two</li><li>Three (no margin)</li></ul>
<h4>Today’s <span>special</span></h4>
<div class="card"><img src="images/ladoo-400.webp" alt="" width="80"> card with an image gets a gold border (:has)</div>
▶  Smart styling without adding extra classes

Pseudo-classes: states and positions

HTML + CSS
<style>
.btn { background: #264de4; color: #fff; border: 0; padding: .6rem 1rem; border-radius: 8px; cursor: pointer; }
.btn:hover         { background: #1e3a8a; }
.btn:active        { transform: scale(.97); }
.btn:focus-visible { outline: 3px solid #f59e0b; outline-offset: 2px; }
.btn:disabled      { background: #9ca3af; cursor: not-allowed; }
tr:nth-child(even) { background: #f1f5f9; }
tr:first-child     { font-weight: 700; background: #264de4; color: #fff; }
input:checked + label { color: #15803d; font-weight: 700; text-decoration: line-through; }
</style>

<button class="btn">Hover / Tab to me</button> <button class="btn" disabled>Sold out</button>
<table style="margin-top:10px;border-collapse:collapse;width:100%">
  <tr><td>Sweet</td><td>Price</td></tr><tr><td>Kaju katli</td><td>₹900</td></tr><tr><td>Ghewar</td><td>₹650</td></tr><tr><td>Ladoo</td><td>₹500</td></tr>
</table>
<p><input type="checkbox" id="t1"><label for="t1"> Pack 20 Diwali boxes</label></p>
▶  Hover, focus, disabled, zebra rows and a checkbox to-do
Pseudo-classMatches
:hover / :activeMouse over / being pressed
:focus-visible ⭐Keyboard focus (better than :focus for outlines)
:nth-child(2n) / (odd) / (3)Position among siblings
:first-child / :last-childFirst / last sibling
:checked, :disabled, :required, :invalidForm states (Day 15)
:has(x)Parent that contains x – the “parent selector”

Pseudo-elements: ::before and ::after

HTML + CSS
<style>
.req::after   { content: " *"; color: #dc2626; }
.new::before  { content: "NEW"; background: #16a34a; color: #fff; font-size: 10px; font-weight: 700; padding: 2px 6px; border-radius: 4px; margin-right: 6px; }
.quote::before { content: "“"; font-size: 3rem; color: #f59e0b; line-height: 0; vertical-align: -0.4em; margin-right: 4px; }
ul.tick { list-style: none; padding: 0; }
ul.tick li::before { content: "✔"; color: #16a34a; margin-right: 8px; }
p::first-letter { font-size: 1.4em; font-weight: 700; color: #264de4; }
::selection { background: #fde68a; }
</style>

<p><label class="req">Mobile number</label></p>
<p class="new">Sugar-free kaju katli launched</p>
<p class="quote">Best ghewar in Jaipur!</p>
<ul class="tick"><li>Pure desi ghee</li><li>No preservatives</li><li>Made today</li></ul>
▶  Decorations added by CSS – no extra HTML (select some text too)
⚠️ content: is decoration only

Text from ::before/::after is not selectable and is read inconsistently by screen readers. Never put important information (prices, instructions) there.

The cascade: who wins?

  1. 1Importance: !important beats normal declarations (avoid it)
  2. 2Specificity: the more specific selector wins
  3. 3Order: if specificity is equal, the rule written LAST wins
  4. 4Inheritance: if no rule targets the element, some properties (color, font) come from the parent
How the browser decides
SelectorScore (ID, class, element)Wins against
p0, 0, 1—
.price0, 1, 0any number of elements
.card .price0, 2, 0.price
nav ul li a:hover0, 1, 4.price? No – 1 class = 1 class, then 4 elements beat 0
#special1, 0, 0any number of classes
style="…" (inline)beats all selectorsonly !important beats it
HTML + CSS
<style>
.card .price { color: #16a34a; }   /* 0,2,0 – wins */
.price        { color: #dc2626; }   /* 0,1,0 – written later, but loses */
p             { color: #374151; }
.card         { color: #264de4; font-family: Georgia, serif; }  /* inherited by children */
</style>

<div class="card">
  <p>This text inherits the card’s font, but p sets its own colour.</p>
  <span class="price">₹900 – green, because .card .price is more specific</span>
</div>
▶  Specificity beats order; inheritance fills the gaps

Real debugging: “my colour doesn’t apply”

  1. Inspect the element. Is your rule listed at all? If not: wrong selector, typo, or the CSS file is not linked/cached (Ctrl+F5).
  2. Your rule is crossed out? Look at the rule above it in the Styles pane – that one wins. Compare specificity.
  3. Fix by matching the existing pattern (e.g. write .card .price), not by adding !important.
  4. Prefer flat, single-class selectors in your own CSS (BEM, Day 17) so these fights never start.
⚠️ Why !important is a trap

It works today, but the next fix needs another !important to beat it, and soon nothing can be overridden. Acceptable uses: utility classes like .hidden { display: none !important } and overriding third-party CSS you cannot edit.

🏅 Job skills unlocked today

✔ Target elements with combinators and attribute selectors✔ Style states with pseudo-classes✔ Decorate with ::before and ::after✔ Calculate specificity and debug the cascade in DevTools

Practice tasks

🏋️ Practice – do it yourself

Task 1: Style a price table: blue header row, zebra rows, highlight a row on hover.
Show solution
▶  Result
Task 2: Add a red “*” after every label of a required field using ::after and a class.
Task 3: Write the specificity of: #nav .item a, ul li.active, .btn.primary:hover.

Quick quiz

🧠 Quick Quiz – test yourself

1. ul > li selects…
Child combinator.
2. Which has the highest specificity?
One ID beats any number of classes.
3. Two rules with equal specificity – which wins?
Source order.
4. Best pseudo-class for keyboard focus rings?
Not shown on mouse clicks.
5. ::before needs which property to appear?
Even content: "".

Interview corner

💼 Interview Corner

How is specificity calculated?

As a tuple (IDs, classes/attributes/pseudo-classes, elements/pseudo-elements) compared left to right. Inline styles beat selectors; !important beats normal declarations; :where() adds zero and :is()/:not() take the specificity of their most specific argument.

Pseudo-class vs pseudo-element?

A pseudo-class (:hover) selects an element in a particular state or position; a pseudo-element (::before) styles a part of an element or creates a virtual child that is not in the HTML.

Summary

  • Combinators: space, >, +, ~; attribute selectors like [href^="https"].
  • Pseudo-classes = states/positions; pseudo-elements = parts/decorations.
  • Cascade order: importance → specificity → source order → inheritance.
  • Debug in DevTools; avoid !important and deep selectors.
➡️ Next

Day 6: display, position (relative, absolute, fixed, sticky), z-index and overflow – badges, sticky headers and WhatsApp buttons.

Frequently Asked Questions

Is :has() supported?
Yes, in all current major browsers (Chrome, Edge, Safari, Firefox). Older browsers simply ignore the rule, so use it for enhancements.
Which properties inherit?
Mostly text-related ones: color, font-*, line-height, text-align, visibility, cursor, list-style. Box properties (margin, padding, border, background, width) do not.
← CSS (20 Days)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicDay 6: Display, Position, z-index & Overflow Your progress: 5 / 20 (25%) · Lesson 6 / 20 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free