Learn
🤖 AI Hub 📰 News 📖 Dictionary 🧰 Resources
Grow
💼 Jobs 🚀 Community 🏆 Challenges
Explore by Stage
🌑 Zero 📚 Learn 🔧 Practice 🏗 Build 🚀 Launch 💰 Earn
Account
Login Sign Up
🏗️HTML 🎨CSS ⚡JavaScript 🐙Git & GitHub ⚛️React Soon 📘TypeScript Soon 🐍Python 🗄️Database & SQL Soon 🌐Web Development Soon ☁️Cloud & DevOps Soon 🤖AI & ML Soon 📄Resume Prep Soon 🎤Interview Prep Soon 💼Freelancing Soon 🚀SaaS & Side Projects Soon 🤖Automation Soon
Beginner 🕑 17 min read 👁 2 views 📅 Oct 21, 2026

Pseudo-classes: :hover, :focus, :nth-child and More

Style elements by state and position with :hover, :active, :focus-visible, :nth-child, :not and form pseudo-classes, and build an accessible restaurant menu and striped results table.

Why Pseudo-classes Matter: A Restaurant Menu That Reacts

Walk into a good restaurant and the staff respond to you. When you look at the menu for a long time, a waiter comes over. When you point at a dish, they lean in to see which one. The menu card itself might have every second line lightly shaded, so your eyes do not jump from “Veg Biryani” to the price of the dish below it.

A web page can respond in the same way. It can change a menu item’s colour when your mouse is over it, show a clear ring around the button you reached with the keyboard, or shade every second row of a results table. All of this is done with pseudo-classes.

A pseudo-class is a word after a colon, added to a selector, that selects an element in a particular state or position. For example, button:hover means “a button, but only while the mouse is over it”. In this lesson you will build an interactive menu for a family restaurant and a striped class results table.

User Action Pseudo-classes

:hover and :active

