Visual Perception and Aesthetics

Pseudo-Classes

Pseudo-classes are dynamic selectors that allow HTML elements to be styled based on "what state they are in" rather than just "who they are."
Below, we will examine pseudo-classes in detail.

Main Topic
Level 4

The Purpose of Pseudo-Classes States, Interactions, and Virtual Segments

The "Invisible Class" Logic

In the world of web development, a standard CSS class (.class) is like a label permanently attached to an element by the developer.

However, the web is not a static poster; it is a living, breathing, and constantly changing environment.

Pseudo-Classes, as the name suggests, are "ghost classes" that the browser automatically and temporarily adds to an element when specific conditions are met.

For Example: The moment a user clicks a button, the browser attaches a virtual "Being Clicked" label to that button and removes it once the click is finished.

Instead of you having to say with JavaScript, "If clicked, add this class; if released, delete it," the CSS engine handles this process in milliseconds.

What Do They Target? (Scope) Pseudo-classes target not just an element's appearance, but its journey through time and position:

Syntax (The Single Colon Rule) The easiest way to identify a Pseudo-Class is the single colon ( : ) prefix.

This sends a message to the browser: "I don't want to change a part of an element; I want to change its state."

Selector Combination and Chaining

Pseudo-classes can be used alone, or multiple pseudo-classes can be chained on the same selector to target much more specific states.

For example: The button:hover:active selector targets only buttons that are being both hovered over and clicked simultaneously.

This approach allows for handling user interactions as layered states and makes UI behaviors much more precise.

Important Note: Chained pseudo-classes are read from left to right, and each one narrows down the previous condition.

Specificity Effect Pseudo-classes are evaluated at the class level in CSS specificity calculations.

This means that a:hover and .btn share the same specificity level, but a more specific chain (e.g., .nav a:hover) can override others.

Therefore, when using pseudo-classes, the selector structure must be carefully constructed to avoid conflicting rules.

Advanced Selection with :is(), :not(), and :where()

Some pseudo-classes introduced with modern CSS make selector writing more powerful and flexible.

:is() → Reduces repetition by grouping multiple selectors in a single line.

:not() → Allows for inverse selection by excluding specific conditions.

:where() → Works like :is() but does not add specificity.

Especially in large projects, these structures ensure that CSS code is both more readable and more sustainable.

Pseudo-Class vs. Pseudo-Element Distinction

Pseudo-classes (:) and pseudo-elements (::) are often confused, but they are entirely different concepts.

While a pseudo-class targets an element's state, a pseudo-element targets a part of that element.

For example:
a:hover → State of the link
p::first-line → First line of the paragraph

This distinction is critical for using the right selector for the right problem.

Pseudo-Class Categories Classification of Interaction, State, and Structural Selectors
Category
Description
User Interaction

Is the mouse hovering? Is it being clicked? Has it gained focus?

History & Links

Has this link been visited before?

Structural (DOM Tree)

Is this element the 3rd child of its parent? Is it an only child?

Form States

Is the checkbox checked? Is the input field empty? Is the data valid?

What Have We Learned So Far?

Core Concepts Mastered
  • The concept of pseudo-classes and their fundamental logic
  • The functional purpose of pseudo-classes in web design
  • State management and interaction paradigms
What's Next?
  • Dynamic interaction classes
  • Responding to real-time user actions
  • Selectors such as :hover, :focus, and :active
Level 4

Dynamic Interaction Classes Responding to User Actions

Introduction

Dynamic interaction classes serve as the bridge between a "static image" and a "functional interface" in web design.

Technically defined within CSS, these structures determine not just how an HTML element looks, but how the user interacts and builds a relationship with that element.

This is the fundamental mechanism that transforms websites from a magazine page to be merely "read" into a tool to be actively "used."

The Body Language of Interfaces

Consider real-life communication: when you call someone's name, they look at you; when you shake their hand, they respond.

In the digital realm, these responses are facilitated by Pseudo-Classes.

These classes give the interface its own "body language."

When a user performs an action ( moving the cursor, clicking, or touching the keyboard ), the interface must signal that it has perceived this action.

If the interface fails to react, the user may assume the system is frozen, broken, or that their action was invalid.

The Concept of State

In traditional graphic design ( posters, brochures ), a visual exists in a single, fixed state.

However, in web design, every interactive element (button, link, input) possesses multiple "states."

These classes answer the question: "What is this element doing RIGHT NOW?"

Is it idling? (Normal/Default)

Is it being inspected? (Hover)

Is it selected? (Focus)

Is it being processed? (Active)

By defining distinct visual rules ( color, size, shadow ) for each state, the designer ensures the interface feels fluid and responsive.

Trust and a Sense of Control

Users need to feel that they are in control of the experience.

Dynamic classes build this trust through the Visual Feedback they provide.

Provides Predictability: An element changing color upon hover sends a clear message to the user: "If you click this, something will happen."

Reduces Error Rates: A user who clearly sees which box they are typing into (Focus) is much less likely to enter data into the wrong field.

Creates a Sense of Satisfaction: A subtle movement during the click (Active) sends a subconscious signal that the operation was successful.

The Foundation of Micro-Interactions

One of the most popular topics in modern web design, "Micro-Interactions," is built entirely upon these classes.

An icon heart expanding when a "Like" button is pressed, or a menu gently unfolding upon hover, is the result of these classes combined with CSS animations.

These details elevate a product from being merely "usable" to being truly "delightful."

The Discovery and Intent Phase The :hover Pseudo-Class

Introduction

This is where the flirtation between the user and the system begins in web interfaces.

When a user hovers over an element with their mouse, they are essentially asking the system a silent question:

"What is this, and what can I do with it?"

The Hover state is the system's gentle reply to that question.

No decision has been made yet; there is only intent or curiosity involved.

Therefore, this phase is the most "fragile" yet most "inviting" moment of interaction.

Psychological Interaction: "Affordance"

In the design world, the concept of "Affordance" refers to an object's shape suggesting how it should be used

(like the shape of a door handle saying "press me down").

Digital screens are flat; therefore, :hover creates the sensation of depth and functionality.

The Safe Zone: Users often scan content by moving their cursor across the page before committing to a click.

Hover effects reduce the user's fear of clicking the wrong thing.

It sends the message: "Don't worry, you're just looking right now; I will only process an action if you click."

Focus Management: In a crowded layout, the user's eye follows visual responses that match the movement of the mouse.

Hover acts as a spotlight to manage user attention.

Visual Implementation Strategies

While methods for indicating a "hover" state vary by brand character, the fundamental goal is "differentiation."

Color Manipulation: The most common method.

The "brightness" value of the button's current color is adjusted.

Lightening the color ( brightening ) usually gives a sense of "approach/elevation," while darkening it suggests "seriousness/readiness."

Depth and Elevation: Frequently seen in Material Design philosophy.

The element's shadow grows and diffuses upon hover.

This creates the illusion that the element is physically rising from the screen toward the user.

It signals: "I am closer to you now, you can touch me."

Translation (Movement): The element might shift 2-3 pixels upward from its position.

This simple movement animates the interface and breaks the feeling of staticity.

Cursor Change: Though not a visual style per se, changing the mouse cursor from a standard arrow to a "pointing hand" ( pointer ) is an inseparable part of the hover experience.

The Mobile Device Paradox (The Hover Trap)

A common trap for web designers is focusing exclusively on the desktop experience while forgetting mobile reality.

The Nature of Touch Screens: On phones, there is no such action as "hovering a finger in the air."

The moment you touch the screen, a "click" technically occurs.

Therefore, hover effects either never appear on mobile or flicker for a split second during the tap.

The "Sticky Hover" Problem: In some mobile browsers, touching a button causes its hover style (like a background color) to get "stuck."

That color won't revert until the user taps elsewhere.

This leads to confusion: "Is the button still pressed?"

Critical Content Warning: If sub-menu options only open on hover, mobile users will never be able to access them.

Consequently, hover should remain a "visual embellishment" or an "extra hint," never the sole key to primary navigation.

Design Tip: Transition Smoothness

A high-quality hover effect shouldn't just "snap" into existence.

Color changes or movements should occur smoothly over a duration of 0.2 or 0.3 seconds.

This makes the interface perceived as more modern and professional.

Abrupt color shifts strain the eyes and can feel like a digital glitch.

</>
Interaction-Based Pseudo-Classes: :hover Simple Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hover Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <div class="container">
        <h2>Hover Interaction</h2>
        <button class="btn-hover">Hover Over Me</button>
    </div>

</body>

</html>

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: #ececec;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
}

