Pseudo-Classes & Pseudo-Elements
সিউডো-ক্লাস ও সিউডো-এলিমেন্ট
1. Styling States and Content Without Touching HTML
So far, most of your CSS has targeted elements that already exist in the HTML. But CSS can also react to
state — is the mouse hovering, is the input focused — and can even generate brand-new
visual content that never appears in the HTML source at all. These two families of selectors are called
pseudo-classes (state-based, single colon :) and
pseudo-elements (content-based, double colon ::).
:) এবং pseudo-element (কনটেন্ট-ভিত্তিক, দুটি কোলন ::)।
Core insight: ::before and ::after let you insert visual content before or
after an element's actual content, without changing the HTML at all.
::before ও ::after দিয়ে HTML না বদলিয়েই একটি এলিমেন্টের আগে বা পরে ভিজুয়াল কনটেন্ট যোগ করা যায়।
2. :hover, :focus, :active — Reacting to the User
:hover applies while the pointer is over an element. :focus applies while an
element (usually a link, button, or form field) has keyboard focus — critical for accessibility, since
keyboard-only users rely on it to see where they are. :active applies during the brief
moment an element is being clicked or pressed. Combine them thoughtfully: a button should usually change
on :hover for mouse users and always show a visible outline on :focus for
keyboard users — never remove focus outlines without replacing them with something equally visible.
:hover প্রযোজ্য হয় যখন পয়েন্টার একটি এলিমেন্টের ওপর থাকে। :focus প্রযোজ্য হয় যখন একটি এলিমেন্টে (সাধারণত লিংক, বাটন, বা ফর্ম ফিল্ড) কীবোর্ড focus থাকে — accessibility-এর জন্য এটি অত্যন্ত গুরুত্বপূর্ণ, কারণ কীবোর্ড-নির্ভর ব্যবহারকারীরা এর ওপর ভরসা করেই বোঝেন তারা কোথায় আছেন। :active প্রযোজ্য হয় ঠিক যে মুহূর্তে একটি এলিমেন্টে ক্লিক করা হচ্ছে। এগুলো বুদ্ধিমত্তার সাথে মেলান — মাউস ব্যবহারকারীদের জন্য বাটন :hover-এ বদলাক, আর কীবোর্ড ব্যবহারকারীদের জন্য :focus-এ সবসময় একটি স্পষ্ট outline দেখাক — focus outline কখনো এমনি এমনি সরাবেন না।
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Button States</title></head>
<body>
<button class="btn-demo">Hover, focus, or click me</button>
<p>Try tabbing to the button with the keyboard, or hovering/clicking with the mouse.</p>
</body>
</html>
.btn-demo {
padding: 10px 18px;
font-size: 1rem;
border: 2px solid #39b549;
background: white;
color: #1f6e2a;
border-radius: 6px;
cursor: pointer;
}
.btn-demo:hover {
background: #39b549;
color: white;
}
.btn-demo:focus {
outline: 3px solid #2563eb;
outline-offset: 2px;
}
.btn-demo:active {
transform: scale(0.96);
}
Note: hover inside the live preview iframe above to see the color swap — the preview is a real rendered page. প্রিভিউর ভেতরেই hover করে দেখুন।
3. :first-child, :nth-child — Selecting by Position
Structural pseudo-classes select elements based on their position among siblings, without needing an
extra class in the HTML. :first-child and :last-child match the first or last
element inside a parent. :nth-child(n) is the most flexible: :nth-child(2)
matches the second child, :nth-child(odd) matches 1st, 3rd, 5th…, and
:nth-child(3n) matches every third element — extremely useful for zebra-striping tables or
spacing out grid items.
:first-child ও :last-child একটি parent-এর ভেতরে প্রথম বা শেষ এলিমেন্ট ম্যাচ করে। :nth-child(n) সবচেয়ে নমনীয় — :nth-child(2) দ্বিতীয় সন্তানকে ম্যাচ করে, :nth-child(odd) ১ম, ৩য়, ৫ম... ম্যাচ করে, আর :nth-child(3n) প্রতি তৃতীয় এলিমেন্ট ম্যাচ করে — table-এ zebra-stripe বা grid item-এর মাঝে স্পেসিং দেওয়ার জন্য অত্যন্ত কার্যকর।
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Zebra Stripes</title></head>
<body>
<ul class="list">
<li>Row One</li>
<li>Row Two</li>
<li>Row Three</li>
<li>Row Four</li>
<li>Row Five</li>
</ul>
</body>
</html>
.list {
list-style: none;
padding: 0;
font-family: sans-serif;
}
.list li {
padding: 10px;
}
.list li:nth-child(odd) {
background: #f1f5f9;
}
.list li:first-child {
font-weight: bold;
color: #1f6e2a;
}
.list li:last-child {
border-bottom: 2px solid #39b549;
}
4. ::before & ::after — Generated Content
::before and ::after insert a virtual, style-only element immediately before or
after an element's real content. They require a content property to render — even
content: ""; works, and is commonly used just to draw a decorative shape. They're used
everywhere: little quote marks around a blockquote, arrow icons after a link, badges, tooltips, and
decorative underlines that appear on hover.
::before ও ::after একটি এলিমেন্টের আসল কনটেন্টের ঠিক আগে বা পরে একটি ভার্চুয়াল, স্টাইল-অনলি এলিমেন্ট বসায়। রেন্ডার হওয়ার জন্য এদের একটি content প্রপার্টি লাগে — এমনকি content: "";-ও কাজ করে, এবং প্রায়ই কেবল একটি ডেকোরেটিভ শেপ আঁকার জন্য ব্যবহৃত হয়। এগুলো সর্বত্র ব্যবহৃত হয় — blockquote-এর চারপাশে ছোট quote mark, লিংকের পরে arrow আইকন, badge, tooltip, এবং hover-এ দেখা যাওয়া ডেকোরেটিভ underline।
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Before After</title></head>
<body>
<a href="#" class="ext-link">Read the docs</a>
<p class="quote">CSS makes the web beautiful.</p>
</body>
</html>
.ext-link {
color: #2563eb;
font-family: sans-serif;
}
.ext-link::after {
content: " \2197"; /* arrow character */
font-weight: bold;
}
.quote {
font-family: sans-serif;
font-style: italic;
color: #374151;
}
.quote::before {
content: "\201C"; /* left double quote */
color: #39b549;
font-weight: bold;
margin-right: 2px;
}
.quote::after {
content: "\201D"; /* right double quote */
color: #39b549;
font-weight: bold;
margin-left: 2px;
}
5. :not() & Combinators
:not(selector) matches anything that does not match the given selector — for
example, li:not(:last-child) selects every list item except the last, handy for adding a
border between items without a trailing border underneath the final one. Combinators refine this
further: A + B (adjacent sibling) matches a B immediately after an
A, while A ~ B (general sibling) matches any B that comes after an
A anywhere within the same parent.
:not(selector) এমন যেকোনো কিছু ম্যাচ করে যা দেওয়া সিলেক্টরের সাথে মেলে না — যেমন, li:not(:last-child) শেষটি বাদে প্রতিটি list item বেছে নেয়, আইটেমগুলোর মাঝে border যোগ করতে কাজে লাগে, শেষটির নিচে অতিরিক্ত border ছাড়াই। Combinator আরও নিখুঁত করে — A + B (adjacent sibling) একটি A-এর ঠিক পরের B-কে ম্যাচ করে, আর A ~ B (general sibling) একই parent-এর ভেতরে A-এর পরে যেকোনো জায়গায় থাকা B-কে ম্যাচ করে।
:not() combined with structural pseudo-classes often replaces the need to add or remove
classes with JavaScript just to style "all but the last" or "all but the first" element.
:not()-কে structural pseudo-class-এর সাথে মিলিয়ে ব্যবহার করলে "শেষটি বাদে সব" বা "প্রথমটি বাদে সব" স্টাইল করতে JavaScript দিয়ে ক্লাস যোগ/বাদ দেওয়ার দরকার প্রায়ই এড়ানো যায়।
6. Styling Form States
Forms have their own set of useful pseudo-classes: :checked for checked checkboxes/radios,
:disabled and :enabled for interactive availability, :valid and
:invalid based on built-in HTML validation, and :placeholder-shown while a field
still shows its placeholder text instead of real input. These let you give the user instant visual
feedback — a green border on a valid email field, a red one on an invalid one — using pure CSS, no
JavaScript required.
:checked, ইন্টারঅ্যাকটিভ availability-এর জন্য :disabled ও :enabled, বিল্ট-ইন HTML validation-এর ওপর ভিত্তি করে :valid ও :invalid, এবং একটি ফিল্ডে এখনো placeholder টেক্সট দেখা যাচ্ছে কিনা তার জন্য :placeholder-shown। এগুলো দিয়ে JavaScript ছাড়াই, শুধু CSS দিয়ে ব্যবহারকারীকে তাৎক্ষণিক ভিজুয়াল ফিডব্যাক দেওয়া যায় — বৈধ email ফিল্ডে সবুজ বর্ডার, অবৈধ হলে লাল।
| Selector | Matches | বাংলায় |
|---|---|---|
:hover | Pointer is over the element. | পয়েন্টার এলিমেন্টের ওপর আছে। |
:focus | Element has keyboard/click focus. | এলিমেন্টে কীবোর্ড/ক্লিক focus আছে। |
:active | Element is being pressed/clicked right now. | এলিমেন্টটি এই মুহূর্তে ক্লিক/চাপ দেওয়া হচ্ছে। |
:first-child / :last-child | First / last element among its siblings. | সিবলিং-দের মধ্যে প্রথম / শেষ এলিমেন্ট। |
:nth-child(n) | Nth element; supports odd/even/An+B patterns. | n-তম এলিমেন্ট; odd/even/An+B প্যাটার্ন সাপোর্ট করে। |
:not(sel) | Anything that does not match sel. | sel-এর সাথে না মেলা যেকোনো কিছু। |
:checked | A checked checkbox or radio button. | একটি checked checkbox বা radio button। |
:disabled / :enabled | Interactive state of form fields. | ফর্ম ফিল্ডের ইন্টারঅ্যাকটিভ অবস্থা। |
:valid / :invalid | Passes / fails built-in HTML validation. | বিল্ট-ইন HTML validation পাস / ফেল করে। |
::before / ::after | Generated content before/after the element. | এলিমেন্টের আগে/পরে তৈরি হওয়া কনটেন্ট। |
7. Practice Problems
Try each problem yourself first, then open the answer and run it in the live preview.
-
Make a button turn from green to dark green on hover, and show a visible blue outline on focus.hover করলে একটি বাটন সবুজ থেকে গাঢ় সবুজ হবে, এবং focus হলে স্পষ্ট নীল outline দেখাবে — এভাবে CSS লিখুন।
✨ Show Answer (উত্তর দেখুন)
ans1.html<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Button</title></head> <body> <button class="go">Go</button> </body> </html>style.css.go { background: #39b549; color: white; border: none; padding: 10px 16px; border-radius: 6px; } .go:hover { background: #1f6e2a; } .go:focus { outline: 3px solid #2563eb; outline-offset: 2px; } -
Style every even row of a list with a light gray background using
:nth-child.:nth-childব্যবহার করে একটি লিস্টের প্রতিটি জোড় (even) সারিতে হালকা ধূসর background দিন।✨ Show Answer (উত্তর দেখুন)
ans2.html<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Even Rows</title></head> <body> <ul> <li>One</li><li>Two</li><li>Three</li><li>Four</li> </ul> </body> </html>style.cssli:nth-child(even) { background: #f1f5f9; } -
Add a small red asterisk after every
labelusing::after, without editing the HTML.HTML না বদলিয়ে::afterব্যবহার করে প্রতিটিlabel-এর পরে একটি ছোট লাল asterisk যোগ করুন।✨ Show Answer (উত্তর দেখুন)
ans3.html<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Required Field</title></head> <body> <label>Email</label> <input type="email"> </body> </html>style.csslabel { font-family: sans-serif; font-weight: bold; } label::after { content: " *"; color: #dc2626; } -
Select every paragraph except the first one and give it a top margin, using
:not().:not()ব্যবহার করে প্রথমটি বাদে প্রতিটি paragraph বেছে নিয়ে top margin দিন।✨ Show Answer (উত্তর দেখুন)
ans4.html<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Not First</title></head> <body> <p>First paragraph, no extra margin.</p> <p>Second paragraph, gets margin.</p> <p>Third paragraph, gets margin.</p> </body> </html>style.cssp:not(:first-child) { margin-top: 20px; } -
Give a text input a green border when its content is valid, and a red border when invalid.একটি text input-এর কনটেন্ট বৈধ হলে সবুজ border এবং অবৈধ হলে লাল border দিন।
✨ Show Answer (উত্তর দেখুন)
ans5.html<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Validation Colors</title></head> <body> <form> <input type="email" required placeholder="you@example.com"> </form> </body> </html>style.cssinput { padding: 8px; border: 2px solid #d1d5db; border-radius: 4px; } input:valid { border-color: #39b549; } input:invalid { border-color: #dc2626; }
Summary — Module 19
Pseudo-classes (:hover, :focus, :nth-child, :not())
style elements based on state or position without adding classes. Pseudo-elements
(::before, ::after) generate extra visual content without touching the HTML.
Together they let you build polished, interactive interfaces with far less markup and no JavaScript.
:hover, :focus, :nth-child, :not()) ক্লাস যোগ না করেই state বা position অনুযায়ী এলিমেন্ট স্টাইল করে। Pseudo-element (::before, ::after) HTML স্পর্শ না করেই বাড়তি ভিজুয়াল কনটেন্ট তৈরি করে। একসাথে এগুলো দিয়ে অনেক কম মার্কআপ ও কোনো JavaScript ছাড়াই polished, ইন্টারঅ্যাকটিভ ইন্টারফেস বানানো যায়।