:hover applies while the mouse pointer is over an element. :active applies at the moment the element is being pressed (between pressing and releasing the mouse button or your finger). Together they make buttons feel alive, like a real button that moves when you press it.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>hover and active</title>
  <style>
    body { font-family: Arial, sans-serif; }
    .dish {
      padding: 12px;
      margin-bottom: 8px;
      border: 1px solid #dddddd;
      border-radius: 8px;
    }
    .dish:hover {
      background-color: #fff3e0;
      border-color: #fb8c00;
    }
    .order {
      padding: 10px 20px;
      font-size: 16px;
      color: #ffffff;
      background-color: #e65100;
      border: none;
      border-radius: 6px;
    }
    .order:hover  { background-color: #bf360c; }
    .order:active { background-color: #8d2a0b; transform: scale(0.96); }
  </style>
</head>
<body>
  <div class="dish">Paneer Butter Masala: Rs 240</div>
  <div class="dish">Veg Biryani: Rs 210</div>
  <button class="order">Order now</button>
</body>
</html>

Notice that :hover works on any element, not just links and buttons. Here each dish gets a warm highlight. The transform: scale(0.96) line shrinks the button a tiny bit while it is pressed. You will learn transforms properly in a later lesson.

Link states: :link and :visited

Links have two extra pseudo-classes. :link selects links that the user has not visited yet, and :visited selects links that the user has already opened. When you style all four link states, write them in this order: :link, :visited, :hover, :active. If you change the order, a later rule can cancel an earlier one, and your hover colour may never appear on visited links.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Link States</title>
  <style>
    body { font-family: Arial, sans-serif; font-size: 18px; }
    a:link    { color: #1565c0; }
    a:visited { color: #6a1b9a; }
    a:hover   { color: #e65100; }
    a:active  { color: #b71c1c; }
  </style>
</head>
<body>
  <p><a href="#">A link you have not opened (#)</a></p>
  <p><a href="https://example.com">Another link (example.com)</a></p>
  <p>Hover over a link, then press and hold the mouse button on it.</p>
</body>
</html>

For privacy, browsers allow only colour changes on :visited. Otherwise, a website could find out which other sites you have been to. So you cannot change the size or the background image of visited links.

Focus: Helping Keyboard Users

Many people use a website without a mouse: people with some disabilities, people using a screen reader, and power users who prefer the keyboard. They press Tab to jump from one link, button or input to the next. The element that is ready to receive keys is said to have focus.

  • :focus applies whenever an element has focus, whether it was clicked, tapped or reached with the keyboard.
  • :focus-visible applies only when the browser thinks a visible focus ring is helpful, mainly when the user is using the keyboard. Clicking a button with a mouse usually does not trigger it, but pressing Tab does.

For text inputs, browsers treat both the same, because a user typing always needs to see where the text goes. For buttons and links, :focus-visible lets you show a strong ring to keyboard users without showing it after every mouse click.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>focus and focus-visible</title>
  <style>
    body { font-family: Arial, sans-serif; }
    input {
      padding: 8px;
      font-size: 16px;
      border: 2px solid #bdbdbd;
      border-radius: 6px;
    }
    input:focus {
      border-color: #2e7d32;
      outline: none;
      box-shadow: 0 0 0 3px rgba(46, 125, 50, 0.25);
    }
    button {
      padding: 8px 16px;
      font-size: 16px;
    }
    button:focus-visible {
      outline: 3px solid #1565c0;
      outline-offset: 2px;
    }
  </style>
</head>
<body>
  <p>Click in the box, then press Tab to move to the button.</p>
  <input type="text" placeholder="Table number">
  <button>Call waiter</button>
</body>
</html>
Accessibility rule: every link, button and input must show clearly when it has focus. If you remove the default outline, always add your own style with :focus or :focus-visible.

Structural Pseudo-classes: Position in the Family

These pseudo-classes select elements by their position among their siblings, the elements that share the same parent. Think of children in a family photo, counted from left to right.

Pseudo-classSelects
:first-childThe first child of its parent
:last-childThe last child of its parent
:nth-child(2)The second child
:nth-child(odd)Children 1, 3, 5, 7...
:nth-child(even)Children 2, 4, 6, 8...
:nth-child(3n)Every third child: 3, 6, 9...

Counting starts at 1, not 0. In 3n, the browser tries n = 0, 1, 2, 3 and so on, and selects children number 0 (none), 3, 6, 9 and so on.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Structural Pseudo-classes</title>
  <style>
    body { font-family: Arial, sans-serif; }
    li { padding: 6px; }
    .a li:first-child { font-weight: bold; color: #2e7d32; }
    .a li:last-child  { color: #c62828; }
    .b li:nth-child(odd)  { background-color: #f5f5f5; }
    .c li:nth-child(3n)   { background-color: #fff59d; }
  </style>
</head>
<body>
  <p>first-child and last-child:</p>
  <ul class="a"><li>Rank 1: Kavya</li><li>Rank 2: Arjun</li><li>Rank 3: Imran</li><li>Last: Neha</li></ul>
  <p>nth-child(odd):</p>
  <ul class="b"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>
  <p>nth-child(3n): every third item:</p>
  <ul class="c"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>
</body>
</html>

:not(): everything except

:not() selects elements that do not match the selector inside the brackets. td:not(:first-child) means “every table cell except the first one in its row”. It saves you from writing a rule and then another rule to undo it.

Here is a class results table that uses almost everything so far. Even rows are striped so each row is easy to follow, the row under the mouse is highlighted, number columns are right-aligned with :not(), and the average row at the bottom is bold with :last-child.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Class Results</title>
  <style>
    body { font-family: Arial, sans-serif; }
    table { border-collapse: collapse; width: 100%; max-width: 28rem; }
    th, td { padding: 8px 12px; text-align: left; }
    th { background-color: #283593; color: #ffffff; }
    tr:nth-child(even) td { background-color: #e8eaf6; }
    tr:hover td { background-color: #fff9c4; }
    td:not(:first-child), th:not(:first-child) { text-align: right; }
    tr:last-child td { font-weight: bold; border-top: 2px solid #283593; }
  </style>
</head>
<body>
  <table>
    <tr><th>Student</th><th>Maths</th><th>Science</th></tr>
    <tr><td>Kavya</td><td>92</td><td>88</td></tr>
    <tr><td>Arjun</td><td>78</td><td>84</td></tr>
    <tr><td>Imran</td><td>85</td><td>91</td></tr>
    <tr><td>Neha</td><td>69</td><td>75</td></tr>
    <tr><td>Class average</td><td>81</td><td>84.5</td></tr>
  </table>
</body>
</html>

Form Pseudo-classes

Form elements have states too, and CSS can react to them:

  • :checked selects a checkbox or radio button that is ticked.
  • :disabled selects a button or input that has the disabled attribute, so it cannot be used.
  • :placeholder-shown selects an input that is still empty and showing its placeholder text.

The example below uses input:checked + span. The + means “the element directly after”, so the rule styles the text right next to a ticked checkbox. Tick and untick the boxes, and type in the input to see its border change.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Form States</title>
  <style>
    body { font-family: Arial, sans-serif; }
    label { display: block; padding: 6px; }
    input:checked + span { color: #2e7d32; font-weight: bold; }
    input[type="text"] {
      padding: 8px;
      font-size: 16px;
      border: 2px solid #2e7d32;
    }
    input:placeholder-shown { border-color: #bdbdbd; }
    button:disabled {
      background-color: #e0e0e0;
      color: #9e9e9e;
      cursor: not-allowed;
    }
  </style>
</head>
<body>
  <label><input type="checkbox" checked> <span>Extra butter</span></label>
  <label><input type="checkbox"> <span>Less spicy</span></label>
  <p><input type="text" placeholder="Any special request?"></p>
  <button disabled>Pay now (add an item first)</button>
</body>
</html>

Touch Screens Have No Hover

Most of your visitors in India will use a phone. A finger cannot “hover” over a screen without touching it. On phones, a tap often triggers :hover briefly, and sometimes the hover style stays stuck until the user taps somewhere else.

So follow one simple rule: use hover only for extra decoration, never to hide important things. A dropdown menu or a price that appears only on hover cannot be reached on many phones. Make everything important visible or available with a tap. In the CSS Media Queries lesson you will see @media (hover: hover), which applies styles only on devices that can really hover.

Real-Life Example: Annapurna Bhojanalaya Menu

Annapurna Bhojanalaya is a family restaurant that wants a simple online menu. The category tabs change colour on hover and show a clear focus ring for keyboard users. The first tab is highlighted with :first-child. Menu rows are striped, highlighted on hover and the last row has no bottom line. :not(.veg) marks non-vegetarian dishes in red. The button reacts to hover, press and keyboard focus.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Annapurna Bhojanalaya: Menu</title>
  <style>
    body { font-family: Arial, sans-serif; color: #3e2723; padding: 16px; }
    .tabs a {
      display: inline-block;
      padding: 8px 14px;
      margin-right: 4px;
      color: #6d4c41;
      text-decoration: none;
      border-radius: 999px;
    }
    .tabs a:hover { background-color: #efebe9; }
    .tabs a:focus-visible { outline: 3px solid #1565c0; outline-offset: 2px; }
    .tabs a:first-child { background-color: #6d4c41; color: #ffffff; }
    .menu { list-style: none; padding: 0; max-width: 26rem; }
    .menu li {
      display: flex;
      justify-content: space-between;
      padding: 10px 12px;
      border-bottom: 1px solid #eeeeee;
    }
    .menu li:nth-child(even) { background-color: #fafafa; }
    .menu li:hover { background-color: #fff3e0; }
    .menu li:last-child { border-bottom: none; }
    .menu li:not(.veg) { color: #b71c1c; }
    .add {
      padding: 8px 16px;
      font-size: 15px;
      color: #ffffff;
      background-color: #e65100;
      border: none;
      border-radius: 6px;
    }
    .add:hover { background-color: #bf360c; }
    .add:active { transform: scale(0.96); }
    .add:focus-visible { outline: 3px solid #1565c0; outline-offset: 2px; }
  </style>
</head>
<body>
  <nav class="tabs">
    <a href="#">Thali</a>
    <a href="#">Starters</a>
    <a href="#">Desserts</a>
  </nav>
  <ul class="menu">
    <li class="veg"><span>Mini Thali</span><span>Rs 120</span></li>
    <li class="veg"><span>Deluxe Thali</span><span>Rs 180</span></li>
    <li><span>Chicken Thali</span><span>Rs 220</span></li>
    <li class="veg"><span>Jain Thali</span><span>Rs 160</span></li>
    <li><span>Fish Thali</span><span>Rs 240</span></li>
  </ul>
  <button class="add">Add to order</button>
</body>
</html>

The menu rows use display: flex to push the price to the right. You will learn it in the CSS Flexbox lesson.

Try these changes, one at a time:

  1. Change nth-child(even) to nth-child(odd) and see which rows change.
  2. Click inside the result panel and press Tab several times. Watch the focus ring move through the tabs and the button.
  3. Add a rule .menu li:first-child { font-weight: bold; } to highlight the most popular dish.

Common Mistakes (and How to Fix Them)

  • A space before the colon. button :hover means “a hovered element inside a button”, which is not what you want. Write button:hover with no space.
  • Removing focus outlines. *:focus { outline: none; } makes your site unusable with a keyboard. Style :focus-visible instead.
  • Link states in the wrong order. Put :hover after :link and :visited, and :active last.
  • Expecting :first-child to mean “first of its type”. p:first-child only matches if the paragraph is the very first child of its parent. If an h2 comes first, nothing is selected.
  • Hiding important content behind hover. Phone users cannot reach it. Make it visible or tappable.

Practice Task: A Cricket Points Table

Your college is running an inter-department cricket league, and you are making the points table page. Complete the five TODO steps using pseudo-classes only. Do not add any classes to the HTML.

  • Even rows are striped and rows highlight on hover
  • The top team is bold (hint: the heading row is child number 1)
  • All columns except the first are right-aligned
  • The button shows a clear outline when reached with Tab
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Cricket Points Table</title>
  <style>
    body { font-family: Arial, sans-serif; }
    table { border-collapse: collapse; width: 100%; max-width: 26rem; }
    th, td { padding: 8px 12px; text-align: left; }
    th { background-color: #1b5e20; color: #ffffff; }
    /* TODO 1: Stripe the even rows (light grey) */
    /* TODO 2: Highlight a row in yellow on hover */
    /* TODO 3: Make the first team (top of the table) bold */
    /* TODO 4: Right-align every column except the first */
    .btn { margin-top: 12px; padding: 8px 16px; font-size: 16px; }
    /* TODO 5: Give the button a visible focus-visible outline */
  </style>
</head>
<body>
  <table>
    <tr><th>Team</th><th>Played</th><th>Points</th></tr>
    <tr><td>Chennai Chargers</td><td>10</td><td>16</td></tr>
    <tr><td>Mumbai Mavericks</td><td>10</td><td>14</td></tr>
    <tr><td>Delhi Dashers</td><td>10</td><td>10</td></tr>
    <tr><td>Kolkata Comets</td><td>10</td><td>8</td></tr>
  </table>
  <button class="btn">Full schedule</button>
</body>
</html>
Show one possible answer (try it yourself first!)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Cricket Points Table</title>
  <style>
    body { font-family: Arial, sans-serif; }
    table { border-collapse: collapse; width: 100%; max-width: 26rem; }
    th, td { padding: 8px 12px; text-align: left; }
    th { background-color: #1b5e20; color: #ffffff; }
    tr:nth-child(even) td { background-color: #f1f1f1; }
    tr:hover td { background-color: #fff59d; }
    tr:nth-child(2) td { font-weight: bold; }
    td:not(:first-child), th:not(:first-child) { text-align: right; }
    .btn { margin-top: 12px; padding: 8px 16px; font-size: 16px; }
    .btn:focus-visible { outline: 3px solid #1565c0; outline-offset: 2px; }
  </style>
</head>
<body>
  <table>
    <tr><th>Team</th><th>Played</th><th>Points</th></tr>
    <tr><td>Chennai Chargers</td><td>10</td><td>16</td></tr>
    <tr><td>Mumbai Mavericks</td><td>10</td><td>14</td></tr>
    <tr><td>Delhi Dashers</td><td>10</td><td>10</td></tr>
    <tr><td>Kolkata Comets</td><td>10</td><td>8</td></tr>
  </table>
  <button class="btn">Full schedule</button>
</body>
</html>

Key Takeaways

  • A pseudo-class selects an element in a certain state or position, written with a colon: a:hover.
  • :hover and :active react to the mouse. Style links in the order :link, :visited, :hover, :active.
  • :focus and :focus-visible help keyboard users. Never remove focus styles without a replacement.
  • :first-child, :last-child, :nth-child() and :not() select by position, which makes striped tables easy.
  • :checked, :disabled and :placeholder-shown style form states. Remember that touch screens have no real hover.

❓ Frequently Asked Questions

A class is a name you add to HTML yourself, like class="veg". A pseudo-class is built into CSS and selects elements by state or position, such as :hover or :nth-child(2), without changing the HTML.
Use :focus-visible for buttons and links, so keyboard users see a clear ring and mouse users are not distracted. Text inputs show focus either way, and :focus is fine for them.
Phones have no real hover, so a tap triggers the hover style and it may stay until you tap elsewhere. Use hover only for small decoration on phones.
They select exactly the same elements: the 1st, 3rd, 5th and so on. odd is simply easier to read.
Was this lesson helpful?

🎯 Finished this lesson?

🔗 Related Tutorials
🤖 Got a Doubt? Ask AI
Get instant answers in Hindi or English
🤖
Z2T Bot
Online
Ask me anything about this tutorial — I'm here! 👋