.container {
    background: linear-gradient(145deg, #ffffff, #dcdcdc);
    padding: 40px;
    border-radius: 14px;
    width: 300px;
    text-align: center;
    border: 2px solid rgba(0, 0, 0, 0.1);
    box-shadow:
        inset 0 1px 4px rgba(255, 255, 255, 0.7),
        0 6px 18px rgba(0, 0, 0, 0.2);
}

h2 {
    font-size: 22px;
    margin-bottom: 20px;
    color: #333;
    text-transform: uppercase;
    font-weight: 600;
}

.btn-hover {
    padding: 14px 30px;
    background: linear-gradient(135deg, #6a5af9, #4d3be6);
    color: white;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 8px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: 0.25s; /* Smooth state transition */
}

/* Pseudo-class applied on hover */
.btn-hover:hover {
    background: linear-gradient(135deg, #7e6cfb, #5949f2);
    transform: translateY(-2px) scale(1.05); /* Visual feedback through movement and scaling */
}
                            

Action and Tactile Feedback The :active Pseudo-Class

Introduction

This state represents the moment of "actualization" in digital interaction.

The user's intent ( hover ) and focus ( focus ) have now transformed into an action.

Technically, it covers the millisecond timeframe while the primary mouse button is being held down, but the sensation it creates seals the entire user experience.

If :hover is an invitation, :active is the handshake.

Physical Sensation in a Digital World (Tactile Feedback)

The human brain has evolved according to the action-reaction principles of the physical world.

When you push a door handle, you feel resistance; when you press a piano key, it moves downward.

However, touch screens and mice are flat glass surfaces; they provide no inherent physical feedback.

This is where the :active state completes this deficiency through a visual illusion.

The Skeuomorphism Legacy: In early interface designs, buttons were drawn in 3D and embossed styles to mimic real life.

Even in today's "Flat" design world, we still crave this sensation.

The :active state signals our brain that "Yes, a physical contact has occurred" by making the button appear momentarily depressed or sunken.

Sense of Vitality: An unresponsive button gives the user the impression of a "frozen" or "broken" system.

A responsive button, however, makes the interface feel alive, listening, and processing.

Preventing "Rage Clicking"

Have you ever clicked a button 5 or 6 times in frustration because you thought it wasn't working?

In the world of UX, this is known as "Rage Clicking."

Eliminating Ambiguity: If no visual change occurs ( color change or movement ) when the user clicks, they assume the system hasn't registered the command.

This doubt triggers repeated clicks.

Consequences: In e-commerce, this can lead to accidental double purchases; in forms, it can result in duplicate data submissions or unnecessary server load.

The :active effect is a visual confirmation saying, "Okay, stay calm, I heard your click."

Implementation Techniques: How Should It Feel?

The secret to designing this stage is "subtlety."

Large changes tire the eye, while microscopic changes go unnoticed.

The Pressure Illusion (Scale): This is the most popular modern method.

The button is scaled down to 95% or 98% at the moment of click ( transform: scale(0.98) ).

This mimics the physical act of pressing and compressing a button with your finger.

Depth Movement (Translation): If a button has a shadow, the shadow is removed and the button is shifted 2-3 pixels down

(transform: translateY).

This provides the sensation of the button being embedded into the surface.

The Ripple Effect: Frequently seen in the Android ecosystem, this is a wave-like effect that spreads outward from the point of contact.

Since it highlights the exact coordinates of the touch, it is one of the most satisfying forms of feedback.

A Note for Links While we usually discuss buttons, text links should also benefit from this state.

Changing a link's color to red or a darker shade momentarily confirms that the finger hit the right word, which is especially vital on mobile devices.

</>
Interaction-Based Pseudo-Classes: :active Simple Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Active Pseudo Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="container">
        <h3>Active Pseudo</h3>
        <button class="btn-active">Click Me</button>
    </div>
</body>

</html>
body {
    font-family: 'Segoe UI', sans-serif;
    background: linear-gradient(160deg, #e6e9f0, #eef1f5);
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
}

.container {
    background: rgba(255, 255, 255, 0.35);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    padding: 40px;
    border-radius: 18px;
    width: 300px;
    text-align: center;
    border: 2px solid rgba(255, 255, 255, 0.4);
    box-shadow:
        0 8px 25px rgba(0, 0, 0, 0.12),
        inset 0 1px 3px rgba(255, 255, 255, .5);
}

.container h3 {
    text-align: center;
    font-weight: 600;
    letter-spacing: 1px;
    margin-bottom: 20px;
    color: #2b2b2b;
    text-transform: uppercase;
}

.btn-active {
    position: relative;
    padding: 16px 35px;
    background: linear-gradient(135deg, #4b9bff, #1e6bff);
    color: white;
    border: none;
    border-radius: 10px;
    font-size: 17px;
    font-weight: 600;
    cursor: pointer;
    transition: .25s ease;
    letter-spacing: 0.6px;
    box-shadow:
        0 6px 18px rgba(50, 120, 255, 0.35),
        inset 0 1px 4px rgba(255, 255, 255, 0.4);
}

/* State 1: Discovery */
.btn-active:hover {
    background: linear-gradient(135deg, #5ca8ff, #2b7dff);
    transform: translateY(-5px) scale(1.06);
    box-shadow:
        0 14px 32px rgba(30, 80, 255, 0.4),
        inset 0 2px 8px rgba(255, 255, 255, 0.25);
}

/* State 2: Interaction/Physical Touch */
.btn-active:active {
    transform: scale(0.95) translateY(2px); /* Mimics being pressed down */
    background: linear-gradient(135deg, #2d6cff, #184fde);
    box-shadow:
        inset 0 5px 15px rgba(0, 0, 0, 0.25), /* Creates inner depth shadow */
        0 4px 8px rgba(0, 0, 0, 0.1);
}

Phase of Navigation and Intent The :focus Pseudo-Class

Introduction

Navigating a web page is akin to finding your way through a dark room with a flashlight.

For mouse users, the cursor is that flashlight; they see wherever they point.

However, for keyboard users, the "beam of that light" is the :focus state.

This state serves as a digital compass, indicating exactly where the user is on the page and which element they are about to interact with.

Keyboard Navigation and "Sequential Access"

A significant portion of web users do not—or cannot—use a mouse.

Individuals with limited motor skills, power users, or those simply wishing to fill out a form quickly use the TAB key to navigate.

Digital Hopscotch: Every time the TAB key is pressed, the focus state jumps to the next interactive element (link, input, button) based on the DOM order.

Visual Tracking: If no :focus style is defined, the user presses TAB but sees no change on the screen.

They have no way of knowing which link they are on or which button they are about to trigger.

This is like "trying to drive a car while blindfolded."

Accessibility Sin: "Outline: None"

One of the greatest mistakes web designers make due to aesthetic concerns is removing the browser's default focus ring

(that blue or black outline) using the outline: none rule.

The Invisibility Problem: The moment you write this code, you effectively blind keyboard users on your page.

The visitor is there, they are pressing keys, but they can never see their current position.

WCAG Standards: According to the Web Content Accessibility Guidelines, making the focused element visually distinct is not a preference—it is a requirement.

Failing to follow this rule is equivalent to not providing a wheelchair ramp for a physical store; it simply excludes a specific group of users.

Intelligent Design Approach

Browser default focus styles (often jagged or thick blue lines) can sometimes clash with modern designs.

The correct approach is not to remove the style entirely, but to redesign it to align with your brand.

Alternative Solutions: Instead of the default ring, you can use a soft glow effect in the brand's primary color, a thick and high-contrast border, or a dramatic change in background color.

Dual-Layer Appearance: In advanced designs, combining color changes with a slight increase in element size makes the focus state unmistakably clear.

Input Fields: The colored border that appears when a text box is clicked during form entry tells the user,

"The keyboard is currently writing here."

This prevents accidental typing into empty space and facilitates focus.

Role in Mobile Experience

While the Focus state is usually associated with desktop/keyboards, it is also critical for mobile forms.

When you tap "Next" on a phone keyboard while filling out a form, the screen automatically scrolling to the next box and that box lighting up is a result of the :focus mechanism.

This fluidity reduces the friction of mobile data entry.

</>
Interaction-Based Pseudo-Classes: :focus Simple Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Focus Pseudo Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="container">
        <h3>Focus Pseudo Example</h3>
        <button class="btn-focus">Focus Me</button>
    </div>

</body>

</html>
body {
    font-family: 'Segoe UI', sans-serif;
    background: linear-gradient(160deg, #e6e9f0, #eef1f5);
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
}

.container {
    background: rgba(255, 255, 255, 0.35);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    padding: 40px;
    border-radius: 18px;
    width: 400px;
    text-align: center;
    border: 2px solid rgba(255, 255, 255, 0.4);
    box-shadow:
        0 8px 25px rgba(0, 0, 0, 0.12),
        inset 0 1px 3px rgba(255, 255, 255, .5);
}

h3 {
    text-align: center;
    font-weight: 600;
    letter-spacing: 1px;
    margin-bottom: 20px;
    color: #2b2b2b;
    text-transform: uppercase;
}

.btn-focus {
    padding: 14px 28px;
    background: #4a6cff;
    color: white;
    border: none;
    border-radius: 8px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: 0.25s;
    outline: none; /* Removing default ring for custom design */
}

.btn-focus:hover {
    background: #5c7cff;
}

/* State: Sequential Keyboard Focus */
.btn-focus:focus {
    /* Custom glow effect replaces default outline */
    box-shadow: 0 0 0 4px rgba(76, 104, 255, 0.35); 
    transform: translateY(-3px); /* Visual elevation feedback */
}

Intelligent Focusing and Accessibility :focus-visible

The Great Problem: The "Blue Ring" Crisis

This pseudo-class applies styles when an element is focused, but only triggers in situations where the browser determines that the focus should be visible to the user.

This selector is the smartest answer to one of modern web design's greatest dilemmas: "Aesthetics or Accessibility?"

The standard :focus class activates whether a button is clicked with a mouse or reached via a keyboard (Tab key).

A visitor using a mouse typically does not want to see a thick blue or black outline around a sleek button upon clicking; for designers, this is often considered a visual flaw.

Consequently, for years, designers utilized outline: none to remove this ring entirely. However, this caused individuals with disabilities who rely on keyboards to become "lost" on the page.

The Solution: Browser Intelligence (Heuristics) :focus-visible distinguishes between these two interaction modes.

If the user clicks with a mouse, the browser concludes, "This user's eyes are already on the cursor; they don't need an extra ring," and suppresses the style.

However, if the user navigates via keyboard, the browser determines, "This user needs to see exactly where they are," and renders the focus indicator.

</>
Interaction-Based Pseudo-Classes: :focus-visible Example 1 (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Focus-visible Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="focus-panel">
        <input type="text" placeholder="Enter your name">
        <button>Submit</button>
    </div>

</body>

</html>
body {
    font-family: 'Segoe UI', sans-serif;
    background: #eef1f6;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    margin: 0;
}

.focus-panel {
    background: #fff;
    padding: 30px;
    border-radius: 16px;
    box-shadow:
        0 6px 18px rgba(0, 0, 0, 0.1),
        inset 0 1px 3px rgba(255, 255, 255, 0.6);
    border: 2px solid rgba(0, 0, 0, 0.07);
    max-width: 350px;
    width: 100%;
    text-align: center;
}

input,
button {
    width: 100%;
    padding: 14px;
    font-size: 16px;
    margin: 12px 0;
    border-radius: 10px;
    border: 1px solid #ccc;
    transition: .25s;
    outline: none; /* Removing default ring for custom logic */
    box-sizing: border-box;
}

/* Fallback for general focus */
input:focus,
button:focus {
    border-color: #4c8dff;
}

/* Triggers ONLY when navigating with keyboard (TAB) */
input:focus-visible,
button:focus-visible {
    box-shadow: 0 0 0 4px rgba(77, 130, 255, 0.35);
    transform: translateY(-2px);
    border-color: #4c8dff;
}

button:hover {
    cursor: pointer;
    background: #4c8dff;
    color: white;
}
</>
Interaction-Based Pseudo-Classes: :focus-visible Example 2 (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Focus-Visible Example 2</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="focus-visible-demo">
        <h3>Focus vs Focus-Visible Comparison</h3>

        <div class="demo-buttons">
            <button class="btn btn-focus">
                :focus (Mouse + Keyboard)
            </button>
            <button class="btn btn-focus-visible">
                :focus-visible (Keyboard Only)
            </button>
        </div>

        <div class="explanation">
            <p><strong>How to test:</strong></p>
            <p>• Click with mouse - only :focus triggers</p>
            <p>• Navigate with Tab key - both will trigger</p>

            <div class="key-instruction">
                ↹ Use the Tab key to navigate between buttons!
            </div>
        </div>
    </div>

</body>

</html>
body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: #f8f9fa;
    margin: 0;
    padding: 20px;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
}

.focus-visible-demo {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    padding: 30px;
    border-radius: 12px;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
    text-align: center;
    max-width: 500px;
    width: 100%;
}

.focus-visible-demo h3 {
    color: white;
    margin-bottom: 25px;
}

.demo-buttons {
    display: flex;
    gap: 15px;
    justify-content: center;
    flex-wrap: wrap;
}

.btn {
    padding: 12px 20px;
    background: #fff;
    border: none;
    border-radius: 8px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.3s ease;
}

/* Always triggers regardless of input method */
.btn-focus:focus {
    outline: 3px solid #ff3838;
    background: #ffcccc;
}

/* Triggers ONLY when the browser detects keyboard navigation */
.btn-focus-visible:focus-visible {
    outline: 3px solid #17c0eb;
    background: #c7ecee;
    transform: scale(1.05);
}

.explanation {
    background: rgba(255, 255, 255, 0.1);
    padding: 15px;
    border-radius: 8px;
    margin-top: 20px;
    color: white;
}

.explanation p {
    margin: 5px 0;
    font-size: 14px;
}

.key-instruction {
    background: #ffeaa7;
    color: #2d3436;
    padding: 8px 12px;
    border-radius: 6px;
    font-weight: bold;
    margin-top: 10px;
    display: inline-block;
}

Memory and Orientation The :visited Pseudo-Class

Introduction

This state is where the website respects the user's personal history and provides vital guidance.

Technically, it triggers when a link on the page matches a URL already stored in the browser's history.

The internet is a vast forest, and the :visited state acts as the "breadcrumb trail" left by the user along their journey, much like the tale of Hansel and Gretel.

Reducing Cognitive Load

When users navigate content-heavy sites ( news portals, forums, search engines ), they are constantly making rapid-fire decisions:

"Should I read this?", "Have I seen this already?"

External Memory: The human brain has a limited capacity for information in short-term memory.

The :visited state offloads this memory burden from the user's mind and embeds it into the interface.

By simply glancing at the link color, the user can decide in less than a second: "I've already been here; I don't need to click again."

Efficiency: Consider Google search results.

If the color of clicked results didn't change, you would waste significant time clicking into the same pages repeatedly.

This color shift allows the user to focus exclusively on new and unexplored content.

Color Codes and Design Standards

Since the early days of the web, an unwritten rule has prevailed: Blue represents the unexplored, while Purple represents the visited.

Why Muted Colors?: In modern design, you aren't strictly required to use purple.

However, the fundamental principle remains: visited links should be less visually prominent ( more faded, greyer, darker ) than unvisited ones.

Visual Hierarchy: While vibrant colors scream "Click Me!", the visited color reduces visual noise by saying

"I'm passive now, move to the next one."

Privacy and "History Sniffing" Restrictions

There is a critical technical and security detail that separates this state from others (hover, focus, active).

The Firewall: In the past, malicious sites could exploit this feature to read a user's browser history.

Example: Hidden bank links could be placed on a page to check for color changes, allowing a site to determine if a user uses a specific bank.

CSS Restrictions:

To close this "History Sniffing" vulnerability, modern browsers have strictly limited the styles that can be applied to the :visited state.

You cannot use :visited to change font size, font family, or move the element.

Only color-related properties can be modified.

This is a global security measure taken to protect user privacy.

Where to Use It?

You are not obligated to use :visited on every link.

For instance, changing the color of buttons like "Home" or "Contact" in a main menu may be counter-intuitive.

However, for "consumable" content lists such as Blog posts, Documentation pages, Search results, and FAQs, utilizing this state is essential for a superior user experience.

</>
Interaction-Based Pseudo-Classes: :visited Example 1 (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Visited Pseudo-Class Example 1</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="visited-box">
        <a href="https://google.com" target="_blank" class="link-card">
            Go to Google
        </a>
    </div>

</body>

</html>
body {
    font-family: 'Segoe UI', sans-serif;
    background: #f1f2f6;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
}

.visited-box {
    background: #ffffff;
    padding: 30px;
    border-radius: 16px;
    width: 250px;
    text-align: center;
    box-shadow:
        0 6px 18px rgba(0, 0, 0, 0.1),
        inset 0 1px 3px rgba(255, 255, 255, 0.6);
    border: 2px solid rgba(0, 0, 0, 0.06);
}

.link-card {
    text-decoration: none;
    background: #4c8dff;
    color: #fff;
    padding: 14px 20px;
    border-radius: 10px;
    display: inline-block;
    font-size: 17px;
    transition: .25s;
}

.link-card:hover {
    background: #5d9bff;
    transform: translateY(-3px);
    box-shadow: 0 8px 18px rgba(76, 141, 255, 0.35);
}

/* State: Link already visited in browser history */
.link-card:visited {
    /* Note: Only color-based properties work here for privacy */
    background: #8c00ff; 
    box-shadow: none;
    transform: scale(0.98);
}
</>
Interaction-Based Pseudo-Classes: :visited Example 2 (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Visited Pseudo-Class Example 2</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="article-card">
        <a href="https://example.com" target="_blank" class="article-link">
            UI Design with Modern CSS
        </a>

        <p class="sub-text">
            In this post, we explore modern UI techniques, shadow depth, gradient tips, and design behaviors.
        </p>
    </div>
</body>

</html>
body {
    font-family: 'Segoe UI', sans-serif;
    background: #f0f2f5;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
}

.article-card {
    background: #ffffff;
    padding: 24px;
    border-radius: 16px;
    max-width: 400px;
    box-shadow:
        0 6px 18px rgba(0, 0, 0, 0.1),
        inset 0 1px 4px rgba(255, 255, 255, 0.6);
    border: 2px solid rgba(0, 0, 0, 0.06);
}

.article-link {
    display: block;
    font-size: 19px;
    font-weight: 600;
    color: #2c59ff;
    text-decoration: none;
    margin-bottom: 8px;
    transition: .25s;
}

.article-link:hover {
    color: #4a76ff;
    text-shadow: 0 2px 6px rgba(76, 118, 255, 0.25);
}

/* State: Reducing visual weight of consumed content */
.article-link:visited {
    color: #566172; /* Muted color indicates it was previously read */
    text-decoration: underline dashed #a0aec0;
}

.sub-text {
    font-size: 14px;
    color: #6b6b6b;
    line-height: 1.5;
}

Parental Awareness :focus-within

Use Case: Advanced Form Groups

This is a highly powerful selector that triggers not only when the element itself is focused, but also when any of its child elements gain focus.

This selector grants CSS a capability similar to "Event Bubbling": it enables a style flow from the child up to the parent.

In modern designs, an input and its accompanying icon are typically placed within the same container.

When a user clicks the input, you often want the entire wrapper—not just the input—to glow or change color.

Previously, this required JavaScript logic. Now, by using .form-group:focus-within, you can simply declare: "If the input inside is clicked, make the .form-group border blue."

Persistence in Dropdown Menus One of the biggest challenges in dropdown menus is the menu closing while the user navigates between sub-links using a keyboard.

Thanks to :focus-within, as long as the focus remains on the sub-links, the main menu container stays open, acknowledging that

"There is still someone active inside me."

Logical Translation: The :focus structure says: "They are looking at ME." / The :focus-within structure says:

"They are looking at ME OR at someone in my family."

</>
Interaction-Based Pseudo-Classes: :focus-within Example 1 (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:focus-within Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <h2>:focus-within Example</h2>
    <div class="search-box">
        <label>Search:</label>
        <input type="text" placeholder="Type something...">
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
}

h2 {
    font-size: 20px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: #333;
    margin-bottom: 15px;
}

.search-box {
    width: 250px;
    padding: 15px;
    border: 2px solid #ccc;
    border-radius: 6px;
    transition: .3s;
}

.search-box label {
    font-size: 14px;
    font-weight: bold;
    color: #333;
    display: block;
    margin-bottom: 6px;
    letter-spacing: 0.5px;
}

.search-box input {
    width: 100%;
    padding: 10px;
    border: 2px solid #ccc;
    border-radius: 4px;
    outline: none;
    transition: .3s;
    box-sizing: border-box;
    font-size: 14px;
}

/* Parent container reacts when the internal input is focused */
.search-box:focus-within {
    border-color: #007bff;
    background-color: #eef5ff;
}

.search-box input:focus {
    border-color: #007bff;
    background-color: #fff;
}
</>
Interaction-Based Pseudo-Classes: :focus-within Example 2 (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Focus-Within Advanced Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="focus-within-demo">
        <h3>Focus-Within Effect</h3>

        <div class="form-group">
            <label for="name">Name:</label>
            <input type="text" id="name" class="form-input" placeholder="Enter your name...">
        </div>

        <div class="form-group">
            <label for="email">Email:</label>
            <input type="email" id="email" class="form-input" placeholder="Your email address...">
        </div>

        <div class="form-group">
            <label for="message">Message:</label>
            <textarea id="message" class="form-input" placeholder="Your message..." rows="4"></textarea>
        </div>

        <button class="submit-btn">Submit</button>

        <div class="info-box">
            <p><strong>How it works:</strong></p>
            <p>• Click on <span class="highlight">any</span> form field</p>
            <p>• The <span class="highlight">entire container</span> turns green</p>
            <p>• It triggers when any child element within the container gains focus</p>
        </div>
    </div>

</body>

</html>
body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: #f8f9fa;
    margin: 0;
    padding: 20px;
}

.focus-within-demo {
    background: linear-gradient(135deg, #a29bfe 0%, #6c5ce7 100%);
    padding: 30px;
    border-radius: 12px;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
    max-width: 500px;
    margin: 20px auto;
    transition: all 0.3s ease;
}

/* Parent container transforms when a child is focused */
.focus-within-demo:focus-within {
    background: linear-gradient(135deg, #00b894 0%, #55efc4 100%);
    transform: scale(1.02);
    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}

.focus-within-demo h3 {
    color: white;
    text-align: center;
    margin-bottom: 25px;
}

.form-group {
    margin-bottom: 20px;
}

.form-group label {
    display: block;
    color: white;
    margin-bottom: 8px;
    font-weight: 500;
}

.form-input {
    width: 100%;
    padding: 12px 16px;
    border: 2px solid rgba(255, 255, 255, 0.3);
    border-radius: 8px;
    font-size: 16px;
    background: rgba(255, 255, 255, 0.9);
    transition: all 0.3s ease;
    box-sizing: border-box;
}

.form-input:focus {
    outline: none;
    border-color: #0984e3;
    background: white;
}

.submit-btn {
    width: 100%;
    padding: 14px;
    background: #ffeaa7;
    color: #2d3436;
    border: none;
    border-radius: 8px;
    font-size: 16px;
    font-weight: bold;
    cursor: pointer;
    transition: all 0.3s ease;
}

.submit-btn:hover {
    background: #fdcb6e;
    transform: translateY(-2px);
}

.info-box {
    background: rgba(255, 255, 255, 0.1);
    padding: 15px;
    border-radius: 8px;
    margin-top: 20px;
    color: white;
}

.info-box p {
    margin: 5px 0;
    font-size: 14px;
}

.highlight {
    background: #ffeaa7;
    color: #2d3436;
    padding: 4px 8px;
    border-radius: 4px;
    font-weight: bold;
}

In-Page Targeting and Emphasis :target

Preventing User Disorientation

Applies styles to an HTML element that matches the fragment identifier in the URL ( #section-name ).

When a user clicks a link and the page scrolls to a specific section, this selector is used to visually indicate that the section is the current "target."

Imagine clicking a "Comments" link in a long article.

The page scrolls down, but it can be difficult to pinpoint exactly which comment was targeted.

Using :target, you can temporarily change the background color of the destination section ( highlight) to send a clear message:

"What you are looking for is exactly here."

JavaScript-free Modals with CSS This selector is used not just for emphasis, but for functionality as well.

By making a hidden modal window (display: none) visible when it matches the ID in the URL (#modal:target { display: block; }), you can create pop-up windows that function perfectly without writing a single line of JavaScript.

</>
Form Validation Pseudo-Classes: :target Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Target Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <h2>:target Example</h2>

    <nav class="menu">
        <a href="#box1">Box 1</a>
        <a href="#box2">Box 2</a>
        <a href="#box3">Box 3</a>
    </nav>

    <div class="content">
        <div id="box1" class="panel">This is the content of Box 1</div>
        <div id="box2" class="panel">This is the content of Box 2</div>
        <div id="box3" class="panel">This is the content of Box 3</div>
    </div>

</body>

</html>
                            
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
}

h2 {
    text-transform: uppercase;
    margin-bottom: 15px;
}

.menu {
    display: flex;
    gap: 10px;
    margin-bottom: 20px;
}

.menu a {
    text-decoration: none;
    padding: 8px 14px;
    background: #ddd;
    color: #333;
    border-radius: 6px;
    font-weight: 600;
    transition: .3s;
}

.menu a:hover {
    background: #bbb;
}

.panel {
    padding: 20px;
    border: 2px solid transparent;
    border-radius: 8px;
    background: #f2f2f2;
    font-size: 15px;
    margin-bottom: 12px;
    transition: .4s;
    opacity: .6;
}

/* State: The element whose ID matches the URL fragment (#box1, etc.) */
.panel:target {
    border-color: #4caf50;
    background: #e9ffe9;
    transform: scale(1.05); /* Highlight targeted section */
    opacity: 1;
}
</>
Form Validation Pseudo-Classes: :target Pseudo-Class Example 2 (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Target Pseudo-Class Example 2</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="faq-container">
        <h2>Frequently Asked Questions</h2>

        <div class="faq-group">
            <a href="#answer1" class="question">How can I register?</a>
            <div id="answer1" class="answer-box">
                Click the "Login / Sign Up" link in the top menu. Then, select "Create New Account" 
                and fill in the required information.
            </div>
        </div>

        <div class="faq-group">
            <a href="#answer2" class="question">Can I cancel my order?</a>
            <div id="answer2" class="answer-box">
                If your order hasn't shipped yet, you can create a cancellation request from 
                the "My Orders" page in your profile.
            </div>
        </div>

        <div class="faq-group">
            <a href="#answer3" class="question">What are the payment options?</a>
            <div id="answer3" class="answer-box">
                We accept credit/debit cards, wire transfers/EFT, and cash on delivery 
                for specific products.
            </div>
        </div>

    </div>
</body>

</html>
/* CSS */
body {
    font-family: 'Roboto', sans-serif;
    background-color: #f7f9fc;
    padding: 40px 20px;
    display: flex;
    justify-content: center;
}

.faq-container {
    width: 90%;
    max-width: 700px;
    background-color: white;
    padding: 30px;
    border-radius: 10px;
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
}

h2 {
    text-align: center;
    color: #1a237e;
    margin-bottom: 30px;
}

.faq-group {
    margin-bottom: 15px;
    border-bottom: 1px solid #e0e0e0;
    padding-bottom: 15px;
}

.question {
    display: block;
    text-decoration: none;
    color: #3f51b5;
    font-weight: bold;
    padding: 10px 15px;
    background-color: #e8eaf6;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.2s;
}

.question:hover {
    background-color: #c5cae9;
}

.answer-box {
    overflow: hidden;
    max-height: 0; /* Hidden by default */
    padding: 0 15px;
    margin-top: 0;
    background-color: #ffffff;
    border-left: 3px solid #3f51b5;
    color: #455a64;
    transition: max-height 0.4s ease-out, padding 0.4s ease-out;
}

/* State: Triggered when the URL fragment matches the ID */
.answer-box:target {
    max-height: 200px; /* Expands the box */
    padding: 15px;
    margin-top: 10px;
    border: 2px solid #2c97c9;
    border-radius: 6px;
    background-color: #fcfcfc;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
}

/* ** Design Note: 
  ** Only the element with the matching ID becomes the :target.
  ** This allows us to create interactive components like accordions 
  ** using only CSS logic.
*/

Unexplored Connections :link

Technical Distinction: "a" tag vs ":link"

The :link pseudo-class targets the "pure" state of hyperlinks ( a ) that have not yet been clicked by the user—meaning they are not present in the browser's history.

The default blue, underlined appearance of the web is actually the browser's built-in default style for this specific class.

Developers often style all links generally by writing a { color: red; }.

However, utilizing :link is far more specific.

It exclusively selects unvisited connections that possess an href attribute ( meaning they actually point somewhere ).

This distinction is vital when you want to visually differentiate between "visited" and "unvisited" paths.

The Golden Rule: LVHA Order

When writing link states in CSS, there is a universal ordering rule you must follow: Link, Visited, Hover, Active.

:link must always be defined at the very beginning.

If you define :hover or :active rules before :link, your hover effects may not function ( overridden ) due to the Cascade nature of CSS.

Design Strategy

The :link state should reflect your site's "Primary Theme Color."

It is the state that most clearly signals to the user: "This is a clickable area."

In modern designs, the underline property ( text-decoration: underline ) is typically disabled for the :link state and only enabled during the :hover state.

</>
Interaction-Based Pseudo-Classes: :link Example 1 (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Link Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <h2>:link Example</h2>

    <div class="link-container">
        <a href="#feature1" class="nav-link">⭐ Feature 1</a>
        <a href="#feature2" class="nav-link">⭐ Feature 2</a>
        <a href="#feature3" class="nav-link">⭐ Feature 3</a>
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 30px;
    background-color: #f5f7fa;
}
h2 {
    text-align: center;
    text-transform: uppercase;
    font-size: 22px;
    font-weight: 700;
    color: #2c3e50;
    margin-bottom: 20px;
}

.link-container {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-width: 250px;
    margin: 0 auto;
}

/* State: Unvisited links with an href attribute */
a:link {
    text-decoration: none;
    color: #4c84ff;
    font-weight: 600;
    padding: 10px 14px;
    border-radius: 6px;
    background-color: #eaf2ff;
    transition: 0.3s;
}

/* Combining pseudo-classes: Interaction on an unvisited link */
a:link:hover {
    background-color: #d0e1ff;
    transform: translateX(4px);
}   

The Unifier of All Connections :any-link

Critical Difference: :link vs :any-link

The :any-link pseudo-class is a "superset" that covers every instance where an element (typically a, area, or link) contains a source hyperlink.

Simply put; it selects anything that says "This is a link," regardless of whether it has been clicked before.

Many developers mistake the :link selector for "all links," but this is a common misconception.

:link exclusively targets unvisited links; once a link is visited, it falls outside that selector's scope.

:any-link, however, unites both :link and :visited states under a single roof.

Why Isn't the "a" Tag Enough? Writing a { ... } selects every <a> tag.

However, in HTML, you might have a tags without an href attribute (used only as internal anchor points with name="...").

To avoid accidentally styling these "non-link anchors," :any-link is the safest path, targeting only those that are truly clickable.

Code Refactoring Previously, removing underlines from all links required: a:link, a:visited { text-decoration: none; }.

Now you can achieve this in a single stroke: :any-link { text-decoration: none; }.

this significantly simplifies the code, especially within CSS Reset files.

Technical Detail: Specificity Boost The a tag is an Element Selector with low specificity ( 0-0-1 ).

Conversely, :any-link is a Pseudo-Class and carries higher specificity ( 0-1-0 ).

This means: If you define a color using :any-link, it will override general styles written with a simple a tag.

This serves as an insurance policy in global theme files to prevent link styles from being accidentally broken.

Future-Proofing (Polyfill Logic) As web standards evolve, new elements beyond <a> that possess linking capabilities may emerge.

Because :any-link looks at function (whether it connects to a destination) rather than the tag name, it makes your code resilient to future HTML changes.

</>
Internationalization and Language Sensitivity Pseudo-Classes: :any-link Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:any-link Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="anylink-demo">
        <h2>:any-link Example</h2>

        <p>
            The links below receive the same base style regardless of whether they have been visited, 
            because <strong>:any-link</strong> targets both <em>:link</em> and <em>:visited</em> states.
        </p>

        <nav class="nav-links">
            <a href="#home">🏠 Home</a>
            <a href="#blog">📰 Blog</a>
            <a href="#services">🛠 Services</a>
            <a href="https://example.com" target="_blank">🌍 External Site</a>
        </nav>
    </div>

</body>

</html>
body {
    background: #111;
    color: #eee;
    font-family: Arial, sans-serif;
    padding: 40px;
}

.anylink-demo {
    background: #1e1e1e;
    padding: 25px;
    border-radius: 12px;
    max-width: 450px;
    margin: auto;
    box-shadow: 0 0 15px rgba(255, 255, 255, 0.1);
    border: 1px solid #fff;
}

.anylink-demo h2 {
    text-align: center;
    margin-bottom: 20px;
    color: #00e5ff;
}

.nav-links {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-top: 20px;
}

/* Styles any element that is a source anchor, visited or not */
.nav-links a:any-link {
    text-decoration: none;
    color: #fff;
    padding: 14px;
    border: 2px solid #00eaff;
    border-radius: 8px;
    text-align: center;
    transition: 0.3s;
}

.nav-links a:hover {
    background: #00eaff;
    color: #111;
    transform: translateX(6px);
    box-shadow: 0px 0px 10px #00eaff;
}

.nav-links a:active {
    transform: scale(0.96);
}

What Have We Learned So Far?

What We've Learned
  • The concept and core logic of Pseudo-classes
  • The function of dynamic interaction classes
  • Mechanisms for responding to user actions
What's Next?
  • Structural and logical pseudo-classes
  • DOM architecture and relationships
  • Ordering and filtering techniques
Level 4

Structural and Logical Classes DOM Architecture: Ordering, Filtering, and Relationships

From Static Markup to Algorithmic Selection

The classes we have examined so far (:hover, :focus, etc.) were responding to user actions.

However, Structural and Logical Classes operate independently of the user.

They look at the page's architecture, the sequence of elements, and their kinship relationships with one another.

In old web development habits, developers would manually write class="last-item" in HTML just to remove the border of the last item in a list.

Selectors in this group eliminate this manual labor. They allow you to automate design by telling the browser, "Find the last child of this list" ( :last-child ) or

"Select only the odd numbers" ( :nth-child(odd) ).

Navigating the DOM Tree HTML is like a family tree ( Parent, Child, Sibling ). These selectors are the compasses that allow CSS to traverse this tree.

You can calculate which "ordinal sibling" an element is, filter elements of a specific type, or style a parent

"based on the child within it" ( :has ).

Logical Operators This section is where CSS comes closest to programming logic.

It enables you to create "Smart Stylesheets" by determining not just what to select, but also what NOT to select ( :not ) or under which conditions to select.

The Boundary Guards: First and Last :first-child and :last-child

Introduction

These two selectors are the fundamental building blocks of CSS that target the absolute beginning and absolute end of a sequence within a parent element.

They allow you to directly select the first and last members of a group without the need for complex formulas.

:first-child (The Firstborn) Represents the first HTML element inside a parent.

For example, it is used to select the first paragraph of a blog post to increase its font size or to highlight the very top item in a list.

:last-child (The Lastborn) Represents the last HTML element inside a parent.

It is critical for styling the end of a list in dynamic content, such as a comment section where the total number of items is unknown.

Edge Corrections and Cleanup

One of the most common aesthetic issues in design is the unnecessary spacing that occurs at the beginning or end of repeating elements ( lists, menus, cards ).

Example: Imagine designing a horizontal menu where you place a separator line ( border-right ) to the right of every item.

If you apply this rule to all elements, an illogical line appears to the right of the last element, creating an unwanted and flawed look.

Solution Strategy:

This is where :last-child comes into play. By targeting only the final element of the group and applying border: none, you remove that redundant line.

Using similar logic, :first-child targets the very first element in the group.

It is commonly used to remove the indentation of an article's first paragraph or to reset an unnecessary margin-top at the top of a vertical list.

</>
Structural and Logical Classes: :first-child and :last-child Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>First and Last Child Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <h2>First-Child & Last-Child Example</h2>

    <div class="card-list">
        <div class="card">Card 1</div>
        <div class="card">Card 2</div>
        <div class="card">Card 3</div>
        <div class="card">Card 4</div>
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
}

h2 {
    font-size: 20px;
    font-weight: bold;
    margin-bottom: 20px;
    text-transform: uppercase;
}

.card-list {
    max-width: 260px;
}

.card {
    background: #f2f2f2;
    padding: 12px;
    margin: 10px 0;
    border-radius: 8px;
    transition: .3s ease;
}

/* Targets the absolute first element in the sequence */
.card:first-child {
    background: #d3f8d3;
    border-left: 4px solid #2ecc71;
    font-weight: bold;
}

/* Targets the absolute last element in the sequence */
.card:last-child {
    background: #ffe0da;
    border-right: 4px solid #e74c3c;
    font-style: italic;
}

.card:hover {
    transform: translateX(6px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
</>
Structural and Logical Classes: :first-child Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Weekly Menu Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="menu-container">
        <h2>Our Weekly Menu</h2>
        <ul class="menu-list">
            <li class="menu-item">
                <span class="title">Today's Special</span>
                <span class="description">Grilled Salmon, Asparagus and Mashed Potatoes</span>
                <span class="price">350 USD</span>
            </li>

            <li class="menu-item">
                <span class="title">Lentil Soup</span>
                <span class="description">Traditional Homemade Recipe</span>
                <span class="price">80 USD</span>
            </li>

            <li class="menu-item">
                <span class="title">Chicken Saute</span>
                <span class="description">Served with steamed rice</span>
                <span class="price">220 USD</span>
            </li>

            <li class="menu-item">
                <span class="title">Fruit Yogurt</span>
                <span class="description">Light dessert with forest berries</span>
                <span class="price">100 USD</span>
            </li>
        </ul>
    </div>
</body>

</html>
/* CSS */
body {
    font-family: Arial, sans-serif;
    background-color: #f4f7f9;
    padding: 20px;
}

.menu-container {
    width: 80%;
    max-width: 700px;
    margin: 50px auto;
    padding: 30px;
    background-color: white;
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
    border-radius: 12px;
}

h2 {
    color: #333;
    text-align: center;
    margin-bottom: 25px;
}

.menu-list {
    list-style: none;
    padding: 0;
}

.menu-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 15px 0;
    border-bottom: 1px dashed #eee;
    color: #666;
    transition: background-color 0.3s;
}

/* Cleaning up the edge: Removes separator from the last item */
.menu-item:last-child {
    border-bottom: none;
}

.menu-item:hover {
    background-color: #f9f9f9;
}

.title {
    font-weight: bold;
    color: #444;
    flex: 2;
}

.description {
    flex: 3;
    font-size: 0.9em;
    color: #999;
}

.price {
    font-weight: bold;
    color: #007bff;
    flex: 1;
    text-align: right;
}

/* Highlighting the first item: Typically used for "Specials" or "Featured" items */
.menu-item:first-child {
    padding: 20px;
    margin: 10px 0;
    background-color: #ffe0b2;
    border: 2px solid #ff9800;
    border-radius: 8px;
    box-shadow: 0 4px 10px rgba(255, 152, 0, 0.3);
    font-size: 1.1em;
}

.menu-item:first-child .price {
    color: #e65100;
    font-size: 1.2em;
    transform: scale(1.05);
}

.menu-item:first-child .title {
    color: #333;
}
</>
Structural and Logical Classes: :last-child Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Checkout Stepper Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="step-container">
        <h3>Order Completion Steps</h3>

        <ul class="step-list">
            <li class="step">
                <span class="number">1</span>
                <span class="title">Shipping Address</span>
                <span class="status completed">Completed</span>
            </li>

            <li class="step">
                <span class="number">2</span>
                <span class="title">Payment Method</span>
                <span class="status active">Active</span>
            </li>

            <li class="step">
                <span class="number">3</span>
                <span class="title">Confirm & Finish</span>
                <span class="status pending">Pending</span>
            </li>
        </ul>

    </div>
</body>

</html>
/* CSS */
body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background-color: #e8eaf6;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
}

.step-container {
    width: 90%;
    max-width: 500px;
    background-color: white;
    padding: 30px;
    border-radius: 15px;
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1);
}

h3 {
    text-align: center;
    color: #3f51b5;
    margin-bottom: 30px;
}

.step-list {
    list-style: none;
    padding: 0;
}

.step {
    display: flex;
    align-items: center;
    padding: 15px;
    margin-bottom: 10px;
    border-radius: 8px;
    background-color: #f5f5f5;
    transition: transform 0.2s, box-shadow 0.2s;
    border-left: 5px solid #c5cae9;
}

.step:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
}

.number {
    font-size: 1.2em;
    font-weight: bold;
    color: #3f51b5;
    background-color: white;
    border: 2px solid #3f51b5;
    border-radius: 50%;
    width: 30px;
    height: 30px;
    display: flex;
    justify-content: center;
    align-items: center;
    margin-right: 15px;
}

.title {
    flex-grow: 1;
    font-weight: 600;
    color: #444;
}

.status {
    font-size: 0.85em;
    padding: 3px 8px;
    border-radius: 5px;
    font-weight: bold;
}

.completed {
    color: #2e7d32;
    background-color: #e8f5e9;
}

.active {
    color: #ff9800;
    background-color: #fff3e0;
}

.pending {
    color: #757575;
    background-color: #e0e0e0;
}

/* State: Highlighting the final 'Checkout' call to action */
.step:last-child {
    background-color: #3f51b5;
    color: white;
    border-left: 5px solid #ff4081;
    transform: scale(1.02);
    margin-top: 25px;
    box-shadow: 0 8px 15px rgba(63, 81, 181, 0.4);
    cursor: pointer;
}

.step:last-child .number {
    color: white;
    background-color: #ff4081;
    border-color: white;
}

.step:last-child .title {
    color: white;
    font-size: 1.1em;
}

.step:last-child .status {
    color: white;
    background-color: #303f9f;
}

The Power of Math and Loops :nth-child()

Ending Manual Classes (Automation)

This selector is effectively the Swiss Army Knife of the CSS world.

It allows you to target children within a parent not just by their name, but by their position, a specific formula, or a mathematical loop.

In the early days of web design, developers had to manually manipulate HTML code to achieve a "one filled, one empty" ( zebra stripe ) look in tables or lists.

Developers were forced to add classes like odd and even to every single row by hand.

This method caused the entire layout to break whenever a new row was fetched from a database.

Thanks to :nth-child, this process is now dynamic and automated.

No matter how much the content changes, CSS always colors the correct row.

Formula Structure: (an + b) At the heart of this selector lies a simple algebraic formula.

The value written inside the parentheses determines the logic of the selection.

The letter n in the formula is a "counter that starts from 0 and goes to infinity" (0, 1, 2, 3...).

The browser executes this formula for every single element.

a (Cycle Coefficient): Determines the size of the loop.

This is the number we use when we say "select every 3rd element" or "select every 5th element."

b (Offset / Starting Point): The offset value that determines which element the loop begins with.

For example, the formula 2n + 1 means; "Go in cycles of two but start from the 1st position" (which effectively selects odd numbers).

</>
Structural and Logical Classes: :nth-child Example 2 (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Nth Child Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <h2>nth-child() Example</h2>

    <ul class="color-list">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
        <li>Item 4</li>
        <li>Item 5</li>
    </ul>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
}

h2 {
    font-size: 20px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 1px;
    margin-bottom: 15px;
}

.color-list {
    list-style: none;
    padding: 0;
    max-width: 220px;
}

.color-list li {
    background: #f2f2f2;
    padding: 10px;
    margin: 6px 0;
    border-radius: 6px;
    transition: .3s;
}

/* Targets specific indices within the sequence */
.color-list li:nth-child(2) {
    background: #bfe6ff; /* Light blue for the 2nd item */
}

.color-list li:nth-child(4) {
    background: #ffe1b8; /* Light orange for the 4th item */
}

.color-list li:hover {
    transform: translateX(5px);
}
</>
Structural and Logical Classes: :nth-child Example 2 (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Nth Child Pseudo-Class Table Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="table-container">
        <h3>User Access List</h3>

        <table>
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Name</th>
                    <th>Email</th>
                    <th>Status</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>101</td>
                    <td>Ali Yılmaz</td>
                    <td>ali.y@email.com</td>
                    <td>Active</td>
                </tr>
                <tr>
                    <td>102</td>
                    <td>Berna Kaya</td>
                    <td>b.kaya@email.com</td>
                    <td>Active</td>
                </tr>
                <tr>
                    <td>103</td>
                    <td>Can Demir</td>
                    <td>can.d@email.com</td>
                    <td>Passive</td>
                </tr>
                <tr>
                    <td>104</td>
                    <td>Deniz Ece</td>
                    <td>deniz.e@email.com</td>
                    <td>Active</td>
                </tr>
                <tr>
                    <td>105</td>
                    <td>Emre Fırat</td>
                    <td>emre.f@email.com</td>
                    <td>Pending</td>
                </tr>
                <tr>
                    <td>106</td>
                    <td>Gizem Han</td>
                    <td>gizem.h@email.com</td>
                    <td>Active</td>
                </tr>
            </tbody>
        </table>
    </div>
</body>

</html>
body {
    font-family: 'Arial', sans-serif;
    background-color: #e8f4f8;
    padding: 30px;
    display: flex;
    justify-content: center;
}

.table-container {
    width: 90%;
    max-width: 800px;
    background-color: white;
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}

h3 {
    color: #008cba;
    text-align: center;
    margin-bottom: 20px;
}

table {
    width: 100%;
    border-collapse: collapse;
}

th,
td {
    padding: 12px 15px;
    text-align: left;
    border-bottom: 1px solid #ddd;
}

thead th {
    background-color: #008cba;
    color: white;
    font-weight: bold;
    border-bottom: 2px solid #006687;
}

/* Zebra Striping: Automated coloring of even rows */
tbody tr:nth-child(even) {
    background-color: #f2f2f2;
}

/* Automated coloring of odd rows */
tbody tr:nth-child(odd) {
    background-color: #ffffff;
}

/* Targeting a specific column (ID column) */
tbody tr td:nth-child(1) {
    font-weight: bold;
    color: #005f78;
}

/* Targeting a specific row (e.g., Row 5 for emphasis) */
tbody tr:nth-child(5) {
    background-color: #ffcccc;
    color: #cc0000;
    font-weight: bold;
    box-shadow: 0 0 5px rgba(255, 0, 0, 0.3);
}
Nth-Child Pseudo-Class Formulas Commonly Used Patterns and Their Meanings
Value / Formula
Logical Function and Use Case
:nth-child(2)

Single Index Selection: Does not create a loop.
Selects specifically and strictly the 2nd element within the parent.
Typically used to highlight a specific item in a list.

:nth-child(odd)

Odd Numbers: Mathematically equivalent to the 2n+1 formula.
Progresses as 1, 3, 5, 7...
The industry standard for "zebra striping" to differentiate rows and improve readability in long tables.

:nth-child(even)

Even Numbers: Mathematically equivalent to 2n.
Progresses as 2, 4, 6, 8...
Usually used as a complement to odd to create contrasting row patterns.

:nth-child(3n)

Multiplier Loop: Targets multiples of 3 (3, 6, 9...).
Critical for 3-column grid layouts to reset the right margin of the last element in each row.

:nth-child(3n+1)

Offset Loop: Jumps in steps of 3 but begins counting from 1 (1, 4, 7...).
Used to select the first element of every new row in a 3-column layout (e.g., to apply
clear: both).

Negation Logic :not()

Ending the "Override" Culture

By nature, CSS typically defines "what to select"; however, this pseudo-class defines "what NOT to select."

Instead of fixing exceptions after writing a rule, it allows you to exclude them right from the start.

In traditional CSS writing, a general rule was written first, and then that rule was manually reverted for the exceptional element.

For example, in a horizontal menu, adding a separator line ( border-right ) to all items and then selecting the last item to say:

"No, don't apply the border to yourself" (border: none) is a "patching" process.

With :not(), this logic is reversed: "Apply a border to all items EXCEPT the last one."

As a result, the browser never applies the style to the last element in the first place, eliminating the need to cancel it later—this shortens your code and boosts performance.

Logical Filtering and Clean Code By placing a class, ID, or another pseudo-class inside :not(), you can filter out elements with surgical precision.

Real-World Scenario:

Consider buttons in a form. You want to apply a hover effect to all buttons, but the "Disabled" button should not change color.

To achieve this, simply write: .btn:not(.disabled):hover.

This rule translates to: "IF a button does NOT have the .disabled class, change its color on hover."

This way, a user attempting to click a passive button won't see a misleading color change, significantly improving the User Experience (UX).

</>
Structural and Logical Classes: :not Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Not Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <h2>:not() Example</h2>

    <div class="btn-group">
        <button class="btn">Default</button>
        <button class="btn">Save</button>
        <button class="btn danger">Delete</button>
        <button class="btn">Share</button>
    </div>

</body>

</html>
                            
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
}

h2 {
    font-size: 20px;
    margin-bottom: 15px;
    font-weight: bold;
    text-transform: uppercase;
}

.btn-group {
    display: flex;
    gap: 10px;
}

.btn {
    background: #e6e6e6;
    border: none;
    padding: 10px 18px;
    border-radius: 6px;
    cursor: pointer;
    transition: .3s;
    font-size: 14px;
}

.danger {
    background: #ff5c5c;
    color: white;
}

/* Logical Negation: Applies hover effects to all buttons EXCEPT those with the .danger class */
.btn:not(.danger):hover {
    background: #bcdcff;
    transform: translateY(-3px);
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}

.danger:hover {
    background: #ff3b3b;
    transform: scale(1.05);
}

The CSS Revolution: The Parent Selector :has()

Breaking the Rules: "The Backward Glance"

A feature that web developers have dreamed of for 20 years—one that was deemed "impossible" for years due to performance concerns—is now finally running at the core of modern browsers.

By nature, CSS has always flowed "from top to bottom."

A parent element ( parent ) could influence its child ( child ), but a child could never alter the style of its parent.

:has() flips this fundamental rule on its head, effectively pumping the waterfall's water upward.

You can now style a container not just based on its own attributes, but based on the presence or state of its internal content.

The operational logic of this selector is similar to the "IF / THEN" conditional structure in programming:

"IF this box contains an image, THEN turn the box's background black."

Use Case: Smart and Responsive Cards

Imagine you have a blog card design. Some cards coming from the content management system (CMS) have images, while others contain only text.

In the past, you would have needed to write Backend code to add an extra class ( .card--no-image ) to the HTML for cards without images.

Now, by writing .card:has(img), you can simply tell the browser: "Find cards that contain an img tag."

This allows you to apply a specific grid layout to cards with images while leaving those without images in the standard flow.

This method is the most powerful and performant way to write "conditional styling" without writing a single line of JavaScript.

Form Control and UX Improvement:

To enhance the user experience in complex forms, selected fields need to be clearly highlighted.

With traditional CSS, when an input was selected, you could only style the input itself or its adjacent sibling.

However, with :has(), you can target the parent element wrapping the input ( the entire row or the card ).

The .row:has(input:checked) code gives this command: "Find the row where the checkbox inside is checked, and change the background color of that entire row."

This ensures that the user can clearly see which option they have selected, even from a distance.

The Empty State :empty

Eliminating "Ghost Boxes"

This selector is one of the most specific filters in the DOM tree: it targets elements that are completely empty—meaning they contain no child elements, no text, and not even a single whitespace character.

In CSS, when you apply padding or a border to a box, that box occupies space and remains visible on the screen even if it has no content.

In dynamic layouts (such as an alert box or a notification area), this creates an amateurish look where a box is

"empty but still has a visible frame." In design, this is known as a "Ghost Box."

Auto-Hiding: If no content is delivered, you don't want that container to occupy unnecessary space on the screen.

The rule div:empty { display: none; } acts effectively as a "garbage collector."

It instantly hides any box that becomes empty, preserving the integrity and balance of the layout.

Technical Warning: The Whitespace Trap This selector is extremely sensitive. If there is even an invisible "space" character or a line break inside a tag, the browser considers it "full."

Therefore, <div> </div> ( contains a space ) is NOT considered empty, while <div></div> ( adjacent tags ) is considered empty.

</>
Form Validation Pseudo-Classes: :empty Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Empty Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <h2>:empty Example</h2>

    <div class="box-container">
        <div class="box"></div>
        <div class="box">Hello</div>
        <div class="box"></div>
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
}

h2 {
    text-transform: uppercase;
    margin-bottom: 20px;
}

.box-container {
    display: flex;
    gap: 12px;
}

.box {
    width: 120px;
    height: 80px;
    border: 2px solid #ccc;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    background: #ffffff;
    transition: .3s;
}

/* State: Elements with absolutely no children or text nodes */
.box:empty {
    background: #eeeeee;
    border-color: #999;
    color: transparent;
}

.box:hover {
    transform: scale(1.05);
}
</>
Structural and Logical Classes: :has Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Has Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <h2>:has() Example</h2>

    <div class="card">
        <p>This card has no checkbox.</p>
    </div>

    <div class="card">
        <p>This card has a checkbox.</p>
        <input type="checkbox">
    </div>

    <div class="card">
        <p>This card also has a checkbox.</p>
        <input type="checkbox" checked>
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
}

h2 {
    font-size: 20px;
    text-transform: uppercase;
    margin-bottom: 20px;
}

.card {
    border: 2px solid #ccc;
    padding: 15px;
    border-radius: 8px;
    margin-bottom: 12px;
    transition: .3s;
    background: #f7f7f7;
}

/* Condition: Target the parent (.card) IF it contains a checkbox */
.card:has(input[type="checkbox"]) {
    border-color: #007bff;
    background: #eaf3ff;
}

/* Condition: Target the parent IF it contains a CHECKED checkbox */
.card:has(input[type="checkbox"]:checked) {
    background: #d6ffda;
    border-color: #28a745;
    transform: scale(1.02);
}

What Have We Learned So Far?

What We've Learned
  • Transitions from Dynamic Interaction Classes
  • Fundamentals of structural and logical classes
  • :first-child, :last-child, and :nth-child selectors
  • DOM architecture and hierarchical relationships
What's Next?
  • Form and state pseudo-classes
  • :checked, :disabled, and :required selectors
  • Data entry and validation control mechanisms
Level 4

Form and State Classes Data Entry and Control Mechanisms

A Live Dialogue with the User

The most critical moment for a website is when the user stops being a mere spectator and becomes a participant—specifically, the moment they write to you ( filling out a form ).

During this interaction, the interface must "speak" to the user, guiding them and gently correcting their mistakes in real-time.

Form state classes allow you to style an input or button element based on its current "biological" state ( is it full?, is it empty?,

is it selected? ).

The Psychology of Feedback: A user should instantly understand why they cannot click a button ( :disabled ) or why the email they entered is not accepted ( :invalid ).

These classes function as an "early warning system" that operates before the "Submit" button is even pressed, effectively minimizing user errors and friction.

Form State Attributes Interaction States and CSS Equivalents
Pseudo-Class
Detailed Description and Function
:checked

Selection State: Represents the moment when radio buttons ( radio ) and checkboxes ( checkbox ) are active or selected.
It acts as a "logical switch" not just for styling boxes, but for creating Toggle Switches or Accordion menus that function entirely without JavaScript.

:disabled

Restriction and Passivity: Targets elements that have been temporarily or permanently closed by the system.
Triggers whenever the disabled attribute is present in HTML.
Commonly used to reduce opacity ( opacity: 0.5 ) and change the pointer to a forbidden icon ( cursor: not-allowed ).
Sends a clear "You cannot click this right now" message to the user.

:enabled

Default Activity: Represents all form elements that are NOT disabled—meaning they are open for interaction.
Rarely written manually as it is the default state, but can be used in customized forms to emphasize specifically "active" fields.

:read-only

Readable but Not Writable: Selects inputs where the user can see and copy the content but cannot modify it.
Difference from :disabled: Data from these fields is still sent to the server during form submission, and the user can still select the text.

:required

Mandatory State: Selects fields that possess the required attribute, meaning they cannot be left empty.
Usually used to add a visual asterisk ( * ) or a colored border highlight to draw the user's attention to the necessity of the field.

Selection and Triggering Mechanisms :checked

The UI's "Logical Switch"

The :checked pseudo-class represents the "selected" state within an interface.

Technically; radio buttons (input type="radio" ), checkboxes ( input type="checkbox" ), and dropdown options ( option ) can possess this state.

The power of this class is not limited to simply styling a small box; rather, the checkbox serves as a "master switch" that can control the rest of the page.

Through a technique known in modern web development as the "Checkbox Hack," you can create accordion menus, tabbed structures, modals, and sidebars that function perfectly without touching a single line of JavaScript.

Operating Principle: Sibling Selectors When a user checks a box, CSS sibling selectors ( + or ~ ) are used to modify the appearance of elements immediately adjacent to or following that checkbox.

Example: By declaring input:checked + .content { display: block; }, you can toggle the visibility of hidden content.

Visual Freedom: Toggle Switches

The default browser "checkmark" and blue box are often insufficient for professional designers.

In these cases, the actual input is hidden from view.

Then, by utilizing the label tag combined with ::before / ::after, those famous "iPhone-style" sliding on/off switches are crafted. When :checked is triggered, the circular button slides to the right and the background turns green.

</>
Form Validation Pseudo-Classes: :checked Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Checked Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <h2>:checked Example</h2>

    <div class="form-group">
        <label>
            <input type="checkbox" name="newsletter">
            📰 Newsletter Subscription
        </label>

        <label>
            <input type="checkbox" name="updates">
            🔔 Updates
        </label>

        <p class="status">No options selected</p>
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 30px;
    background: #f4f6f9;
}

h2 {
    text-align: center;
    text-transform: uppercase;
    font-size: 22px;
    font-weight: 700;
    color: #2c3e50;
    margin-bottom: 25px;
}

.form-group {
    display: flex;
    flex-direction: column;
    gap: 12px;
    max-width: 300px;
    margin: 0 auto;
}

label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 15px;
    font-weight: 500;
    cursor: pointer;
}

input[type="checkbox"] {
    width: 18px;
    height: 18px;
    cursor: pointer;
}

/* State: Triggered when the checkbox is selected */
input[type="checkbox"]:checked {
    accent-color: #4caf50; /* Modern way to style native checkboxes */
}

.status {
    font-size: 14px;
    color: #555;
    margin-top: 10px;
}

Interaction Disabled / Passive State :disabled

Technical Interruption: Data Flow Stops

The :disabled pseudo-class targets form elements that are "dead" or "frozen," where user interaction is strictly blocked by the system.

Any button, input, or select box with the disabled attribute in HTML automatically transitions into this state within the browser.

This state has a critical technical consequence beyond just visuals:

The data from a disabled input field is NOT transmitted to the server when the form is submitted.

Furthermore, these elements are removed from the "Focus Order." When a user presses the Tab key on the keyboard, the browser skips over these elements entirely, effectively ignoring them.

UX Strategy: Why Not Just Hide It?

Why do we use :disabled instead of simply hiding a button with display: none?

Because we want to send a clear message to the user: "This feature exists here, but you haven't yet met the necessary requirements ( such as filling out the form ) to use it."

Visually, this is typically achieved by lowering opacity ( opacity: 0.5 ), applying grayscale ( filter: grayscale(100%) ), and changing the mouse cursor to the "No Entry" sign ( cursor: not-allowed ).

Active / Interactive State :enabled

The Power of the Default

The :enabled pseudo-class technically represents all form elements that do NOT have the disabled attribute—meaning they are healthy, live, and open for interaction.

Many developers might think, "This is the default state anyway; why do we need such a selector?"

This selector is specifically used in complex forms to avoid "Reverse Engineering" your styles.

Practical Use Case

When designing a form, we usually write a general input style and then override the passive ones using input:disabled.

By using :enabled, we can fix the logic: "Apply shadows and colors ONLY to those that are active."

input:enabled { box-shadow: ...; }

This way, you don't need to write extra code to "reset the shadow" (box-shadow: none) for disabled elements. The browser simply never applies the style to them in the first place.

Critical Tip: Hover and Focus Safety

A common mistake in web interfaces is when a passive (:disabled) button continues to change color when hovered over.

This creates a false perception of "I can click this" for the user. To prevent this error, you should define :hover effects only for the active state, not the element itself.

In other words, if you write button:enabled:hover instead of button:hover, color changes on passive buttons are automatically blocked.

Dynamic State Management

In modern web applications, form fields can open and close instantly based on user choices.

The moment JavaScript code removes the disabled attribute from an input, the :enabled selector kicks in.

There is no need to manually add or remove an "active" class; as soon as the element "comes to life," it automatically gains the vibrant colors and shadows you defined.

</>
Form Validation Pseudo-Classes: :enabled and :disabled Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Enabled and Disabled Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <div class="form-wrapper">
        <h2>:enabled / :disabled Example</h2>

        <div class="form-container">
            <label>
                Full Name:
                <input type="text" placeholder="You can type here">
            </label>

            <label>
                Email:
                <input type="email" placeholder="You can type here">
            </label>

            <label>
                Password (disabled):
                <input type="password" placeholder="Password" disabled>
            </label>

            <button type="submit">Submit</button>
        </div>
    </div>


</body>

</html>
body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: #f4f6f9;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
}

.form-wrapper {
    background: #ffffff;
    padding: 30px 35px;
    border-radius: 14px;
    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
    max-width: 400px;
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.form-wrapper h2 {
    font-size: 22px;
    font-weight: 700;
    text-align: center;
    color: #2c3e50;
    margin: 0;
}

.form-container {
    display: flex;
    flex-direction: column;
    gap: 15px;
}
label {
    display: flex;
    flex-direction: column;
    font-weight: 500;
    font-size: 14px;
    color: #333;
}

input {
    padding: 12px 14px;
    border: 2px solid #ccc;
    border-radius: 10px;
    font-size: 14px;
    outline: none;
    transition: 0.3s;
    background-color: #fafafa;
    box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.05);
}

/* Logic: Apply vibrant styles only to interactive fields */
input:enabled {
    border-color: #4688ff;
    background-color: #eef5ff;
}

/* Logic: Apply "muted" styles to restricted fields */
input:disabled {
    background-color: #f0f0f0;
    border-color: #ccc;
    cursor: not-allowed;
}

input:focus {
    border-color: #2a6cff;
    box-shadow: 0 0 8px rgba(70, 136, 255, 0.4);
}

button {
    padding: 12px 20px;
    border: none;
    border-radius: 10px;
    background: #4caf50;
    color: #fff;
    font-weight: 600;
    cursor: pointer;
    transition: 0.3s;
}

button:hover {
    background: #45a049;
}

Read-Only Mode :read-only

The Critical Difference: Disabled vs Read-only

The :read-only pseudo-class targets form fields that the user can see, select, and copy, but cannot modify.

Any input or textarea with the readonly attribute in HTML is marked with this class by the browser.

These are the two concepts designers confuse most often; however, there is a technical chasm between them.

A field that is :disabled is "dead"—it cannot be clicked, focused on, and its data is not sent to the server when the form is submitted.

In contrast, a field that is :read-only is "live"—the user can click into it, select and copy the text, and this data is transmitted to the server upon form submission.

Use Case: Fixed Data

It is typically used on a profile page to present information that must be visible but cannot be changed, such as a "Username" or a "Membership Number."

In design, these fields are often given a light gray background or have their borders removed ( border: none; ) to create the feeling of "this is not a form field, it's just text."

</>
Form Validation Pseudo-Classes: :read-only Pseudo-Class Example 1 (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:read-only Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <h2>:read-only Example</h2>

    <div class="form-group">
        <label>Full Name</label>
        <input type="text" placeholder="Writable field">

        <label>Country</label>
        <input type="text" value="United Kingdom" readonly>

        <label>ID Number</label>
        <input type="text" value="User-98321" readonly>
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 30px;
    background: #f4f6f9;
}

/* Title Styling */
h2 {
    text-transform: uppercase;
    text-align: center;
    font-size: 22px;
    font-weight: 700;
    color: #2c3e50;
    margin-bottom: 25px;
}

/* Form Container */
.form-group {
    display: flex;
    flex-direction: column;
    gap: 14px;
    max-width: 300px;
    margin: 0 auto;
}

label {
    font-size: 15px;
    font-weight: 600;
    color: #555;
}

input {
    padding: 12px;
    border: 2px solid #ccc;
    border-radius: 6px;
    font-size: 14px;
    outline: none;
    transition: .3s ease;
}

/* Interaction: Visual feedback only for fields that ARE NOT read-only */
input:not([readonly]):hover {
    border-color: #4688ff;
}

/* State: Styling elements that cannot be modified by the user */
input:read-only {
    background-color: #e9ecef;
    border-color: #bfbfbf;
    cursor: not-allowed;
    color: #555;
    font-style: italic;
}

input:focus {
    border-color: #3d8bfd;
    box-shadow: 0 0 5px rgba(61, 139, 253, .3);
}
</>
Form Validation Pseudo-Classes: :read-only Pseudo-Class Example 2 (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>:read-only Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <div class="form-wrapper">
        <h3>User Profile Information</h3>
        <p class="description">Fields marked with 🔒 cannot be modified.</p>

        <form>
            <div class="field-group">
                <label for="username">Username 🔒</label>
                <input type="text" id="username" value="coder_ahmet_42" readonly>
            </div>

            <div class="field-group">
                <label for="email">Email Address</label>
                <input type="email" id="email" value="ahmet.dev@example.com">
            </div>

            <div class="field-group">
                <label for="joinDate">Join Date 🔒</label>
                <input type="text" id="joinDate" value="2023-01-15" readonly>
            </div>

            <div class="field-group">
                <label for="phone">Phone Number</label>
                <input type="tel" id="phone" value="+90 555 123 45 67">
            </div>

            <button type="submit">Update Profile</button>
        </form>
    </div>

</body>

</html>
/* CSS */
body {
    font-family: 'Verdana', sans-serif;
    background-color: #e6eefc;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
}

.form-wrapper {
    width: 90%;
    max-width: 450px;
    background-color: white;
    padding: 30px;
    border-radius: 10px;
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
    border-top: 5px solid #007bff;
}

h3 {
    color: #333;
    text-align: center;
    margin-bottom: 5px;
}

.description {
    text-align: center;
    color: #6c757d;
    font-size: 0.9em;
    margin-bottom: 25px;
}

.field-group {
    margin-bottom: 20px;
}

label {
    display: block;
    font-weight: bold;
    color: #495057;
    margin-bottom: 5px;
    font-size: 0.9em;
}

input[type="text"],
input[type="email"],
input[type="tel"] {
    width: 100%;
    padding: 12px;
    border: 1px solid #ced4da;
    border-radius: 6px;
    box-sizing: border-box;
    font-size: 1em;
    background-color: #fff;
    transition: all 0.3s ease;
}

/* Interaction: Apply focus effects only to fields that are NOT read-only */
input:not([readonly]):focus {
    border-color: #007bff;
    box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
    background-color: #e9f5ff;
}

/* State: Visual indicators for fields the user cannot modify */
input:read-only {
    background-color: #f8f9fa;
    color: #6c757d;
    border-style: dashed; /* Differentiate from regular borders */
    cursor: not-allowed;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
    opacity: 0.9;
}

input:read-only:hover {
    border-color: #adb5bd;
}

button {
    width: 100%;
    padding: 12px;
    background-color: #28a745;
    color: white;
    border: none;
    border-radius: 6px;
    font-size: 1.1em;
    cursor: pointer;
    transition: background-color 0.3s;
    margin-top: 15px;
}

button:hover {
    background-color: #218838;
}

Writable and Editable Fields :read-write

Scope: Standards and Beyond

This pseudo-class defines the boundary between "consumption" mode and "production" mode on a web page.

It represents all fields that are technically permitted for the user to enter data, modify existing content, or delete information.

By default, HTML input and textarea elements are naturally

:read-write elements, provided they do not have readonly or disabled restrictions.

However, the true power of this selector is realized when it goes beyond standard form elements.

Modern Web: The "Contenteditable" Revolution

The contenteditable="true" attribute introduced with HTML5 can instantly transform an ordinary div, p, or span tag into a "Microsoft Word-like" text editor.

The :read-write selector automatically recognizes and targets these "dynamically converted editor" elements as well.

This saves you the trouble of manually adding and removing external classes (like .is-editing) when designing CMS panels, note-taking apps, or comment editing areas.

UX Tip: Making Writability Intuitive

A user should understand at first glance that a piece of text is editable.

Best practices for these areas include setting a white background, adding a subtle inner shadow, or creating a distinct "editing frame" when focused (using :focus).

Furthermore, the mouse cursor automatically changing into a "text selector" (I-beam) is a natural and expected result of this state.

</>
Form Validation Pseudo-Classes: :read-write Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:read-write Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <h2>:read-write Example</h2>

    <div class="form-group">
        <label>Full Name</label>
        <input type="text" placeholder="You can fill this in">

        <label>Email</label>
        <input type="email" placeholder="You can fill this in">

        <label>ID (readonly)</label>
        <input type="text" value="USER-12345" readonly>
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 30px;
    background: #f4f6f9;
}

h2 {
    text-align: center;
    text-transform: uppercase;
    font-size: 22px;
    font-weight: 700;
    color: #2c3e50;
    margin-bottom: 25px;
}

.form-group {
    display: flex;
    flex-direction: column;
    gap: 14px;
    max-width: 300px;
    margin: 0 auto;
}

label {
    font-size: 15px;
    font-weight: 600;
    color: #555;
}

input {
    padding: 12px;
    border: 2px solid #ccc;
    border-radius: 6px;
    font-size: 14px;
    outline: none;
    transition: 0.3s ease;
}

/* State: Targets elements that are editable by the user */
input:read-write {
    border-color: #4688ff;
    background-color: #ffffff;
    font-style: normal;
}

input:read-write:hover {
    box-shadow: 0 0 5px rgba(70, 136, 255, 0.3);
}

/* State: Targets elements that are restricted from editing */
input:read-only {
    background-color: #e9ecef;
    border-color: #bfbfbf;
    cursor: not-allowed;
    font-style: italic;
}

input:focus {
    border-color: #3d8bfd;
    box-shadow: 0 0 5px rgba(61, 139, 253, 0.3);
}

Mandatory Field Management :required

Managing User Expectations

The :required pseudo-class targets form fields that have the required attribute in HTML—meaning they are systematically blocked from being left empty.

When users encounter a long form, they often tend to fill out only the mandatory fields to conserve energy.

Through this selector, you reduce cognitive load by showing at a glance which fields are critical and which are "nice-to-have."

Visual Marking Strategies As an industry standard, a red asterisk ( * ) is placed next to the label of required fields.

To achieve this with CSS, adjacent sibling selectors like input:required + label::after are commonly used.

Alternatively, prominence can be established by giving required fields a very light yellow background tint or by drawing a thick line on the left border.

The Opposite: :optional Technically, every field that is not mandatory is in an :optional state.

In modern designs, instead of marking required fields, a cleaner look is sometimes achieved by simply writing "(optional)" next to the non-mandatory ones.

</>
Form Validation Pseudo-Classes: :required Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Required Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <h2>:required Example</h2>

    <form class="form-box">
        <label for="name">Full Name <span>*</span></label>
        <input type="text" id="name" required placeholder="Required field">

        <label for="email">Email</label>
        <input type="email" id="email" placeholder="Optional">

        <button type="submit">Submit</button>
    </form>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
}

h2 {
    font-size: 20px;
    margin-bottom: 20px;
    text-transform: uppercase;
}

.form-box {
    display: flex;
    flex-direction: column;
    gap: 12px;
    max-width: 300px;
}

label {
    font-size: 14px;
    font-weight: 600;
    display: flex;
    gap: 4px;
}

label span {
    color: #d10000;
}

input {
    padding: 10px;
    border: 2px solid #ccc;
    border-radius: 6px;
    transition: .3s;
    outline: none;
}

/* State: Identifies fields that MUST be filled */
input:required {
    border-left: 4px solid #ff4747;
}

/* State: Changes color when a required field becomes valid */
input:required:valid {
    border-left-color: #2ecc71;
}

input:hover {
    background: #f6f6f6;
}

button {
    padding: 10px;
    border: none;
    font-size: 15px;
    font-weight: bold;
    border-radius: 6px;
    background: #4c84ff;
    color: white;
    cursor: pointer;
    transition: .3s;
}

button:hover {
    background: #3568d4;
}
                            

Optional and Free Fields :optional

Overview

The :optional pseudo-class represents form fields that do not have the required attribute—meaning the user is left free to decide whether to fill them in or not.

Since the process of filling out a form is often stressful, this class defines the areas where the user can "breathe" and feels no pressure.

The Design Paradox: Which One to Mark?

In traditional design, mandatory fields are marked with a red asterisk (*).

However, if 9 out of 10 fields in a form are mandatory, the screen becomes cluttered with red asterisks, creating a "cognitive load" for the user.

In modern UX approaches, the trend has reversed: it is assumed that everything is mandatory by default, and only fields that are :optional are specifically labeled.

This strategy cleanses the interface of visual noise and provides a much sleeker appearance.

Visual Differentiation :optional fields should feel "lighter" compared to mandatory ones.

For example, if mandatory fields have dark gray borders, optional fields can have a lighter gray border or a very subtle background tint to send the message: "This part isn't quite as critical."

Technical Scope This class applies not only to input tags; it is also valid for select and textarea elements.

If an input is both :optional and :valid ( it's valid even if left empty ), remaining "neutral" instead of showing a green checkmark usually provides a better User Experience (UX).

</>
Form Validation Pseudo-Classes: :optional Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:optional Pseudo Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <div class="form-box">
        <h2>Form Validation Example</h2>

        <div class="form-group">
            <label>Name (Required)</label>
            <input type="text" placeholder="Enter your name..." required>
        </div>

        <div class="form-group">
            <label>Phone (Optional)</label>
            <input type="tel" placeholder="Phone number (optional)">
        </div>

        <div class="form-group">
            <label>Email (Required)</label>
            <input type="email" placeholder="Your email address..." required>
        </div>

        <button>Submit</button>
    </div>

</body>

</html>
body {
    font-family: Arial, sans-serif;
    background: #181818;
    color: #fff;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 20px;
}

.form-box {
    background: #222;
    padding: 25px;
    border-radius: 15px;
    width: 330px;
    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4);
}

h2 {
    margin-bottom: 15px;
    font-size: 22px;
    text-align: center;
}

.form-group {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 18px;
}

input {
    padding: 12px;
    border-radius: 8px;
    border: 2px solid #3b3b3b;
    background: #101010;
    color: #fff;
    outline: none;
    transition: .3s ease;
    font-size: 15px;
}

input::placeholder {
    color: #777;
}

/* State: Visual indicators for mandatory fields */
input:required {
    border-color: #ff6161;
}

input:required:focus {
    border-color: #ff3131;
    background: #2a0000;
}

/* State: Visual indicators for optional fields */
input:optional {
    border-color: #4caf50;
}

input:optional:focus {
    border-color: #00e676;
    background: #003f1f;
}

button {
    width: 100%;
    padding: 12px;
    background: #00bcd4;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-size: 16px;
    font-weight: bold;
    transition: .3s;
}

button:hover {
    background: #0097a7;
}

Content Presence and Fill Control :placeholder-shown

JS-Free "Empty/Full" Detection

This pseudo-class is a smart detector that checks whether the placeholder text is currently visible inside an input or textarea field.

The logic is simple: if the user has typed something into the box, the placeholder is hidden; if they haven't, it remains visible.

Previously, to determine if an input field was empty, we had to use JavaScript to check the character count ( value.length ).

Now, with :placeholder-shown, we can handle this entirely through CSS.

If this class is active, it means the box is empty. If it is not active (:not(:placeholder-shown)), it means the user has entered data into the field.

Modern Design: Floating Labels

The most popular use case for this class is the "Floating Label" effect, a hallmark of modern form design.

The label, which normally sits inside the input, shrinks and moves to the top of the field as soon as the user starts typing (:not(:placeholder-shown)).

This saves space on the form while ensuring the user doesn't forget what they are currently writing.

Important Tip: For this selector to function, a placeholder="..." attribute must be defined on the input element.

If you don't want the placeholder text to be visible but still want to use this feature, simply placing a single space character ( " " ) inside the placeholder attribute is sufficient.

</>
Form Validation Pseudo-Classes: :placeholder-shown Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:placeholder-shown Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <h2>:placeholder-shown Example</h2>

    <div class="form-group">
        <label for="username">Username:</label>
        <input type="text" id="username" placeholder="Please enter your name">
    </div>

</body>

</html>
body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    padding: 40px;
    background-color: #f5f7fa;
}

h2 {
    text-transform: uppercase;
    margin-bottom: 25px;
    font-size: 24px;
    font-weight: 700;
    letter-spacing: 1px;
    color: #333;
    text-align: center;
}

.form-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-width: 300px;
    margin: 0 auto;
}

label {
    font-size: 15px;
    font-weight: 600;
    color: #555;
    margin-bottom: 4px;
}

input {
    padding: 12px;
    border: 2px solid #ccc;
    border-radius: 8px;
    font-size: 15px;
    outline: none;
    transition: 0.3s ease, box-shadow 0.3s ease;
}

/* State: Applied when the field is empty (placeholder is visible) */
input:placeholder-shown {
    border-color: #999;
    background-color: #f2f2f2;
}

/* State: Applied as soon as the user starts typing (placeholder disappears) */
input:not(:placeholder-shown) {
    border-color: #4caf50;
    background-color: #e7ffe7;
}

/* Hover effect */
input:hover {
    background-color: #eef6ff;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

Data Validation and Feedback :valid

Technical Triggers (How It Works)

The :valid pseudo-class represents the "success" moment when a form element's content meets all defined rules.

It is the most technical and aesthetic way to silently message the user: "This part is complete, you're doing great."

For this class to trigger, HTML5 validation constraints must be satisfied.

For instance; in a field with type="email", if an "@" symbol and a domain name are present, or if a 6 is entered into a number field with min="5", the browser considers this input valid and applies this style.

If a field has no constraints ( required, pattern, etc.), that field is in a :valid state by default at all times.

Visual Communication Strategies In design, it is commonly used to add a green border to the right side of an input field or to place a "Checkmark" ( ) icon using background-image.

These visual cues increase the user's motivation to complete the form and eliminate uncertainty.

Advanced: Chain Reactions By combining the :valid class with sibling selectors (+ or ~), you can create more complex interactions.

Example: With the input:valid + .error-message selector, you can hide the error message (display: none) or make a success message visible the moment valid data is entered.

</>
Form Validation Pseudo-Classes: :valid Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Valid Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <h2>:valid Example</h2>

    <div class="form-group">
        <label for="email">Email Address:</label>
        <input type="email" id="email" placeholder="example@mail.com" required>
        <small class="msg">Please enter a valid email.</small>
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
}

h2 {
    font-size: 20px;
    text-transform: uppercase;
    margin-bottom: 20px;
}

.form-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-width: 260px;
}

label {
    font-weight: bold;
    font-size: 14px;
}

input {
    padding: 10px;
    border: 2px solid #ccc;
    border-radius: 6px;
    font-size: 14px;
    transition: .3s ease;
    outline: none;
}

/* State: Triggered when data does NOT match the required format */
input:invalid {
    border-color: #ff6b6b;
    background: #ffe9e9;
}

/* State: Triggered when data successfully matches the required format */
input:valid {
    border-color: #28a745;
    background: #e7ffe7;
}

.msg {
    font-size: 13px;
    color: #666;
}

Error Handling and Alerts :invalid

Instant Error Detection

The :invalid pseudo-class represents the state where the data entered into a form element does not match the HTML5 validation rules.

This class triggers instantly when a user enters a letter into a number field or forgets to include an "@" in an email field.

Consequently, the user notices the error before even clicking the "Submit" button.

This significantly reduces friction during the form-filling process.

Visual Alert Methods The most common usage is turning the input border red or placing an "Exclamation Mark" icon on the right side.

In more advanced designs, CSS animations (@keyframes) can be used to create a subtle Shake effect on the input field.

This serves as the universal digital language for saying, "No, this is unacceptable."

Critical Tip: Avoiding UX Pitfalls The :invalid class can also trigger when the page first loads (if the field is required).

This may cause users to encounter red error lines before they've even started typing, leading to unnecessary stress.

To prevent this, developers typically use JavaScript or additional CSS filters like :placeholder-shown to ensure warnings only appear after the user interacts with the field.

</>
Form Validation Pseudo-Classes: :invalid Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Invalid Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <h2>:invalid Example</h2>

    <div class="form-group">
        <label for="username">Username (Min 4 characters):</label>
        <input type="text" id="username" placeholder="e.g. Alex" minlength="4" required>
        <small class="error-msg">⚠ Please enter at least 4 characters.</small>
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
}

h2 {
    font-size: 20px;
    text-transform: uppercase;
    margin-bottom: 20px;
}

.form-group {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-width: 260px;
}

label {
    font-size: 14px;
    font-weight: 600;
}

input {
    padding: 10px;
    border: 2px solid #ccc;
    border-radius: 6px;
    outline: none;
    transition: .3s;
    font-size: 14px;
}

/* Logic: Highlight as invalid ONLY when user has started typing and input is incorrect */
input:not(:placeholder-shown):invalid {
    border-color: #ff4d4d;
    background: #ffeaea;
}

/* Logic: Highlight as valid when requirements are met */
input:valid {
    border-color: #28a745;
    background: #eaffea;
}

.error-msg {
    color: #ff3333;
    font-size: 13px;
    opacity: 0;
    transition: .3s ease;
}

/* Interaction: Display error message when input is invalid AND not empty */
input:not(:placeholder-shown):invalid + .error-msg {
    opacity: 1;
}

The Safe Zone: Within Boundaries :in-range

General Introduction

The :in-range pseudo-class represents the moment when the data in an input field safely resides within the "boundaries" defined by HTML attributes.

This class communicates directly with the browser's built-in validation engine; if the entered value is mathematically or temporally within the scope of the min and max attributes, the style is applied.

Scope: Not Just for Numbers

While often assumed to be only for numeric (type="number") fields, its scope is much broader.

Sliders (type="range"), dates (type="date"), and times (type="time") where you can specify a range are also under the control of this class.

For example, when you ask a user to "Select a date between 2023 and 2025," the :in-range selector activates if the user's choice falls within that span; this is the form's "Safe Zone."

Logical Consistency and Data Quality

In web forms, it makes logical sense for certain data ( age, quantity, score ) to remain within a specific mathematical range.

Anything outside these boundaries contradicts the business logic.

Example: In a reservation system, when selecting the "Number of Guests," the value must be at least 1 and at most the restaurant's current available capacity.

If you define input type="number" min="1" max="10" in HTML and the user enters 5, this class triggers and applies the styling rules.

Visual Confirmation and Positive Feedback Instantly showing the user that their entered number is acceptable to the system increases form-filling confidence.

In design, the text color is often set to dark green, the input background is tinted a very light green, or a "confirmation icon" is placed on the right side.

This whispers to the user's subconscious: "I'm on the right track, I'm within the limits, I can proceed."

</>
Form Validation Pseudo-Classes: :in-range Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:in-range / :out-of-range Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <h2>:in-range / :out-of-range Example</h2>

    <div class="form-group">
        <label for="age">Age (18-60):</label>
        <input type="number" id="age" min="18" max="60" placeholder="Between 18-60">
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
    background-color: #f5f7fa;
}

h2 {
    text-transform: uppercase;
    font-size: 24px;
    font-weight: 700;
    letter-spacing: 1.5px;
    color: #2c3e50;
    text-align: center;
    margin-bottom: 25px;
    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
}

.form-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-width: 250px;
    margin: 0 auto;
}

label {
    font-weight: 600;
    color: #555;
}

input {
    padding: 10px;
    border: 2px solid #ccc;
    border-radius: 6px;
    font-size: 14px;
    outline: none;
    transition: 0.3s ease;
}

/* State: Applied when the value is within the min/max boundaries */
input:in-range {
    border-color: #4caf50;
    background-color: #e7ffe7;
}

/* State: Applied when the value exceeds or falls below the boundaries */
input:out-of-range {
    border-color: #ff4d4d;
    background-color: #ffeaea;
}

input:hover {
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

Boundary Violation and Alert :out-of-range

Error Prevention Mechanism

The :out-of-range pseudo-class targets the error state where a numeric value or date entered by the user overflows the limits ( min/max ) you have defined.

In an e-commerce site, a user accidentally entering "-5" for product quantity or requesting more than the 10 items in stock can lead to systemic issues.

The :out-of-range class instantly catches these illogical inputs.

Attention-Grabbing Alerts

When this state occurs, more aggressive styles ( bold text, warning icon ) should be used beyond just turning the input border red to capture the user's attention.

The goal is to immediately notify the user that they are attempting an impossible action ( such as an underage user trying to enter an 18+ site ).

Remember that this class only functions in fields where min and max attributes are explicitly defined.

</>
Form Validation Pseudo-Classes: :out-of-range Pseudo-Class Alternative Example (+)
<!DOCTYPE html>
        <html lang="en">
        
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>:out-of-range Alternative Example</title>
            <link rel="stylesheet" href="style.css?v=1.0.150">
        </head>
        
        <body>
            <h2>:out-of-range Alternative Example</h2>
        
            <div class="slider-group">
                <label for="volume">Volume Level (0-100):</label>
                <input type="range" id="volume" min="0" max="100" value="50">
                <span class="msg">Warning: Do not exceed the specified range!</span>
            </div>
        </body>
        
        </html>
body {
            font-family: Arial, Helvetica, sans-serif;
            padding: 20px;
            background-color: #f5f7fa;
        }
        
        h2 {
            text-transform: uppercase;
            font-size: 22px;
            font-weight: 700;
            text-align: center;
            color: #2c3e50;
            margin-bottom: 20px;
        }
        
        .slider-group {
            display: flex;
            flex-direction: column;
            gap: 10px;
            max-width: 300px;
            margin: 0 auto;
        }
        
        label {
            font-weight: 600;
            color: #555;
        }
        
        input[type="range"] {
            width: 100%;
            accent-color: #4caf50;
            cursor: pointer;
        }
        
        .msg {
            font-size: 13px;
            color: #ff4d4d;
            opacity: 0;
            transition: opacity 0.3s ease;
        }
        
        /* Logic: Display the warning message ONLY when the input value is out of range */
        input:out-of-range + .msg {
            opacity: 1;
        }
        
        input[type="range"]:hover {
            outline: 2px solid rgba(76, 132, 255, 0.2);
        }

Uncertainty and Intermediate State :indeterminate

Most Common Scenario: "Select All" Checkbox

This pseudo-class represents a "State of Limbo" where a form element is neither checked nor unchecked, but somewhere in between.

It sends a message to the user: "There is a partial selection here" or "The process is ongoing, but the exact progress is unknown."

Imagine a "Select All" checkbox in an email list. If you select only 3 out of 10 emails, what should the master checkbox at the top display?

If it shows a checkmark, it tells the lie that "Everything is selected"; if it remains empty, it tells the lie that "Nothing is selected."

This is where the :indeterminate state comes into play, placing a dash (-) or square inside the box to signal:

"Some of the items below are selected, others are not."

Technical Detail: The Necessity of JavaScript

You cannot trigger this state in checkboxes by simply writing an HTML attribute; this property does not exist in the basic HTML standard.

You can only activate this state via JavaScript: element.indeterminate = true;

However, once set, you can capture that checkbox on the CSS side using the input:indeterminate selector to customize its color or icon.

Progress Bars The situation is different for the <progress> element.

If you do not provide a value to a progress bar, the browser automatically considers it :indeterminate.

This creates that familiar "loading" animation that moves back and forth—signaling "It's loading, but I don't know the percentage yet."

</>
Form Validation Pseudo-Classes: :indeterminate Pseudo-Class Example (++)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Indeterminate Example (HTML, CSS, JS)</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <div class="checkbox-container">
        <h2>:indeterminate Example</h2>
        <div class="form-group">
            <label>
                <input type="checkbox" id="select-all">
                Select All
            </label>

            <label>
                <input type="checkbox" class="child"> Option 1
            </label>
            <label>
                <input type="checkbox" class="child"> Option 2
            </label>
            <label>
                <input type="checkbox" class="child"> Option 3
            </label>
        </div>
    </div>

    <script src="script.js?v=1.0.150"></script>
</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    background: #f4f6f9;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
}

h2 {
    text-align: center;
    text-transform: uppercase;
    font-size: 22px;
    font-weight: 700;
    color: #2c3e50;
    margin-bottom: 20px;
}

.checkbox-container {
    background: #ffffff;
    padding: 25px 30px;
    border-radius: 12px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
    max-width: 400px;
    width: 100%;
}

.form-group {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

label {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 15px;
    font-weight: 500;
    cursor: pointer;
}

input[type="checkbox"] {
    width: 18px;
    height: 18px;
    cursor: pointer;
}

/* State: Custom color when the checkbox is fully selected */
input[type="checkbox"]:checked {
    accent-color: #4caf50;
}

/* State: Custom color when the master checkbox is in a partial selection state */
input#select-all:indeterminate {
    accent-color: #ffb236;
}
const selectAll = document.getElementById("select-all");
const children = document.querySelectorAll(".child");

children.forEach((ch) => {
  ch.addEventListener("change", () => {
    const total = children.length;
    const checkedCount = document.querySelectorAll(".child:checked").length;

    if (checkedCount === 0) {
        selectAll.indeterminate = false;
        selectAll.checked = false;
    } else if (checkedCount === total) {
        selectAll.indeterminate = false;
        selectAll.checked = true;
    } else {
        selectAll.indeterminate = true;
    }
  });
});

selectAll.addEventListener("change", () => {
  children.forEach((ch) => (ch.checked = selectAll.checked));
});

What Have We Learned So Far?

What We've Covered
  • Functionality of form and state classes
  • Selectors like :checked, :disabled, and :required
  • Data entry and control mechanisms
  • Form validation and user feedback loops
What's Next?
  • Internationalization and language sensitivity
  • The :lang() and :dir() selectors
  • Global accessibility and cultural adaptation
Level 4

Internationalization and Language Sensitivity Global Access: Languages, Directions, and Culture

Beyond Language: Typography and Structure

To truly live up to the name "World Wide Web," the interfaces we design must be flexible enough to appeal to the entire world, not just a single language or culture.

Internationalization is the architectural approach that allows a website to automatically adapt to different languages and writing directions without changing its core code structure.

Translating a site from English to Japanese is more than just changing words; it may require adjusting line heights, font families, and even accent colors.

For example, the italic emphasis used in English is often avoided in some Asian languages because it degrades readability.

This is where CSS language-oriented selectors step in, automating cultural adjustments like: "If the language is Japanese, do not use italics; use bold instead."

The Direction Paradox: LTR and RTL

Languages using the Latin alphabet flow Left-to-Right (LTR).

However, languages like Arabic and Hebrew flow Right-to-Left (RTL).

This affects not just text alignment, but the placement of icons, the direction of margin and padding values, and even the position of the scrollbar.

The selectors we will examine in this section allow you to instantly reorganize the page skeleton by looking at the HTML itself (lang="tr" or dir="rtl").

Cultural Punctuation and "Automatic" Quotes Every language has its own unique punctuation style.

Example: While quotes in English are written as “...”, French uses «...» marks.

Using only the standard <q> tag in HTML and having CSS automatically switch quote marks (using the quotes property) based on language is a true example of internationalization.

Design Risk: Text Expansion A button labeled "Login" might look perfect in English.

However, when translated into German, it becomes "Anmelden," or it could be significantly longer in other languages.

Language-oriented selectors help you prevent design "breakage" by dynamically shrinking font sizes (font-size) for specific languages.

Language-Based Styling and Typography :lang()

Overview

The :lang() pseudo-class detects the language an element (or its parent) is written in by looking at the lang attribute in HTML, and applies specific styles accordingly.

Even if a web page is written primarily in one language, quotes or technical terms within it may be in different languages.

CSS is intelligent enough to detect these transitions.

Critical Technical Difference: Smart Matching

Many developers ask, "Why not use [lang="en"] (the Attribute Selector)?" The answer lies in hierarchical intelligence.

If you use [lang="en"], the browser looks for the exact value "en" and nothing else.

It will ignore values like "en-US" or "en-GB."

However, by using :lang(en), the browser automatically includes all sub-dialects starting with "en," making your code future-proof.

Typographic Culture (The CJK Issue)

A font designed for the Latin alphabet may fail or look unappealing when displaying complex characters in Asian languages ( Chinese, Japanese, Korean - CJK ).

By using :lang(ja) ( Japanese ) or :lang(zh) ( Chinese ), you can assign a specialized, readable font-family specifically for those texts without affecting the rest of the page.

Hyphenation Rules

How long words are broken at the end of a line varies from language to language.

With :lang(), you can enable automatic hyphenation (hyphens: auto) for languages with long words like German, while keeping it disabled for others to optimize reading flow.

Automatic Quotes

Punctuation culture differs globally. English uses “...”, while French uses «...», and German utilizes „...“ (low-starting) quotes.

By defining the quotes property alongside :lang(), you ensure that all <q> tags in your site automatically adopt the correct punctuation based on the content's language.

Investing in the Future: Voice Assistants

Language definition is not just visual; it is an auditory experience.

Proper use of :lang() ensures that Screen Readers pronounce the text with the correct accent.

Using this selector on the CSS side is also a great visual tool for debugging whether your HTML language definitions are correctly implemented.

</>
Internationalization and Language Sensitivity: :lang Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:lang() Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="lang-box">
        <h2>:lang() Example</h2>

        <p lang="tr">Merhaba! Bu paragraf Türkçe yazılmıştır.</p>
        <p lang="en">Hello! This paragraph is written in English.</p>
        <p lang="de">Hallo! Dieser Absatz ist auf Deutsch geschrieben.</p>
    </div>

</body>

</html>
body {
    font-family: system-ui, Arial, sans-serif;
    padding: 30px;
    background: #f7f7f7;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
}

.lang-box {
    background: white;
    padding: 25px;
    border-radius: 12px;
    width: 420px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
}

.lang-box h2 {
    text-align: center;
    margin-bottom: 20px;
    font-weight: 700;
    color: #2d3436;
}

.lang-box p {
    padding: 10px 14px;
    border-left: 4px solid transparent;
    background: #f1f1f1;
    border-radius: 6px;
    margin-bottom: 10px;
    transition: 0.3s;
    font-size: 15px;
}

/* Specific styling for Turkish content */
p:lang(tr) {
    border-left-color: #e74c3c;
}

/* Specific styling for English content */
p:lang(en) {
    border-left-color: #0984e3;
    font-style: italic;
}

/* Specific styling for German content */
p:lang(de) {
    border-left-color: #2ecc71;
    letter-spacing: 1px;
}

Direction and Flow Control :dir()

Overview

The :dir() pseudo-class detects whether an element's text reading direction is Left-to-Right (LTR) or Right-to-Left (RTL) based on the browser's directionality calculations.

The web is not composed solely of Latin-based languages like English or Turkish.

For languages such as Arabic, Hebrew, or Persian, the entire page structure needs to be reversed.

Critical Difference: Attribute Selector ([dir]) vs Pseudo-class (:dir)

Many developers use the attribute selector [dir="rtl"] to control direction. However, this method is insufficient.

An attribute selector only finds the element that explicitly has that attribute written on it.

In contrast, :dir(rtl) is much smarter; even if an element lacks a specific definition, it inherits the direction from its parents (like html or body) and makes a decision based on the computed value.

UI Mirroring

When the direction changes, not just the text, but the meaning of icons changes as well.

A right-pointing arrow ( ) representing "Forward" might express going "Back" in an RTL layout.

By using :dir(rtl), you can automatically rotate these icons 180 degrees (transform: scaleX(-1)) in an Arabic interface to correct the logical error.

Relationship with Logical Properties In modern CSS, using margin-inline-start instead of margin-left solves most issues.

However, for cases that cannot be resolved with "Logical Properties"—such as background images, shadow directions (box-shadow), or specific transformations—:dir() remains an indispensable tool.

</>
Internationalization and Language Sensitivity: :dir Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:dir() Directional Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="dir-container">

        <h2>Dir Attribute Example</h2>

        <div class="dir-box" dir="ltr">
            <p>LTR Direction content text example.</p>
        </div>

        <div class="dir-box" dir="rtl">
            <p>‮Pseudo RTL directional text sample.‬</p>
        </div>

        <div class="dir-box" dir="auto">
            <p>Auto detects based on first character.</p>
        </div>

    </div>

</body>

</html>
body {
    display: flex;
    justify-content: center;
    background: #111;
    padding: 40px;
    font-family: sans-serif;
    color: #fff;
}

.dir-container {
    width: 480px;
    display: flex;
    flex-direction: column;
    gap: 1.6rem;
}

.dir-box {
    padding: 20px;
    border-radius: 12px;
    background: #1c1c1c;
    border: 2px solid transparent;
    transition: 0.3s;
    font-size: 17px;
}

/* Logic: Styling specifically for Left-to-Right flow */
.dir-box:dir(ltr) {
    border-color: #00c3ff;
    box-shadow: 0 0 8px #00c3ff88;
    text-align: left;
}

/* Logic: Styling specifically for Right-to-Left flow */
.dir-box:dir(rtl) {
    border-color: #ff007a;
    box-shadow: 0 0 8px #ff007a88;
    text-align: right;
}

.dir-box:hover {
    transform: scale(1.03);
}

What Have We Learned So Far?

What We've Covered
  • Internationalization (i18n) and language sensitivity
  • The :lang() and :dir() selectors
  • Global accessibility and cultural adaptation
  • Multilingual web design techniques
What's Next?
  • Global and logical selectors
  • :root, :not(), :is(), and :where() selectors
  • Management and logic layers in CSS
Level 5

Global and Logical Selectors Management and Logic Layer

The Root and Variable Hub: :root

Rather than focusing on an element's state or interaction, these pseudo-classes focus on targeting logical structures such as position, hierarchy, or whether a document meets a specific condition.

They are the most powerful tools for building design systems and adhering to the DRY (Don't Repeat Yourself) principle.

It targets the root element of the HTML document (which is always the <html> tag).

It is more specific than the html type selector and provides the highest global scope supported by the browser.

This selector is primarily used to define CSS Variables (--variable-name), which were introduced with CSS Module 4.

Variables defined at the root level can be inherited and used by every single element on that page.

The Central Hub for Global Themes: It ensures that global settings like the site’s main color palette, base font sizes, and transition durations are gathered in a single center.

This makes theme switching ( such as transitioning from light mode to dark mode ) or updating brand colors from a single location incredibly efficient and fast.

The Document Root and Global Variables :root

Technical Duel: :root vs html

The :root pseudo-class selects the root element at the very top of the document tree, which serves as the ancestor for all other elements.

In HTML documents, this always corresponds to the <html> element; however, in other document types like SVG or XML, it represents the root of that specific document.

Many developers ask, "Why don't we just write html { ... }?" The answer lies in the Specificity score.

html is a type (tag) selector and has a low score ( 0-0-1 ).

However, :root is a pseudo-class and has a higher specificity score ( 0-1-0 ).

This technical distinction makes :root more dominant and reliable, especially when you need to override browser defaults or CSS libraries.

The Home of CSS Variables

In modern web development, :root acts as the site's "Configuration File."

Color palettes (--primary-color), font sizes, and spacing values are defined here.

A variable defined on the root element becomes accessible to all descendant elements within the DOM tree.

This allows you to update the site's entire theme from top to bottom by changing just a single line of code.

Dynamic Theme Management (Dark Mode) When you want to switch themes via JavaScript, this is usually where the intervention happens.

When JS changes the value of variables on :root, the colors of thousands of elements on the page update within milliseconds without any performance loss.

The Heart of Typography: The REM Unit One of the most popular measurement units in CSS, rem, derives its name and power directly from this selector.

The 1rem value is always equal to the font size assigned to the :root tag.

If you define :root { font-size: 16px; }, all rem values in your site will be calculated based on this 16px.

This enables you to instantly rescale the entire site by changing a single number at the root.

SVG and Independent Files If you open an external .svg file directly in the browser, there is no <html> tag; the root element is <svg>.

In this case, styles given via html { ... } will not work, but :root { ... } works perfectly in both environments.

This feature is vital when designing portable graphic components that can be used both within a web page and independently.

</>
Global and Logical Selectors: :root Pseudo-Class Example (++)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:root Theme Switcher</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <div class="container">
        <h2>🎨 Theme Switcher</h2>
        <p>
            In this example, theme variables were defined globally using the <strong>:root</strong> pseudo-class. 
            The entire style changes with a single click.
        </p>

        <button id="toggleTheme">🌙 Switch to Dark Mode</button>
    </div>

    <script src="script.js?v=1.0.150"></script>

</body>

</html>
/* Default Light Theme Variables */
:root {
    --bg-color: #ffffff;
    --text-color: #111;
    --box-bg: rgba(255, 255, 255, 0.55);
    --btn-bg: #007bff;
    --btn-text: #fff;
    --shadow: rgba(0, 0, 0, 0.14);
    --radius: 14px;
    --transition: .35s ease;
}

/* Dark Theme Overrides */
:root.dark {
    --bg-color: #0f0f0f;
    --text-color: #ffffff;
    --box-bg: rgba(50, 50, 50, 0.4);
    --btn-bg: #ffd43b;
    --btn-text: #111;
    --shadow: rgba(255, 255, 255, 0.1);
}

body {
    font-family: "Segoe UI", sans-serif;
    background: var(--bg-color);
    color: var(--text-color);
    margin: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
}

.container {
    width: 450px;
    background: var(--box-bg);
    backdrop-filter: blur(20px);
    padding: 35px;
    border-radius: var(--radius);
    box-shadow: 0 8px 28px var(--shadow);
    text-align: center;
    transition: var(--transition);
}

.container h2 {
    margin: 0 0 18px;
    font-size: 22px;
    font-weight: 700;
}

.container p {
    font-size: 15px;
    line-height: 1.6;
    margin-bottom: 30px;
    opacity: 0.85;
}

button {
    width: 100%;
    padding: 14px;
    background: var(--btn-bg);
    color: var(--btn-text);
    border: none;
    border-radius: var(--radius);
    font-size: 16px;
    cursor: pointer;
    transition: var(--transition);
    font-weight: 600;
}

button:hover {
    transform: translateY(-2px);
    box-shadow: 0 5px 18px var(--shadow);
}

button:active {
    transform: scale(.97);
}
const btn = document.getElementById("toggleTheme");

btn.addEventListener("click", () => {
  // Toggles the 'dark' class on the root (html) element
  document.documentElement.classList.toggle("dark");

  if (document.documentElement.classList.contains("dark")) {
    btn.textContent = "☀️ Switch to Light Mode";
  } else {
    btn.textContent = "🌙 Switch to Dark Mode";
  }
});

Smart Grouping and Code Shortening :is()

Preventing Code Duplication (DRY Principle)

One of the greatest conveniences of modern CSS, :is(), is a "syntactic sugar" that shortens long and repetitive selector chains.

It selects elements that match any item in the selector list written inside the parentheses. It allows you to combine multiple complex rules into a single line.

Previously, to apply a style to paragraphs inside header, main, and footer, we would write:
header p, main p, footer p { ... }

With :is(), this is now much cleaner: :is(header, main, footer) p { ... }

Critical Detail: Specificity Score The most important technical feature of this selector is that the specificity of the :is() pseudo-class is equal to the score of the

highest-specificity selector within its arguments.

In other words, if your list contains a simple tag (p) and a powerful ID ( #hero ), the browser treats the entire group as if it were an ID selector.

This can sometimes lead to unexpected style overrides due to high specificity dominance.

Forgiving Selector In normal CSS rules, if you include an invalid selector ( such as a feature not yet supported ) in a comma-separated list, the browser invalidates the entire line.

However, :is() is "forgiving."

It ignores invalid parts within the parentheses and continues to execute the valid ones.

</>
Global and Logical Selectors: :is() Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:is() Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <h2>:is() Example</h2>

    <div class="buttons">
        <button class="primary">Primary</button>
        <button class="secondary">Secondary</button>
        <button class="danger">Danger</button>
        <button class="info">Info</button>
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
}

h2 {
    text-transform: uppercase;
    margin-bottom: 15px;
}

.buttons button {
    padding: 10px 16px;
    margin-right: 10px;
    border: none;
    border-radius: 6px;
    color: white;
    font-weight: 600;
    cursor: pointer;
    transition: .3s;
}

/* Logic: Applying hover effects to multiple classes at once using :is() */
:is(.primary, .secondary, .info):hover {
    transform: scale(1.05);
    opacity: 0.85;
}

.primary {
    background: #4c84ff;
}

.secondary {
    background: #777;
}

.danger {
    background: #ff4d4d;
}

.info {
    background: #00bcd4;
}

/* Specific logic: Danger button has a different hover state */
.danger:hover {
    transform: scale(1.08);
    opacity: 0.9;
}

Zero Specificity and Easy Overridability :where()

The Single Big Difference: Zero Specificity

Functionally, it works exactly like :is(); it selects and groups elements that match any item in the list within the parentheses.

What makes the :where() selector unique is that no matter what you write inside ( be it an ID, or thousands of classes ), the specificity score assigned by the browser is always ZERO (0).

This is the "Ghost" selector of CSS—it exists, it selects, but it carries absolutely no weight in style wars.

Use Case: CSS Libraries and Resets

When creating a CSS library or a "Reset CSS" file, you want the rules you write to be easily overridable by the end-user.

If you write your base styles using :where(), the developer using your project can easily override your rules later with a simple class.

This eliminates the need for the dreaded !important declaration.

In summary: use :is() for strong and dominant groupings, and :where() for gentle and easily changeable defaults.

</>
Global and Logical Selectors: :where() Pseudo-Class Example (+)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:where() Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <h2>:where() Example</h2>

    <div class="cards">
        <div class="card primary">Primary Card</div>
        <div class="card secondary">Secondary Card</div>
        <div class="card info">Info Card</div>
        <div class="card danger">Danger Card</div>
    </div>

</body>

</html>
body {
    font-family: Arial, Helvetica, sans-serif;
    padding: 20px;
}

h2 {
    text-transform: uppercase;
    margin-bottom: 15px;
}

.cards {
    display: flex;
    gap: 12px;
}

.card {
    padding: 20px;
    border-radius: 8px;
    color: white;
    font-weight: 600;
    transition: .3s;
    cursor: pointer;
}

/* Logic: Grouping with ZERO specificity. 
   These styles can be easily overridden by any class selector. */
:where(.primary, .secondary, .info):hover {
    transform: scale(1.05);
    opacity: 0.85;
}

.primary {
    background: #4c84ff;
}

.secondary {
    background: #777;
}

.info {
    background: #00bcd4;
}

.danger {
    background: #ff4d4d;
}

/* Specific logic: Danger card has a higher specificity hover state here */
.danger:hover {
    transform: scale(1.08);
    opacity: 0.9;
}

What Have We Learned So Far?

What We've Covered
  • Global and logical selectors
  • Selectors like :root, :not(), :is(), and :where()
  • Management and logic layers in CSS
  • CSS variables and theme management
What's Next?
  • Media and specialized UI states
  • Selectors like :fullscreen and :picture-in-picture
  • Screen management and display modes
Level 5

Media and Specialized UI States Screen Management and Display Modes

The Bridge Between Browser and OS

Web pages typically live within the boundaries of the browser window (viewport). However, the modern web offers experiences that transcend these limits.

Scenarios such as a video occupying the entire screen or a presentation being stripped of all distractions move beyond the standard CSS flow.

Selectors in this category target not just an HTML element's state within the page, but its relationship with the operating system and

screen hardware.

When a user enters "Full Screen" mode or moves a video into "Picture-in-Picture" ( PiP ) mode, the element's context changes entirely.

CSS captures this context shift instantly, offering the developer an opportunity:

"This element is no longer in the normal flow; it's in a special mode—style it accordingly."

Technical Architecture: The "Top Layer"

In modern browsers, there is a special layer independent of the page flow that sits above all "z-index" calculations: the Top Layer.

When an element enters :fullscreen or :picture-in-picture mode, the browser visually detaches it from its place in the DOM tree and moves it to this top layer.

Consequently, even if a parent element has overflow: hidden, the media content can occupy the entire screen without being clipped.

Security Rule: User Activation

These special states are considered "Privileged Modes."

A website cannot automatically force you into Full Screen mode as soon as the page loads.

Triggering these modes requires an explicit user action ( click or keypress ).

CSS steps in once this action occurs and the browser grants permission; thus, CSS is not the "initiator" here, but the "responder" ( reactive side ).

Focus and Immersive Experience :fullscreen

The Need for Visual Transformation

The :fullscreen pseudo-class targets the element that occupies the user's entire monitor, triggered by the browser's "Fullscreen API."

This applies not just to videos, but also to games ( canvas ), presentations, maps, or any div intended to be shown in full screen.

While an element is in the normal page flow, it may have borders, shadows, or rounded corners ( border-radius ).

However, when switching to fullscreen mode, these decorative details are usually unwanted; instead, the element is expected to perfectly fill the corners of the screen.

Using the :fullscreen selector, you can remove borders, change background colors, or scale text to massive sizes the moment an element goes full screen.

The Unsung Hero: ::backdrop

What happens if the aspect ratio of an image in fullscreen doesn't match the screen? You get empty spaces on the sides.

To style these gaps (the black curtain behind the element), the ::backdrop pseudo-element is used.

This is a virtual layer that works alongside :fullscreen, sitting immediately behind the fullscreen element.

Technical Pitfall: Disappearing Scrollbars

Scrolling down a web page is natural browser behavior, but when you make a specific div element fullscreen, it no longer inherits the page's scroll properties.

If the box you made fullscreen contains a lot of text and you haven't managed the overflow, the user won't be able to see the rest of the content.

Therefore, you must add overflow-y: auto; within the :fullscreen block to ensure it creates its own scrollbar when necessary.

"Glassmorphism" Effect with Backdrop

The ::backdrop doesn't have to be just a black curtain.

If your page has a colorful design, instead of completely hiding the background in fullscreen mode, you can use:

::backdrop { background: rgba(0,0,0,0.8); backdrop-filter: blur(10px); } to show the content behind as if it were through frosted glass.

This is a modern and sleek technique that maintains the user's feeling of "I'm still on the same site, just focused."

</>
Media and Specialized UI States: :fullscreen Pseudo-Class Example (++)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fullscreen API Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <div class="fullscreen-wrapper" id="fullscreenBox">
        <header>
            <h2>📺 Fullscreen Mode</h2>
            <p class="subtitle">You can enter or exit fullscreen mode for this box.</p>
        </header>

        <div class="content">
            <p>
                In fullscreen mode, the background, typography, and layout will change.
This page was designed with modern CSS + JavaScript. </p> </div> <button id="fullscreenBtn" class="toggle-fullscreen-btn"> ⛶ Open Fullscreen </button> </div> <script src="script.js?v=1.0.150"></script> </body> </html>
body {
    background: linear-gradient(135deg, #1e1e2f, #13131f);
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    font-family: 'Segoe UI', Tahoma, sans-serif;
    margin: 0;
    padding: 20px;
    color: #eee;
}

.fullscreen-wrapper {
    width: 90%;
    max-width: 600px;
    padding: 30px;
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.07);
    backdrop-filter: blur(12px);
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 15px 40px rgba(0, 0, 0, 0.4);
    transition: .4s ease;
    text-align: center;
}

.fullscreen-wrapper header h2 {
    margin: 0;
    font-size: 1.8rem;
    font-weight: 600;
}

.subtitle {
    opacity: 0.7;
    font-size: 0.9rem;
    margin-top: 4px;
}

.content {
    margin: 20px 0;
    line-height: 1.6;
    font-size: 1.05rem;
    opacity: 0.9;
}

.toggle-fullscreen-btn {
    background: #00e5ff;
    border: none;
    color: #000;
    font-weight: bold;
    padding: 14px 24px;
    font-size: 1rem;
    border-radius: 10px;
    cursor: pointer;
    transition: 0.3s ease;
}

.toggle-fullscreen-btn:hover {
    transform: scale(1.05);
    background: #53f0ff;
}

/* State: Transformations applied when the box enters fullscreen */
#fullscreenBox:fullscreen {
    background: #00e5ff;
    color: #111;
    box-shadow: none;
    border-radius: 0;
    width: 100vw;
    height: 100vh;
    padding: 50px;
    justify-content: center;
    align-items: center;
    display: flex;
    flex-direction: column;
    font-size: 1.3rem;
}
const box = document.getElementById("fullscreenBox");
const btn = document.getElementById("fullscreenBtn");

btn.addEventListener("click", async () => {
  if (!document.fullscreenElement) {
    // Requests the browser to move the element to the "Top Layer"
    await box.requestFullscreen();
    btn.textContent = "⤫ Exit Fullscreen";
    btn.style.background = "#ff4f63";
  } else {
    // Exits fullscreen mode
    await document.exitFullscreen();
    btn.textContent = "⛶ Open Fullscreen";
    btn.style.background = "#00e5ff";
  }
});

Multitasking and Floating Window :picture-in-picture

What Does It Target? (Source vs. Window)

This pseudo-class represents the state when a user detaches a video from the main page to watch it in a small floating window

( PiP - Picture-in-Picture ) at the corner of the screen.

Technical Detail: You cannot style the interior of the floating PiP window itself via CSS ( this is controlled by the operating system ).

Instead, this selector targets the original element left behind on the page.

Usage Scenario: Placeholder When a video enters PiP mode, the original video tag on the page often appears black or empty.

By using :picture-in-picture, you can add a stylish background image or a blur effect ( backdrop-filter ) to this empty area with a message like "Video is currently playing in PiP mode."

This is a great UX touch that reminds the user the video hasn't disappeared—it has simply moved.

Critical UX: Preventing Layout Shift (CLS) When a video enters PiP mode, some browsers might completely hide the original element or reset its size if not managed by CSS.

This causes the text below the video to suddenly jump up, ruining the reading experience.

With the :picture-in-picture selector, you can assign a fixed width/height or a "skeleton screen" background to the original video area, ensuring the page layout remains stable.

Synergy with Pseudo-Elements (::after) You don't need extra HTML tags to display the "Video is playing" message.

Using the video:picture-in-picture::after combination, you can place a message directly via CSS:

( content: "Video playing in the corner ↘"; ) along with an icon.

This is a brilliant example of combining CSS powers for a polished interface.

</>
Media and Specialized UI States: :picture-in-picture Pseudo-Class Example (++)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:picture-in-picture Pseudo-Class Example</title>
</head>

<body>

    <div class="modern-pip-card">
        <div class="card-header">
            <div class="icon-box">
                <i class="fas fa-layer-group"></i>
            </div>
            <div class="header-text">
                <h3>Floating Window Experience</h3>
                <p>Detach the video and browse freely.</p>
            </div>
        </div>

        <div class="video-frame">
            <div class="pip-overlay">
                <div class="overlay-content">
                    <i class="fas fa-external-link-alt"></i>
                    <span>Video is playing in Picture-in-Picture mode</span>
                </div>
            </div>

            <video id="demoVideo" controls>
                <source src="sample-video.mp4" type="video/mp4">
                Your browser does not support the video tag.
            </video>
        </div>

        <button id="togglePipBtn" class="action-btn">
            <i class="fas fa-images"></i>
            <span>Detach Video</span>
        </button>
    </div>

    <script src="script.js?v=1.0.150"></script>
</body>

</html>
.modern-pip-card {
    background: #ffffff;
    border-radius: 20px;
    padding: 24px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.08);
    max-width: 550px;
    width: 100%;
    margin: 20px auto;
    font-family: 'Segoe UI', system-ui, sans-serif;
    border: 1px solid rgba(0, 0, 0, 0.05);
}

.card-header {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-bottom: 24px;
    text-align: left;
}

.icon-box {
    width: 48px;
    height: 48px;
    background: rgba(99, 102, 241, 0.1);
    color: #6366f1;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
}

.header-text h3 {
    margin: 0;
    font-size: 18px;
    color: #1e293b;
    font-weight: 700;
}

.header-text p {
    margin: 4px 0 0 0;
    font-size: 14px;
    color: #64748b;
}

/* Video Frame */
.video-frame {
    position: relative;
    border-radius: 16px;
    overflow: hidden;
    background: #0f172a;
    aspect-ratio: 16/9;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}

video {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
    transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

/* --- THE MAGIC: WHEN PIP IS ACTIVE --- */
video:picture-in-picture {
    opacity: 0;
    /* Hide the original video while it's floating */
}

/* Placeholder Overlay Message */
.pip-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f8fafc;
    border: 2px dashed #cbd5e1;
    border-radius: 16px;
    opacity: 0;
    transition: opacity 0.3s ease;
    z-index: 0;
}

.overlay-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    color: #64748b;
    font-weight: 600;
}

.overlay-content i {
    font-size: 24px;
    color: #94a3b8;
}

/* Show the overlay when video is in PiP mode using :has */
.video-frame:has(video:picture-in-picture) .pip-overlay {
    opacity: 1;
    z-index: 10;
}

/* Modern UI Button */
.action-btn {
    margin-top: 24px;
    width: 100%;
    padding: 14px;
    background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
    color: white;
    border: none;
    border-radius: 12px;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    transition: transform 0.2s, box-shadow 0.2s;
}

.action-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 10px 20px -10px rgba(99, 102, 241, 0.5);
}

.action-btn:active {
    transform: translateY(0);
}

.action-btn:disabled {
    background: #e2e8f0;
    color: #94a3b8;
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
}
const video = document.getElementById("demoVideo");
const btn = document.getElementById("togglePipBtn");
const btnText = btn.querySelector("span");

// Check for PiP Support
if ("pictureInPictureEnabled" in document) {
  btn.addEventListener("click", async () => {
    // If already in PiP mode, exit
    if (document.pictureInPictureElement) {
      await document.exitPictureInPicture();
    } else {
      // Ensure video is ready before requesting PiP
      if (video.readyState === 0) {
        alert("Please wait for the video to load or press play.");
        return;
      }
      // Request PiP mode
      try {
        await video.requestPictureInPicture();
      } catch (error) {
        console.error("PiP Request Failed:", error);
      }
    }
  });

  // Listen for Events and Update UI
  video.addEventListener("enterpictureinpicture", () => {
    btnText.innerText = "Exit Floating Window";
    btn.style.background = "#334155";
  });

  video.addEventListener("leavepictureinpicture", () => {
    btnText.innerText = "Detach Video";
    btn.style.background = "";
  });
} else {
  btn.disabled = true;
  btnText.innerText = "PiP Not Supported";
}

Restricted Focus and Modality :modal

Overview

The :modal pseudo-class represents elements that completely cut off interaction with the rest of the page ( blocking state ), forcing the user to interact only with the element itself.

In web standards, its counterpart is typically the <dialog> element; however, this element must be opened using the JavaScript .showModal() method to trigger this state.

Technical Revolution: The "Inert" State

When this class is active, the browser renders everything in the background ( buttons, links, text selection ) "Inert"—meaning

dead or unresponsive.

This is vital for accessibility.

When a visitor using a keyboard presses the TAB key, the focus never leaves the modal window, and the background page cannot be accidentally clicked.

End of the Z-Index Wars: In the past, random and high numbers like z-index: 99999; were used to bring a modal window to the top.

An element in the :modal state is moved to the browser's special Top Layer.

Consequently, no matter how deep the modal is within the HTML structure ( even if nested inside 10 divs ), it will visually always be at the very top, above everything else.

Spotlight with Backdrop: Just like with :fullscreen, :modal also works alongside the ::backdrop pseudo-element.

You use this duo to darken, blur, or color the rest of the page when the modal opens.

(dialog:modal::backdrop { background: rgba(0,0,0,0.5); })

</>
Media and Specialized UI States: :modal Pseudo-Class Example (++)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:modal Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <button id="open">Open Modal</button>

    <dialog id="myModal">
        <div class="modal-content">
            <h2>Modern Modal</h2>
            <p>This is a modern example enhanced with the :modal pseudo-class.</p>
            <button id="close">Close</button>
        </div>
    </dialog>

    <script src="script.js?v=1.0.150"></script>

</body>

</html>
* {
    margin: 0;
    box-sizing: border-box;
    font-family: "Segoe UI", sans-serif;
}

body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background: linear-gradient(135deg, #1f1c2c, #928dab);
}

button {
    padding: 12px 24px;
    border: none;
    background: #ffffff15;
    color: white;
    border-radius: 8px;
    backdrop-filter: blur(5px);
    cursor: pointer;
    transition: 0.3s;
}

button:hover {
    background: #ffffff30;
}

/* Default state of the dialog */
dialog {
    padding: 0;
    border: none;
    border-radius: 18px;
    background: transparent;
    opacity: 0;
    transform: translateY(-20px) scale(0.8);
    transition: all 0.35s ease, opacity 0.3s;
}

dialog .modal-content {
    padding: 30px;
    background: rgba(255, 255, 255, 0.12);
    border-radius: 18px;
    backdrop-filter: blur(14px) saturate(180%);
    border: 1px solid rgba(255, 255, 255, 0.25);
    color: #fff;
    min-width: 320px;
    text-align: center;
}

/* Logic: Applied when showModal() is called */
dialog:modal {
    opacity: 1;
    transform: translateY(0) scale(1);
}

/* Backdrop logic: Styling the page background while modal is active */
:modal::backdrop {
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(6px);
    animation: fadeIn 0.4s ease;
}

@keyframes fadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}
const modal = document.getElementById("myModal");

// Triggering the :modal state using the Fullscreen/Dialog API
document.getElementById("open").onclick = () => modal.showModal();

// Removing the :modal state
document.getElementById("close").onclick = () => modal.close();

Media Stream and Playback States :playing & :paused

Farewell to JavaScript Event Listeners

These two pseudo-classes listen to the "heartbeat" of <video> or <audio> elements on the page.

Is the media currently streaming (:playing), or is it stopped/waiting (:paused)? CSS can now make instantaneous style changes based on the answer to this question.

Previously, to show a "Play" icon when a video stopped or to dim the background while it was playing, we had to use JavaScript to listen for play and pause events and manually toggle classes like .is-playing.

Thanks to these new selectors, the browser detects these states automatically.

Example: By defining video:paused + .play-icon { display: block; }, you can make the play button visible the moment the video stops.

Use Case: Visual Equalizer Imagine moving bars (an animated equalizer) while an audio file is playing.

When the music stops, this animation must also stop.

By applying animation-play-state: paused; to the audio:paused + .equalizer selector, you can perfectly synchronize CSS animations with the media state.

Bleeding Edge Technology These selectors are part of the CSS Selectors Level 4 specification and are among the "newest" features.

While full standard support may not be available across all browsers yet, it is the clearest indicator of where modern web media management is headed.

Performance Gap: Freeing the Main Thread

Listening to a video's state with JavaScript ( event listener ) keeps the browser's main thread busy.

If your site is performing heavy operations, JavaScript's command to "The video has stopped, show the icon" might be delayed by milliseconds, causing a perceived stutter in the UI.

CSS selectors like :paused, however, are processed directly by the browser's rendering engine.

This ensures that no matter how heavy the site is, the icon reacts in the "same frame" as the video.

Design Tip: Ambient Videos

Modern sites frequently use silent, looping background videos in their "Hero" sections.

If the browser auto-pauses this video due to "Power Saving Mode," the page might look stagnant.

Using video:paused, you can preserve the design's vibrancy by adding a stylish static image or a color filter that triggers the moment the video is paused.

</>
Media and Specialized UI States: :playing and :paused Pseudo-Class Example (++)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:playing and :paused Pseudo-Class Example</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <div class="animation-container">
        <div id="box" class="box"></div>
        <button id="toggleBtn" class="control-btn"></button>
    </div>

    <script src="script.js?v=1.0.150"></script>

</body>

</html>
body {
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #111623;
    font-family: Arial, sans-serif;
}

.animation-container {
    position: relative;
}

.box {
    width: 120px;
    height: 120px;
    background: linear-gradient(135deg, #4F46E5, #06B6D4);
    border-radius: 16px;
    animation: spin 2s linear infinite;
    border: 5px solid #555;
    transition: 0.4s;
}

/* State: Applied when the element's animation or media is active */
.box:playing {
    border-color: #2ecc71;
    box-shadow: 0 0 22px rgba(46, 204, 113, 0.6);
}

/* State: Applied when the animation or media is paused */
.box:paused {
    border-color: #e74c3c;
    opacity: 0.6;
    box-shadow: none;
}

.control-btn {
    position: absolute;
    bottom: -100px;
    left: 30px;
    width: 60px;
    height: 60px;
    border: none;
    border-radius: 50%;
    cursor: pointer;
    background: rgba(255, 255, 255, 0.15);
    backdrop-filter: blur(10px);
    transition: 0.3s;
    border: 1px solid #fff;
}

.control-btn:hover {
    transform: scale(1.1);
}

.control-btn::before {
    content: "▶";
    font-size: 30px;
    color: white;
    display: flex;
    justify-content: center;
    align-items: center;
}

/* Logic: Dynamic icon change based on the sibling's :playing state */
.box:playing + .control-btn::before {
    content: "⏸";
}

@keyframes spin {
    from {
        transform: rotate(0);
    }
    to {
        transform: rotate(360deg);
    }
}
const box = document.getElementById("box");
const btn = document.getElementById("toggleBtn");

let running = true;

btn.addEventListener("click", () => {
  running = !running;
  // Triggering the CSS :playing/:paused state via animationPlayState
  box.style.animationPlayState = running ? "running" : "paused";
});

What Have We Learned So Far?

What We've Covered
  • Media and specialized UI states
  • The :fullscreen and :picture-in-picture selectors
  • Screen management and display modes
  • CSS integration with video and audio control
Completed!
  • All categories of pseudo-classes
  • Dynamic, structural, form, and media selectors
  • Modern CSS techniques and practical applications