|

CSS 59 💻 1 – 58 Full

1. Introduction to CSS

CSS (Cascading Style Sheets) is the language used to control the visual presentation of HTML documents. It allows you to style everything from colors and fonts to layouts and animations.


What is CSS?

CSS specifies how HTML elements should be displayed on screen, paper, or in other media. It separates content (HTML) from presentation (CSS), making websites easier to maintain and update.

Key Benefits:

BenefitDescription
Separation of concernsContent and design are kept separate
ReusabilityOne CSS file can style multiple HTML pages
ConsistencyUniform design across an entire website
FlexibilityEasy to update and maintain

Three Ways to Use CSS

MethodDescriptionExample
InlineCSS applied directly to an HTML element using the style attribute<h1 style="color:blue">Hello</h1>
InternalCSS defined inside the <style> element in the <head> section<style>h1 { color: blue; }</style>
ExternalCSS defined in a separate .css file and linked with <link><link rel="stylesheet" href="styles.css">

1. Inline CSS

<h1 style="color:blue">CSS Introduction</h1>
<p style="font-size: 20px;">This is a paragraph.</p>

Pros: Quick and easy for single elements
Cons: Not reusable, hard to maintain


2. Internal CSS

<!DOCTYPE html>
<html>
<head>
    <style>
        p {
            color: red;
        }
        h1 {
            font-size: 24px;
        }
    </style>
</head>
<body>
    <p>This paragraph is red.</p>
</body>
</html>

Pros: Good for single-page sites
Cons: Not reusable across multiple pages


3. External CSS

<!-- HTML file -->
<head>
    <link rel="stylesheet" href="styles.css">
</head>

<!-- styles.css file -->
p {
    color: red;
}
span {
    color: green;
}

Pros: Reusable, easy to maintain, best practice
Cons: Requires an extra HTTP request


CSS Basic Syntax

A CSS rule consists of a selector and a declaration block.

selector {
    property: value;
    property: value;
}

Example:

p {
    color: red;
    font-size: 16px;
    margin: 10px;
}

Components:

ComponentDescriptionExample
SelectorThe HTML element(s) to stylep, .class, #id
PropertyThe style characteristic to changecolor, font-size, margin
ValueThe value assigned to the propertyred, 16px, 10px

Common Selectors

SelectorExampleDescription
Elementp { }Selects all <p> elements
Class.myClass { }Selects elements with class="myClass"
ID#myId { }Selects the element with id="myId"
Attribute[ type="text" ] { }Selects elements with a specific attribute
Universal* { }Selects all elements
Groupingh1, h2, p { }Selects multiple elements

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS Introduction</title>

    <!-- ====== INTERNAL CSS ====== -->
    <style>
        /* Element Selector */
        p {
            color: red;
            font-size: 18px;
        }

        /* Class Selector */
        .highlight {
            background-color: yellow;
            font-weight: bold;
        }

        /* ID Selector */
        #main-heading {
            color: blue;
            text-align: center;
            font-size: 2em;
        }

        /* Grouping Selector */
        h1, h2, h3 {
            font-family: Arial, sans-serif;
        }
    </style>

    <!-- ====== EXTERNAL CSS ====== -->
    <link rel="stylesheet" href="styles.css">

</head>
<body>

    <!-- ====== INLINE CSS ====== -->
    <h1 style="color:blue; text-align:center;">CSS Introduction</h1>

    <p>Cascading Style Sheets</p>

    <p class="highlight">This paragraph has a yellow background.</p>

    <span style="color: green;">Inline styled span</span>

    <div id="main-heading">Styled with an ID selector</div>

</body>
</html>

External CSS File (styles.css):

span {
    color: green;
    font-weight: bold;
}

body {
    background-color: #f8f9fa;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    padding: 20px;
}

.highlight {
    background-color: #ffc107;
    padding: 5px 10px;
    border-radius: 4px;
}

Quick Reference

ConceptExampleDescription
Inline CSS<h1 style="color:red">Applied directly to an element
Internal CSS<style>h1{color:red;}</style>Defined in the <head>
External CSS<link rel="stylesheet" href="style.css">Linked from a separate file
Selectorp { }Targets HTML elements
PropertycolorWhat to change
ValueredThe new value
Declarationcolor: red;Property + Value

Best Practices

Do This:

/* Use external CSS for maintainability */
<link rel="stylesheet" href="styles.css">

/* Use meaningful class names */
.button-primary { }

/* Group related properties */
h1 {
    color: blue;
    font-size: 2em;
    text-align: center;
}

Don’t Do This:

/* Don't use inline CSS for styling multiple elements */
<h1 style="color:red">Title 1</h1>
<h1 style="color:red">Title 2</h1>
/* Use a class instead */

/* Don't use IDs for styling reusable components */
#button1 { }
#button2 { }
/* Use classes instead: .button { } */

/* Don't use vague class names */
.a { }
.b { }

Pro Tip: Always prefer external CSS for anything more than a single page. It makes your code cleaner, more maintainable, and faster to load (browsers cache external CSS files). Use classes for reusable styles and IDs only for unique elements!

2. Comments and Selectors

CSS selectors are patterns used to select and style HTML elements. Understanding selectors is essential for applying styles effectively. CSS also allows comments to document your code.


CSS Comments

Comments are used to add notes or explanations in your CSS code. They are ignored by the browser.

Syntax:

/* This is a single-line comment */

/*
   This is a
   multi-line comment
*/

Types of Selectors

Selector TypeSymbol/PatternExampleDescription
Elementelementp { }Targets all elements with a specific tag name
Class.classname.button { }Targets all elements with a specific class
ID#idname#header { }Targets only one element with a specific ID
Attribute[ attribute="value" ][ type="text" ] { }Targets elements with specific attributes
Pseudo-element::pseudo::placeholder { }Styles parts of an element
Pseudo-class:pseudo:hover { }Targets elements based on their state
Child>nav > ul { }Targets direct children of an element
Descendant(space).container .content { }Targets descendants of a parent element
Adjacent sibling+.header + .footer { }Targets the immediate sibling element
General sibling~.header ~ .footer { }Targets all siblings following an element
Grouping,h1, h2 { }Targets multiple elements at once

1. Element Selector

Targets all elements with a specific tag name.

p {
    font-size: 16px;
}
<p>This is a paragraph.</p>

2. Class Selector

Targets all elements with a specific class. Classes start with a dot (.).

.button {
    background-color: #FFC;
}
<button class="button">Click me!</button>

3. ID Selector

Targets only one element with a specific ID. IDs start with a hash (#).

#header {
    color: red;
}
<h1 id="header">Header</h1>

4. Attribute Selector

Targets elements with specific attributes or attribute values.

/* Exact match */
[type="text"] {
    border: none;
}

/* Attribute value starts with "img" */
[class^="img"] { }

/* Attribute value contains "logo" */
[class*="logo"] { }

/* Attribute value ends with "-btn" */
[class$="-btn"] { }

/* Attribute value is not equal to "hidden" */
[type!="hidden"] { }
<input type="text" placeholder="Enter your text here">

5. Pseudo-element Selector

Styles specific parts of an element.

input::placeholder {
    color: gray;
}
Pseudo-elementDescription
::beforeInserts content before the element
::afterInserts content after the element
::first-lineSelects the first line of a block-level element
::first-letterSelects the first letter of a block-level element
::placeholderSelects the placeholder of an input or textarea
<input type="text" placeholder="Enter some text">

6. Child Selector

Targets only direct children of an element using >.

nav > ul {
    list-style-type: none;
}
<nav>
    <ul>  <!-- Selected -->
        <li><a href="#">Home</a></li>
    </ul>
</nav>

7. Descendant Selector

Targets any descendant of a parent element using a space.

.container .content {
    background-color: #FFC;
}
<div class="container">
    <p class="content">This is some content.</p>
</div>

8. Adjacent Sibling Selector

Targets the sibling element that directly follows another element using +.

.header + .footer {
    text-align: center;
}
<h2 class="header">Header</h2>
<footer class="footer">Footer</footer>

9. General Sibling Selector

Targets all siblings following a specific element using ~.

.header ~ .footer {
    margin-top: 10px;
}
<h2 class="header">Header</h2>
<div class="content"></div>
<footer class="footer">Footer</footer>

10. Pseudo-class Selector

Targets elements based on their state.

a:hover {
    text-decoration: underline;
}
Pseudo-classDescription
:hoverWhen the user hovers over an element
:activeWhen the user clicks on an element
:focusWhen an element has focus
:visitedWhen a link has been visited
<a href="#">Click me!</a>

11. Group Selector

Targets multiple elements at once using a comma.

h1, h2 {
    background-color: red;
}
<h1>Header</h1>
<h2>Header 2</h2>

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS Selectors</title>
    <style>
        /* ====== ELEMENT SELECTOR ====== */
        p {
            font-size: 16px;
            color: #333;
        }

        /* ====== CLASS SELECTOR ====== */
        .button {
            background-color: #ffc107;
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }

        .button:hover {
            background-color: #e0a800;
        }

        /* ====== ID SELECTOR ====== */
        #header {
            color: blue;
            text-align: center;
        }

        /* ====== ATTRIBUTE SELECTOR ====== */
        [type="text"] {
            border: 2px solid #ddd;
            padding: 8px;
            border-radius: 4px;
            width: 200px;
        }

        [type="text"]:focus {
            border-color: #007bff;
            outline: none;
        }

        /* ====== PSEUDO-ELEMENT SELECTOR ====== */
        input::placeholder {
            color: #999;
            font-style: italic;
        }

        /* ====== CHILD SELECTOR ====== */
        nav > ul {
            list-style-type: none;
            padding: 0;
            display: flex;
            gap: 20px;
        }

        nav > ul > li > a {
            text-decoration: none;
            color: #007bff;
        }

        /* ====== DESCENDANT SELECTOR ====== */
        .container .content {
            background-color: #fff3cd;
            padding: 15px;
            border-radius: 4px;
            border: 1px solid #ffc107;
        }

        /* ====== ADJACENT SIBLING SELECTOR ====== */
        .header + .footer {
            text-align: center;
            margin-top: 20px;
            color: #6c757d;
        }

        /* ====== GENERAL SIBLING SELECTOR ====== */
        .header ~ .sibling {
            color: #28a745;
            font-weight: bold;
        }

        /* ====== GROUP SELECTOR ====== */
        h1, h2 {
            font-family: Arial, sans-serif;
        }

        /* ====== COMBINATION EXAMPLE ====== */
        .container p.highlight {
            background-color: #ffc107;
            padding: 5px;
        }

        /* ====== MULTILINE COMMENT ====== */
        /*
            This is a multiline comment.
            It can span multiple lines.
            Useful for documenting complex sections.
        */
    </style>
</head>
<body>

    <!-- ====== ELEMENT SELECTOR ====== -->
    <h1 id="header">Header</h1>
    <p>This is a paragraph.</p>

    <!-- ====== CLASS SELECTOR ====== -->
    <button class="button">Click me!</button>

    <!-- ====== ATTRIBUTE SELECTOR ====== -->
    <input type="text" placeholder="Enter your text here">

    <!-- ====== CHILD SELECTOR ====== -->
    <nav>
        <ul>
            <li><a href="#">Home</a></li>
            <li><a href="#">About</a></li>
            <li><a href="#">Contact</a></li>
        </ul>
    </nav>

    <!-- ====== DESCENDANT SELECTOR ====== -->
    <div class="container">
        <p class="content">This is some content.</p>
    </div>

    <!-- ====== ADJACENT SIBLING SELECTOR ====== -->
    <h2 class="header">Header 2</h2>
    <footer class="footer">Footer</footer>

    <!-- ====== GENERAL SIBLING SELECTOR ====== -->
    <h2 class="header">Another Header</h2>
    <div class="sibling">This is a sibling div.</div>
    <div class="sibling">This is another sibling div.</div>

    <!-- ====== COMBINATION EXAMPLE ====== -->
    <div class="container">
        <p class="highlight">This is highlighted text.</p>
    </div>

</body>
</html>

Quick Reference

SelectorSyntaxExampleDescription
Elementelementp { }All <p> elements
Class.class.button { }Elements with class="button"
ID#id#header { }Element with id="header"
Attribute[ attr="value" ][ type="text" ] { }Elements with type="text"
Childparent > childnav > ul { }Direct children of nav
Descendantparent child.container p { }All <p> inside .container
Adjacent siblingprev + nexth2 + p { }<p> directly after <h2>
General siblingprev ~ nexth2 ~ p { }All <p> after <h2>
Pseudo-class:statea:hover { }Link on hover
Pseudo-element::part::placeholder { }Input placeholder
Groupa, bh1, h2 { }All <h1> and <h2>

Best Practices

Do This:

/* Use meaningful class names */
.button-primary { }

/* Use comments to document sections */
/* ====== HEADER STYLES ====== */

/* Group related selectors */
h1, h2, h3 {
    font-family: 'Arial', sans-serif;
}

/* Use child selectors to avoid over-styling */
nav > ul { }  /* Only direct children */

Don’t Do This:

/* Don't use IDs for reusable styles */
#button1 { }  /* Use .button instead */

/* Don't use overly specific selectors */
body > div > div > p { }  /* Overly specific */

/* Don't use vague class names */
.a { }  /* Not descriptive */

Pro Tip: Use the specificity hierarchy to understand which styles take precedence:

  • ID > Class/Attribute/Pseudo-class > Element/Pseudo-element
  • Inline styles have the highest specificity
  • Use classes for most styling to keep your CSS maintainable and reusable

3. Units in CSS

CSS units are used to specify various properties like width, height, margin, padding, font-size, and more. Choosing the right unit is essential for creating responsive and accessible designs.


Overview of CSS Units

CategoryUnitsDescription
Absolutepx, cm, mm, in, pt, pcFixed size, not responsive
Relative (font)em, rem, ex, ch, lh, rlhRelative to font size or line height
Relative (viewport)vw, vh, vmin, vmaxRelative to the viewport size
Relative (container)%Relative to the parent element
Anglesdeg, rad, grad, turnFor rotations and gradients
GridfrFractional unit for CSS Grid

1. Absolute Units

Absolute units have fixed sizes and do not scale with the viewport or font size.

UnitFull NameEquivalentUse Case
pxPixels1/96th of an inchMost common for screen design
cmCentimeters1cm = 37.8pxPrint styles
mmMillimeters1mm = 3.78pxPrint styles
inInches1in = 96pxPrint styles
ptPoints1pt = 1/72nd of an inchPrint styles, typography
pcPicas1pc = 12ptPrint styles
.box {
    width: 200px;
    padding: 10px;
    border: 2px solid black;
    font-size: 14pt;
}

When to use: When you need fixed, predictable sizing that doesn’t change (e.g., borders, print styles).


2. Relative (Font-Based) Units

These units are relative to font sizes, making them great for typography and accessibility.

UnitDescriptionExample
emRelative to the current element’s font size2em = 2 × current font size
remRelative to the root element’s (<html>) font size2rem = 2 × root font size
exRelative to the x-height of the fontApproximately 0.5 of font size
chWidth of the ‘0’ character in the fontUseful for text width limits
lhRelative to the line height of the element2lh = 2 × line height
rlhRelative to the root line height2rlh = 2 × root line height
html {
    font-size: 16px; /* Base font size: 1rem = 16px */
}

h1 {
    font-size: 2.5em; /* 2.5 × 16px = 40px */
}

p {
    line-height: 1.6; /* 1.6 × font size */
}

.container {
    padding: 1rem; /* 16px */
    max-width: 60ch; /* Approximately 60 characters wide */
}

em vs rem:

  • em is relative to the parent element’s font size — can cause compounding issues
  • rem is relative to the root (<html>) font size — more predictable
/* Example of em compounding */
div {
    font-size: 1.2em; /* 1.2 × parent */
}

/* Example of rem consistency */
div {
    font-size: 1.2rem; /* 1.2 × root (16px = 19.2px) */
}

3. Relative (Viewport) Units

These units are relative to the viewport (browser window) size.

UnitDescriptionExample
vw1% of viewport width50vw = 50% of screen width
vh1% of viewport height50vh = 50% of screen height
vmin1% of the smaller dimensionUseful for mobile
vmax1% of the larger dimensionUseful for desktop
.hero {
    height: 100vh; /* Full viewport height */
    width: 100vw; /* Full viewport width */
}

.text {
    font-size: 5vw; /* Scales with viewport width */
}

.square {
    width: 50vmin; /* 50% of the smaller dimension */
    height: 50vmin;
}

4. Relative (Parent) Unit — Percentage (%)

Percentage is relative to the parent element’s size.

.container {
    width: 80%; /* 80% of parent's width */
    margin: 0 auto; /* Auto margins for centering */
}

.child {
    width: 50%; /* 50% of .container's width */
    padding: 10%; /* 10% of parent's width */
}

5. Angle Units

Used for rotations, gradients, and transformations.

UnitDescriptionExample
degDegrees (360° = full circle)transform: rotate(45deg)
radRadians (2π = full circle)transform: rotate(3.14rad)
gradGradians (400 = full circle)transform: rotate(100grad)
turnTurns (1 = full circle)transform: rotate(0.5turn)
.spinner {
    transform: rotate(360deg);
    transition: transform 2s;
}

.gradient {
    background: linear-gradient(45deg, red, blue);
}

6. Grid Unit — fr

The fr (fraction) unit is used in CSS Grid to distribute available space.

.grid {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
    /* 1:2:1 ratio */
    gap: 10px;
}

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS Units</title>
    <style>
        /* ====== ROOT SETUP ====== */
        html {
            font-size: 16px; /* 1rem = 16px */
            scroll-behavior: smooth;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 0;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        /* ====== SECTION STYLING ====== */
        section {
            background: white;
            padding: 1.5rem;
            margin: 1.5rem 0;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 0.5rem;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 1rem;
        }

        .demo-box {
            background: #e9ecef;
            padding: 1rem;
            border-radius: 4px;
            margin: 0.5rem 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 1rem;
            border-radius: 4px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            margin: 0.5rem 0;
        }

        /* ====== UNIT DEMONSTRATIONS ====== */

        /* ---- Absolute Units ---- */
        .absolute-demo {
            width: 300px;
            height: 100px;
            background: #007bff;
            color: white;
            padding: 10px;
            border: 2px solid #0056b3;
            border-radius: 4px;
        }

        /* ---- Percentage ---- */
        .percent-demo {
            width: 80%;
            max-width: 600px;
            background: #28a745;
            color: white;
            padding: 1rem;
            border-radius: 4px;
        }

        .percent-child {
            width: 50%;
            background: #1e7e34;
            padding: 0.5rem;
            border-radius: 4px;
            text-align: center;
        }

        /* ---- EM & REM ---- */
        .em-demo {
            font-size: 1.2em;
            padding: 1em;
            background: #ffc107;
            border-radius: 4px;
        }

        .em-child {
            font-size: 1.5em;
            padding: 0.5em;
            background: #e0a800;
            border-radius: 4px;
        }

        .rem-demo {
            font-size: 1.2rem;
            padding: 1rem;
            background: #6c5ce7;
            color: white;
            border-radius: 4px;
        }

        .rem-child {
            font-size: 1.5rem;
            padding: 0.5rem;
            background: #4a2a9e;
            border-radius: 4px;
        }

        /* ---- Viewport Units ---- */
        .viewport-demo {
            height: 30vh;
            width: 50vw;
            min-height: 100px;
            min-width: 200px;
            background: linear-gradient(135deg, #dc3545, #c92a2a);
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ---- ch Unit ---- */
        .ch-demo {
            max-width: 60ch;
            background: #17a2b8;
            color: white;
            padding: 1rem;
            border-radius: 4px;
            margin: 0.5rem 0;
        }

        /* ---- Angle Units ---- */
        .angle-demo {
            width: 100px;
            height: 100px;
            background: #ffc107;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            border-radius: 4px;
            margin: 0.5rem;
            transition: transform 0.5s;
        }

        .angle-demo:hover {
            transform: rotate(45deg);
        }

        /* ---- Grid with fr ---- */
        .grid-demo {
            display: grid;
            grid-template-columns: 1fr 2fr 1fr;
            gap: 10px;
            background: #e9ecef;
            padding: 1rem;
            border-radius: 4px;
        }

        .grid-demo > div {
            background: #007bff;
            color: white;
            padding: 1rem;
            text-align: center;
            border-radius: 4px;
        }

        .grid-demo > div:nth-child(2) {
            background: #28a745;
        }

        .grid-demo > div:nth-child(3) {
            background: #dc3545;
        }

        /* ---- Combined Responsive Example ---- */
        .responsive-box {
            width: 80%;
            max-width: 600px;
            margin: 1rem auto;
            padding: 1.5rem;
            background: #f8f9fa;
            border: 2px solid #007bff;
            border-radius: 8px;
            text-align: center;
        }

        .responsive-box h3 {
            font-size: clamp(1.2rem, 4vw, 2.5rem);
            margin: 0 0 0.5rem 0;
        }

        .responsive-box p {
            font-size: 1rem;
            line-height: 1.6;
        }

        .responsive-box img {
            width: 100%;
            max-width: 400px;
            height: auto;
            border-radius: 4px;
        }
    </style>
</head>
<body>

    <h1>CSS Units</h1>

    <!-- ====== 1. ABSOLUTE UNITS ====== -->
    <section>
        <h2>1. Absolute Units (px)</h2>
        <div class="absolute-demo">
            <strong>Width: 300px</strong><br>
            Height: 100px<br>
            Border: 2px
        </div>
        <p><small>Fixed size — does not scale with font size or viewport.</small></p>
    </section>

    <!-- ====== 2. PERCENTAGE ====== -->
    <section>
        <h2>2. Percentage (%)</h2>
        <div class="percent-demo">
            <strong>Parent: width: 80% of container</strong>
            <div class="percent-child">
                Child: width: 50% of parent
            </div>
        </div>
        <p><small>Relative to the parent element's size.</small></p>
    </section>

    <!-- ====== 3. EM ====== -->
    <section>
        <h2>3. em — Relative to Current Font Size</h2>
        <div class="em-demo" style="font-size: 16px;">
            <strong>Parent font-size: 16px</strong> (1.2em = 19.2px)
            <div class="em-child">
                <strong>Child font-size: 1.5em</strong> (1.5 × 19.2px = 28.8px)
            </div>
            <p style="font-size: 0.8em; padding: 0.5em; background: #d39e00; border-radius: 4px;">
                This text uses 0.8em (relative to parent)
            </p>
        </div>
        <p><small>⚠️ <code>em</code> compounds — each nested level multiplies the font size.</small></p>
    </section>

    <!-- ====== 4. REM ====== -->
    <section>
        <h2>4. rem — Relative to Root Font Size</h2>
        <div class="rem-demo" style="font-size: 16px;">
            <strong>Root font-size: 16px</strong> (1.2rem = 19.2px)
            <div class="rem-child">
                <strong>Child font-size: 1.5rem</strong> (1.5 × 16px = 24px)
            </div>
            <p style="font-size: 0.8rem; padding: 0.5rem; background: #3a1a7e; border-radius: 4px;">
                This text uses 0.8rem (always relative to root)
            </p>
        </div>
        <p><small>✅ <code>rem</code> is consistent — always relative to the root font size.</small></p>
    </section>

    <!-- ====== 5. VIEWPORT UNITS ====== -->
    <section>
        <h2>5. Viewport Units (vw, vh)</h2>
        <div class="viewport-demo">
            <div>
                <strong>30vh × 50vw</strong><br>
                (min 100px × 200px)
            </div>
        </div>
        <p><small>Relative to the viewport (browser window) size.</small></p>
    </section>

    <!-- ====== 6. ch UNIT ====== -->
    <section>
        <h2>6. ch — Character Width</h2>
        <div class="ch-demo">
            <strong>max-width: 60ch</strong>
            <p style="margin-top: 0.5rem;">
                This text is limited to approximately 60 characters per line,
                which improves readability. Lorem ipsum dolor sit amet,
                consectetur adipiscing elit.
            </p>
        </div>
        <p><small>1<code>ch</code> ≈ the width of the '0' character.</small></p>
    </section>

    <!-- ====== 7. ANGLE UNITS ====== -->
    <section>
        <h2>7. Angle Units (deg, turn, rad, grad)</h2>
        <div style="display: flex; flex-wrap: wrap; gap: 10px;">
            <div class="angle-demo" style="transform: rotate(0deg);">
                0deg
            </div>
            <div class="angle-demo" style="transform: rotate(45deg);">
                45deg
            </div>
            <div class="angle-demo" style="transform: rotate(90deg);">
                90deg
            </div>
            <div class="angle-demo" style="transform: rotate(0.25turn);">
                0.25turn
            </div>
            <div class="angle-demo" style="transform: rotate(0.5turn);">
                0.5turn
            </div>
        </div>
        <p><small>Hover over any box to rotate it 45 degrees.</small></p>
    </section>

    <!-- ====== 8. GRID — fr ====== -->
    <section>
        <h2>8. Grid: fr (Fractional Unit)</h2>
        <div class="grid-demo">
            <div>1fr</div>
            <div>2fr</div>
            <div>1fr</div>
        </div>
        <p><small>Columns are in ratio <strong>1:2:1</strong> using <code>fr</code> units.</small></p>
    </section>

    <!-- ====== 9. RESPONSIVE EXAMPLE ====== -->
    <section>
        <h2>9. Responsive Example</h2>
        <div class="responsive-box">
            <h3>Responsive Typography</h3>
            <p>
                This heading uses <code>clamp()</code> for responsive font sizing.
                The image scales to fit the container using <code>max-width: 100%</code>.
            </p>
            <img src="https://via.placeholder.com/600x200/007bff/ffffff?text=Responsive+Image" alt="Example Image">
            <p style="font-size: 0.9rem; color: #6c757d; margin-top: 0.5rem;">
                Image uses <code>width: 100%; max-width: 400px;</code>
            </p>
        </div>
    </section>

    <!-- ====== REFERENCE TABLE ====== -->
    <section>
        <h2>10. Units Reference</h2>

        <h3>Absolute Units</h3>
        <table style="width: 100%; border-collapse: collapse; margin: 10px 0;">
            <tr style="background: #007bff; color: white;">
                <th style="padding: 8px; border: 1px solid #ddd;">Unit</th>
                <th style="padding: 8px; border: 1px solid #ddd;">Description</th>
            </tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>px</code></td><td style="padding: 8px; border: 1px solid #ddd;">1/96th of an inch</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>cm</code></td><td style="padding: 8px; border: 1px solid #ddd;">Centimeters (1cm = 37.8px)</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>mm</code></td><td style="padding: 8px; border: 1px solid #ddd;">Millimeters (1mm = 3.78px)</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>in</code></td><td style="padding: 8px; border: 1px solid #ddd;">Inches (1in = 96px)</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>pt</code></td><td style="padding: 8px; border: 1px solid #ddd;">Points (1pt = 1/72in)</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>pc</code></td><td style="padding: 8px; border: 1px solid #ddd;">Picas (1pc = 12pt)</td></tr>
        </table>

        <h3>Relative Units</h3>
        <table style="width: 100%; border-collapse: collapse; margin: 10px 0;">
            <tr style="background: #28a745; color: white;">
                <th style="padding: 8px; border: 1px solid #ddd;">Unit</th>
                <th style="padding: 8px; border: 1px solid #ddd;">Relative To</th>
            </tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>%</code></td><td style="padding: 8px; border: 1px solid #ddd;">Parent element</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>em</code></td><td style="padding: 8px; border: 1px solid #ddd;">Current element's font size</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>rem</code></td><td style="padding: 8px; border: 1px solid #ddd;">Root element's font size</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>vw</code></td><td style="padding: 8px; border: 1px solid #ddd;">Viewport width (1% = 1% of viewport width)</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>vh</code></td><td style="padding: 8px; border: 1px solid #ddd;">Viewport height (1% = 1% of viewport height)</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>vmin</code></td><td style="padding: 8px; border: 1px solid #ddd;">Smaller of vw and vh</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>vmax</code></td><td style="padding: 8px; border: 1px solid #ddd;">Larger of vw and vh</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>ch</code></td><td style="padding: 8px; border: 1px solid #ddd;">Width of the '0' character</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>ex</code></td><td style="padding: 8px; border: 1px solid #ddd;">x-height of the font</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>fr</code></td><td style="padding: 8px; border: 1px solid #ddd;">Available space in CSS Grid</td></tr>
        </table>

        <h3>Angle Units</h3>
        <table style="width: 100%; border-collapse: collapse; margin: 10px 0;">
            <tr style="background: #dc3545; color: white;">
                <th style="padding: 8px; border: 1px solid #ddd;">Unit</th>
                <th style="padding: 8px; border: 1px solid #ddd;">Description</th>
            </tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>deg</code></td><td style="padding: 8px; border: 1px solid #ddd;">Degrees (360 = full circle)</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>rad</code></td><td style="padding: 8px; border: 1px solid #ddd;">Radians (2π = full circle)</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>grad</code></td><td style="padding: 8px; border: 1px solid #ddd;">Gradians (400 = full circle)</td></tr>
            <tr><td style="padding: 8px; border: 1px solid #ddd;"><code>turn</code></td><td style="padding: 8px; border: 1px solid #ddd;">Turns (1 = full circle)</td></tr>
        </table>
    </section>

</body>
</html>

Quick Reference

CategoryUnitsDescription
Absolutepx, cm, mm, in, pt, pcFixed size, not responsive
Relative (font)em, rem, ex, ch, lh, rlhRelative to font or line height
Relative (viewport)vw, vh, vmin, vmaxRelative to viewport size
Relative (parent)%Relative to parent element
Angledeg, rad, grad, turnFor rotations and gradients
GridfrFractional unit for CSS Grid

Best Practices

Do This:

/* Use rem for typography */
html { font-size: 16px; }
h1 { font-size: 2rem; }  /* 32px */
p { font-size: 1rem; }   /* 16px */

/* Use em for component-based spacing */
.card {
    padding: 1.5em;  /* Relative to card's font size */
}

/* Use vw/vh for full-screen sections */
.hero {
    height: 100vh;
    min-height: 500px;
}

/* Use ch for readable text */
.article {
    max-width: 65ch;  /* Optimal reading width */
}

/* Use % for fluid layouts */
.container {
    width: 90%;
    max-width: 1200px;
}

Don’t Do This:

/* Don't use px for font sizes */
p { font-size: 16px; }  /* Doesn't scale with user preferences */

/* Don't use vw for body text */
body { font-size: 2vw; }  /* Too small on mobile, too large on desktop */

/* Don't overuse em for nesting */
ul { font-size: 0.9em; }  /* Can cause compounding issues */
ul ul { font-size: 0.9em; }  /* Even smaller */

Pro Tip: A common best practice is to use rem for typography (font sizes, spacing), % for layout (widths, heights), em for component-based spacing, and vw/vh for full-screen or viewport-dependent elements. Use ch for readable text widths (approximately 60–70 characters per line is optimal for readability).

4. Colors and Color Properties

CSS provides multiple ways to specify colors, allowing you to style text, backgrounds, borders, and more. Understanding color formats and properties is essential for creating visually appealing web pages.


Color Formats

FormatExampleDescription
Named Colorsred, blue, yellowPredefined color names
Hexadecimal#FF0000, #F006-digit or 3-digit hex values
RGBrgb(255, 0, 0)Red, Green, Blue (0–255)
RGBArgba(255, 0, 0, 0.5)RGB with opacity (0–1)
HSLhsl(0, 100%, 50%)Hue, Saturation, Lightness
HSLAhsla(0, 100%, 50%, 0.5)HSL with opacity

1. Named Colors

CSS supports over 140 predefined color names.

p {
    color: red;
}

.container {
    background-color: lightblue;
}

.warning {
    color: orange;
    background-color: black;
}

Common Named Colors:
red, blue, green, yellow, orange, purple, pink, brown, black, white, gray, cyan, magenta, lime, navy, olive, teal, violet, gold, silver


2. Hexadecimal Colors

Hex values use a # followed by 6 characters (0–9, A–F) or 3 characters (shorthand).

/* Full hex (6 digits) */
.container {
    background-color: #123456;
}

/* Shorthand hex (3 digits) */
.box {
    background-color: #F00; /* Same as #FF0000 (red) */
}

/* RGB */
body {
    background-color: rgb(255, 0, 0); /* Red */
}

/* RGBA (with opacity) */
div {
    background-color: rgba(255, 0, 0, 0.5); /* 50% opacity */
}
ShorthandFullColor
#F00#FF0000Red
#0F0#00FF00Green
#00F#0000FFBlue
#FFF#FFFFFFWhite
#000#000000Black

3. RGB and RGBA

RGB uses values from 0 to 255 for each color channel. RGBA adds an alpha channel for opacity.

div {
    background-color: rgb(255, 0, 0); /* Red */
    color: rgb(0, 255, 0); /* Green text */
    border-color: rgb(0, 0, 255); /* Blue border */
}

.transparent {
    background-color: rgba(255, 0, 0, 0.5); /* 50% transparent red */
}

4. HSL and HSLA

HSL stands for Hue, Saturation, and Lightness.

  • Hue: 0–360 (color wheel)
  • Saturation: 0–100% (0% = gray, 100% = vibrant)
  • Lightness: 0–100% (0% = black, 100% = white)
.hsl-blue {
    background-color: hsl(240, 100%, 50%); /* Blue */
}

.hsl-pastel {
    background-color: hsl(0, 50%, 80%); /* Soft red */
}

.hsla-transparent {
    background-color: hsla(22, 55%, 64%, 0.7); /* With opacity */
}

Color Properties

PropertyDescriptionExample
colorSets text colorcolor: #333;
background-colorSets background colorbackground-color: rgba(255, 0, 0, 0.5);
border-colorSets border colorborder-color: hsl(0, 100%, 75%);
text-shadowAdds shadow to texttext-shadow: 2px 2px 4px rgba(0,0,0,0.5);
box-shadowAdds shadow to elementbox-shadow: 2px 2px 4px rgba(0,0,0,0.3);
opacityElement opacity (0–1)opacity: 0.7;
caret-colorSets input cursor colorcaret-color: red;

Color Formats Comparison

FormatExampleUse Case
NamedredQuick prototyping
Hex#FF0000Most common, compact
RGBrgb(255, 0, 0)Easy to adjust values
RGBArgba(255, 0, 0, 0.5)Transparent colors
HSLhsl(0, 100%, 50%)Easy to adjust hue/saturation
HSLAhsla(0, 100%, 50%, 0.5)Transparent HSL

CSS Gradients

Gradients allow you to create smooth transitions between colors.

/* Linear Gradient (left to right) */
.linear {
    background-image: linear-gradient(to right, red, blue);
}

/* Linear Gradient (top to bottom) */
.linear-vertical {
    background-image: linear-gradient(to bottom, red, blue);
}

/* Linear Gradient (diagonal) */
.linear-diagonal {
    background-image: linear-gradient(45deg, red, blue);
}

/* Linear Gradient (multiple colors) */
.linear-multi {
    background-image: linear-gradient(to right, red, orange, yellow, green, blue, purple);
}

/* Radial Gradient (circle) */
.radial {
    background-image: radial-gradient(circle, red, blue);
}

/* Radial Gradient (ellipse) */
.radial-ellipse {
    background-image: radial-gradient(ellipse, red, blue);
}

/* Conic Gradient */
.conic {
    background-image: conic-gradient(from red, blue);
}

/* Repeating Linear Gradient */
.repeating-linear {
    background-image: repeating-linear-gradient(45deg, red 10%, blue 20%);
}

/* Repeating Radial Gradient */
.repeating-radial {
    background-image: repeating-radial-gradient(circle, red 10%, blue 20%);
}

CSS Filters

Filters apply graphical effects to elements.

.filter-demo {
    /* Hue rotation */
    filter: hue-rotate(180deg);

    /* Brightness */
    filter: brightness(50%);

    /* Contrast */
    filter: contrast(200%);

    /* Grayscale (0-100%) */
    filter: grayscale(100%);

    /* Saturation (0-100%) */
    filter: saturate(200%);

    /* Invert (0-100%) */
    filter: invert(100%);

    /* Sepia (0-100%) */
    filter: sepia(70%);

    /* Multiple filters */
    filter: brightness(150%) contrast(120%) saturate(150%);
}

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Colors and Color Properties</title>
    <style>
        /* ====== GLOBAL SETUP ====== */
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .demo-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            text-align: center;
        }

        .grid-3 {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
        }

        .grid-3 .demo-box {
            min-height: 100px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== COLOR PROPERTY DEMOS ====== */

        /* ---- Named Colors ---- */
        .named-demo {
            background-color: lightblue;
            color: navy;
            border: 2px solid blue;
        }

        /* ---- Hex Colors ---- */
        .hex-demo {
            background-color: #123456;
            color: #FFFFFF;
            border: 2px solid #FFD700;
        }

        /* ---- RGB Colors ---- */
        .rgb-demo {
            background-color: rgb(255, 0, 0);
            color: rgb(255, 255, 255);
            border: 2px solid rgb(0, 255, 0);
        }

        /* ---- RGBA Colors ---- */
        .rgba-demo {
            background-color: rgba(255, 0, 0, 0.5);
            color: #333;
            border: 2px solid rgba(0, 0, 255, 0.5);
        }

        /* ---- HSL Colors ---- */
        .hsl-demo {
            background-color: hsl(240, 100%, 50%);
            color: hsl(0, 0%, 100%);
            border: 2px solid hsl(0, 100%, 75%);
        }

        /* ---- HSLA Colors ---- */
        .hsla-demo {
            background-color: hsla(22, 55%, 64%, 0.7);
            color: #333;
            border: 2px solid hsla(22, 55%, 64%, 0.3);
        }

        /* ---- Text Shadow ---- */
        .text-shadow-demo {
            font-size: 2rem;
            font-weight: bold;
            color: #007bff;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
        }

        /* ---- Box Shadow ---- */
        .box-shadow-demo {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
        }

        /* ---- Opacity ---- */
        .opacity-demo {
            background: #007bff;
            color: white;
            padding: 15px;
            opacity: 0.7;
        }

        /* ---- Caret Color ---- */
        .caret-demo {
            caret-color: red;
            padding: 10px;
            border: 2px solid #ddd;
            border-radius: 4px;
            width: 100%;
            max-width: 300px;
            font-size: 1rem;
        }

        .caret-demo:focus {
            border-color: red;
            outline: none;
        }

        /* ====== GRADIENT DEMOS ====== */

        .gradient-linear {
            background-image: linear-gradient(to right, red, blue);
        }

        .gradient-linear-multi {
            background-image: linear-gradient(to right, red, orange, yellow, green, blue, purple);
        }

        .gradient-radial {
            background-image: radial-gradient(circle, red, blue);
        }

        .gradient-conic {
            background-image: conic-gradient(red, blue, green, red);
        }

        .gradient-repeating {
            background-image: repeating-linear-gradient(45deg, red 10%, blue 20%);
        }

        /* ====== FILTER DEMOS ====== */

        .filter-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 15px;
            margin: 15px 0;
        }

        .filter-grid .demo-box {
            min-height: 100px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            background: #007bff;
            color: white;
            border: none;
        }

        .filter-hue {
            filter: hue-rotate(180deg);
        }

        .filter-brightness {
            filter: brightness(50%);
        }

        .filter-contrast {
            filter: contrast(200%);
        }

        .filter-grayscale {
            filter: grayscale(100%);
        }

        .filter-saturate {
            filter: saturate(200%);
        }

        .filter-invert {
            filter: invert(100%);
        }

        .filter-sepia {
            filter: sepia(70%);
        }

        .filter-multiple {
            filter: brightness(150%) contrast(120%) saturate(150%);
        }

        /* ---- Mix Blend Mode ---- */
        .blend-container {
            background-image: linear-gradient(to right, #ff6b6b, #4ecdc4);
            padding: 20px;
            border-radius: 8px;
            margin: 10px 0;
        }

        .blend-demo {
            color: white;
            font-size: 2rem;
            font-weight: bold;
            text-align: center;
            mix-blend-mode: multiply;
        }
    </style>
</head>
<body>

    <h1>Colors and Color Properties</h1>

    <!-- ====== COLOR FORMATS ====== -->
    <section>
        <h2>1. Color Formats</h2>

        <h3>Named Colors</h3>
        <div class="demo-box named-demo">Named Color: lightblue / navy</div>

        <h3>Hexadecimal Colors</h3>
        <div class="demo-box hex-demo">Hex: #123456 / #FFFFFF / #FFD700</div>

        <h3>RGB Colors</h3>
        <div class="demo-box rgb-demo">RGB: rgb(255, 0, 0) / rgb(0, 255, 0)</div>

        <h3>RGBA Colors (with opacity)</h3>
        <div class="demo-box rgba-demo">RGBA: rgba(255, 0, 0, 0.5)</div>

        <h3>HSL Colors</h3>
        <div class="demo-box hsl-demo">HSL: hsl(240, 100%, 50%)</div>

        <h3>HSLA Colors (with opacity)</h3>
        <div class="demo-box hsla-demo">HSLA: hsla(22, 55%, 64%, 0.7)</div>

        <div class="code-block">
            /* Named Colors */
            background-color: lightblue;
            color: navy;

            /* Hexadecimal */
            background-color: #123456;
            color: #FFFFFF;

            /* RGB */
            background-color: rgb(255, 0, 0);
            color: rgb(255, 255, 255);

            /* RGBA */
            background-color: rgba(255, 0, 0, 0.5);

            /* HSL */
            background-color: hsl(240, 100%, 50%);

            /* HSLA */
            background-color: hsla(22, 55%, 64%, 0.7);
        </div>
    </section>

    <!-- ====== COLOR PROPERTIES ====== -->
    <section>
        <h2>2. Color Properties</h2>

        <div class="grid-3">
            <div class="demo-box" style="background: #007bff; color: white;">
                <code>color</code><br>Sets text color
            </div>
            <div class="demo-box" style="background: #28a745; color: white;">
                <code>background-color</code><br>Sets background color
            </div>
            <div class="demo-box" style="background: white; border: 3px solid #dc3545;">
                <code>border-color</code><br>Sets border color
            </div>
        </div>

        <h3>Text Shadow</h3>
        <div class="demo-box text-shadow-demo">Text Shadow</div>

        <h3>Box Shadow</h3>
        <div class="demo-box box-shadow-demo">Box Shadow</div>

        <h3>Opacity</h3>
        <div class="demo-box opacity-demo">Opacity: 0.7</div>

        <h3>Caret Color</h3>
        <input type="text" class="caret-demo" placeholder="Caret is red">

        <div class="code-block">
            /* Text Properties */
            color: #333;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);

            /* Background Properties */
            background-color: rgba(255, 0, 0, 0.5);

            /* Border Properties */
            border-color: hsl(0, 100%, 75%);

            /* Box Shadow */
            box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);

            /* Opacity */
            opacity: 0.7;

            /* Caret Color */
            caret-color: red;
        </div>
    </section>

    <!-- ====== GRADIENTS ====== -->
    <section>
        <h2>3. Gradients</h2>

        <div class="grid-3">
            <div class="demo-box gradient-linear">Linear Gradient</div>
            <div class="demo-box gradient-linear-multi">Multi-color Linear</div>
            <div class="demo-box gradient-radial">Radial Gradient</div>
            <div class="demo-box gradient-conic">Conic Gradient</div>
            <div class="demo-box gradient-repeating">Repeating Linear</div>
        </div>

        <div class="code-block">
            /* Linear Gradient (left to right) */
            background-image: linear-gradient(to right, red, blue);

            /* Linear Gradient (multiple colors) */
            background-image: linear-gradient(to right, red, orange, yellow, green, blue, purple);

            /* Radial Gradient (circle) */
            background-image: radial-gradient(circle, red, blue);

            /* Conic Gradient */
            background-image: conic-gradient(red, blue, green, red);

            /* Repeating Linear Gradient */
            background-image: repeating-linear-gradient(45deg, red 10%, blue 20%);
        </div>
    </section>

    <!-- ====== FILTERS ====== -->
    <section>
        <h2>4. Filters</h2>

        <div class="filter-grid">
            <div class="demo-box filter-hue">hue-rotate(180deg)</div>
            <div class="demo-box filter-brightness">brightness(50%)</div>
            <div class="demo-box filter-contrast">contrast(200%)</div>
            <div class="demo-box filter-grayscale">grayscale(100%)</div>
            <div class="demo-box filter-saturate">saturate(200%)</div>
            <div class="demo-box filter-invert">invert(100%)</div>
            <div class="demo-box filter-sepia">sepia(70%)</div>
            <div class="demo-box filter-multiple">Multiple Filters</div>
        </div>

        <div class="code-block">
            /* Individual Filters */
            filter: hue-rotate(180deg);
            filter: brightness(50%);
            filter: contrast(200%);
            filter: grayscale(100%);
            filter: saturate(200%);
            filter: invert(100%);
            filter: sepia(70%);

            /* Multiple Filters */
            filter: brightness(150%) contrast(120%) saturate(150%);
        </div>
    </section>

    <!-- ====== REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>Color Formats</h3>
        <table class="reference-table">
            <tr>
                <th>Format</th>
                <th>Example</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>Named</code></td>
                <td><code>red</code></td>
                <td>Predefined color names</td>
            </tr>
            <tr>
                <td><code>Hex</code></td>
                <td><code>#FF0000</code></td>
                <td>6-digit or 3-digit hex values</td>
            </tr>
            <tr>
                <td><code>RGB</code></td>
                <td><code>rgb(255, 0, 0)</code></td>
                <td>Red, Green, Blue (0–255)</td>
            </tr>
            <tr>
                <td><code>RGBA</code></td>
                <td><code>rgba(255, 0, 0, 0.5)</code></td>
                <td>RGB with opacity (0–1)</td>
            </tr>
            <tr>
                <td><code>HSL</code></td>
                <td><code>hsl(0, 100%, 50%)</code></td>
                <td>Hue, Saturation, Lightness</td>
            </tr>
            <tr>
                <td><code>HSLA</code></td>
                <td><code>hsla(0, 100%, 50%, 0.5)</code></td>
                <td>HSL with opacity</td>
            </tr>
        </table>

        <h3>Color Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>color</code></td>
                <td>Sets text color</td>
                <td><code>color: #333;</code></td>
            </tr>
            <tr>
                <td><code>background-color</code></td>
                <td>Sets background color</td>
                <td><code>background-color: rgba(255, 0, 0, 0.5);</code></td>
            </tr>
            <tr>
                <td><code>border-color</code></td>
                <td>Sets border color</td>
                <td><code>border-color: hsl(0, 100%, 75%);</code></td>
            </tr>
            <tr>
                <td><code>text-shadow</code></td>
                <td>Adds shadow to text</td>
                <td><code>text-shadow: 2px 2px 4px rgba(0,0,0,0.5);</code></td>
            </tr>
            <tr>
                <td><code>box-shadow</code></td>
                <td>Adds shadow to element</td>
                <td><code>box-shadow: 2px 2px 4px rgba(0,0,0,0.3);</code></td>
            </tr>
            <tr>
                <td><code>opacity</code></td>
                <td>Element opacity (0–1)</td>
                <td><code>opacity: 0.7;</code></td>
            </tr>
            <tr>
                <td><code>caret-color</code></td>
                <td>Sets input cursor color</td>
                <td><code>caret-color: red;</code></td>
            </tr>
        </table>

        <h3>Filters</h3>
        <table class="reference-table">
            <tr>
                <th>Filter</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>hue-rotate</code></td>
                <td>Rotates the color wheel</td>
                <td><code>hue-rotate(180deg)</code></td>
            </tr>
            <tr>
                <td><code>brightness</code></td>
                <td>Changes brightness</td>
                <td><code>brightness(50%)</code></td>
            </tr>
            <tr>
                <td><code>contrast</code></td>
                <td>Changes contrast</td>
                <td><code>contrast(200%)</code></td>
            </tr>
            <tr>
                <td><code>grayscale</code></td>
                <td>Converts to grayscale</td>
                <td><code>grayscale(100%)</code></td>
            </tr>
            <tr>
                <td><code>saturate</code></td>
                <td>Changes saturation</td>
                <td><code>saturate(200%)</code></td>
            </tr>
            <tr>
                <td><code>invert</code></td>
                <td>Inverts colors</td>
                <td><code>invert(100%)</code></td>
            </tr>
            <tr>
                <td><code>sepia</code></td>
                <td>Converts to sepia</td>
                <td><code>sepia(70%)</code></td>
            </tr>
        </table>
    </section>

</body>
</html>

Quick Reference

FormatExampleUse Case
NamedredQuick prototyping
Hex#FF0000Most common, compact
RGBrgb(255, 0, 0)Easy to adjust values
RGBArgba(255, 0, 0, 0.5)Transparent colors
HSLhsl(0, 100%, 50%)Easy to adjust hue/saturation
HSLAhsla(0, 100%, 50%, 0.5)Transparent HSL

Best Practices

Do This:

/* Use rgba/hsla for transparency */
background-color: rgba(255, 0, 0, 0.5);

/* Use hex for solid colors (compact) */
color: #007bff;

/* Use hsl for color variations */
background: hsl(200, 80%, 50%);
border-color: hsl(200, 80%, 40%);

/* Use text-shadow for readability on images */
text-shadow: 0 0 10px rgba(0, 0, 0, 0.7);

/* Use opacity for hover effects */
.button:hover { opacity: 0.8; }

Don’t Do This:

/* Don't use too many color formats inconsistently */
h1 { color: red; }
h2 { color: #00F; }
h3 { color: rgb(0, 255, 0); }
/* Use one format consistently */

/* Don't use too low contrast */
color: #999;
background: #fff; /* Hard to read */

/* Don't overuse opacity on text */
opacity: 0.5; /* Might be hard to read */

Pro Tip: Use HSL when you need to create color variations (e.g., hover states). HSLA is great for transparent overlays. For solid colors, hex is the most common and compact. For transparency, use rgba or hsla. Always consider contrast and accessibility when choosing colors!

5. Background-Related Properties

CSS provides a rich set of properties to control the background of any element. You can set colors, images, gradients, and control how they are positioned, repeated, scaled, and clipped.


Overview of Background Properties

PropertyDescriptionExample
background-colorSets the background colorbackground-color: red;
background-imageSets the background image or gradientbackground-image: url("image.jpg");
background-repeatControls how the image repeatsbackground-repeat: no-repeat;
background-positionSets the position of the imagebackground-position: center top;
background-attachmentControls scrolling behaviorbackground-attachment: fixed;
background-clipDefines the clipping areabackground-clip: padding-box;
background-originSets the positioning originbackground-origin: border-box;
background-sizeControls the scaling of the imagebackground-size: cover;

1. background-color

Sets the color behind the content of the element.

/* Named colors */
.red-background {
    background-color: red;
}

/* Hexadecimal */
.hex-background {
    background-color: #123456;
}

/* RGB/RGBA */
.rgb-background {
    background-color: rgb(255, 0, 0);
}

.rgba-background {
    background-color: rgba(255, 0, 0, 0.5);
}

/* HSL/HSLA */
.hsl-background {
    background-color: hsl(0, 100%, 50%);
}

.hsla-background {
    background-color: hsla(0, 100%, 50%, 0.5);
}

2. background-image

Sets the background to an image or a gradient.

/* Image */
.image-background {
    background-image: url("path/to/image.jpg");
}

/* Linear Gradient */
.gradient-background {
    background-image: linear-gradient(to right, red, orange);
}

/* Radial Gradient */
.radial-background {
    background-image: radial-gradient(circle, red, blue);
}

/* Multiple backgrounds */
.multiple-background {
    background-image: 
        url("top-image.png"),
        url("bottom-image.png");
}

3. background-repeat

Controls how the background image repeats.

ValueDescriptionExample
repeatRepeats both horizontally and vertically (default)background-repeat: repeat;
no-repeatDoes not repeatbackground-repeat: no-repeat;
repeat-xRepeats only horizontallybackground-repeat: repeat-x;
repeat-yRepeats only verticallybackground-repeat: repeat-y;
spaceRepeats with space between imagesbackground-repeat: space;
roundRepeats and stretches to fitbackground-repeat: round;
.repeated-background {
    background-image: url("path/to/image.jpg");
    background-repeat: repeat;
}

.no-repeat-background {
    background-image: url("path/to/image.jpg");
    background-repeat: no-repeat;
}

.repeat-x-background {
    background-image: url("path/to/image.jpg");
    background-repeat: repeat-x;
}

.repeat-y-background {
    background-image: url("path/to/image.jpg");
    background-repeat: repeat-y;
}

4. background-position

Sets the position of the background image relative to its container.

ValuesDescriptionExample
left, center, rightHorizontal positionbackground-position: center;
top, center, bottomVertical positionbackground-position: top;
x% y%Percentage valuesbackground-position: 50% 50%;
xpx ypxPixel valuesbackground-position: 100px 50px;
.positioned-background {
    background-image: url("path/to/image.jpg");
    background-repeat: no-repeat;
    background-position: center top;
}

/* Center the background */
.centered-background {
    background-position: center center;
}

/* Offset from the top-left */
.offset-background {
    background-position: 20px 30px;
}

/* Using percentages */
.percent-background {
    background-position: 75% 25%;
}

5. background-attachment

Controls whether the background image scrolls with the content.

ValueDescriptionExample
scrollScrolls with the page (default)background-attachment: scroll;
fixedFixed to the viewportbackground-attachment: fixed;
localScrolls with the element’s contentbackground-attachment: local;
/* Fixed background (parallax effect) */
.fixed-background {
    background-image: url("path/to/image.jpg");
    background-repeat: no-repeat;
    background-attachment: fixed;
}

/* Scrolls with the element */
.scroll-background {
    background-attachment: scroll;
}

/* Local scrolling */
.local-background {
    background-attachment: local;
}

6. background-clip

Defines the area where the background is visible.

ValueDescriptionExample
border-boxExtends to the outer edge of the border (default)background-clip: border-box;
padding-boxExtends to the inside of the borderbackground-clip: padding-box;
content-boxExtends only to the content areabackground-clip: content-box;
textClips to the text (experimental)background-clip: text;
.clipped-background {
    background-image: url("path/to/image.jpg");
    background-repeat: no-repeat;
    background-clip: padding-box;
}

/* Clip to text (needs text color transparent) */
.text-clip {
    background-image: linear-gradient(to right, red, blue);
    background-clip: text;
    color: transparent;
}

7. background-origin

Sets the origin point for positioning the background image.

ValueDescriptionExample
border-boxOrigin at the upper-left corner of the borderbackground-origin: border-box;
padding-boxOrigin at the upper-left corner of the padding (default)background-origin: padding-box;
content-boxOrigin at the upper-left corner of the contentbackground-origin: content-box;
.origin-background {
    background-image: url("path/to/image.jpg");
    background-repeat: no-repeat;
    background-origin: border-box;
}

8. background-size

Controls the scaling of the background image.

ValueDescriptionExample
autoOriginal size (default)background-size: auto;
coverFills the entire container (may crop)background-size: cover;
containFits the entire image in the containerbackground-size: contain;
x% y%Percentage of the containerbackground-size: 100% 50%;
xpx ypxPixel valuesbackground-size: 300px 200px;
/* Cover the entire element */
.scaled-background {
    background-image: url("path/to/image.jpg");
    background-repeat: no-repeat;
    background-size: cover;
}

/* Contain the entire image */
.contain-background {
    background-size: contain;
}

/* Specific dimensions */
.specific-size {
    background-size: 300px 200px;
}

/* Percentage of container */
.percent-size {
    background-size: 100% 50%;
}

The Shorthand background Property

You can combine multiple background properties into a single background shorthand.

/* Shorthand: image, position, size, repeat, attachment, color */
.background-shorthand {
    background: 
        url("image.jpg") 
        center center / cover 
        no-repeat 
        fixed 
        #f8f9fa;
}

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Background Properties</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .demo-box {
            height: 150px;
            border-radius: 8px;
            margin: 10px 0;
            padding: 15px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            color: white;
            border: 5px solid #333;
        }

        .demo-box.light-text {
            color: #333;
        }

        .grid-2 {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== BACKGROUND DEMOS ====== */

        /* ---- background-color ---- */
        .bg-color-demo {
            background-color: #007bff;
        }

        .bg-color-rgba {
            background-color: rgba(255, 0, 0, 0.5);
            color: #333;
        }

        /* ---- background-image (gradients) ---- */
        .bg-gradient-linear {
            background-image: linear-gradient(to right, #007bff, #6c5ce7);
        }

        .bg-gradient-radial {
            background-image: radial-gradient(circle, #28a745, #1e7e34);
        }

        .bg-gradient-conic {
            background-image: conic-gradient(#ffc107, #dc3545, #007bff);
        }

        /* ---- background-image (image) ---- */
        .bg-image-demo {
            background-image: url('https://via.placeholder.com/400x200/007bff/ffffff?text=Background+Image');
            background-repeat: no-repeat;
            background-position: center;
            background-size: cover;
        }

        /* ---- background-repeat ---- */
        .bg-repeat-repeat {
            background-image: url('https://via.placeholder.com/50x50/ff6b6b/ffffff?text=A');
            background-repeat: repeat;
            background-size: 50px 50px;
        }

        .bg-repeat-no-repeat {
            background-image: url('https://via.placeholder.com/50x50/4ecdc4/ffffff?text=B');
            background-repeat: no-repeat;
            background-position: center;
        }

        .bg-repeat-repeat-x {
            background-image: url('https://via.placeholder.com/50x50/ffc107/333333?text=C');
            background-repeat: repeat-x;
            background-size: 50px 50px;
        }

        .bg-repeat-repeat-y {
            background-image: url('https://via.placeholder.com/50x50/6c5ce7/ffffff?text=D');
            background-repeat: repeat-y;
            background-size: 50px 50px;
        }

        /* ---- background-position ---- */
        .bg-position-center {
            background-image: url('https://via.placeholder.com/100x100/007bff/ffffff?text=Center');
            background-repeat: no-repeat;
            background-position: center center;
        }

        .bg-position-top-left {
            background-image: url('https://via.placeholder.com/100x100/28a745/ffffff?text=TL');
            background-repeat: no-repeat;
            background-position: top left;
        }

        .bg-position-bottom-right {
            background-image: url('https://via.placeholder.com/100x100/dc3545/ffffff?text=BR');
            background-repeat: no-repeat;
            background-position: bottom right;
        }

        /* ---- background-attachment ---- */
        .bg-attachment-fixed {
            background-image: url('https://via.placeholder.com/400x300/6610f2/ffffff?text=Fixed');
            background-repeat: no-repeat;
            background-size: cover;
            background-attachment: fixed;
            min-height: 250px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.5rem;
            color: white;
            text-shadow: 0 0 10px rgba(0,0,0,0.5);
        }

        /* ---- background-clip ---- */
        .bg-clip-border {
            background-image: url('https://via.placeholder.com/400x200/ffc107/333333?text=Border+Box');
            background-repeat: no-repeat;
            background-size: cover;
            background-clip: border-box;
            border: 10px dashed rgba(0,0,0,0.3);
        }

        .bg-clip-padding {
            background-image: url('https://via.placeholder.com/400x200/17a2b8/ffffff?text=Padding+Box');
            background-repeat: no-repeat;
            background-size: cover;
            background-clip: padding-box;
            border: 10px dashed rgba(0,0,0,0.3);
        }

        .bg-clip-content {
            background-image: url('https://via.placeholder.com/400x200/dc3545/ffffff?text=Content+Box');
            background-repeat: no-repeat;
            background-size: cover;
            background-clip: content-box;
            border: 10px dashed rgba(0,0,0,0.3);
            padding: 20px;
        }

        .bg-clip-text {
            background-image: linear-gradient(to right, #007bff, #dc3545);
            background-clip: text;
            color: transparent;
            font-size: 3rem;
            font-weight: bold;
            text-align: center;
            display: flex;
            align-items: center;
            justify-content: center;
            height: 150px;
        }

        /* ---- background-origin ---- */
        .bg-origin-border {
            background-image: url('https://via.placeholder.com/100x100/28a745/ffffff?text=Border');
            background-repeat: no-repeat;
            background-origin: border-box;
            border: 20px solid rgba(0,0,0,0.1);
            padding: 20px;
            background-color: #f8f9fa;
        }

        .bg-origin-padding {
            background-image: url('https://via.placeholder.com/100x100/007bff/ffffff?text=Pad');
            background-repeat: no-repeat;
            background-origin: padding-box;
            border: 20px solid rgba(0,0,0,0.1);
            padding: 20px;
            background-color: #f8f9fa;
        }

        .bg-origin-content {
            background-image: url('https://via.placeholder.com/100x100/dc3545/ffffff?text=Content');
            background-repeat: no-repeat;
            background-origin: content-box;
            border: 20px solid rgba(0,0,0,0.1);
            padding: 20px;
            background-color: #f8f9fa;
        }

        /* ---- background-size ---- */
        .bg-size-cover {
            background-image: url('https://via.placeholder.com/800x200/007bff/ffffff?text=Cover');
            background-repeat: no-repeat;
            background-size: cover;
        }

        .bg-size-contain {
            background-image: url('https://via.placeholder.com/800x200/28a745/ffffff?text=Contain');
            background-repeat: no-repeat;
            background-size: contain;
        }

        .bg-size-50 {
            background-image: url('https://via.placeholder.com/800x200/dc3545/ffffff?text=50%');
            background-repeat: no-repeat;
            background-size: 50% 50%;
            background-position: center;
        }

        /* ---- Shorthand ---- */
        .bg-shorthand {
            background: 
                url('https://via.placeholder.com/400x200/6610f2/ffffff?text=Shorthand') 
                center center / cover 
                no-repeat 
                fixed 
                #f8f9fa;
            min-height: 200px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 1.5rem;
            text-shadow: 0 0 10px rgba(0,0,0,0.5);
        }
    </style>
</head>
<body>

    <h1>Background Properties</h1>

    <!-- ====== 1. background-color ====== -->
    <section>
        <h2>1. background-color</h2>
        <div class="grid-2">
            <div class="demo-box bg-color-demo">background-color: #007bff</div>
            <div class="demo-box bg-color-rgba">background-color: rgba(255, 0, 0, 0.5)</div>
        </div>
        <div class="code-block">
            background-color: #007bff;
            background-color: rgba(255, 0, 0, 0.5);
        </div>
    </section>

    <!-- ====== 2. background-image (Gradients) ====== -->
    <section>
        <h2>2. background-image (Gradients)</h2>
        <div class="grid-2">
            <div class="demo-box bg-gradient-linear">Linear Gradient</div>
            <div class="demo-box bg-gradient-radial">Radial Gradient</div>
            <div class="demo-box bg-gradient-conic">Conic Gradient</div>
        </div>
        <div class="code-block">
            background-image: linear-gradient(to right, #007bff, #6c5ce7);
            background-image: radial-gradient(circle, #28a745, #1e7e34);
            background-image: conic-gradient(#ffc107, #dc3545, #007bff);
        </div>
    </section>

    <!-- ====== 3. background-image (Image) ====== -->
    <section>
        <h2>3. background-image (Image)</h2>
        <div class="demo-box bg-image-demo">Background Image</div>
        <div class="code-block">
            background-image: url('path/to/image.jpg');
            background-repeat: no-repeat;
            background-position: center;
            background-size: cover;
        </div>
    </section>

    <!-- ====== 4. background-repeat ====== -->
    <section>
        <h2>4. background-repeat</h2>
        <div class="grid-2">
            <div class="demo-box bg-repeat-repeat">repeat</div>
            <div class="demo-box bg-repeat-no-repeat">no-repeat</div>
            <div class="demo-box bg-repeat-repeat-x">repeat-x</div>
            <div class="demo-box bg-repeat-repeat-y">repeat-y</div>
        </div>
        <div class="code-block">
            background-repeat: repeat;
            background-repeat: no-repeat;
            background-repeat: repeat-x;
            background-repeat: repeat-y;
        </div>
    </section>

    <!-- ====== 5. background-position ====== -->
    <section>
        <h2>5. background-position</h2>
        <div class="grid-2">
            <div class="demo-box bg-position-center">center center</div>
            <div class="demo-box bg-position-top-left">top left</div>
            <div class="demo-box bg-position-bottom-right">bottom right</div>
        </div>
        <div class="code-block">
            background-position: center center;
            background-position: top left;
            background-position: bottom right;
        </div>
    </section>

    <!-- ====== 6. background-attachment ====== -->
    <section>
        <h2>6. background-attachment</h2>
        <div class="demo-box bg-attachment-fixed">Fixed Background (scroll the page!)</div>
        <div class="code-block">
            background-attachment: fixed;
        </div>
    </section>

    <!-- ====== 7. background-clip ====== -->
    <section>
        <h2>7. background-clip</h2>
        <div class="grid-2">
            <div class="demo-box bg-clip-border" style="color: #333;">border-box</div>
            <div class="demo-box bg-clip-padding" style="color: #333;">padding-box</div>
            <div class="demo-box bg-clip-content" style="color: #333; background-color: white;">content-box</div>
            <div class="demo-box bg-clip-text" style="background: none;">Gradient Text</div>
        </div>
        <div class="code-block">
            background-clip: border-box;  /* Default */
            background-clip: padding-box;
            background-clip: content-box;
            background-clip: text;        /* Experimental */
        </div>
    </section>

    <!-- ====== 8. background-origin ====== -->
    <section>
        <h2>8. background-origin</h2>
        <div class="grid-2">
            <div class="demo-box bg-origin-border" style="color: #333; min-height: 150px;">border-box</div>
            <div class="demo-box bg-origin-padding" style="color: #333; min-height: 150px;">padding-box</div>
            <div class="demo-box bg-origin-content" style="color: #333; min-height: 150px;">content-box</div>
        </div>
        <div class="code-block">
            background-origin: border-box;
            background-origin: padding-box;  /* Default */
            background-origin: content-box;
        </div>
    </section>

    <!-- ====== 9. background-size ====== -->
    <section>
        <h2>9. background-size</h2>
        <div class="grid-2">
            <div class="demo-box bg-size-cover">cover</div>
            <div class="demo-box bg-size-contain">contain</div>
            <div class="demo-box bg-size-50">50% 50%</div>
        </div>
        <div class="code-block">
            background-size: cover;    /* Fills container (may crop) */
            background-size: contain;  /* Fits image in container */
            background-size: 50% 50%;  /* Percentage of container */
        </div>
    </section>

    <!-- ====== 10. Shorthand ====== -->
    <section>
        <h2>10. Background Shorthand</h2>
        <div class="demo-box bg-shorthand">Shorthand</div>
        <div class="code-block">
            background: 
                url('image.jpg') 
                center center / cover 
                no-repeat 
                fixed 
                #f8f9fa;
        </div>
    </section>

    <!-- ====== REFERENCE TABLES ====== -->
    <section>
        <h2>11. Reference Tables</h2>

        <h3>Background Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>background-color</code></td>
                <td>Sets the background color</td>
                <td><code>background-color: red;</code></td>
            </tr>
            <tr>
                <td><code>background-image</code></td>
                <td>Sets the background image or gradient</td>
                <td><code>background-image: url("image.jpg");</code></td>
            </tr>
            <tr>
                <td><code>background-repeat</code></td>
                <td>Controls image repetition</td>
                <td><code>background-repeat: no-repeat;</code></td>
            </tr>
            <tr>
                <td><code>background-position</code></td>
                <td>Sets the image position</td>
                <td><code>background-position: center top;</code></td>
            </tr>
            <tr>
                <td><code>background-attachment</code></td>
                <td>Controls scrolling behavior</td>
                <td><code>background-attachment: fixed;</code></td>
            </tr>
            <tr>
                <td><code>background-clip</code></td>
                <td>Defines the clipping area</td>
                <td><code>background-clip: padding-box;</code></td>
            </tr>
            <tr>
                <td><code>background-origin</code></td>
                <td>Sets the positioning origin</td>
                <td><code>background-origin: border-box;</code></td>
            </tr>
            <tr>
                <td><code>background-size</code></td>
                <td>Controls image scaling</td>
                <td><code>background-size: cover;</code></td>
            </tr>
        </table>

        <h3>background-repeat Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr><td><code>repeat</code></td><td>Repeats both horizontally and vertically (default)</td></tr>
            <tr><td><code>no-repeat</code></td><td>Does not repeat</td></tr>
            <tr><td><code>repeat-x</code></td><td>Repeats only horizontally</td></tr>
            <tr><td><code>repeat-y</code></td><td>Repeats only vertically</td></tr>
            <tr><td><code>space</code></td><td>Repeats with space between images</td></tr>
            <tr><td><code>round</code></td><td>Repeats and stretches to fit</td></tr>
        </table>

        <h3>background-size Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr><td><code>auto</code></td><td>Original size (default)</td></tr>
            <tr><td><code>cover</code></td><td>Fills the entire container (may crop)</td></tr>
            <tr><td><code>contain</code></td><td>Fits the entire image in the container</td></tr>
            <tr><td><code>x% y%</code></td><td>Percentage of the container</td></tr>
            <tr><td><code>xpx ypx</code></td><td>Pixel values</td></tr>
        </table>

        <h3>background-position Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr><td><code>left</code>, <code>center</code>, <code>right</code></td><td>Horizontal position</td></tr>
            <tr><td><code>top</code>, <code>center</code>, <code>bottom</code></td><td>Vertical position</td></tr>
            <tr><td><code>x% y%</code></td><td>Percentage values</td></tr>
            <tr><td><code>xpx ypx</code></td><td>Pixel values</td></tr>
        </table>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionCommon Values
background-colorSets background colorred, #FF0000, rgb(255,0,0)
background-imageSets background imageurl("image.jpg"), linear-gradient(...)
background-repeatControls repetitionrepeat, no-repeat, repeat-x, repeat-y
background-positionSets image positioncenter, top left, 50% 50%
background-attachmentControls scrollingscroll, fixed, local
background-clipDefines clipping areaborder-box, padding-box, content-box
background-originSets positioning originborder-box, padding-box, content-box
background-sizeControls scalingcover, contain, auto, 100%

Best Practices

Do This:

/* Always set a fallback background-color when using images */
background-color: #f8f9fa;
background-image: url("image.jpg");

/* Use cover for hero sections */
.hero {
    background-image: url("hero.jpg");
    background-size: cover;
    background-position: center;
}

/* Use contain for logos */
.logo {
    background-image: url("logo.png");
    background-size: contain;
    background-repeat: no-repeat;
}

Don’t Do This:

/* Don't use images without a fallback color */
background-image: url("image.jpg");
/* If the image fails to load, the background is transparent */

/* Don't use cover with important content that might be cropped */
.important-image {
    background-size: cover;
}
/* Use contain instead for important content */

Pro Tip: Always set a background-color fallback when using background-image. This ensures readability if the image fails to load. Use background-size: cover for hero/header sections and background-size: contain for logos and icons. The background shorthand is powerful but can be confusing — use it when you’re comfortable with the syntax!

6. Fonts

Fonts play a crucial role in web design, affecting readability, user experience, and overall aesthetics. CSS provides several properties to customize the appearance of text, including font family, size, weight, style, and more.


Overview of Font Properties

PropertyDescriptionExample
font-familySpecifies the font familyfont-family: Arial, sans-serif;
font-sizeSpecifies the font sizefont-size: 16px;
font-weightSpecifies the boldnessfont-weight: bold;
font-styleSpecifies the style (italic, oblique)font-style: italic;
font-variantSpecifies small-caps or normalfont-variant: small-caps;
line-heightSpecifies the height of a lineline-height: 1.6;
letter-spacingSpecifies space between charactersletter-spacing: 2px;
word-spacingSpecifies space between wordsword-spacing: 4px;
text-alignAligns text (left, right, center, justify)text-align: center;
text-decorationAdds decoration (underline, overline, line-through)text-decoration: underline;
text-transformTransforms text (uppercase, lowercase, capitalize)text-transform: uppercase;

1. font-family

Specifies the font family to be used for a text element. You can provide multiple font names as a fallback system.

.custom-font {
    /* Primary font: Arial, fallback: sans-serif */
    font-family: Arial, sans-serif;

    /* Multiple fallbacks */
    font-family: 'Times New Roman', Times, serif;

    /* Google Font (imported) */
    font-family: 'Open Sans', Arial, sans-serif;
}

Key Points:

  • Font names with spaces should be enclosed in quotes (e.g., "Times New Roman")
  • Multiple fonts are separated by commas (the browser will try each one in order)
  • Always end with a generic font family (serif, sans-serif, monospace, etc.)

2. font-size

Specifies the size of the font. You can use absolute units (px, pt), relative units (em, rem, %), or keywords.

/* Pixels (absolute) */
.pixel-size {
    font-size: 16px;
}

/* Ems (relative to parent) */
.em-size {
    font-size: 1.2em; /* 1.2 × parent font size */
}

/* Rems (relative to root) */
.rem-size {
    font-size: 1.2rem; /* 1.2 × root font size */
}

/* Percentage (relative to parent) */
.percent-size {
    font-size: 120%; /* 120% of parent font size */
}

/* Keywords */
.keyword-size {
    font-size: medium; /* xx-small, x-small, small, medium, large, x-large, xx-large */
    font-size: smaller; /* relative to parent */
    font-size: larger; /* relative to parent */
}

/* Viewport-based (responsive) */
.vw-size {
    font-size: 2vw; /* 2% of viewport width */
}

3. font-weight

Specifies the boldness of the font. You can use keywords or numerical values.

ValueDescriptionExample
normalNormal weight (400)font-weight: normal;
boldBold weight (700)font-weight: bold;
bolderOne level bolder than parentfont-weight: bolder;
lighterOne level lighter than parentfont-weight: lighter;
100900Numerical values (100 = thin, 900 = black)font-weight: 300;
.custom-font {
    font-weight: bold; /* 700 */
}

.thin-text {
    font-weight: 100; /* Thin */
}

.light-text {
    font-weight: 300; /* Light */
}

.regular-text {
    font-weight: 400; /* Normal */
}

.semi-bold-text {
    font-weight: 600; /* Semi-bold */
}

.black-text {
    font-weight: 900; /* Black (very bold) */
}

4. font-style

Specifies the style of the font.

ValueDescriptionExample
normalNormal style (default)font-style: normal;
italicItalic stylefont-style: italic;
obliqueOblique style (slanted)font-style: oblique;
.custom-font {
    font-style: italic;
}

.normal-style {
    font-style: normal;
}

.oblique-style {
    font-style: oblique;
}

5. font-variant

Specifies whether the text should be displayed in small-caps.

.small-caps {
    font-variant: small-caps;
}

.normal-variant {
    font-variant: normal;
}

6. Additional Text Properties

line-height

Controls the height of a line of text.

.text {
    line-height: 1.6;   /* Unitless — 1.6 × font size */
    line-height: 24px;  /* Fixed pixel value */
    line-height: 150%;  /* Percentage of font size */
}

letter-spacing

Controls the space between characters.

.text {
    letter-spacing: 2px;   /* Adds space between letters */
    letter-spacing: -1px;  /* Reduces space between letters */
}

word-spacing

Controls the space between words.

.text {
    word-spacing: 4px;   /* Adds space between words */
}

text-align

Aligns text horizontally.

.text {
    text-align: left;     /* Left-aligned (default) */
    text-align: right;    /* Right-aligned */
    text-align: center;   /* Center-aligned */
    text-align: justify;  /* Justified (spread across line) */
}

text-decoration

Adds decoration to text.

.text {
    text-decoration: underline;           /* Underline */
    text-decoration: overline;            /* Overline */
    text-decoration: line-through;        /* Strikethrough */
    text-decoration: underline overline;  /* Multiple decorations */
}

text-transform

Transforms the case of text.

.text {
    text-transform: uppercase;   /* ALL CAPS */
    text-transform: lowercase;   /* all lowercase */
    text-transform: capitalize;  /* First Letter Capitalized */
    text-transform: none;        /* Original case */
}

The Shorthand font Property

You can combine multiple font properties into a single font shorthand.

/* Shorthand: style variant weight size/line-height family */
.font-shorthand {
    font: italic small-caps bold 16px/1.6 Arial, sans-serif;
}

/* Minimal shorthand: size family */
.font-shorthand-minimal {
    font: 16px Arial, sans-serif;
}

Order:

  1. font-style (optional)
  2. font-variant (optional)
  3. font-weight (optional)
  4. font-size (required)
  5. / line-height (optional)
  6. font-family (required)

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Font Properties</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .demo-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            background: #e9ecef;
            border-left: 4px solid #007bff;
        }

        .grid-2 {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
        }

        .grid-2 .demo-box {
            border-left: 4px solid #28a745;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== FONT DEMOS ====== */

        /* ---- font-family ---- */
        .ff-arial {
            font-family: Arial, sans-serif;
        }

        .ff-times {
            font-family: 'Times New Roman', Times, serif;
        }

        .ff-courier {
            font-family: 'Courier New', monospace;
        }

        .ff-georgia {
            font-family: Georgia, 'Times New Roman', serif;
        }

        /* ---- font-size ---- */
        .fs-px {
            font-size: 16px;
        }

        .fs-em {
            font-size: 1.5em;
        }

        .fs-rem {
            font-size: 1.5rem;
        }

        .fs-vw {
            font-size: 2vw;
        }

        .fs-small {
            font-size: small;
        }

        .fs-large {
            font-size: large;
        }

        /* ---- font-weight ---- */
        .fw-thin {
            font-weight: 100;
        }

        .fw-light {
            font-weight: 300;
        }

        .fw-normal {
            font-weight: 400;
        }

        .fw-bold {
            font-weight: 700;
        }

        .fw-black {
            font-weight: 900;
        }

        /* ---- font-style ---- */
        .fs-normal {
            font-style: normal;
        }

        .fs-italic {
            font-style: italic;
        }

        .fs-oblique {
            font-style: oblique;
        }

        /* ---- font-variant ---- */
        .fv-smallcaps {
            font-variant: small-caps;
        }

        /* ---- text-decoration ---- */
        .td-underline {
            text-decoration: underline;
        }

        .td-overline {
            text-decoration: overline;
        }

        .td-line-through {
            text-decoration: line-through;
        }

        .td-combined {
            text-decoration: underline overline;
        }

        /* ---- text-transform ---- */
        .tt-uppercase {
            text-transform: uppercase;
        }

        .tt-lowercase {
            text-transform: lowercase;
        }

        .tt-capitalize {
            text-transform: capitalize;
        }

        /* ---- letter-spacing & word-spacing ---- */
        .ls-wide {
            letter-spacing: 4px;
        }

        .ls-tight {
            letter-spacing: -1px;
        }

        .ws-wide {
            word-spacing: 8px;
        }

        /* ---- text-align ---- */
        .ta-left {
            text-align: left;
        }

        .ta-center {
            text-align: center;
        }

        .ta-right {
            text-align: right;
        }

        .ta-justify {
            text-align: justify;
        }

        /* ---- line-height ---- */
        .lh-tight {
            line-height: 1.2;
        }

        .lh-normal {
            line-height: 1.6;
        }

        .lh-loose {
            line-height: 2.5;
        }

        /* ---- Shorthand ---- */
        .font-shorthand {
            font: italic bold 18px/1.8 'Georgia', serif;
        }
    </style>
</head>
<body>

    <h1>Font Properties</h1>

    <!-- ====== 1. font-family ====== -->
    <section>
        <h2>1. font-family</h2>
        <div class="grid-2">
            <div class="demo-box ff-arial"><strong>font-family:</strong> Arial, sans-serif</div>
            <div class="demo-box ff-times"><strong>font-family:</strong> 'Times New Roman', Times, serif</div>
            <div class="demo-box ff-courier"><strong>font-family:</strong> 'Courier New', monospace</div>
            <div class="demo-box ff-georgia"><strong>font-family:</strong> Georgia, 'Times New Roman', serif</div>
        </div>
        <div class="code-block">
            font-family: Arial, sans-serif;
            font-family: 'Times New Roman', Times, serif;
            font-family: 'Courier New', monospace;
            font-family: Georgia, 'Times New Roman', serif;
        </div>
    </section>

    <!-- ====== 2. font-size ====== -->
    <section>
        <h2>2. font-size</h2>
        <div class="grid-2">
            <div class="demo-box fs-px"><strong>font-size:</strong> 16px</div>
            <div class="demo-box fs-em"><strong>font-size:</strong> 1.5em (1.5 × parent)</div>
            <div class="demo-box fs-rem"><strong>font-size:</strong> 1.5rem (1.5 × root)</div>
            <div class="demo-box fs-vw"><strong>font-size:</strong> 2vw (2% of viewport width)</div>
            <div class="demo-box fs-small"><strong>font-size:</strong> small (keyword)</div>
            <div class="demo-box fs-large"><strong>font-size:</strong> large (keyword)</div>
        </div>
        <div class="code-block">
            font-size: 16px;
            font-size: 1.5em;
            font-size: 1.5rem;
            font-size: 2vw;
            font-size: small;
            font-size: large;
        </div>
    </section>

    <!-- ====== 3. font-weight ====== -->
    <section>
        <h2>3. font-weight</h2>
        <div class="grid-2">
            <div class="demo-box fw-thin">font-weight: 100 (Thin)</div>
            <div class="demo-box fw-light">font-weight: 300 (Light)</div>
            <div class="demo-box fw-normal">font-weight: 400 (Normal)</div>
            <div class="demo-box fw-bold">font-weight: 700 (Bold)</div>
            <div class="demo-box fw-black">font-weight: 900 (Black)</div>
        </div>
        <div class="code-block">
            font-weight: 100;  /* Thin */
            font-weight: 300;  /* Light */
            font-weight: 400;  /* Normal */
            font-weight: 700;  /* Bold */
            font-weight: 900;  /* Black */
        </div>
    </section>

    <!-- ====== 4. font-style ====== -->
    <section>
        <h2>4. font-style</h2>
        <div class="grid-2">
            <div class="demo-box fs-normal">font-style: normal</div>
            <div class="demo-box fs-italic">font-style: italic</div>
            <div class="demo-box fs-oblique">font-style: oblique</div>
        </div>
        <div class="code-block">
            font-style: normal;
            font-style: italic;
            font-style: oblique;
        </div>
    </section>

    <!-- ====== 5. font-variant ====== -->
    <section>
        <h2>5. font-variant</h2>
        <div class="demo-box fv-smallcaps">font-variant: small-caps</div>
        <div class="code-block">
            font-variant: small-caps;
        </div>
    </section>

    <!-- ====== 6. text-decoration ====== -->
    <section>
        <h2>6. text-decoration</h2>
        <div class="grid-2">
            <div class="demo-box td-underline">text-decoration: underline</div>
            <div class="demo-box td-overline">text-decoration: overline</div>
            <div class="demo-box td-line-through">text-decoration: line-through</div>
            <div class="demo-box td-combined">text-decoration: underline overline</div>
        </div>
        <div class="code-block">
            text-decoration: underline;
            text-decoration: overline;
            text-decoration: line-through;
            text-decoration: underline overline;
        </div>
    </section>

    <!-- ====== 7. text-transform ====== -->
    <section>
        <h2>7. text-transform</h2>
        <div class="grid-2">
            <div class="demo-box tt-uppercase">text-transform: uppercase</div>
            <div class="demo-box tt-lowercase">TEXT-TRANSFORM: lowercase</div>
            <div class="demo-box tt-capitalize">text-transform: capitalize</div>
        </div>
        <div class="code-block">
            text-transform: uppercase;  /* ALL CAPS */
            text-transform: lowercase;  /* all lowercase */
            text-transform: capitalize; /* First Letter Capitalized */
        </div>
    </section>

    <!-- ====== 8. letter-spacing & word-spacing ====== -->
    <section>
        <h2>8. letter-spacing & word-spacing</h2>
        <div class="grid-2">
            <div class="demo-box ls-wide">letter-spacing: 4px (wide)</div>
            <div class="demo-box ls-tight">letter-spacing: -1px (tight)</div>
            <div class="demo-box ws-wide">word-spacing: 8px (wide words)</div>
        </div>
        <div class="code-block">
            letter-spacing: 4px;
            letter-spacing: -1px;
            word-spacing: 8px;
        </div>
    </section>

    <!-- ====== 9. text-align ====== -->
    <section>
        <h2>9. text-align</h2>
        <div class="grid-2">
            <div class="demo-box ta-left">text-align: left</div>
            <div class="demo-box ta-center">text-align: center</div>
            <div class="demo-box ta-right">text-align: right</div>
            <div class="demo-box ta-justify" style="width: 300px;">
                text-align: justify — this text will be spread across the entire line width.
            </div>
        </div>
        <div class="code-block">
            text-align: left;
            text-align: center;
            text-align: right;
            text-align: justify;
        </div>
    </section>

    <!-- ====== 10. line-height ====== -->
    <section>
        <h2>10. line-height</h2>
        <div class="grid-2">
            <div class="demo-box lh-tight" style="width: 300px;">
                line-height: 1.2 (tight) <br>
                This is a second line.
            </div>
            <div class="demo-box lh-normal" style="width: 300px;">
                line-height: 1.6 (normal) <br>
                This is a second line.
            </div>
            <div class="demo-box lh-loose" style="width: 300px;">
                line-height: 2.5 (loose) <br>
                This is a second line.
            </div>
        </div>
        <div class="code-block">
            line-height: 1.2;
            line-height: 1.6;
            line-height: 2.5;
        </div>
    </section>

    <!-- ====== 11. Shorthand ====== -->
    <section>
        <h2>11. font Shorthand</h2>
        <div class="demo-box font-shorthand">
            font: italic bold 18px/1.8 'Georgia', serif;
        </div>
        <div class="code-block">
            /* Shorthand: style variant weight size/line-height family */
            font: italic small-caps bold 16px/1.6 Arial, sans-serif;
            font: italic bold 18px/1.8 'Georgia', serif;
        </div>
    </section>

    <!-- ====== REFERENCE TABLES ====== -->
    <section>
        <h2>12. Reference Tables</h2>

        <h3>Font Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>font-family</code></td>
                <td>Specifies the font family</td>
                <td><code>font-family: Arial, sans-serif;</code></td>
            </tr>
            <tr>
                <td><code>font-size</code></td>
                <td>Specifies the font size</td>
                <td><code>font-size: 16px;</code></td>
            </tr>
            <tr>
                <td><code>font-weight</code></td>
                <td>Specifies the boldness</td>
                <td><code>font-weight: bold;</code></td>
            </tr>
            <tr>
                <td><code>font-style</code></td>
                <td>Specifies the style</td>
                <td><code>font-style: italic;</code></td>
            </tr>
            <tr>
                <td><code>font-variant</code></td>
                <td>Specifies small-caps</td>
                <td><code>font-variant: small-caps;</code></td>
            </tr>
            <tr>
                <td><code>line-height</code></td>
                <td>Specifies the line height</td>
                <td><code>line-height: 1.6;</code></td>
            </tr>
            <tr>
                <td><code>letter-spacing</code></td>
                <td>Specifies space between characters</td>
                <td><code>letter-spacing: 2px;</code></td>
            </tr>
            <tr>
                <td><code>word-spacing</code></td>
                <td>Specifies space between words</td>
                <td><code>word-spacing: 4px;</code></td>
            </tr>
            <tr>
                <td><code>text-align</code></td>
                <td>Aligns text horizontally</td>
                <td><code>text-align: center;</code></td>
            </tr>
            <tr>
                <td><code>text-decoration</code></td>
                <td>Adds decoration</td>
                <td><code>text-decoration: underline;</code></td>
            </tr>
            <tr>
                <td><code>text-transform</code></td>
                <td>Transforms text case</td>
                <td><code>text-transform: uppercase;</code></td>
            </tr>
        </table>

        <h3>font-weight Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr><td><code>100</code></td><td>Thin / Hairline</td></tr>
            <tr><td><code>200</code></td><td>Extra Light (Ultra Light)</td></tr>
            <tr><td><code>300</code></td><td>Light</td></tr>
            <tr><td><code>400</code></td><td>Normal (default)</td></tr>
            <tr><td><code>500</code></td><td>Medium</td></tr>
            <tr><td><code>600</code></td><td>Semi Bold (Demi Bold)</td></tr>
            <tr><td><code>700</code></td><td>Bold</td></tr>
            <tr><td><code>800</code></td><td>Extra Bold (Ultra Bold)</td></tr>
            <tr><td><code>900</code></td><td>Black (Heavy)</td></tr>
            <tr><td><code>normal</code></td><td>Equivalent to 400</td></tr>
            <tr><td><code>bold</code></td><td>Equivalent to 700</td></tr>
        </table>

        <h3>Generic Font Families</h3>
        <table class="reference-table">
            <tr>
                <th>Generic Family</th>
                <th>Description</th>
                <th>Example Fonts</th>
            </tr>
            <tr><td><code>serif</code></td><td>Fonts with decorative strokes</td><td>Times New Roman, Georgia, Garamond</td></tr>
            <tr><td><code>sans-serif</code></td><td>Fonts without decorative strokes</td><td>Arial, Helvetica, Verdana, Open Sans</td></tr>
            <tr><td><code>monospace</code></td><td>Fonts with fixed character width</td><td>Courier New, Consolas, Monaco</td></tr>
            <tr><td><code>cursive</code></td><td>Fonts that resemble handwriting</td><td>Brush Script, Comic Sans</td></tr>
            <tr><td><code>fantasy</code></td><td>Decorative fonts</td><td>Impact, Papyrus</td></tr>
        </table>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionCommon Values
font-familyFont familyArial, sans-serif
font-sizeFont size16px, 1rem, 1.2em
font-weightBoldnessnormal, bold, 100900
font-styleStylenormal, italic, oblique
font-variantVariantnormal, small-caps
line-heightLine height1.6, 24px, 150%
letter-spacingCharacter spacing2px, -1px
word-spacingWord spacing4px
text-alignHorizontal alignmentleft, center, right, justify
text-decorationDecorationnone, underline, overline, line-through
text-transformCase transformationnone, uppercase, lowercase, capitalize

Best Practices

Do This:

/* Use rem for font sizes (accessibility) */
html { font-size: 16px; }
h1 { font-size: 2rem; }  /* 32px */
p { font-size: 1rem; }   /* 16px */

/* Always provide fallback fonts */
font-family: 'Open Sans', Arial, sans-serif;

/* Use line-height for readability */
body { line-height: 1.6; }

/* Use relative units for responsive typography */
h1 { font-size: clamp(1.5rem, 4vw, 3rem); }

Don’t Do This:

/* Don't use px for font sizes (accessibility issue) */
font-size: 16px;  /* Prefer rem */

/* Don't forget fallback fonts */
font-family: 'CustomFont';  /* If font fails, browser default is used */

/* Don't set line-height to a fixed unit for body text */
body { line-height: 24px; }  /* Prefer unitless (1.6) */

Pro Tip: Use rem for font sizes to ensure accessibility (users can change the root font size in their browser settings). Use em for component-based sizing (e.g., within a card or button). Always provide fallback fonts and end with a generic family. Use line-height: 1.6 for optimal readability on the web!

7. line-height and text-decoration

Line height and text decoration are essential CSS properties for controlling the spacing and visual styling of text. They enhance readability and allow you to add decorative elements to your text.


line-height

The line-height property specifies the space between lines of text. It’s one of the most important properties for readability.

p {
    line-height: 1.5em; /* Adjust for desired spacing */
}

Values

Value TypeExampleDescription
Number1.5Multiplied by the current font size (recommended)
Length24pxFixed pixel value
Percentage150%Percentage of the current font size
KeywordnormalBrowser default (usually 1.2)
/* Different line-height values */
.lh-number {
    line-height: 1.5; /* 1.5 × font size — recommended */
}

.lh-pixel {
    line-height: 30px; /* Fixed pixel value */
}

.lh-percent {
    line-height: 150%; /* 150% of font size */
}

.lh-normal {
    line-height: normal; /* Browser default ~1.2 */
}

.lh-tight {
    line-height: 1.2; /* Tighter spacing */
}

.lh-loose {
    line-height: 2.0; /* Looser spacing */
}

text-decoration

The text-decoration property adds decorative lines to text. It’s commonly used for links, headings, and emphasizing content.

h1 {
    text-decoration: underline; /* Underlines Headers 1-3 */
}

h2 {
    text-decoration: overline dotted green;
}

h3 {
    text-decoration: overline underline purple;
}

Values

ValueDescriptionExample
noneNo decoration (default)text-decoration: none;
underlineLine below the texttext-decoration: underline;
overlineLine above the texttext-decoration: overline;
line-throughLine through the texttext-decoration: line-through;
underline overlineMultiple decorationstext-decoration: underline overline;

Style and Color

You can also specify the style and color of the decoration.

/* Style: solid (default), dotted, dashed, wavy, double */
.text-decoration-style {
    text-decoration: underline dotted red;
    text-decoration: overline wavy blue;
    text-decoration: line-through double green;
}

/* Separate properties */
.text-decoration-separate {
    text-decoration-line: underline;
    text-decoration-style: wavy;
    text-decoration-color: #ff6b6b;
}
StyleDescriptionExample
solidSingle solid line (default)text-decoration: underline solid red;
dottedDotted linetext-decoration: underline dotted blue;
dashedDashed linetext-decoration: underline dashed green;
wavyWavy linetext-decoration: underline wavy purple;
doubleDouble linetext-decoration: underline double orange;

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>line-height and text-decoration</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f4;
            margin: 0;
            padding: 20px;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .demo-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            background: #e9ecef;
        }

        .grid-2 {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
        }

        .grid-2 .demo-box {
            border-left: 4px solid #28a745;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== LINE HEIGHT DEMOS ====== */
        .lh-tight {
            line-height: 1.2;
        }

        .lh-normal {
            line-height: 1.6;
        }

        .lh-loose {
            line-height: 2.5;
        }

        .lh-pixel {
            line-height: 30px;
        }

        .lh-percent {
            line-height: 200%;
        }

        /* ====== TEXT DECORATION DEMOS ====== */
        .td-none {
            text-decoration: none;
        }

        .td-underline {
            text-decoration: underline;
        }

        .td-overline {
            text-decoration: overline;
        }

        .td-line-through {
            text-decoration: line-through;
        }

        .td-combined {
            text-decoration: underline overline;
        }

        .td-solid {
            text-decoration: underline solid #007bff;
        }

        .td-dotted {
            text-decoration: underline dotted #28a745;
        }

        .td-dashed {
            text-decoration: underline dashed #dc3545;
        }

        .td-wavy {
            text-decoration: underline wavy #ffc107;
        }

        .td-double {
            text-decoration: underline double #6c5ce7;
        }

        .td-underline-color {
            text-decoration: underline #dc3545;
        }

        .td-overline-dotted {
            text-decoration: overline dotted #28a745;
        }

        .td-overline-underline {
            text-decoration: overline underline #6c5ce7;
        }

        .td-wavy-underline {
            text-decoration: underline wavy #dc3545;
        }

        .td-no-link {
            text-decoration: none;
        }

        /* ====== COMBINED DEMOS ====== */
        .combined-demo {
            background: #f8f9fa;
            padding: 20px;
            border-radius: 8px;
            margin: 10px 0;
        }

        .combined-demo h3 {
            margin-top: 0;
        }
    </style>
</head>
<body>

    <h1>line-height and text-decoration</h1>

    <!-- ====== 1. LINE HEIGHT ====== -->
    <section>
        <h2>1. line-height</h2>

        <div class="grid-2">
            <div class="demo-box lh-tight">
                <strong>line-height: 1.2 (Tight)</strong><br>
                This is the first line of text.<br>
                This is the second line of text.<br>
                This is the third line of text.
            </div>

            <div class="demo-box lh-normal">
                <strong>line-height: 1.6 (Normal)</strong><br>
                This is the first line of text.<br>
                This is the second line of text.<br>
                This is the third line of text.
            </div>

            <div class="demo-box lh-loose">
                <strong>line-height: 2.5 (Loose)</strong><br>
                This is the first line of text.<br>
                This is the second line of text.<br>
                This is the third line of text.
            </div>

            <div class="demo-box lh-pixel">
                <strong>line-height: 30px (Fixed)</strong><br>
                This is the first line of text.<br>
                This is the second line of text.<br>
                This is the third line of text.
            </div>

            <div class="demo-box lh-percent">
                <strong>line-height: 200% (Percentage)</strong><br>
                This is the first line of text.<br>
                This is the second line of text.<br>
                This is the third line of text.
            </div>
        </div>

        <div class="code-block">
            /* Number (recommended) */
            line-height: 1.5;  /* 1.5 × font size */

            /* Pixel */
            line-height: 30px;

            /* Percentage */
            line-height: 150%;

            /* Keyword */
            line-height: normal;  /* Browser default ~1.2 */
        </div>
    </section>

    <!-- ====== 2. TEXT DECORATION ====== -->
    <section>
        <h2>2. text-decoration</h2>

        <h3>Decoration Lines</h3>
        <div class="grid-2">
            <div class="demo-box td-none"><strong>text-decoration:</strong> none (no decoration)</div>
            <div class="demo-box td-underline"><strong>text-decoration:</strong> underline</div>
            <div class="demo-box td-overline"><strong>text-decoration:</strong> overline</div>
            <div class="demo-box td-line-through"><strong>text-decoration:</strong> line-through</div>
            <div class="demo-box td-combined"><strong>text-decoration:</strong> underline overline</div>
        </div>

        <h3>Decoration Styles & Colors</h3>
        <div class="grid-2">
            <div class="demo-box td-solid"><strong>text-decoration:</strong> underline solid blue</div>
            <div class="demo-box td-dotted"><strong>text-decoration:</strong> underline dotted green</div>
            <div class="demo-box td-dashed"><strong>text-decoration:</strong> underline dashed red</div>
            <div class="demo-box td-wavy"><strong>text-decoration:</strong> underline wavy yellow</div>
            <div class="demo-box td-double"><strong>text-decoration:</strong> underline double purple</div>
        </div>

        <h3>Multiple Decorations</h3>
        <div class="grid-2">
            <div class="demo-box td-overline-dotted">
                <strong>text-decoration:</strong> overline dotted green
            </div>
            <div class="demo-box td-overline-underline">
                <strong>text-decoration:</strong> overline underline purple
            </div>
            <div class="demo-box td-wavy-underline">
                <strong>text-decoration:</strong> underline wavy red
            </div>
        </div>

        <div class="code-block">
            /* Basic decorations */
            text-decoration: none;
            text-decoration: underline;
            text-decoration: overline;
            text-decoration: line-through;
            text-decoration: underline overline;

            /* With style and color */
            text-decoration: underline solid blue;
            text-decoration: underline dotted green;
            text-decoration: underline dashed red;
            text-decoration: underline wavy yellow;
            text-decoration: underline double purple;

            /* Multiple decorations */
            text-decoration: overline dotted green;
            text-decoration: overline underline purple;
        </div>
    </section>

    <!-- ====== 3. HEADER EXAMPLES ====== -->
    <section>
        <h2>3. Header Examples (from the lesson)</h2>

        <div class="demo-box">
            <h1 style="text-decoration: underline; color: #007bff;">
                This is a Header 1 (underline)
            </h1>
            <h2 style="text-decoration: overline dotted green; color: #28a745;">
                This is a Header 2 (overline dotted green)
            </h2>
            <h3 style="text-decoration: overline underline purple; color: #6c5ce7;">
                This is a Header 3 (overline underline purple)
            </h3>
        </div>

        <div class="code-block">
            h1 {
                text-decoration: underline;  /* Underline only */
            }

            h2 {
                text-decoration: overline dotted green;  /* Overline dotted green */
            }

            h3 {
                text-decoration: overline underline purple;  /* Overline and underline purple */
            }
        </div>
    </section>

    <!-- ====== 4. PARAGRAPH EXAMPLES ====== -->
    <section>
        <h2>4. Paragraph Example (line-height)</h2>

        <div class="demo-box">
            <p style="line-height: 1.6; color: #333;">
                <strong>line-height: 1.6</strong><br>
                This is a paragraph with some example text. Notice how the lines are spaced out according to the `line-height` property value set to 1.6. You can change this value to adjust the spacing as needed. Proper line height improves readability and makes your content more accessible.
            </p>
            <p style="line-height: 2.0; color: #333;">
                <strong>line-height: 2.0</strong><br>
                This is a paragraph with a looser line height. The lines are more spaced out, which can be useful for certain design styles or when you want more breathing room between lines of text.
            </p>
            <p style="line-height: 1.2; color: #333;">
                <strong>line-height: 1.2</strong><br>
                This is a paragraph with a tighter line height. The lines are closer together, which can be useful for headings or when you want to save vertical space.
            </p>
        </div>
    </section>

    <!-- ====== 5. COMBINED EXAMPLES ====== -->
    <section>
        <h2>5. Combined Examples</h2>

        <div class="combined-demo">
            <h3 style="text-decoration: underline wavy #007bff; line-height: 1.8;">
                Wavy Underline Heading
            </h3>
            <p style="line-height: 1.6; font-size: 1rem;">
                This paragraph has a <span style="text-decoration: line-through dashed #dc3545;">strikethrough</span> and
                <span style="text-decoration: underline wavy #28a745;">wavy underline</span> for emphasis.
                You can combine different <span style="text-decoration: underline overline dotted #6c5ce7;">decorations</span>
                on different parts of your text.
            </p>
        </div>

        <div class="combined-demo" style="background: #1e1e1e; color: #d4d4d4;">
            <h3 style="text-decoration: underline wavy #ffc107; color: #ffc107; line-height: 1.8;">
                Dark Theme Example
            </h3>
            <p style="line-height: 1.8; font-size: 1rem;">
                <span style="text-decoration: underline solid #4ecdc4;">Underlined</span> text with
                <span style="text-decoration: overline dotted #ff6b6b;">overlined</span> text and
                <span style="text-decoration: line-through wavy #ffc107;">strikethrough</span>.
            </p>
        </div>
    </section>

    <!-- ====== 6. LINK EXAMPLE ====== -->
    <section>
        <h2>6. Links (text-decoration)</h2>

        <div class="demo-box">
            <p>
                <a href="#" style="text-decoration: none; color: #007bff;">
                    Link with no underline (text-decoration: none)
                </a>
                <br><br>
                <a href="#" style="text-decoration: underline; color: #28a745;">
                    Link with underline (text-decoration: underline)
                </a>
                <br><br>
                <a href="#" style="text-decoration: underline wavy #dc3545; color: #dc3545;">
                    Link with wavy underline (text-decoration: underline wavy red)
                </a>
            </p>
        </div>

        <div class="code-block">
            /* Remove underline from links */
            a {
                text-decoration: none;
            }

            /* Custom link underline */
            a:hover {
                text-decoration: underline wavy #007bff;
            }
        </div>
    </section>

    <!-- ====== REFERENCE TABLES ====== -->
    <section>
        <h2>7. Reference Tables</h2>

        <h3>line-height Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value Type</th>
                <th>Example</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><strong>Number</strong></td>
                <td><code>1.5</code></td>
                <td>Multiplied by font size — <strong>recommended</strong></td>
            </tr>
            <tr>
                <td><strong>Length</strong></td>
                <td><code>24px</code></td>
                <td>Fixed pixel value</td>
            </tr>
            <tr>
                <td><strong>Percentage</strong></td>
                <td><code>150%</code></td>
                <td>Percentage of font size</td>
            </tr>
            <tr>
                <td><strong>Keyword</strong></td>
                <td><code>normal</code></td>
                <td>Browser default (~1.2)</td>
            </tr>
        </table>

        <h3>text-decoration Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>No decoration (default)</td>
                <td><code>text-decoration: none;</code></td>
            </tr>
            <tr>
                <td><code>underline</code></td>
                <td>Line below the text</td>
                <td><code>text-decoration: underline;</code></td>
            </tr>
            <tr>
                <td><code>overline</code></td>
                <td>Line above the text</td>
                <td><code>text-decoration: overline;</code></td>
            </tr>
            <tr>
                <td><code>line-through</code></td>
                <td>Line through the text</td>
                <td><code>text-decoration: line-through;</code></td>
            </tr>
            <tr>
                <td><code>underline overline</code></td>
                <td>Multiple decorations</td>
                <td><code>text-decoration: underline overline;</code></td>
            </tr>
        </table>

        <h3>text-decoration Styles</h3>
        <table class="reference-table">
            <tr>
                <th>Style</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>solid</code></td>
                <td>Single solid line (default)</td>
                <td><code>text-decoration: underline solid red;</code></td>
            </tr>
            <tr>
                <td><code>dotted</code></td>
                <td>Dotted line</td>
                <td><code>text-decoration: underline dotted blue;</code></td>
            </tr>
            <tr>
                <td><code>dashed</code></td>
                <td>Dashed line</td>
                <td><code>text-decoration: underline dashed green;</code></td>
            </tr>
            <tr>
                <td><code>wavy</code></td>
                <td>Wavy line</td>
                <td><code>text-decoration: underline wavy purple;</code></td>
            </tr>
            <tr>
                <td><code>double</code></td>
                <td>Double line</td>
                <td><code>text-decoration: underline double orange;</code></td>
            </tr>
        </table>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionCommon Values
line-heightSpace between lines1.5, 1.6, 24px, 150%, normal
text-decorationAdds decoration to textnone, underline, overline, line-through
text-decoration-styleStyle of the decorationsolid, dotted, dashed, wavy, double
text-decoration-colorColor of the decorationred, #ff0000, rgb(255,0,0)

Best Practices

Do This:

/* Use unitless values for line-height */
body {
    line-height: 1.6;  /* Recommended for body text */
}

/* Use line-height for headings */
h1 { line-height: 1.2; }
h2 { line-height: 1.3; }
p  { line-height: 1.6; }

/* Remove underline from links when not needed */
a { text-decoration: none; }

/* Add custom underline on hover */
a:hover { text-decoration: underline; }

Don’t Do This:

/* Don't use fixed pixel line-height for body text */
body { line-height: 24px; }  /* Use unitless instead */

/* Don't use line-height: normal for body text (too tight) */
body { line-height: normal; }  /* ~1.2 is too tight for readability */

/* Don't overuse text-decoration */
text-decoration: underline;  /* Use sparingly for emphasis */

Pro Tip: Use unitless numbers for line-height (e.g., 1.6) because they scale with the font size and work well with inheritance. For body text, 1.6 is often considered optimal for readability. For headings, tighter values like 1.21.3 work better. Use text-decoration sparingly — underline for links, overline for headings, and line-through for deleted content!

8. text-align, letter-spacing, word-spacing, and text-transform

These CSS properties control the alignment, spacing, and case transformation of text, helping you create visually appealing and well-structured content.


Overview of Properties

PropertyDescriptionCommon Values
text-alignAligns text horizontally within its parentleft, center, right, justify
letter-spacingSets space between charactersnormal, 2px, 0.1em
word-spacingSets space between wordsnormal, 4px, 0.2em
text-transformTransforms text casenone, uppercase, lowercase, capitalize

1. text-align

The text-align property specifies how text is aligned horizontally within its parent element.

/* Left-aligned */
div.left-aligned {
    text-align: left;
}

/* Center-aligned */
div.center-aligned {
    text-align: center;
}

/* Right-aligned */
div.right-aligned {
    text-align: right;
}

/* Justified (spread across the line) */
div.justified {
    text-align: justify;
}

Values

ValueDescriptionExample
leftAligns text to the left (default for LTR languages)text-align: left;
centerCenters texttext-align: center;
rightAligns text to the righttext-align: right;
justifySpreads text across the full line widthtext-align: justify;
startAligns to the start of the text directiontext-align: start;
endAligns to the end of the text directiontext-align: end;

2. letter-spacing

The letter-spacing property sets the space between characters in a text.

/* Normal spacing (default) */
p.normal-spacing {
    letter-spacing: normal;
}

/* Expanded spacing */
p.expanded-spacing {
    letter-spacing: 2px;
}

/* Tight spacing */
p.tight-spacing {
    letter-spacing: -1px;
}

/* Relative spacing */
p.relative-spacing {
    letter-spacing: 0.1em;
}

Values

ValueDescriptionExample
normalDefault spacing (browser default)letter-spacing: normal;
lengthFixed or relative spacingletter-spacing: 2px;
negativeTighter spacingletter-spacing: -1px;

3. word-spacing

The word-spacing property sets the space between words in a text.

/* Normal spacing (default) */
p.normal-spacing {
    word-spacing: normal;
}

/* Expanded spacing */
p.expanded-spacing {
    word-spacing: 4px;
}

/* Relative spacing */
p.relative-spacing {
    word-spacing: 0.2em;
}

Values

ValueDescriptionExample
normalDefault spacing (browser default)word-spacing: normal;
lengthFixed or relative spacingword-spacing: 4px;

4. text-transform

The text-transform property changes the case of text.

/* All uppercase */
p.uppercase {
    text-transform: uppercase;
}

/* All lowercase */
p.lowercase {
    text-transform: lowercase;
}

/* Capitalize first letter of each word */
p.capitalize {
    text-transform: capitalize;
}

/* Original case (default) */
p.none {
    text-transform: none;
}

Values

ValueDescriptionExample
noneOriginal case (default)text-transform: none;
uppercaseAll letters in uppercasetext-transform: uppercase;
lowercaseAll letters in lowercasetext-transform: lowercase;
capitalizeFirst letter of each word capitalizedtext-transform: capitalize;

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>text-align, letter-spacing, word-spacing, text-transform</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .demo-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border: 2px solid #ddd;
            background: #f8f9fa;
        }

        .demo-box.bordered {
            border: 2px solid #ddd;
            width: 70%;
        }

        .grid-2 {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== TEXT ALIGN DEMOS ====== */
        .ta-left {
            text-align: left;
        }

        .ta-center {
            text-align: center;
        }

        .ta-right {
            text-align: right;
        }

        .ta-justify {
            text-align: justify;
        }

        /* ====== LETTER SPACING DEMOS ====== */
        .ls-normal {
            letter-spacing: normal;
        }

        .ls-expanded {
            letter-spacing: 2px;
        }

        .ls-tight {
            letter-spacing: -1px;
        }

        .ls-wide {
            letter-spacing: 4px;
        }

        /* ====== WORD SPACING DEMOS ====== */
        .ws-normal {
            word-spacing: normal;
        }

        .ws-expanded {
            word-spacing: 4px;
        }

        .ws-wide {
            word-spacing: 8px;
        }

        /* ====== TEXT TRANSFORM DEMOS ====== */
        .tt-uppercase {
            text-transform: uppercase;
        }

        .tt-lowercase {
            text-transform: lowercase;
        }

        .tt-capitalize {
            text-transform: capitalize;
        }
    </style>
</head>
<body>

    <h1>text-align, letter-spacing, word-spacing, text-transform</h1>

    <!-- ====== 1. TEXT ALIGN ====== -->
    <section>
        <h2>1. text-align</h2>

        <div class="demo-box bordered ta-left">
            <strong>text-align: left</strong><br>
            This text is left-aligned within the div.
        </div>

        <div class="demo-box bordered ta-center" style="width: 70%; margin: 10px auto;">
            <strong>text-align: center</strong><br>
            This text is centered within the div.
        </div>

        <div class="demo-box bordered ta-right">
            <strong>text-align: right</strong><br>
            This text is right-aligned within the div.
        </div>

        <div class="demo-box bordered ta-justify">
            <strong>text-align: justify</strong><br>
            This text is justified — it is spread across the full line width. The browser adds extra space between words so that both the left and right edges of the text align with the container's edges.
        </div>

        <div class="code-block">
            text-align: left;    /* Aligns text to the left (default) */
            text-align: center;  /* Centers text */
            text-align: right;   /* Aligns text to the right */
            text-align: justify; /* Spreads text across the full line */
        </div>
    </section>

    <!-- ====== 2. LETTER SPACING ====== -->
    <section>
        <h2>2. letter-spacing</h2>

        <div class="grid-2">
            <div class="demo-box ls-normal">
                <strong>letter-spacing: normal</strong><br>
                This text has normal letter spacing.
            </div>

            <div class="demo-box ls-expanded">
                <strong>letter-spacing: 2px</strong><br>
                This text has expanded letter spacing.
            </div>

            <div class="demo-box ls-wide">
                <strong>letter-spacing: 4px</strong><br>
                This text has wide letter spacing.
            </div>

            <div class="demo-box ls-tight">
                <strong>letter-spacing: -1px</strong><br>
                This text has tight letter spacing.
            </div>
        </div>

        <div class="code-block">
            letter-spacing: normal;  /* Default */
            letter-spacing: 2px;     /* Expanded spacing */
            letter-spacing: 4px;     /* Wide spacing */
            letter-spacing: -1px;    /* Tight spacing */
        </div>
    </section>

    <!-- ====== 3. WORD SPACING ====== -->
    <section>
        <h2>3. word-spacing</h2>

        <div class="grid-2">
            <div class="demo-box ws-normal">
                <strong>word-spacing: normal</strong><br>
                This text has normal word spacing between words.
            </div>

            <div class="demo-box ws-expanded">
                <strong>word-spacing: 4px</strong><br>
                This text has expanded word spacing between words.
            </div>

            <div class="demo-box ws-wide">
                <strong>word-spacing: 8px</strong><br>
                This text has wide word spacing between words.
            </div>
        </div>

        <div class="code-block">
            word-spacing: normal;  /* Default */
            word-spacing: 4px;     /* Expanded word spacing */
            word-spacing: 8px;     /* Wide word spacing */
        </div>
    </section>

    <!-- ====== 4. TEXT TRANSFORM ====== -->
    <section>
        <h2>4. text-transform</h2>

        <div class="grid-2">
            <div class="demo-box tt-uppercase">
                <strong>text-transform: uppercase</strong><br>
                This text is in uppercase.
            </div>

            <div class="demo-box tt-lowercase">
                <strong>text-transform: lowercase</strong><br>
                THIS TEXT IS IN LOWERCASE.
            </div>

            <div class="demo-box tt-capitalize">
                <strong>text-transform: capitalize</strong><br>
                this text is capitalized. (first letter of each word)
            </div>

            <div class="demo-box" style="text-transform: none;">
                <strong>text-transform: none</strong><br>
                This text retains its original case.
            </div>
        </div>

        <div class="code-block">
            text-transform: uppercase;  /* ALL CAPS */
            text-transform: lowercase;  /* all lowercase */
            text-transform: capitalize; /* First Letter Of Each Word Capitalized */
            text-transform: none;       /* Original case (default) */
        </div>
    </section>

    <!-- ====== 5. COMBINED EXAMPLES ====== -->
    <section>
        <h2>5. Combined Examples</h2>

        <div class="demo-box" style="text-align: center; letter-spacing: 2px; text-transform: uppercase; color: #007bff;">
            <strong>Combined: center + letter-spacing: 2px + uppercase</strong><br>
            This text is centered, has expanded letter spacing, and is in uppercase.
        </div>

        <div class="demo-box" style="text-align: justify; word-spacing: 6px; letter-spacing: 0.5px; text-transform: capitalize;">
            <strong>Combined: justify + word-spacing: 6px + capitalize</strong><br>
            this text is justified, has wide word spacing, and each word is capitalized.
        </div>

        <div class="demo-box" style="text-align: right; letter-spacing: -0.5px; word-spacing: 2px; text-transform: lowercase; color: #28a745;">
            <strong>Combined: right + tight letter-spacing + lowercase</strong><br>
            THIS TEXT IS RIGHT-ALIGNED, HAS TIGHT LETTER SPACING, AND IS IN LOWERCASE.
        </div>
    </section>

    <!-- ====== REFERENCE TABLES ====== -->
    <section>
        <h2>6. Reference Tables</h2>

        <h3>text-align Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>left</code></td>
                <td>Aligns text to the left (default for LTR languages)</td>
                <td><code>text-align: left;</code></td>
            </tr>
            <tr>
                <td><code>center</code></td>
                <td>Centers text</td>
                <td><code>text-align: center;</code></td>
            </tr>
            <tr>
                <td><code>right</code></td>
                <td>Aligns text to the right</td>
                <td><code>text-align: right;</code></td>
            </tr>
            <tr>
                <td><code>justify</code></td>
                <td>Spreads text across the full line</td>
                <td><code>text-align: justify;</code></td>
            </tr>
            <tr>
                <td><code>start</code></td>
                <td>Aligns to the start of the text direction</td>
                <td><code>text-align: start;</code></td>
            </tr>
            <tr>
                <td><code>end</code></td>
                <td>Aligns to the end of the text direction</td>
                <td><code>text-align: end;</code></td>
            </tr>
        </table>

        <h3>letter-spacing Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>normal</code></td>
                <td>Default spacing</td>
                <td><code>letter-spacing: normal;</code></td>
            </tr>
            <tr>
                <td><code>length</code></td>
                <td>Fixed spacing (px, em, etc.)</td>
                <td><code>letter-spacing: 2px;</code></td>
            </tr>
            <tr>
                <td><code>negative</code></td>
                <td>Tighter spacing</td>
                <td><code>letter-spacing: -1px;</code></td>
            </tr>
        </table>

        <h3>word-spacing Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>normal</code></td>
                <td>Default spacing</td>
                <td><code>word-spacing: normal;</code></td>
            </tr>
            <tr>
                <td><code>length</code></td>
                <td>Fixed spacing (px, em, etc.)</td>
                <td><code>word-spacing: 4px;</code></td>
            </tr>
        </table>

        <h3>text-transform Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>Original case (default)</td>
                <td><code>text-transform: none;</code></td>
            </tr>
            <tr>
                <td><code>uppercase</code></td>
                <td>All letters in uppercase</td>
                <td><code>text-transform: uppercase;</code></td>
            </tr>
            <tr>
                <td><code>lowercase</code></td>
                <td>All letters in lowercase</td>
                <td><code>text-transform: lowercase;</code></td>
            </tr>
            <tr>
                <td><code>capitalize</code></td>
                <td>First letter of each word capitalized</td>
                <td><code>text-transform: capitalize;</code></td>
            </tr>
        </table>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionCommon Values
text-alignAligns text horizontallyleft, center, right, justify
letter-spacingSpace between charactersnormal, 2px, -1px
word-spacingSpace between wordsnormal, 4px
text-transformTransforms text casenone, uppercase, lowercase, capitalize

Best Practices

Do This:

/* Use justify for large text blocks */
.article {
    text-align: justify;
}

/* Use center for headings and short text */
h1 { text-align: center; }

/* Use letter-spacing for headings */
h1 { letter-spacing: 2px; }

/* Use uppercase for emphasis */
.important { text-transform: uppercase; }

Don’t Do This:

/* Don't center large blocks of text */
.long-text { text-align: center; }  /* Hard to read */

/* Don't use excessive letter-spacing */
p { letter-spacing: 5px; }  /* Makes text hard to read */

/* Don't use uppercase for long text */
.long-text { text-transform: uppercase; }  /* Hard to read */

Pro Tip: Use text-align: justify for long articles and columns to create clean edges, but be mindful that it can create awkward gaps. For headings, use letter-spacing to give them a more refined look. Use text-transform sparingly — uppercase is great for buttons and headings, but hard to read in long paragraphs!

9. text-indent, vertical-align, text-align-last, direction

These CSS properties control the indentation, vertical alignment, last-line alignment, and text direction of elements, offering fine-grained control over text layout and readability.


Overview of Properties

PropertyDescriptionCommon Values
text-indentIndents the first line of a block element40px, 2em, 10%
vertical-alignAligns inline/inline-block elements verticallybaseline, middle, top, bottom
text-align-lastAligns the last line of text in a blockleft, center, right, justify
directionSets text direction (LTR or RTL)ltr, rtl

1. text-indent

The text-indent property controls the indentation of the first line of a block-level element.

p.indented {
    text-indent: 40px; /* Indent first line by 40px */
}

p.no-indent {
    text-indent: 0; /* No indentation */
}

p.relative-indent {
    text-indent: 2em; /* Indent by 2 × font size */
}

p.percentage-indent {
    text-indent: 10%; /* Indent by 10% of parent width */
}

Values

ValueDescriptionExample
lengthFixed indentationtext-indent: 40px;
percentagePercentage of parent widthtext-indent: 10%;
0 / noneNo indentationtext-indent: 0;

2. vertical-align

The vertical-align property aligns inline, inline-block, and table-cell elements vertically within their parent.

.container {
    vertical-align: middle; /* Centers content vertically */
}

.inline {
    display: inline-block;
    vertical-align: middle; /* Aligns inline-block elements */
}

/* Different alignment values */
.top-align {
    vertical-align: top;
}

.bottom-align {
    vertical-align: bottom;
}

.baseline-align {
    vertical-align: baseline; /* Default */
}

Values

ValueDescriptionExample
baselineAligns to the baseline (default)vertical-align: baseline;
topAligns to the top of the parentvertical-align: top;
bottomAligns to the bottom of the parentvertical-align: bottom;
middleCenters verticallyvertical-align: middle;
text-topAligns to the top of the textvertical-align: text-top;
text-bottomAligns to the bottom of the textvertical-align: text-bottom;
subAligns as subscriptvertical-align: sub;
superAligns as superscriptvertical-align: super;

3. text-align-last

The text-align-last property controls the alignment of the last line of text in a block-level element.

p.left-aligned-last {
    text-align: justify;
    text-align-last: left; /* Last line aligned left */
}

p.right-aligned-last {
    text-align: justify;
    text-align-last: right; /* Last line aligned right */
}

p.center-aligned-last {
    text-align: justify;
    text-align-last: center; /* Last line centered */
}

Values

ValueDescriptionExample
leftAligns the last line to the lefttext-align-last: left;
centerCenters the last linetext-align-last: center;
rightAligns the last line to the righttext-align-last: right;
justifyJustifies the last linetext-align-last: justify;
startAligns to the start of the text directiontext-align-last: start;
endAligns to the end of the text directiontext-align-last: end;

4. direction

The direction property sets the text direction within a block-level element.

div.ltr {
    direction: ltr; /* Left-to-right (default for English) */
}

div.rtl {
    direction: rtl; /* Right-to-left (for Arabic, Hebrew) */
}

Values

ValueDescriptionExample
ltrLeft-to-right (default)direction: ltr;
rtlRight-to-leftdirection: rtl;

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>text-indent, vertical-align, text-align-last, direction</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .demo-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
        }

        .demo-box.bordered {
            border: 2px solid #ddd;
        }

        .grid-2 {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== TEXT INDENT DEMOS ====== */
        .ti-40px {
            text-indent: 40px;
        }

        .ti-2em {
            text-indent: 2em;
        }

        .ti-10p {
            text-indent: 10%;
        }

        .ti-none {
            text-indent: 0;
        }

        /* ====== VERTICAL ALIGN DEMOS ====== */
        .va-container {
            border: 2px solid #ddd;
            padding: 15px;
            height: 80px;
            background: #f8f9fa;
            border-radius: 8px;
            margin: 10px 0;
        }

        .va-container .va-child {
            display: inline-block;
            background: #007bff;
            color: white;
            padding: 5px 10px;
            border-radius: 4px;
            margin: 0 5px;
        }

        .va-top .va-child {
            vertical-align: top;
        }

        .va-middle .va-child {
            vertical-align: middle;
        }

        .va-bottom .va-child {
            vertical-align: bottom;
        }

        .va-baseline .va-child {
            vertical-align: baseline;
        }

        .va-text-top .va-child {
            vertical-align: text-top;
        }

        .va-text-bottom .va-child {
            vertical-align: text-bottom;
        }

        /* ====== TEXT ALIGN LAST DEMOS ====== */
        .tal-left {
            text-align: justify;
            text-align-last: left;
        }

        .tal-center {
            text-align: justify;
            text-align-last: center;
        }

        .tal-right {
            text-align: justify;
            text-align-last: right;
        }

        .tal-justify {
            text-align: justify;
            text-align-last: justify;
        }

        /* ====== DIRECTION DEMOS ====== */
        .dir-ltr {
            direction: ltr;
        }

        .dir-rtl {
            direction: rtl;
        }

        .dir-rtl p {
            text-align: right;
        }
    </style>
</head>
<body>

    <h1>text-indent, vertical-align, text-align-last, direction</h1>

    <!-- ====== 1. TEXT INDENT ====== -->
    <section>
        <h2>1. text-indent</h2>

        <div class="demo-box bordered ti-40px">
            <strong>text-indent: 40px</strong><br>
            This paragraph has a left indentation of 40 pixels. The first line is indented to create a traditional paragraph style commonly used in books and articles.
        </div>

        <div class="demo-box bordered ti-2em">
            <strong>text-indent: 2em</strong><br>
            This paragraph has an indentation of 2em (2 × the current font size), making it relative to the text size.
        </div>

        <div class="demo-box bordered ti-10p">
            <strong>text-indent: 10%</strong><br>
            This paragraph has an indentation of 10% of the parent container's width, making it responsive to the container size.
        </div>

        <div class="demo-box bordered ti-none">
            <strong>text-indent: 0 (no indent)</strong><br>
            This paragraph does not have any indentation. The first line starts exactly at the left edge of the container.
        </div>

        <div class="code-block">
            text-indent: 40px;  /* Fixed indentation */
            text-indent: 2em;   /* Relative to font size */
            text-indent: 10%;   /* Percentage of parent width */
            text-indent: 0;     /* No indentation */
        </div>
    </section>

    <!-- ====== 2. VERTICAL ALIGN ====== -->
    <section>
        <h2>2. vertical-align</h2>

        <h3>top vs middle vs bottom</h3>
        <div class="va-container va-top">
            <span class="va-child" style="height: 30px;">top</span>
            <span class="va-child" style="height: 30px;">top</span>
            <span style="display: inline-block; font-size: 14px;">All aligned <strong>top</strong></span>
        </div>

        <div class="va-container va-middle">
            <span class="va-child" style="height: 30px;">middle</span>
            <span class="va-child" style="height: 30px;">middle</span>
            <span style="display: inline-block; font-size: 14px;">All aligned <strong>middle</strong></span>
        </div>

        <div class="va-container va-bottom">
            <span class="va-child" style="height: 30px;">bottom</span>
            <span class="va-child" style="height: 30px;">bottom</span>
            <span style="display: inline-block; font-size: 14px;">All aligned <strong>bottom</strong></span>
        </div>

        <h3>baseline vs text-top vs text-bottom</h3>
        <div class="va-container va-baseline">
            <span class="va-child" style="height: 30px;">baseline</span>
            <span style="display: inline-block; font-size: 24px;">Big Text</span>
            <span class="va-child" style="height: 30px;">baseline</span>
            <span style="display: inline-block; font-size: 14px;">Aligned to <strong>baseline</strong></span>
        </div>

        <div class="va-container va-text-top">
            <span class="va-child" style="height: 30px;">text-top</span>
            <span style="display: inline-block; font-size: 24px;">Big Text</span>
            <span class="va-child" style="height: 30px;">text-top</span>
            <span style="display: inline-block; font-size: 14px;">Aligned to <strong>text-top</strong></span>
        </div>

        <div class="va-container va-text-bottom">
            <span class="va-child" style="height: 30px;">text-bottom</span>
            <span style="display: inline-block; font-size: 24px;">Big Text</span>
            <span class="va-child" style="height: 30px;">text-bottom</span>
            <span style="display: inline-block; font-size: 14px;">Aligned to <strong>text-bottom</strong></span>
        </div>

        <div class="code-block">
            vertical-align: top;          /* Aligns to the top */
            vertical-align: middle;       /* Centers vertically */
            vertical-align: bottom;       /* Aligns to the bottom */
            vertical-align: baseline;     /* Aligns to the baseline (default) */
            vertical-align: text-top;     /* Aligns to the top of the text */
            vertical-align: text-bottom;  /* Aligns to the bottom of the text */
        </div>
    </section>

    <!-- ====== 3. TEXT ALIGN LAST ====== -->
    <section>
        <h2>3. text-align-last</h2>

        <div class="grid-2">
            <div class="demo-box bordered tal-left">
                <strong>text-align-last: left</strong><br>
                This paragraph is justified, but the last line is aligned to the left. It's quite long and has a bunch of words to demonstrate how this property works. The last line will be left-aligned while the rest are justified.
            </div>

            <div class="demo-box bordered tal-center">
                <strong>text-align-last: center</strong><br>
                This paragraph is justified, but the last line is centered. It's quite long and has a bunch of words to demonstrate how this property works. The last line will be centered while the rest are justified.
            </div>

            <div class="demo-box bordered tal-right">
                <strong>text-align-last: right</strong><br>
                This paragraph is justified, but the last line is aligned to the right. It's quite long and has a bunch of words to demonstrate how this property works. The last line will be right-aligned while the rest are justified.
            </div>

            <div class="demo-box bordered tal-justify">
                <strong>text-align-last: justify</strong><br>
                This paragraph is justified, and the last line is also justified. It's quite long and has a bunch of words to demonstrate how this property works. The last line is spread across the full width.
            </div>
        </div>

        <div class="code-block">
            text-align-last: left;     /* Last line aligned left */
            text-align-last: center;   /* Last line centered */
            text-align-last: right;    /* Last line aligned right */
            text-align-last: justify;  /* Last line justified */
        </div>
    </section>

    <!-- ====== 4. DIRECTION ====== -->
    <section>
        <h2>4. direction</h2>

        <div class="grid-2">
            <div class="demo-box bordered dir-ltr">
                <strong>direction: ltr (Left-to-Right)</strong><br>
                This is a left-to-right language (e.g., English) block. The text reads from left to right, which is the default direction for most languages.
            </div>

            <div class="demo-box bordered dir-rtl">
                <strong>direction: rtl (Right-to-Left)</strong><br>
                هذا هو نص من اليمين إلى اليسار (مثل العربية أو العبرية). يتم محاذاة النص إلى اليمين ويقرأ من اليمين إلى اليسار.
                <br><br>
                <span style="font-size: 0.9rem; color: #6c757d;">
                    (This is right-to-left text, like Arabic or Hebrew. It is aligned to the right and reads from right to left.)
                </span>
            </div>
        </div>

        <div class="code-block">
            direction: ltr;  /* Left-to-right (default for English) */
            direction: rtl;  /* Right-to-left (for Arabic, Hebrew) */
        </div>
    </section>

    <!-- ====== 5. COMBINED EXAMPLES ====== -->
    <section>
        <h2>5. Combined Examples</h2>

        <div class="demo-box bordered" style="text-indent: 2em; text-align: justify; text-align-last: center; direction: ltr;">
            <strong>Combined: text-indent: 2em + text-align: justify + text-align-last: center</strong><br>
            This paragraph combines multiple text formatting properties. The first line is indented, the text is justified, and the last line is centered. This creates a unique and visually interesting layout.
        </div>

        <div class="demo-box bordered dir-rtl" style="text-indent: 2em; text-align: justify; text-align-last: center;">
            <strong>Combined: RTL + text-indent + justify</strong><br>
            هذا النص يجمع بين الاتجاه من اليمين إلى اليسار مع المسافة البادئة والتبرير والمحاذاة المركزية للسطر الأخير. هذا يوضح كيف تعمل هذه الخصائص معًا في اللغات ذات الاتجاه المختلف.
            <br><br>
            <span style="font-size: 0.9rem; color: #6c757d; direction: ltr;">
                (This text combines RTL direction with indentation, justification, and centered last-line alignment.)
            </span>
        </div>
    </section>

    <!-- ====== REFERENCE TABLES ====== -->
    <section>
        <h2>6. Reference Tables</h2>

        <h3>text-indent Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>length</code></td>
                <td>Fixed indentation (px, em, etc.)</td>
                <td><code>text-indent: 40px;</code></td>
            </tr>
            <tr>
                <td><code>percentage</code></td>
                <td>Percentage of parent width</td>
                <td><code>text-indent: 10%;</code></td>
            </tr>
            <tr>
                <td><code>0</code></td>
                <td>No indentation</td>
                <td><code>text-indent: 0;</code></td>
            </tr>
        </table>

        <h3>vertical-align Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>baseline</code></td>
                <td>Aligns to the baseline (default)</td>
                <td><code>vertical-align: baseline;</code></td>
            </tr>
            <tr>
                <td><code>top</code></td>
                <td>Aligns to the top</td>
                <td><code>vertical-align: top;</code></td>
            </tr>
            <tr>
                <td><code>middle</code></td>
                <td>Centers vertically</td>
                <td><code>vertical-align: middle;</code></td>
            </tr>
            <tr>
                <td><code>bottom</code></td>
                <td>Aligns to the bottom</td>
                <td><code>vertical-align: bottom;</code></td>
            </tr>
            <tr>
                <td><code>text-top</code></td>
                <td>Aligns to the top of the text</td>
                <td><code>vertical-align: text-top;</code></td>
            </tr>
            <tr>
                <td><code>text-bottom</code></td>
                <td>Aligns to the bottom of the text</td>
                <td><code>vertical-align: text-bottom;</code></td>
            </tr>
            <tr>
                <td><code>sub</code></td>
                <td>Aligns as subscript</td>
                <td><code>vertical-align: sub;</code></td>
            </tr>
            <tr>
                <td><code>super</code></td>
                <td>Aligns as superscript</td>
                <td><code>vertical-align: super;</code></td>
            </tr>
        </table>

        <h3>text-align-last Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>left</code></td>
                <td>Last line aligned left</td>
                <td><code>text-align-last: left;</code></td>
            </tr>
            <tr>
                <td><code>center</code></td>
                <td>Last line centered</td>
                <td><code>text-align-last: center;</code></td>
            </tr>
            <tr>
                <td><code>right</code></td>
                <td>Last line aligned right</td>
                <td><code>text-align-last: right;</code></td>
            </tr>
            <tr>
                <td><code>justify</code></td>
                <td>Last line justified</td>
                <td><code>text-align-last: justify;</code></td>
            </tr>
        </table>

        <h3>direction Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>ltr</code></td>
                <td>Left-to-right (default)</td>
                <td><code>direction: ltr;</code></td>
            </tr>
            <tr>
                <td><code>rtl</code></td>
                <td>Right-to-left</td>
                <td><code>direction: rtl;</code></td>
            </tr>
        </table>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionCommon Values
text-indentIndents the first line of a block40px, 2em, 10%
vertical-alignAligns inline/inline-block elements verticallybaseline, middle, top, bottom
text-align-lastAligns the last line of a blockleft, center, right, justify
directionSets text directionltr, rtl

Best Practices

Do This:

/* Use text-indent for paragraphs in articles */
.article p {
    text-indent: 2em;
}

/* Use vertical-align: middle for icons next to text */
.icon {
    vertical-align: middle;
}

/* Use text-align-last for justified text blocks */
.justified-text {
    text-align: justify;
    text-align-last: left;
}

Don’t Do This:

/* Don't use text-indent for all paragraphs */
p { text-indent: 2em; }  /* May look odd for short paragraphs */

/* Don't use vertical-align for block elements */
div { vertical-align: middle; }  /* Only works for inline/inline-block */

/* Don't use direction: rtl without proper text */
.english { direction: rtl; }  /* Only use for RTL languages */

Pro Tip: Use text-indent to create traditional paragraph styles in long-form content. Use vertical-align: middle to align icons or small elements with text. Use text-align-last when working with justified text to control the appearance of the last line. Use direction: rtl only for languages that are naturally right-to-left, such as Arabic or Hebrew!

10. white-space, text-emphasis, and text-shadow

These CSS properties control the handling of whitespace, add emphasis marks to text, and create shadow effects for enhanced typography.


Overview of Properties

PropertyDescriptionCommon Values
white-spaceControls whitespace handling and wrappingnormal, nowrap, pre, pre-wrap, pre-line
text-emphasisAdds emphasis marks (shorthand for style + color)fill, before "•", filled double-circle #ffb703
text-shadowAdds shadow effects to text2px 2px 4px rgba(0,0,0,0.5)

1. white-space

The white-space property controls how whitespace characters (spaces, tabs, newlines) are handled within an element.

p.normal-white-space {
    white-space: normal; /* Default — wraps text, collapses spaces */
}

p.nowrap-white-space {
    white-space: nowrap; /* Prevents wrapping, collapses spaces */
}

p.pre-white-space {
    white-space: pre; /* Preserves spaces and line breaks, no wrapping */
}

p.preline-white-space {
    white-space: pre-line; /* Collapses spaces, preserves line breaks, wraps */
}

p.pre-wrap-white-space {
    white-space: pre-wrap; /* Preserves spaces and line breaks, wraps */
}

Values

ValueSpacesLine BreaksWrappingExample
normalCollapsesCollapsesWrapsDefault behavior
nowrapCollapsesCollapsesNo wrapSingle line text
prePreservesPreservesNo wrapLike <pre> tag
pre-wrapPreservesPreservesWrapsCode with line wrapping
pre-lineCollapsesPreservesWrapsPoetry or formatted text

2. text-emphasis

The text-emphasis property adds emphasis marks (dots, circles, symbols) to text. It’s a shorthand for text-emphasis-style and text-emphasis-color.

p.fill-emphasis {
    text-emphasis: fill; /* Default — filled dot emphasis */
}

p.before-emphasis {
    text-emphasis: before "•"; /* Mark placed before each word */
}

p.after-emphasis {
    text-emphasis: after "•"; /* Mark placed after each word */
}

p.emphasis-combined {
    text-emphasis: filled double-circle #ffb703; /* Style + color */
}

Syntax

text-emphasis: <style> [ <color> ] | before | after <string>

Values

ValueDescriptionExample
filledFilled dot (default)text-emphasis: filled;
openOpen dottext-emphasis: open;
filled sesameFilled sesame shapetext-emphasis: filled sesame;
open sesameOpen sesame shapetext-emphasis: open sesame;
beforePlaces mark before the texttext-emphasis: before "•";
afterPlaces mark after the texttext-emphasis: after "•";
stringCustom symboltext-emphasis: "★"
colorSets the colortext-emphasis: filled #ff6b6b;

3. text-shadow

The text-shadow property adds shadow effects to text. It accepts a comma-separated list of shadows.

p.default-shadow {
    text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}

p.custom-shadow {
    text-shadow: -2px -2px 4px rgba(0, 0, 0, 0.3), 
                 2px 2px 6px rgba(255, 255, 255, 0.7);
}

p.simple-shadow {
    text-shadow: 3px 6px; /* Uses default color and blur radius */
}

p.colored-shadow {
    text-shadow: blue 3px 6px; /* Sets color and offsets */
}

Syntax

text-shadow: <offset-x> <offset-y> <blur-radius> <color> | none

Values

ValueDescriptionExample
offset-xHorizontal shadow offset2px, -2px
offset-yVertical shadow offset2px, -2px
blur-radiusBlur radius (optional)4px
colorShadow color (optional)rgba(0,0,0,0.5)
noneNo shadowtext-shadow: none;

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>white-space, text-emphasis, text-shadow</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .demo-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border: 2px solid #ddd;
            background: #f8f9fa;
        }

        .grid-2 {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== WHITE SPACE DEMOS ====== */
        .ws-normal {
            white-space: normal;
        }

        .ws-nowrap {
            white-space: nowrap;
        }

        .ws-pre {
            white-space: pre;
        }

        .ws-pre-line {
            white-space: pre-line;
        }

        .ws-pre-wrap {
            white-space: pre-wrap;
        }

        /* ====== TEXT EMPHASIS DEMOS ====== */
        .te-fill {
            text-emphasis: fill;
        }

        .te-open {
            text-emphasis: open;
        }

        .te-sesame {
            text-emphasis: filled sesame;
        }

        .te-before {
            text-emphasis: before "•";
        }

        .te-after {
            text-emphasis: after "•";
        }

        .te-star {
            text-emphasis: "★";
        }

        .te-combined {
            text-emphasis: filled double-circle #ffb703;
        }

        /* ====== TEXT SHADOW DEMOS ====== */
        .ts-default {
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
        }

        .ts-custom {
            text-shadow: -2px -2px 4px rgba(0, 0, 0, 0.3), 
                         2px 2px 6px rgba(255, 255, 255, 0.7);
        }

        .ts-heavy {
            text-shadow: 0 0 10px rgba(0, 0, 0, 0.3), 
                         0 0 20px rgba(0, 0, 0, 0.2);
        }

        .ts-glow {
            text-shadow: 0 0 10px #007bff, 0 0 20px #007bff;
        }

        .ts-multiple {
            text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3),
                         2px 2px 4px rgba(0, 0, 0, 0.2),
                         3px 3px 6px rgba(0, 0, 0, 0.1);
        }

        .ts-neon {
            text-shadow: 0 0 5px #ff6b6b, 
                         0 0 15px #ff6b6b, 
                         0 0 30px #ff6b6b;
        }
    </style>
</head>
<body>

    <h1>white-space, text-emphasis, text-shadow</h1>

    <!-- ====== 1. WHITE SPACE ====== -->
    <section>
        <h2>1. white-space</h2>

        <div class="demo-box ws-normal">
            <strong>white-space: normal (default)</strong><br>
            This is some normal text with a bunch of spaces and words. Spaces are collapsed, and text wraps when needed.
        </div>

        <div class="demo-box ws-nowrap">
            <strong>white-space: nowrap</strong><br>
            This is some nowrap text, but the spaces are not preserved or wrapped. The text stays on a single line, and you can scroll to see the full content.
        </div>

        <div class="demo-box ws-pre">
            <strong>white-space: pre</strong><br>
            This is pre text,   which preserves both spaces and line breaks,
            but it doesn't wrap the text. Everything stays as written.
        </div>

        <div class="demo-box ws-pre-line">
            <strong>white-space: pre-line</strong><br>
            This is pre-line text, which preserves line breaks and wraps lines at word boundaries.
            Multiple spaces are collapsed into a single space. This is useful for poetry or formatted text.
        </div>

        <div class="demo-box ws-pre-wrap">
            <strong>white-space: pre-wrap</strong><br>
            This is pre-wrap text, which preserves both spaces and line breaks, and also wraps the text when needed.
            It combines the best of both pre and normal.
        </div>

        <div class="code-block">
            white-space: normal;     /* Default — wraps text, collapses spaces */
            white-space: nowrap;     /* Prevents wrapping, collapses spaces */
            white-space: pre;        /* Preserves spaces and line breaks, no wrapping */
            white-space: pre-line;   /* Collapses spaces, preserves line breaks, wraps */
            white-space: pre-wrap;   /* Preserves spaces and line breaks, wraps */
        </div>
    </section>

    <!-- ====== 2. TEXT EMPHASIS ====== -->
    <section>
        <h2>2. text-emphasis</h2>

        <div class="grid-2">
            <div class="demo-box te-fill">
                <strong>text-emphasis: fill</strong><br>
                This is some fill emphasis text with the default filled dot emphasis mark.
            </div>

            <div class="demo-box te-open">
                <strong>text-emphasis: open</strong><br>
                This is some open emphasis text with an open dot emphasis mark.
            </div>

            <div class="demo-box te-sesame">
                <strong>text-emphasis: filled sesame</strong><br>
                This is some sesame emphasis text with filled sesame marks.
            </div>

            <div class="demo-box te-before">
                <strong>text-emphasis: before "•"</strong><br>
                This is some before emphasis text with a bullet mark placed before each word.
            </div>

            <div class="demo-box te-after">
                <strong>text-emphasis: after "•"</strong><br>
                This is some after emphasis text with a bullet mark placed after each word.
            </div>

            <div class="demo-box te-star">
                <strong>text-emphasis: "★"</strong><br>
                This is some star emphasis text with a custom star symbol.
            </div>

            <div class="demo-box te-combined">
                <strong>text-emphasis: filled double-circle #ffb703</strong><br>
                This is some combined emphasis text with a filled double-circle style and custom color.
            </div>
        </div>

        <div class="code-block">
            text-emphasis: fill;                           /* Filled dot (default) */
            text-emphasis: open;                           /* Open dot */
            text-emphasis: filled sesame;                 /* Filled sesame marks */
            text-emphasis: before "•";                    /* Mark before each word */
            text-emphasis: after "•";                     /* Mark after each word */
            text-emphasis: "★";                           /* Custom symbol */
            text-emphasis: filled double-circle #ffb703;  /* Style + color */
        </div>
    </section>

    <!-- ====== 3. TEXT SHADOW ====== -->
    <section>
        <h2>3. text-shadow</h2>

        <div class="grid-2">
            <div class="demo-box ts-default" style="font-size: 1.2rem; font-weight: bold;">
                <strong>text-shadow: 2px 2px 4px rgba(0,0,0,0.5)</strong><br>
                Default shadow effect
            </div>

            <div class="demo-box ts-custom" style="font-size: 1.2rem; font-weight: bold;">
                <strong>text-shadow: -2px -2px 4px rgba(0,0,0,0.3), 2px 2px 6px rgba(255,255,255,0.7)</strong><br>
                Custom shadow with depth
            </div>

            <div class="demo-box ts-heavy" style="font-size: 1.2rem; font-weight: bold;">
                <strong>text-shadow: 0 0 10px rgba(0,0,0,0.3), 0 0 20px rgba(0,0,0,0.2)</strong><br>
                Heavy soft shadow
            </div>

            <div class="demo-box ts-glow" style="font-size: 1.2rem; font-weight: bold; color: #007bff;">
                <strong>text-shadow: 0 0 10px #007bff, 0 0 20px #007bff</strong><br>
                Glowing effect
            </div>

            <div class="demo-box ts-multiple" style="font-size: 1.2rem; font-weight: bold;">
                <strong>Multiple Shadows</strong><br>
                Three shadows for layered depth
            </div>

            <div class="demo-box ts-neon" style="font-size: 1.2rem; font-weight: bold; color: #ff6b6b;">
                <strong>text-shadow: 0 0 5px #ff6b6b, 0 0 15px #ff6b6b, 0 0 30px #ff6b6b</strong><br>
                Neon glow effect
            </div>
        </div>

        <div class="code-block">
            /* Basic shadow */
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);

            /* Multiple shadows */
            text-shadow: -2px -2px 4px rgba(0, 0, 0, 0.3),
                         2px 2px 6px rgba(255, 255, 255, 0.7);

            /* Glow effect */
            text-shadow: 0 0 10px #007bff, 0 0 20px #007bff;

            /* Neon effect */
            text-shadow: 0 0 5px #ff6b6b, 0 0 15px #ff6b6b, 0 0 30px #ff6b6b;
        </div>
    </section>

    <!-- ====== 4. COMBINED EXAMPLES ====== -->
    <section>
        <h2>4. Combined Examples</h2>

        <div class="demo-box" style="white-space: pre-wrap; text-emphasis: before "★"; text-shadow: 2px 2px 4px rgba(0,0,0,0.2);">
            <strong>Combined: pre-wrap + text-emphasis + text-shadow</strong><br>
            This text combines multiple properties: white-space: pre-wrap,
            text-emphasis: before "★", and a subtle text shadow.
            All working together for a unique style.
        </div>

        <div class="demo-box" style="white-space: nowrap; text-emphasis: after "•"; text-shadow: 0 0 10px rgba(0,123,255,0.3); font-size: 1.1rem;">
            <strong>Combined: nowrap + after emphasis + glow</strong><br>
            This text is nowrap with a subtle glow and emphasis marks after each word.
        </div>
    </section>

    <!-- ====== REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>white-space Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Spaces</th>
                <th>Line Breaks</th>
                <th>Wrapping</th>
            </tr>
            <tr>
                <td><code>normal</code></td>
                <td>Collapses</td>
                <td>Collapses</td>
                <td>Wraps</td>
            </tr>
            <tr>
                <td><code>nowrap</code></td>
                <td>Collapses</td>
                <td>Collapses</td>
                <td>No wrap</td>
            </tr>
            <tr>
                <td><code>pre</code></td>
                <td>Preserves</td>
                <td>Preserves</td>
                <td>No wrap</td>
            </tr>
            <tr>
                <td><code>pre-wrap</code></td>
                <td>Preserves</td>
                <td>Preserves</td>
                <td>Wraps</td>
            </tr>
            <tr>
                <td><code>pre-line</code></td>
                <td>Collapses</td>
                <td>Preserves</td>
                <td>Wraps</td>
            </tr>
        </table>

        <h3>text-emphasis Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>fill</code></td>
                <td>Filled dot (default)</td>
                <td><code>text-emphasis: fill;</code></td>
            </tr>
            <tr>
                <td><code>open</code></td>
                <td>Open dot</td>
                <td><code>text-emphasis: open;</code></td>
            </tr>
            <tr>
                <td><code>filled sesame</code></td>
                <td>Filled sesame shape</td>
                <td><code>text-emphasis: filled sesame;</code></td>
            </tr>
            <tr>
                <td><code>before "•"</code></td>
                <td>Mark before each word</td>
                <td><code>text-emphasis: before "•";</code></td>
            </tr>
            <tr>
                <td><code>after "•"</code></td>
                <td>Mark after each word</td>
                <td><code>text-emphasis: after "•";</code></td>
            </tr>
            <tr>
                <td><code>"string"</code></td>
                <td>Custom symbol</td>
                <td><code>text-emphasis: "★";</code></td>
            </tr>
        </table>

        <h3>text-shadow Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>offset-x offset-y blur-radius color</code></td>
                <td>Basic shadow</td>
                <td><code>text-shadow: 2px 2px 4px rgba(0,0,0,0.5);</code></td>
            </tr>
            <tr>
                <td><code>offset-x offset-y</code></td>
                <td>No blur, default color</td>
                <td><code>text-shadow: 3px 6px;</code></td>
            </tr>
            <tr>
                <td><code>color offset-x offset-y</code></td>
                <td>Color with offsets</td>
                <td><code>text-shadow: blue 3px 6px;</code></td>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>No shadow</td>
                <td><code>text-shadow: none;</code></td>
            </tr>
        </table>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionCommon Values
white-spaceControls whitespace handlingnormal, nowrap, pre, pre-wrap, pre-line
text-emphasisAdds emphasis marksfill, before "•", filled double-circle #ffb703
text-shadowAdds shadow effects2px 2px 4px rgba(0,0,0,0.5)

Best Practices

Do This:

/* Use white-space: pre for code blocks */
.code-block {
    white-space: pre-wrap;
}

/* Use text-shadow for headings and emphasis */
h1 {
    text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
}

/* Use text-emphasis for annotations */
.highlight {
    text-emphasis: before "★";
}

/* Use multiple text-shadows for depth */
.text-depth {
    text-shadow: 1px 1px 2px rgba(0,0,0,0.3),
                 2px 2px 4px rgba(0,0,0,0.2);
}

Don’t Do This:

/* Don't use nowrap for long paragraphs */
p { white-space: nowrap; }  /* May overflow the container */

/* Don't use text-shadow on large blocks of text */
p { text-shadow: 2px 2px 4px rgba(0,0,0,0.5); }  /* Can strain readability */

/* Don't overuse text-emphasis on long text */
p { text-emphasis: before "•"; }  /* Can be visually overwhelming */

Pro Tip: Use white-space: pre-wrap for code blocks to preserve formatting while allowing wrapping. Use text-shadow sparingly for headings, logos, or emphasis — too much shadow can hurt readability. text-emphasis is great for marking important words in educational or annotation contexts!

11. line-break and word-break Properties

These CSS properties control how text breaks across lines, making them essential for handling long words, URLs, or content in narrow containers.


Overview of Properties

PropertyDescriptionCommon Values
line-breakControls line-breaking behaviorauto, normal, loose, strict, anywhere
word-breakControls word-breaking behaviornormal, break-all, keep-all

1. line-break

The line-break property specifies how line breaks should be handled, particularly for CJK (Chinese, Japanese, Korean) text and punctuation.

p.line-break-auto {
    line-break: auto; /* Uses the default break rule */
}

p.line-break-normal {
    line-break: normal; /* Uses the most common break rule */
}

p.line-break-anywhere {
    line-break: anywhere; /* Breaks at any point in the text block */
}

p.line-break-loose {
    line-break: loose; /* Uses the least restrictive rule */
}

p.line-break-strict {
    line-break: strict; /* Uses the most stringent rule */
}

Values

ValueDescriptionExample
autoUses the default break rule (browser default)line-break: auto;
normalUses the most common break ruleline-break: normal;
looseUses the least restrictive ruleline-break: loose;
strictUses the most stringent ruleline-break: strict;
anywhereAllows line breaks at any point in the text blockline-break: anywhere;

2. word-break

The word-break property controls how words break when they reach the end of a line.

p.word-break-normal {
    word-break: normal; /* Default — breaks only at whitespace */
}

p.word-break-break-all {
    word-break: break-all; /* Breaks at any point in the text block */
}

p.word-break-keep-all {
    word-break: keep-all; /* Breaks only at whitespace, not in the middle */
}

Values

ValueDescriptionExample
normalDefault — words break only at whitespace charactersword-break: normal;
break-allWords can break at any point, even in the middle of a wordword-break: break-all;
keep-allWords break only at whitespace characters (not in the middle)word-break: keep-all;

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>line-break and word-break Properties</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1000px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .demo-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border: 2px solid #ddd;
            background: #f8f9fa;
            max-width: 400px;
        }

        .grid-2 {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
            gap: 20px;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== LINE BREAK DEMOS ====== */
        .lb-auto {
            line-break: auto;
        }

        .lb-normal {
            line-break: normal;
        }

        .lb-loose {
            line-break: loose;
        }

        .lb-strict {
            line-break: strict;
        }

        .lb-anywhere {
            line-break: anywhere;
        }

        /* ====== WORD BREAK DEMOS ====== */
        .wb-normal {
            word-break: normal;
        }

        .wb-break-all {
            word-break: break-all;
        }

        .wb-keep-all {
            word-break: keep-all;
        }

        .note {
            font-size: 0.85rem;
            color: #6c757d;
            margin-top: 5px;
        }
    </style>
</head>
<body>

    <h1>line-break and word-break Properties</h1>

    <!-- ====== 1. LINE BREAK ====== -->
    <section>
        <h2>1. line-break</h2>

        <p style="margin-bottom: 5px;">These examples are displayed in a container with <strong>max-width: 400px</strong> to show how line breaks behave.</p>

        <div class="grid-2">
            <div class="demo-box lb-auto">
                <strong>line-break: auto (default)</strong><br>
                This is a very long sentence without any specified line breaks. By default, the browser will break the word at spaces or punctuation marks to fit within the container width.
            </div>

            <div class="demo-box lb-normal">
                <strong>line-break: normal</strong><br>
                This is a very long sentence with irregular words and symbols like "--" and "-". By setting the <code>line-break: normal;</code> property, we can allow line breaks between words or within a word. However, it may not work as expected in all browsers.
            </div>

            <div class="demo-box lb-loose">
                <strong>line-break: loose</strong><br>
                This is a very long sentence with irregular words and symbols like "--" and "-". Using the least restrictive rule allows more flexible line breaks, especially for CJK text.
            </div>

            <div class="demo-box lb-strict">
                <strong>line-break: strict</strong><br>
                This is a very long sentence with irregular words and symbols like "--" and "-". Using the most stringent rule restricts line breaks, maintaining stricter formatting for CJK text.
            </div>

            <div class="demo-box lb-anywhere">
                <strong>line-break: anywhere</strong><br>
                This is a very long sentence without any spaces or punctuation marks and no line breaks are allowed. Setting <code>line-break: anywhere;</code> will allow line breaks at any point in the text block, but it may not work as expected in some browsers.
            </div>
        </div>

        <div class="code-block">
            line-break: auto;     /* Uses the default break rule */
            line-break: normal;   /* Uses the most common break rule */
            line-break: loose;    /* Uses the least restrictive rule */
            line-break: strict;   /* Uses the most stringent rule */
            line-break: anywhere; /* Allows line breaks at any point */
        </div>
    </section>

    <!-- ====== 2. WORD BREAK ====== -->
    <section>
        <h2>2. word-break</h2>

        <p style="margin-bottom: 5px;">These examples are displayed in a container with <strong>max-width: 400px</strong> to show how word breaks behave.</p>

        <div class="grid-2">
            <div class="demo-box wb-normal">
                <strong>word-break: normal (default)</strong><br>
                This is a very long sentence without any specified word breaks. By default, the browser will break the word at whitespace characters to fit within the container width.
            </div>

            <div class="demo-box wb-break-all">
                <strong>word-break: break-all</strong><br>
                This is a very long sentence with irregular words and symbols like "--" and "-". By setting the <code>word-break: break-all;</code> property, we can force words to break at any point in the text block, even in the middle of a word.
            </div>

            <div class="demo-box wb-keep-all">
                <strong>word-break: keep-all</strong><br>
                This is a very long sentence without any spaces or punctuation marks and no word breaks are allowed. Setting <code>word-break: keep-all;</code> will prevent words from breaking in the middle of a word.
            </div>
        </div>

        <div class="code-block">
            word-break: normal;     /* Default — breaks only at whitespace */
            word-break: break-all;  /* Words can break at any point */
            word-break: keep-all;   /* Words break only at whitespace */
        </div>
    </section>

    <!-- ====== 3. COMPARISON: line-break vs word-break ====== -->
    <section>
        <h2>3. Comparison: line-break vs word-break</h2>

        <div class="grid-2">
            <div class="demo-box" style="max-width: 400px;">
                <strong>line-break: anywhere</strong>
                <p style="line-break: anywhere; border: 1px solid #ddd; padding: 10px; border-radius: 4px; margin-top: 5px;">
                    This very long string of text with no spaces will break at any point because of line-break: anywhere.
                </p>
                <p class="note">Breaks at any point in the text block</p>
            </div>

            <div class="demo-box" style="max-width: 400px;">
                <strong>word-break: break-all</strong>
                <p style="word-break: break-all; border: 1px solid #ddd; padding: 10px; border-radius: 4px; margin-top: 5px;">
                    This very long string of text with no spaces will break at any point because of word-break: break-all.
                </p>
                <p class="note">Breaks words at any point</p>
            </div>
        </div>

        <div class="code-block">
            /* line-break affects line break behavior for punctuation and CJK */
            line-break: anywhere;

            /* word-break affects how words break within a line */
            word-break: break-all;
        </div>
    </section>

    <!-- ====== 4. REFERENCE TABLES ====== -->
    <section>
        <h2>4. Reference Tables</h2>

        <h3>line-break Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>auto</code></td>
                <td>Uses the default break rule (browser default)</td>
                <td><code>line-break: auto;</code></td>
            </tr>
            <tr>
                <td><code>normal</code></td>
                <td>Uses the most common break rule</td>
                <td><code>line-break: normal;</code></td>
            </tr>
            <tr>
                <td><code>loose</code></td>
                <td>Uses the least restrictive rule</td>
                <td><code>line-break: loose;</code></td>
            </tr>
            <tr>
                <td><code>strict</code></td>
                <td>Uses the most stringent rule</td>
                <td><code>line-break: strict;</code></td>
            </tr>
            <tr>
                <td><code>anywhere</code></td>
                <td>Allows line breaks at any point in the text block</td>
                <td><code>line-break: anywhere;</code></td>
            </tr>
        </table>

        <h3>word-break Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>normal</code></td>
                <td>Default — words break only at whitespace characters</td>
                <td><code>word-break: normal;</code></td>
            </tr>
            <tr>
                <td><code>break-all</code></td>
                <td>Words can break at any point, even in the middle of a word</td>
                <td><code>word-break: break-all;</code></td>
            </tr>
            <tr>
                <td><code>keep-all</code></td>
                <td>Words break only at whitespace characters (not in the middle)</td>
                <td><code>word-break: keep-all;</code></td>
            </tr>
        </table>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionCommon Values
line-breakControls line-breaking behaviorauto, normal, loose, strict, anywhere
word-breakControls word-breaking behaviornormal, break-all, keep-all

line-break vs word-break — When to Use Which

PropertyBest ForExample Use Case
line-breakControlling line breaks with punctuation and CJK textInternational websites with Chinese/Japanese/Korean content
word-break: break-allHandling long words or URLs in narrow containersCode blocks, URLs, user-generated content
word-break: keep-allPreventing mid-word breaksBrand names, proper nouns, headlines

Best Practices

Do This:

/* Handle long URLs in narrow containers */
.url {
    word-break: break-all;
}

/* Keep brand names intact */
.brand-name {
    word-break: keep-all;
}

/* For CJK text, use line-break */
.chinese-text {
    line-break: strict;
}

Don’t Do This:

/* Don't use break-all on body text */
body {
    word-break: break-all;  /* Makes text hard to read */
}

/* Don't use word-break when overflow-wrap is more appropriate */
/* Use overflow-wrap: break-word instead for better readability */

Pro Tip: Use word-break: break-all for code blocks, URLs, or user-generated content where long words might overflow. Use word-break: keep-all to preserve brand names and proper nouns. For general text, word-break: normal (the default) is usually the best choice. If you need to break long words, overflow-wrap: break-word often provides better readability than word-break: break-all!

12. text-combine-upright, text-underline-offset, text-underline-position, text-overflow

These CSS properties control character combination, underline positioning, and overflow handling for text, offering fine-grained control over typography and layout.


Overview of Properties

PropertyDescriptionCommon Values
text-combine-uprightCombines characters into a single upright glyphnone, all
text-underline-offsetSets the distance of the underlineauto, 2px, 0.2em, 10%
text-underline-positionSets the position of the underlineauto, under, left, right
text-overflowControls how hidden overflow is displayedclip, ellipsis

1. text-combine-upright

The text-combine-upright property controls how characters are combined into a single upright glyph — primarily used in vertical writing modes (e.g., for CJK text or numbers).

.text-combine-upright-none {
    text-combine-upright: none; /* Default — no combining */
}

.text-combine-upright-all {
    text-combine-upright: all; /* Combines all characters into one upright unit */
}

Values

ValueDescriptionExample
noneDefault — does not combine characterstext-combine-upright: none;
allCombines all characters in a word into one upright unittext-combine-upright: all;
digits <n>Combines up to N digitstext-combine-upright: digits 4;

Use case: In vertical Japanese text, numbers like “2024” can be combined into a single upright block instead of being rotated.


2. text-underline-offset

The text-underline-offset property sets the distance between the text and its underline.

.text-underline-offset-auto {
    text-decoration: underline;
    text-underline-offset: auto; /* Default — browser decides */
}

.text-underline-offset-2px {
    text-decoration: underline;
    text-underline-offset: 2px; /* Moves underline down by 2px */
}

.text-underline-offset-relative {
    text-decoration: underline;
    text-underline-offset: 0.2em; /* Relative to font size */
}

.text-underline-offset-percent {
    text-decoration: underline;
    text-underline-offset: 10%; /* Percentage of font size */
}

Values

ValueDescriptionExample
autoDefault — browser determines the offsettext-underline-offset: auto;
lengthFixed offset (px, em, rem)text-underline-offset: 2px;
percentagePercentage of font sizetext-underline-offset: 10%;

3. text-underline-position

The text-underline-position property specifies where the underline should appear.

.text-underline-position-auto {
    text-decoration: underline;
    text-underline-position: auto; /* Default — browser decides */
}

.text-underline-position-under {
    text-decoration: underline;
    text-underline-position: under; /* Below the text (avoids descenders) */
}

.text-underline-position-left {
    text-decoration: underline;
    text-underline-position: left; /* Left of the text (vertical writing) */
}

.text-underline-position-right {
    text-decoration: underline;
    text-underline-position: right; /* Right of the text (vertical writing) */
}

Values

ValueDescriptionExample
autoDefault — browser decidestext-underline-position: auto;
underPlaces underline below the text (avoids descenders)text-underline-position: under;
leftPlaces underline to the left (vertical writing)text-underline-position: left;
rightPlaces underline to the right (vertical writing)text-underline-position: right;

4. text-overflow

The text-overflow property controls how hidden content is displayed when it overflows its container. It only works with white-space: nowrap and a constrained width.

.overflow-clip {
    width: 100px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: clip; /* Cuts off the text */
}

.overflow-ellipsis {
    width: 100px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis; /* Shows "..." */
}

Values

ValueDescriptionExample
clipCuts off the text at the container edgetext-overflow: clip;
ellipsisShows “…” to indicate clipped texttext-overflow: ellipsis;
stringUses a custom string (e.g., “→”)text-overflow: "→";

Global Values (for all properties)

ValueDescription
inheritInherits the value from the parent element
initialSets the property to its default value
unsetInherits if possible, otherwise uses initial
revertReverts to the browser’s default styles
revert-layerReverts to the value in the previous cascade layer

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>text-combine-upright, text-underline-offset, text-underline-position, text-overflow</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.8;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .demo-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border: 2px solid #ddd;
            background: #f8f9fa;
        }

        .grid-2 {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== TEXT COMBINE UPRIGHT ====== */
        .tcu-none {
            text-combine-upright: none;
            writing-mode: vertical-rl;
            height: 200px;
            border: 1px solid #ddd;
            padding: 10px;
        }

        .tcu-all {
            text-combine-upright: all;
            writing-mode: vertical-rl;
            height: 200px;
            border: 1px solid #ddd;
            padding: 10px;
        }

        /* ====== UNDERLINE OFFSET ====== */
        .tuo-auto {
            text-decoration: underline;
            text-underline-offset: auto;
        }

        .tuo-2px {
            text-decoration: underline;
            text-underline-offset: 2px;
        }

        .tuo-6px {
            text-decoration: underline;
            text-underline-offset: 6px;
        }

        .tuo-em {
            text-decoration: underline;
            text-underline-offset: 0.3em;
        }

        /* ====== UNDERLINE POSITION ====== */
        .tup-auto {
            text-decoration: underline;
            text-underline-position: auto;
        }

        .tup-under {
            text-decoration: underline;
            text-underline-position: under;
        }

        .tup-left {
            text-decoration: underline;
            text-underline-position: left;
            writing-mode: vertical-rl;
            height: 150px;
            border: 1px solid #ddd;
            padding: 10px;
        }

        .tup-right {
            text-decoration: underline;
            text-underline-position: right;
            writing-mode: vertical-rl;
            height: 150px;
            border: 1px solid #ddd;
            padding: 10px;
        }

        /* ====== TEXT OVERFLOW ====== */
        .to-clip {
            width: 180px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: clip;
            border: 1px solid #ddd;
            padding: 5px;
            background: #f8f9fa;
            border-radius: 4px;
        }

        .to-ellipsis {
            width: 180px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            border: 1px solid #ddd;
            padding: 5px;
            background: #f8f9fa;
            border-radius: 4px;
        }

        .to-string {
            width: 180px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: "→";
            border: 1px solid #ddd;
            padding: 5px;
            background: #f8f9fa;
            border-radius: 4px;
        }

        .note {
            font-size: 0.85rem;
            color: #6c757d;
            margin-top: 5px;
        }
    </style>
</head>
<body>

    <h1>text-combine-upright, text-underline-offset, text-underline-position, text-overflow</h1>

    <!-- ====== 1. TEXT COMBINE UPRIGHT ====== -->
    <section>
        <h2>1. text-combine-upright</h2>

        <p>These examples use <code>writing-mode: vertical-rl</code> to demonstrate how characters can be combined in vertical text.</p>

        <div class="grid-2">
            <div>
                <div class="demo-box tcu-none">
                    <strong>text-combine-upright: none</strong><br>
                    <span style="font-size: 1.2rem;">2024</span> 年
                </div>
                <p class="note">Characters are not combined — each digit is separate.</p>
            </div>

            <div>
                <div class="demo-box tcu-all">
                    <strong>text-combine-upright: all</strong><br>
                    <span style="font-size: 1.2rem;">2024</span> 年
                </div>
                <p class="note">All characters combined into a single upright unit.</p>
            </div>
        </div>

        <div class="code-block">
            text-combine-upright: none;  /* Default — no combining */
            text-combine-upright: all;   /* Combines all characters */
            text-combine-upright: digits 4; /* Combines up to 4 digits */
        </div>
    </section>

    <!-- ====== 2. TEXT UNDERLINE OFFSET ====== -->
    <section>
        <h2>2. text-underline-offset</h2>

        <div class="grid-2">
            <div class="demo-box tuo-auto">
                <strong>text-underline-offset: auto</strong><br>
                This is a sample text with an automatically placed underline below it.
            </div>

            <div class="demo-box tuo-2px">
                <strong>text-underline-offset: 2px</strong><br>
                This is a sample text with the underline offset down by 2 pixels.
            </div>

            <div class="demo-box tuo-6px">
                <strong>text-underline-offset: 6px</strong><br>
                This is a sample text with the underline offset down by 6 pixels.
            </div>

            <div class="demo-box tuo-em">
                <strong>text-underline-offset: 0.3em</strong><br>
                This is a sample text with the underline offset relative to the font size.
            </div>
        </div>

        <div class="code-block">
            text-underline-offset: auto;   /* Default — browser decides */
            text-underline-offset: 2px;    /* Moves underline down by 2px */
            text-underline-offset: 6px;    /* Moves underline down by 6px */
            text-underline-offset: 0.3em;  /* Relative to font size */
        </div>
    </section>

    <!-- ====== 3. TEXT UNDERLINE POSITION ====== -->
    <section>
        <h2>3. text-underline-position</h2>

        <div class="grid-2">
            <div class="demo-box tup-auto">
                <strong>text-underline-position: auto</strong><br>
                This is a sample text with an automatically placed underline.
            </div>

            <div class="demo-box tup-under">
                <strong>text-underline-position: under</strong><br>
                This is a sample text with the underline below the text, avoiding descenders like g, j, p, q, y.
            </div>
        </div>

        <h3>Vertical Writing Modes</h3>
        <div class="grid-2">
            <div>
                <div class="demo-box tup-left">
                    <strong>text-underline-position: left</strong><br>
                    This text is in vertical writing mode with underline on the left.
                </div>
                <p class="note">Underline appears to the left of vertical text.</p>
            </div>

            <div>
                <div class="demo-box tup-right">
                    <strong>text-underline-position: right</strong><br>
                    This text is in vertical writing mode with underline on the right.
                </div>
                <p class="note">Underline appears to the right of vertical text.</p>
            </div>
        </div>

        <div class="code-block">
            text-underline-position: auto;   /* Default — browser decides */
            text-underline-position: under;  /* Below the text (avoids descenders) */
            text-underline-position: left;   /* Left of text (vertical writing) */
            text-underline-position: right;  /* Right of text (vertical writing) */
        </div>
    </section>

    <!-- ====== 4. TEXT OVERFLOW ====== -->
    <section>
        <h2>4. text-overflow</h2>

        <p><code>text-overflow</code> only works with <code>white-space: nowrap</code> and <code>overflow: hidden</code>.</p>

        <div class="grid-2">
            <div>
                <div class="to-clip">
                    <strong>text-overflow: clip</strong> — This text will be clipped.
                </div>
                <p class="note">Cuts off the text at the container edge.</p>
            </div>

            <div>
                <div class="to-ellipsis">
                    <strong>text-overflow: ellipsis</strong> — This text will show an ellipsis.
                </div>
                <p class="note">Shows "..." to indicate clipped text.</p>
            </div>

            <div>
                <div class="to-string">
                    <strong>text-overflow: "→"</strong> — This text will show an arrow.
                </div>
                <p class="note">Uses a custom string to indicate clipped text.</p>
            </div>
        </div>

        <div class="code-block">
            /* text-overflow only works with these conditions */
            .container {
                width: 200px;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: clip;      /* Cuts off the text */
                text-overflow: ellipsis;  /* Shows "..." */
                text-overflow: "→";       /* Custom string */
            }
        </div>
    </section>

    <!-- ====== 5. COMBINED EXAMPLE ====== -->
    <section>
        <h2>5. Combined Example</h2>

        <div class="demo-box" style="text-decoration: underline; text-underline-offset: 4px; text-underline-position: under;">
            <strong>Combined: underline + offset + position</strong><br>
            This text has an underline that is offset 4px below the text and positioned under (avoiding descenders).
        </div>

        <div class="demo-box" style="width: 250px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; border: 1px solid #ddd; padding: 8px; border-radius: 4px;">
            This is a long text that will be truncated with an ellipsis when it exceeds the container width.
        </div>

        <div class="code-block">
            /* Combined underline styling */
            text-decoration: underline;
            text-underline-offset: 4px;
            text-underline-position: under;

            /* Overflow with ellipsis */
            width: 250px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        </div>
    </section>

    <!-- ====== REFERENCE TABLES ====== -->
    <section>
        <h2>6. Reference Tables</h2>

        <h3>text-combine-upright Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>Default — does not combine characters</td>
                <td><code>text-combine-upright: none;</code></td>
            </tr>
            <tr>
                <td><code>all</code></td>
                <td>Combines all characters into one upright unit</td>
                <td><code>text-combine-upright: all;</code></td>
            </tr>
            <tr>
                <td><code>digits <n></code></td>
                <td>Combines up to N digits</td>
                <td><code>text-combine-upright: digits 4;</code></td>
            </tr>
        </table>

        <h3>text-underline-offset Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>auto</code></td>
                <td>Default — browser determines the offset</td>
                <td><code>text-underline-offset: auto;</code></td>
            </tr>
            <tr>
                <td><code>length</code></td>
                <td>Fixed offset (px, em, rem)</td>
                <td><code>text-underline-offset: 2px;</code></td>
            </tr>
            <tr>
                <td><code>percentage</code></td>
                <td>Percentage of font size</td>
                <td><code>text-underline-offset: 10%;</code></td>
            </tr>
        </table>

        <h3>text-underline-position Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>auto</code></td>
                <td>Default — browser decides</td>
                <td><code>text-underline-position: auto;</code></td>
            </tr>
            <tr>
                <td><code>under</code></td>
                <td>Places underline below the text (avoids descenders)</td>
                <td><code>text-underline-position: under;</code></td>
            </tr>
            <tr>
                <td><code>left</code></td>
                <td>Places underline to the left (vertical writing)</td>
                <td><code>text-underline-position: left;</code></td>
            </tr>
            <tr>
                <td><code>right</code></td>
                <td>Places underline to the right (vertical writing)</td>
                <td><code>text-underline-position: right;</code></td>
            </tr>
        </table>

        <h3>text-overflow Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>clip</code></td>
                <td>Cuts off the text at the container edge</td>
                <td><code>text-overflow: clip;</code></td>
            </tr>
            <tr>
                <td><code>ellipsis</code></td>
                <td>Shows "..." to indicate clipped text</td>
                <td><code>text-overflow: ellipsis;</code></td>
            </tr>
            <tr>
                <td><code>string</code></td>
                <td>Uses a custom string</td>
                <td><code>text-overflow: "→";</code></td>
            </tr>
        </table>

        <h3>Global Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>inherit</code></td>
                <td>Inherits the value from the parent element</td>
            </tr>
            <tr>
                <td><code>initial</code></td>
                <td>Sets the property to its default value</td>
            </tr>
            <tr>
                <td><code>unset</code></td>
                <td>Inherits if possible, otherwise uses initial</td>
            </tr>
            <tr>
                <td><code>revert</code></td>
                <td>Reverts to the browser's default styles</td>
            </tr>
            <tr>
                <td><code>revert-layer</code></td>
                <td>Reverts to the value in the previous cascade layer</td>
            </tr>
        </table>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionCommon Values
text-combine-uprightCombines characters into one upright glyphnone, all, digits <n>
text-underline-offsetDistance of the underlineauto, 2px, 0.3em
text-underline-positionPosition of the underlineauto, under, left, right
text-overflowHow hidden overflow is displayedclip, ellipsis, "→"

Best Practices

Do This:

/* Use text-overflow: ellipsis for truncated content */
.truncate {
    width: 200px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Use text-underline-offset for better readability */
a {
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* Use text-underline-position: under for links with descenders */
a {
    text-decoration: underline;
    text-underline-position: under;
}

Don’t Do This:

/* Don't use text-overflow without white-space: nowrap */
.container {
    text-overflow: ellipsis;  /* Won't work without nowrap */
    /* Add white-space: nowrap and overflow: hidden */
}

/* Don't use text-combine-upright without vertical writing mode */
.text {
    text-combine-upright: all;  /* Only works in vertical writing modes */
}

Pro Tip: Use text-overflow: ellipsis for truncating long text in tables, cards, or navigation. Use text-underline-offset and text-underline-position: under for better readability of underlined links, especially those with descenders (g, j, p, q, y). text-combine-upright is primarily for CJK vertical text — use it when numbers or Latin characters need to fit into a single character space!

15. The position Property

The position property is one of the most powerful tools in CSS for controlling the layout and placement of elements. It determines how an element is positioned in the document flow and how it responds to the top, right, bottom, and left properties.


Overview of position Values

ValueDescription
staticDefault — element stays in its normal flow
relativePositioned relative to its normal position
absoluteRemoved from flow — positioned relative to nearest positioned ancestor
fixedRemoved from flow — positioned relative to the viewport
stickyHybrid — relative until a threshold, then fixed

1. position: static

The default value. Elements remain in their normal document flow. The top, right, bottom, left, and z-index properties have no effect.

.static {
    position: static; /* Default */
    margin: 10px;
    padding: 20px;
    border: 1px solid #ddd;
}

2. position: relative

The element is positioned relative to its normal position. The top, right, bottom, and left properties offset it from where it would normally be.

.relative {
    position: relative;
    top: 20px;    /* Moves down 20px from normal position */
    left: 50px;   /* Moves right 50px from normal position */
}

Key Points:

  • The element still occupies its original space in the flow
  • Other elements are not affected by the offset
  • Creates a positioning context for absolutely positioned children

3. position: absolute

The element is removed from the normal flow and positioned relative to its nearest positioned ancestor (or the <html> root if none exists).

.absolute {
    position: absolute;
    top: 20px;
    left: 50px;
}

Key Points:

  • Removed from the normal flow (other elements ignore it)
  • Positioned relative to nearest ancestor with position: relative, absolute, fixed, or sticky
  • If no positioned ancestor exists, it’s positioned relative to the initial containing block (the viewport)
  • Creates a positioning context for its children

4. position: fixed

The element is removed from the normal flow and positioned relative to the viewport. It stays in the same place even when the page is scrolled.

.fixed {
    position: fixed;
    top: 20px;
    right: 20px;
}

Key Points:

  • Removed from the normal flow
  • Positioned relative to the viewport (not the document)
  • Stays fixed when scrolling
  • Commonly used for sticky headers, floating buttons, and modals

5. position: sticky

The element behaves like relative until it reaches a threshold (specified by top, bottom, left, or right), then it becomes fixed relative to its nearest scrolling ancestor.

.sticky {
    position: sticky;
    top: 20px; /* Sticks when it reaches 20px from the top */
}

Key Points:

  • Hybrid between relative and fixed
  • Stays in normal flow until threshold is reached
  • Sticks to the specified position within its parent container
  • Commonly used for sticky headers, sidebars, and table headers

Comparison Table

ValueIn Flow?Positioned Relative ToScrolls?Creates Context?
static✅ YesNormal flow✅ Yes❌ No
relative✅ YesIts normal position✅ Yes✅ Yes
absolute❌ NoNearest positioned ancestor✅ Yes✅ Yes
fixed❌ NoViewport❌ No✅ Yes
sticky✅ YesNearest scrolling ancestorUntil threshold✅ Yes

The z-index Property

When elements overlap, z-index controls which appears on top. It only works on positioned elements (relative, absolute, fixed, sticky).

.element {
    position: relative;
    z-index: 10; /* Higher = on top */
}

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>The position Property</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .demo-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border: 2px solid #ddd;
            background: #f8f9fa;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== POSITION DEMOS ====== */
        .position-demo {
            position: relative;
            background: #e9ecef;
            padding: 20px;
            border-radius: 8px;
            min-height: 300px;
            border: 2px dashed #ccc;
        }

        .position-demo .label {
            position: absolute;
            top: 5px;
            left: 10px;
            font-size: 0.8rem;
            font-weight: bold;
            color: #666;
            background: white;
            padding: 2px 8px;
            border-radius: 4px;
        }

        /* Static */
        .static-box {
            position: static;
            background: #007bff;
            color: white;
            padding: 15px;
            margin: 10px 0;
            border-radius: 4px;
            width: 200px;
        }

        /* Relative */
        .relative-box {
            position: relative;
            top: 20px;
            left: 50px;
            background: #28a745;
            color: white;
            padding: 15px;
            margin: 10px 0;
            border-radius: 4px;
            width: 200px;
        }

        /* Absolute */
        .absolute-container {
            position: relative;
            background: #f8f9fa;
            border: 2px dashed #007bff;
            padding: 20px;
            margin: 20px 0;
            min-height: 200px;
            border-radius: 8px;
        }

        .absolute-box {
            position: absolute;
            top: 20px;
            right: 20px;
            background: #dc3545;
            color: white;
            padding: 15px;
            border-radius: 4px;
            width: 180px;
        }

        /* Fixed */
        .fixed-box {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #6c5ce7;
            color: white;
            padding: 15px 25px;
            border-radius: 50px;
            box-shadow: 0 4px 15px rgba(108, 92, 231, 0.4);
            z-index: 1000;
            cursor: pointer;
            transition: transform 0.3s;
        }

        .fixed-box:hover {
            transform: scale(1.05);
        }

        /* Sticky */
        .sticky-container {
            background: #f8f9fa;
            border: 2px dashed #ffc107;
            padding: 20px;
            margin: 20px 0;
            border-radius: 8px;
            height: 300px;
            overflow-y: auto;
        }

        .sticky-header {
            position: sticky;
            top: 0;
            background: #ffc107;
            color: #333;
            padding: 15px;
            border-radius: 4px;
            font-weight: bold;
            z-index: 10;
        }

        .sticky-content {
            padding: 15px;
        }

        .sticky-content p {
            margin: 10px 0;
        }

        /* Overlap demo */
        .overlap-container {
            position: relative;
            height: 150px;
            background: #f8f9fa;
            border: 2px dashed #ddd;
            border-radius: 8px;
            margin: 20px 0;
        }

        .overlap-box {
            position: absolute;
            width: 120px;
            height: 80px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            border-radius: 8px;
        }

        .overlap-box:nth-child(1) {
            background: #007bff;
            top: 20px;
            left: 20px;
            z-index: 1;
        }

        .overlap-box:nth-child(2) {
            background: #28a745;
            top: 40px;
            left: 60px;
            z-index: 2;
        }

        .overlap-box:nth-child(3) {
            background: #dc3545;
            top: 60px;
            left: 100px;
            z-index: 3;
        }
    </style>
</head>
<body>

    <h1>The position Property</h1>

    <!-- ====== 1. STATIC ====== -->
    <section>
        <h2>1. position: static (default)</h2>
        <p>Elements remain in their normal flow. The <code>top</code>, <code>right</code>, <code>bottom</code>, <code>left</code>, and <code>z-index</code> properties have <strong>no effect</strong>.</p>

        <div class="position-demo">
            <span class="label">static container</span>
            <div class="static-box">Static Box 1</div>
            <div class="static-box">Static Box 2</div>
            <div class="static-box">Static Box 3</div>
        </div>

        <div class="code-block">
            .static {
                position: static; /* Default */
                /* top, left, z-index have NO effect */
            }
        </div>
    </section>

    <!-- ====== 2. RELATIVE ====== -->
    <section>
        <h2>2. position: relative</h2>
        <p>The element is positioned relative to its <strong>normal position</strong>. It still occupies its original space in the flow.</p>

        <div class="position-demo">
            <span class="label">relative container</span>
            <div class="static-box" style="opacity: 0.3;">Normal position (ghost)</div>
            <div class="relative-box">Relative Box (offset: top 20px, left 50px)</div>
            <div class="static-box">Normal Box</div>
        </div>

        <div class="code-block">
            .relative {
                position: relative;
                top: 20px;    /* Moves down 20px from normal position */
                left: 50px;   /* Moves right 50px from normal position */
            }
        </div>
    </section>

    <!-- ====== 3. ABSOLUTE ====== -->
    <section>
        <h2>3. position: absolute</h2>
        <p>The element is removed from the normal flow and positioned relative to its <strong>nearest positioned ancestor</strong>.</p>

        <div class="absolute-container">
            <span class="label">absolute container (position: relative)</span>
            <p>This container has <code>position: relative</code>, making it the positioning context for the absolute box.</p>
            <div class="absolute-box">Absolute Box (top: 20px, right: 20px)</div>
            <div style="height: 150px;"></div>
        </div>

        <div class="code-block">
            .absolute-container {
                position: relative; /* Creates positioning context */
            }

            .absolute {
                position: absolute;
                top: 20px;
                right: 20px;
            }
        </div>
    </section>

    <!-- ====== 4. FIXED ====== -->
    <section>
        <h2>4. position: fixed</h2>
        <p>The element is removed from the flow and positioned relative to the <strong>viewport</strong>. It stays in place when scrolling.</p>

        <p>Scroll down the page — the purple button at the bottom-right stays fixed!</p>

        <div class="code-block">
            .fixed {
                position: fixed;
                bottom: 20px;
                right: 20px;
                z-index: 1000;
            }
        </div>
    </section>

    <!-- ====== 5. STICKY ====== -->
    <section>
        <h2>5. position: sticky</h2>
        <p>The element behaves like <code>relative</code> until it reaches a threshold, then becomes <code>fixed</code> within its parent.</p>

        <div class="sticky-container">
            <div class="sticky-header">📌 Sticky Header (scroll inside this box)</div>
            <div class="sticky-content">
                <p>Scroll inside this container to see the sticky header stay at the top.</p>
                <p>Line 1 — Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
                <p>Line 2 — Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
                <p>Line 3 — Ut enim ad minim veniam, quis nostrud exercitation ullamco.</p>
                <p>Line 4 — Duis aute irure dolor in reprehenderit in voluptate velit.</p>
                <p>Line 5 — Excepteur sint occaecat cupidatat non proident.</p>
                <p>Line 6 — Sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                <p>Line 7 — Sed ut perspiciatis unde omnis iste natus error sit voluptatem.</p>
                <p>Line 8 — Accusantium doloremque laudantium, totam rem aperiam.</p>
                <p>Line 9 — Eaque ipsa quae ab illo inventore veritatis et quasi architecto.</p>
                <p>Line 10 — Beatae vitae dicta sunt explicabo.</p>
            </div>
        </div>

        <div class="code-block">
            .sticky {
                position: sticky;
                top: 0; /* Sticks when it reaches the top */
            }
        </div>
    </section>

    <!-- ====== 6. Z-INDEX ====== -->
    <section>
        <h2>6. z-index (stacking order)</h2>
        <p>When elements overlap, <code>z-index</code> controls which appears on top. Higher values appear on top.</p>

        <div class="overlap-container">
            <div class="overlap-box">z-index: 1</div>
            <div class="overlap-box">z-index: 2</div>
            <div class="overlap-box">z-index: 3</div>
        </div>

        <div class="code-block">
            .overlap-box:nth-child(1) { z-index: 1; }
            .overlap-box:nth-child(2) { z-index: 2; }
            .overlap-box:nth-child(3) { z-index: 3; }
        </div>
    </section>

    <!-- ====== REFERENCE TABLES ====== -->
    <section>
        <h2>7. Reference Tables</h2>

        <h3>position Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>In Flow?</th>
                <th>Positioned Relative To</th>
                <th>Scrolls?</th>
            </tr>
            <tr>
                <td><code>static</code></td>
                <td>✅ Yes</td>
                <td>Normal flow</td>
                <td>✅ Yes</td>
            </tr>
            <tr>
                <td><code>relative</code></td>
                <td>✅ Yes</td>
                <td>Its normal position</td>
                <td>✅ Yes</td>
            </tr>
            <tr>
                <td><code>absolute</code></td>
                <td>❌ No</td>
                <td>Nearest positioned ancestor</td>
                <td>✅ Yes</td>
            </tr>
            <tr>
                <td><code>fixed</code></td>
                <td>❌ No</td>
                <td>Viewport</td>
                <td>❌ No</td>
            </tr>
            <tr>
                <td><code>sticky</code></td>
                <td>✅ Yes</td>
                <td>Nearest scrolling ancestor</td>
                <td>Until threshold</td>
            </tr>
        </table>

        <h3>Positional Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>top</code></td>
                <td>Offset from the top</td>
                <td><code>top: 20px;</code></td>
            </tr>
            <tr>
                <td><code>right</code></td>
                <td>Offset from the right</td>
                <td><code>right: 20px;</code></td>
            </tr>
            <tr>
                <td><code>bottom</code></td>
                <td>Offset from the bottom</td>
                <td><code>bottom: 20px;</code></td>
            </tr>
            <tr>
                <td><code>left</code></td>
                <td>Offset from the left</td>
                <td><code>left: 20px;</code></td>
            </tr>
            <tr>
                <td><code>z-index</code></td>
                <td>Stacking order (higher = on top)</td>
                <td><code>z-index: 10;</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== BEST PRACTICES ====== -->
    <section>
        <h2>8. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>position: relative</code> to create a positioning context for absolute children</li>
                <li>Use <code>position: fixed</code> for sticky headers and floating buttons</li>
                <li>Use <code>position: sticky</code> for table headers and sidebars</li>
                <li>Use <code>z-index</code> sparingly and with meaningful values</li>
                <li>Use <code>position: absolute</code> for overlays, tooltips, and badges</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use <code>position: absolute</code> without a positioned ancestor</li>
                <li>Don't use <code>z-index: 9999</code> — use meaningful values</li>
                <li>Don't use <code>position: fixed</code> for large elements (can block content)</li>
                <li>Don't forget that <code>position: absolute</code> removes elements from the flow</li>
            </ul>
        </div>
    </section>

    <!-- ====== FIXED BUTTON ====== -->
    <div class="fixed-box" onclick="window.scrollTo({top: 0, behavior: 'smooth'});">
        ↑ Back to Top
    </div>

</body>
</html>

Quick Reference

ValueIn Flow?Positioned Relative ToScrolls?Creates Context?
static✅ YesNormal flow✅ Yes❌ No
relative✅ YesIts normal position✅ Yes✅ Yes
absolute❌ NoNearest positioned ancestor✅ Yes✅ Yes
fixed❌ NoViewport❌ No✅ Yes
sticky✅ YesNearest scrolling ancestorUntil threshold✅ Yes

Best Practices

Do This:

/* Create a positioning context */
.card {
    position: relative; /* Parent */
}

.card .badge {
    position: absolute; /* Child */
    top: 10px;
    right: 10px;
}

/* Sticky header */
.header {
    position: sticky;
    top: 0;
    z-index: 100;
}

/* Fixed floating button */
.back-to-top {
    position: fixed;
    bottom: 20px;
    right: 20px;
    z-index: 1000;
}

Don’t Do This:

/* Don't use absolute without a positioned parent */
.badge {
    position: absolute;
    top: 0;
    /* Will position relative to the viewport, not the card */
}

/* Don't use z-index: 9999 */
.element {
    z-index: 9999; /* Use meaningful values like 10, 100, 1000 */
}

/* Don't use fixed for large elements */
.overlay {
    position: fixed;
    width: 100%;
    height: 100%;
    /* May block content and break scrolling */
}

Pro Tip: Use position: relative on a parent to create a positioning context for absolutely positioned children. Use position: fixed for elements that should always be visible (like a back-to-top button). Use position: sticky for table headers or sidebars that should stay visible while scrolling. Remember that absolute and fixed elements are removed from the normal flow, so they don’t affect the layout of other elements!

16. The display Property

The display property is one of the most important CSS properties. It controls how an element is displayed on a webpage and how it behaves in the document flow.


Overview of display Values

ValueDescriptionIn Flow?Dimensions?Line Breaks?
inlineFlows with text✅ Yes❌ No❌ No
blockStarts on new line, full width✅ Yes✅ Yes✅ Yes
inline-blockFlows with text, but respects dimensions✅ Yes✅ Yes❌ No
flexBlock-level flex container✅ Yes✅ Yes✅ Yes
inline-flexInline-level flex container✅ Yes✅ Yes❌ No
gridBlock-level grid container✅ Yes✅ Yes✅ Yes
inline-gridInline-level grid container✅ Yes✅ Yes❌ No
noneHides the element❌ No❌ No❌ No

1. display: inline

The element takes up only as much horizontal space as necessary for its content. It does not generate line breaks before or after itself. You cannot set its width and height.

.inline {
    display: inline;
    background-color: #ddd;
    margin: 5px;
    padding: 10px;
}

Key Points:

  • No line breaks before/after
  • Width and height are ignored
  • Padding and margin work horizontally but not vertically
  • Common inline elements: <span>, <a>, <strong>, <em>, <img>

2. display: block

The element starts on a new line and takes up the full width of its parent. You can set its width and height.

.block {
    display: block;
    background-color: #ddd;
    margin: 5px;
    padding: 10px;
}

Key Points:

  • Starts on a new line
  • Takes full width of parent
  • Width and height work
  • Common block elements: <div>, <p>, <h1><h6>, <ul>, <li>

3. display: inline-block

The element behaves like a block element but maintains inline behavior — no line breaks before or after. You can set its width and height.

.inline-block {
    display: inline-block;
    background-color: #ddd;
    margin: 5px;
    padding: 10px;
}

Key Points:

  • Flows with text (no line breaks)
  • Width and height work
  • Margin, border, and padding work on all sides
  • Great for navigation menus, buttons, and image galleries

4. display: flex

The element behaves like a block element but lays out its contents according to the flexbox model. It arranges its children in a single row or column.

.flex {
    display: flex;
    background-color: #ddd;
    margin: 5px;
    padding: 10px;
}

Key Points:

  • Block-level container
  • Children become flex items
  • Great for one-dimensional layouts (rows or columns)
  • Allows flexible alignment, ordering, and spacing

5. display: grid

The element behaves like a block element but lays out its contents according to the grid model. It arranges its children in a two-dimensional grid.

.grid {
    display: grid;
    background-color: #ddd;
    margin: 5px;
    padding: 10px;
}

Key Points:

  • Block-level container
  • Children become grid items
  • Great for two-dimensional layouts (rows and columns)
  • Allows complex arrangements of elements

6. display: none

The element is completely removed from the document flow. It takes up no space and is not rendered.

.hidden {
    display: none;
}

Key Points:

  • Element is not displayed
  • Takes up no space in the layout
  • Can be toggled with JavaScript for show/hide functionality

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>The display Property</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .demo-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border: 2px dashed #ddd;
            background: #f8f9fa;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== DISPLAY DEMOS ====== */
        .inline-demo {
            display: inline;
            background-color: #007bff;
            color: white;
            padding: 5px 10px;
            margin: 5px;
        }

        .block-demo {
            display: block;
            background-color: #28a745;
            color: white;
            padding: 10px 15px;
            margin: 5px 0;
        }

        .inline-block-demo {
            display: inline-block;
            background-color: #dc3545;
            color: white;
            padding: 10px 15px;
            margin: 5px;
            width: 150px;
            text-align: center;
        }

        .flex-demo {
            display: flex;
            background-color: #ffc107;
            color: #333;
            padding: 10px;
            margin: 5px 0;
            gap: 10px;
        }

        .flex-demo > div {
            background: white;
            padding: 10px 20px;
            border-radius: 4px;
        }

        .grid-demo {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 10px;
            background-color: #6c5ce7;
            color: white;
            padding: 10px;
            margin: 5px 0;
        }

        .grid-demo > div {
            background: rgba(255, 255, 255, 0.2);
            padding: 15px;
            border-radius: 4px;
            text-align: center;
        }

        .none-demo {
            display: none;
        }

        .hidden-note {
            color: #dc3545;
            font-style: italic;
        }
    </style>
</head>
<body>

    <h1>The display Property</h1>

    <!-- ====== 1. INLINE ====== -->
    <section>
        <h2>1. display: inline</h2>
        <p>The element takes up only as much space as needed. Width and height are ignored. No line breaks.</p>

        <div class="demo-box">
            <div class="inline-demo">Inline 1</div>
            <div class="inline-demo">Inline 2</div>
            <span class="inline-demo">Inline 3</span>
            <div class="inline-demo">Inline 4</div>
            <p>Notice how the elements flow inline — they don't start on a new line.</p>
        </div>

        <div class="code-block">
            .inline {
                display: inline;
                /* width and height are IGNORED */
            }
        </div>
    </section>

    <!-- ====== 2. BLOCK ====== -->
    <section>
        <h2>2. display: block</h2>
        <p>The element starts on a new line and takes up the full width of its parent.</p>

        <div class="demo-box">
            <div class="block-demo">Block 1</div>
            <div class="block-demo">Block 2</div>
            <div class="block-demo">Block 3</div>
            <p>Notice how each block starts on a new line and takes the full width.</p>
        </div>

        <div class="code-block">
            .block {
                display: block;
                width: 100%; /* Full width of parent */
                /* Starts on a new line */
            }
        </div>
    </section>

    <!-- ====== 3. INLINE-BLOCK ====== -->
    <section>
        <h2>3. display: inline-block</h2>
        <p>Behaves like a block element but flows inline. Width and height work.</p>

        <div class="demo-box">
            <div class="inline-block-demo">Inline-Block 1</div>
            <div class="inline-block-demo">Inline-Block 2</div>
            <div class="inline-block-demo">Inline-Block 3</div>
            <span class="inline-block-demo">Inline-Block 4</span>
            <p>Notice how they flow inline but respect width and height.</p>
        </div>

        <div class="code-block">
            .inline-block {
                display: inline-block;
                width: 150px;  /* Width works */
                height: 50px;  /* Height works */
                /* Flows inline — no line breaks */
            }
        </div>
    </section>

    <!-- ====== 4. FLEX ====== -->
    <section>
        <h2>4. display: flex</h2>
        <p>The element becomes a flex container. Its children become flex items arranged in a row or column.</p>

        <div class="demo-box">
            <div class="flex-demo">
                <div>Flex Item 1</div>
                <div>Flex Item 2</div>
                <div>Flex Item 3</div>
            </div>
            <p>Children are arranged in a row with equal spacing.</p>
        </div>

        <div class="code-block">
            .flex {
                display: flex;
                gap: 10px; /* Space between items */
            }
        </div>
    </section>

    <!-- ====== 5. GRID ====== -->
    <section>
        <h2>5. display: grid</h2>
        <p>The element becomes a grid container. Its children become grid items arranged in a two-dimensional grid.</p>

        <div class="demo-box">
            <div class="grid-demo">
                <div>Grid Item 1</div>
                <div>Grid Item 2</div>
                <div>Grid Item 3</div>
                <div>Grid Item 4</div>
                <div>Grid Item 5</div>
                <div>Grid Item 6</div>
            </div>
            <p>Children are arranged in a 3-column grid.</p>
        </div>

        <div class="code-block">
            .grid {
                display: grid;
                grid-template-columns: repeat(3, 1fr); /* 3 equal columns */
                gap: 10px;
            }
        </div>
    </section>

    <!-- ====== 6. NONE ====== -->
    <section>
        <h2>6. display: none</h2>
        <p>The element is completely removed from the document flow. It takes up no space.</p>

        <div class="demo-box">
            <p>This text is visible.</p>
            <p class="none-demo">This text has display: none — you shouldn't see it!</p>
            <p>This text is also visible.</p>
            <p class="hidden-note">The hidden paragraph takes up no space.</p>
        </div>

        <div class="code-block">
            .none {
                display: none; /* Completely removed from flow */
            }
        </div>
    </section>

    <!-- ====== 7. COMPARISON ====== -->
    <section>
        <h2>7. Side-by-Side Comparison</h2>

        <h3>inline vs inline-block vs block</h3>
        <div class="demo-box">
            <div style="display: inline; background: #007bff; color: white; padding: 5px 10px; margin: 5px;">
                inline
            </div>
            <div style="display: inline; background: #007bff; color: white; padding: 5px 10px; margin: 5px;">
                inline
            </div>
            <div style="display: inline-block; background: #dc3545; color: white; padding: 10px 15px; margin: 5px; width: 120px; text-align: center;">
                inline-block
            </div>
            <div style="display: inline-block; background: #dc3545; color: white; padding: 10px 15px; margin: 5px; width: 120px; text-align: center;">
                inline-block
            </div>
            <div style="display: block; background: #28a745; color: white; padding: 10px 15px; margin: 5px 0;">
                block
            </div>
            <div style="display: block; background: #28a745; color: white; padding: 10px 15px; margin: 5px 0;">
                block
            </div>
        </div>

        <div class="code-block">
            /* inline — no width/height, no line breaks */
            display: inline;

            /* inline-block — width/height work, no line breaks */
            display: inline-block;

            /* block — width/height work, line breaks before/after */
            display: block;
        </div>
    </section>

    <!-- ====== REFERENCE TABLES ====== -->
    <section>
        <h2>8. Reference Tables</h2>

        <h3>display Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>In Flow?</th>
                <th>Dimensions?</th>
                <th>Line Breaks?</th>
                <th>Common Elements</th>
            </tr>
            <tr>
                <td><code>inline</code></td>
                <td>✅ Yes</td>
                <td>❌ No</td>
                <td>❌ No</td>
                <td><code><span></code>, <code><a></code>, <code><strong></code></td>
            </tr>
            <tr>
                <td><code>block</code></td>
                <td>✅ Yes</td>
                <td>✅ Yes</td>
                <td>✅ Yes</td>
                <td><code><div></code>, <code><p></code>, <code><h1></code></td>
            </tr>
            <tr>
                <td><code>inline-block</code></td>
                <td>✅ Yes</td>
                <td>✅ Yes</td>
                <td>❌ No</td>
                <td>—</td>
            </tr>
            <tr>
                <td><code>flex</code></td>
                <td>✅ Yes</td>
                <td>✅ Yes</td>
                <td>✅ Yes</td>
                <td>—</td>
            </tr>
            <tr>
                <td><code>inline-flex</code></td>
                <td>✅ Yes</td>
                <td>✅ Yes</td>
                <td>❌ No</td>
                <td>—</td>
            </tr>
            <tr>
                <td><code>grid</code></td>
                <td>✅ Yes</td>
                <td>✅ Yes</td>
                <td>✅ Yes</td>
                <td>—</td>
            </tr>
            <tr>
                <td><code>inline-grid</code></td>
                <td>✅ Yes</td>
                <td>✅ Yes</td>
                <td>❌ No</td>
                <td>—</td>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>❌ No</td>
                <td>❌ No</td>
                <td>❌ No</td>
                <td>—</td>
            </tr>
        </table>

        <h3>When to Use Which</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Best For</th>
            </tr>
            <tr>
                <td><code>inline</code></td>
                <td>Text-level elements, links, emphasis</td>
            </tr>
            <tr>
                <td><code>block</code></td>
                <td>Page structure, paragraphs, headings, divs</td>
            </tr>
            <tr>
                <td><code>inline-block</code></td>
                <td>Navigation items, buttons, image galleries</td>
            </tr>
            <tr>
                <td><code>flex</code></td>
                <td>One-dimensional layouts (rows/columns), navigation bars</td>
            </tr>
            <tr>
                <td><code>grid</code></td>
                <td>Two-dimensional layouts, page layouts, complex arrangements</td>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>Hiding elements (toggles with JavaScript)</td>
            </tr>
        </table>
    </section>

    <!-- ====== BEST PRACTICES ====== -->
    <section>
        <h2>9. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>inline</code> for text-level elements</li>
                <li>Use <code>block</code> for structural elements</li>
                <li>Use <code>inline-block</code> for horizontal navigation items</li>
                <li>Use <code>flex</code> for one-dimensional layouts</li>
                <li>Use <code>grid</code> for two-dimensional layouts</li>
                <li>Use <code>display: none</code> to hide elements completely</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use <code>inline</code> for elements that need width/height</li>
                <li>Don't use <code>block</code> for text-level elements</li>
                <li>Don't use <code>display: none</code> for accessibility — use <code>visibility: hidden</code> or <code>aria-hidden</code> instead</li>
                <li>Don't use <code>inline-block</code> when <code>flex</code> would be cleaner</li>
                <li>Don't use <code>display</code> to change the semantic meaning of elements</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

ValueIn Flow?Dimensions?Line Breaks?Common Elements
inline✅ Yes❌ No❌ No<span>, <a>, <strong>
block✅ Yes✅ Yes✅ Yes<div>, <p>, <h1>
inline-block✅ Yes✅ Yes❌ No
flex✅ Yes✅ Yes✅ Yes
inline-flex✅ Yes✅ Yes❌ No
grid✅ Yes✅ Yes✅ Yes
inline-grid✅ Yes✅ Yes❌ No
none❌ No❌ No❌ No

Best Practices

Do This:

/* Use flex for one-dimensional layouts */
.nav {
    display: flex;
    gap: 20px;
}

/* Use grid for two-dimensional layouts */
.gallery {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 15px;
}

/* Use inline-block for buttons in a row */
.btn {
    display: inline-block;
    padding: 10px 20px;
}

/* Hide elements completely */
.hidden {
    display: none;
}

Don’t Do This:

/* Don't use inline for elements that need dimensions */
.box {
    display: inline;
    width: 200px;  /* Ignored! */
    height: 100px; /* Ignored! */
}

/* Don't use block for text-level elements */
.highlight {
    display: block;  /* Breaks the text flow */
}

/* Don't use display: none for accessibility */
.screen-reader-only {
    display: none;  /* Screen readers will ignore it too */
    /* Use position: absolute; left: -9999px; instead */
}

Pro Tip: Use display: flex for one-dimensional layouts (rows or columns) and display: grid for two-dimensional layouts. Use inline-block for horizontal navigation items and buttons. Remember that display: none removes the element completely — use it for show/hide functionality, but avoid it for accessibility purposes (use visibility: hidden or visually-hidden CSS instead)!

17. Margin, Padding, and Border Properties

These three properties are the foundation of the CSS Box Model. They control the spacing around elements (margin), the spacing inside elements (padding), and the outline of elements (border).


Overview of the Three Properties

PropertyDescriptionWhere It Applies
marginSpace outside the borderBetween the element and its neighbors
paddingSpace inside the borderBetween the content and the border
borderLine around the padding and contentSurrounds the element

Visual Representation

┌─────────────────────────────────────────────┐
│                   MARGIN                     │
│  ┌───────────────────────────────────────┐  │
│  │               BORDER                   │  │
│  │  ┌─────────────────────────────────┐  │  │
│  │  │            PADDING              │  │  │
│  │  │  ┌───────────────────────────┐  │  │  │
│  │  │  │         CONTENT           │  │  │  │
│  │  │  └───────────────────────────┘  │  │  │
│  │  └─────────────────────────────────┘  │  │
│  └───────────────────────────────────────┘  │
└─────────────────────────────────────────────┘

1. Margin

The margin property specifies the space around an element (outside the border).

/* All sides */
.box {
    margin: 20px;
}

/* Individual sides */
.box-individual {
    margin-top: 10px;
    margin-right: 20px;
    margin-bottom: 30px;
    margin-left: 40px;
}

Shorthand Values

ValuesTopRightBottomLeft
margin: 20px;20px20px20px20px
margin: 10px 20px;10px20px10px20px
margin: 10px 20px 30px;10px20px30px20px
margin: 10px 20px 30px 40px;10px20px30px40px

Values

ValueDescriptionExample
lengthFixed margin (px, em, rem)margin: 20px;
percentagePercentage of parent widthmargin: 10%;
autoBrowser calculates the marginmargin: 0 auto;
negativeNegative marginmargin: -10px;

2. Padding

The padding property specifies the space between the border and the content (inside the border).

/* All sides */
.box-padding {
    padding: 20px;
}

/* Individual sides */
.box-padding-individual {
    padding-top: 10px;
    padding-right: 20px;
    padding-bottom: 30px;
    padding-left: 40px;
}

Shorthand Values

ValuesTopRightBottomLeft
padding: 20px;20px20px20px20px
padding: 10px 20px;10px20px10px20px
padding: 10px 20px 30px;10px20px30px20px
padding: 10px 20px 30px 40px;10px20px30px40px

Values

ValueDescriptionExample
lengthFixed padding (px, em, rem)padding: 20px;
percentagePercentage of parent widthpadding: 10%;

Important: Padding adds to the total size of the element (in the standard box model). Negative padding is not allowed.


3. Border

The border property is a shorthand for border-width, border-style, and border-color.

/* Shorthand: width | style | color */
.box-border {
    border: 1px solid #000;
}

.box-border-dashed {
    border: 2px dashed red;
}

/* Individual sides */
.box-border-individual {
    border-top: 2px solid blue;
    border-right: 3px dashed green;
    border-bottom: 4px dotted orange;
    border-left: 5px double purple;
}

Shorthand Order

border: <border-width> <border-style> <border-color>;

border-width Values

ValueDescriptionExample
thinThin border (1px)border-width: thin;
mediumMedium border (3px)border-width: medium;
thickThick border (5px)border-width: thick;
lengthCustom widthborder-width: 2px;

border-style Values

StyleDescriptionExample
noneNo borderborder-style: none;
hiddenHidden border (like none)border-style: hidden;
dottedDotted lineborder-style: dotted;
dashedDashed lineborder-style: dashed;
solidSolid line (default)border-style: solid;
doubleDouble lineborder-style: double;
groove3D grooved effectborder-style: groove;
ridge3D ridged effectborder-style: ridge;
inset3D inset effectborder-style: inset;
outset3D outset effectborder-style: outset;

border-color Values

ValueDescriptionExample
NamedColor namesborder-color: red;
HexHexadecimalborder-color: #FF0000;
RGB/RGBARGB valuesborder-color: rgb(255, 0, 0);
HSL/HSLAHSL valuesborder-color: hsl(0, 100%, 50%);

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Margin, Padding, and Border</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .demo-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border: 2px dashed #ddd;
            background: #f8f9fa;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== MARGIN DEMOS ====== */
        .margin-all {
            width: 250px;
            height: 80px;
            background-color: #007bff;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            margin: 20px;
            border-radius: 4px;
        }

        .margin-individual {
            width: 250px;
            height: 80px;
            background-color: #28a745;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-top: 10px;
            margin-right: 20px;
            margin-bottom: 30px;
            margin-left: 40px;
            border-radius: 4px;
        }

        /* ====== PADDING DEMOS ====== */
        .padding-all {
            width: 250px;
            height: 80px;
            background-color: #ffc107;
            color: #333;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 20px;
            border: 2px solid #d4a017;
            border-radius: 4px;
        }

        .padding-individual {
            width: 250px;
            height: 80px;
            background-color: #dc3545;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            padding-top: 10px;
            padding-right: 20px;
            padding-bottom: 30px;
            padding-left: 40px;
            border: 2px solid #a71d2a;
            border-radius: 4px;
        }

        /* ====== BORDER DEMOS ====== */
        .border-solid {
            width: 250px;
            height: 80px;
            background-color: #e9ecef;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 3px solid #000;
            border-radius: 4px;
        }

        .border-dashed {
            width: 250px;
            height: 80px;
            background-color: #e9ecef;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 3px dashed #dc3545;
            border-radius: 4px;
        }

        .border-dotted {
            width: 250px;
            height: 80px;
            background-color: #e9ecef;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 3px dotted #007bff;
            border-radius: 4px;
        }

        .border-double {
            width: 250px;
            height: 80px;
            background-color: #e9ecef;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 5px double #28a745;
            border-radius: 4px;
        }

        .border-groove {
            width: 250px;
            height: 80px;
            background-color: #e9ecef;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 5px groove #6c5ce7;
            border-radius: 4px;
        }

        .border-ridge {
            width: 250px;
            height: 80px;
            background-color: #e9ecef;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 5px ridge #ffc107;
            border-radius: 4px;
        }

        .border-inset {
            width: 250px;
            height: 80px;
            background-color: #e9ecef;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 5px inset #17a2b8;
            border-radius: 4px;
        }

        .border-outset {
            width: 250px;
            height: 80px;
            background-color: #e9ecef;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 5px outset #dc3545;
            border-radius: 4px;
        }

        .border-individual {
            width: 250px;
            height: 80px;
            background-color: #e9ecef;
            display: flex;
            align-items: center;
            justify-content: center;
            border-top: 3px solid #007bff;
            border-right: 3px dashed #28a745;
            border-bottom: 3px dotted #dc3545;
            border-left: 3px double #ffc107;
            border-radius: 4px;
        }

        /* ====== VISUAL BOX MODEL ====== */
        .box-model-demo {
            display: flex;
            justify-content: center;
            gap: 30px;
            flex-wrap: wrap;
        }

        .box-model-item {
            text-align: center;
        }

        .box-model-item .box {
            width: 150px;
            height: 100px;
            background: #007bff;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 4px;
            margin: 10px auto;
            font-weight: bold;
        }

        .box-model-item .box.with-margin {
            background: #28a745;
            margin: 30px;
        }

        .box-model-item .box.with-padding {
            background: #ffc107;
            color: #333;
            padding: 30px;
            width: 150px;
            height: 100px;
            box-sizing: content-box;
        }

        .box-model-item .box.with-border {
            background: #dc3545;
            border: 8px solid #333;
        }
    </style>
</head>
<body>

    <h1>Margin, Padding, and Border Properties</h1>

    <!-- ====== 1. MARGIN ====== -->
    <section>
        <h2>1. Margin</h2>
        <p>The <code>margin</code> property specifies the space <strong>outside</strong> the border.</p>

        <h3>All Sides (margin: 20px)</h3>
        <div class="demo-box">
            <div class="margin-all">
                margin: 20px (all sides)
            </div>
            <p>Space around the element is 20px on all sides.</p>
        </div>

        <h3>Individual Sides</h3>
        <div class="demo-box">
            <div class="margin-individual">
                margin: top=10px | right=20px | bottom=30px | left=40px
            </div>
            <p>Each side has a different margin value.</p>
        </div>

        <div class="code-block">
            /* All sides */
            margin: 20px;

            /* Vertical | Horizontal */
            margin: 10px 20px;

            /* Top | Horizontal | Bottom */
            margin: 10px 20px 30px;

            /* Top | Right | Bottom | Left */
            margin: 10px 20px 30px 40px;

            /* Individual sides */
            margin-top: 10px;
            margin-right: 20px;
            margin-bottom: 30px;
            margin-left: 40px;

            /* Auto margins (centers block elements) */
            margin: 0 auto;
        </div>
    </section>

    <!-- ====== 2. PADDING ====== -->
    <section>
        <h2>2. Padding</h2>
        <p>The <code>padding</code> property specifies the space <strong>inside</strong> the border.</p>

        <h3>All Sides (padding: 20px)</h3>
        <div class="demo-box">
            <div class="padding-all">
                padding: 20px (all sides)
            </div>
            <p>Space between content and border is 20px on all sides.</p>
        </div>

        <h3>Individual Sides</h3>
        <div class="demo-box">
            <div class="padding-individual">
                padding: top=10px | right=20px | bottom=30px | left=40px
            </div>
            <p>Each side has a different padding value.</p>
        </div>

        <div class="code-block">
            /* All sides */
            padding: 20px;

            /* Vertical | Horizontal */
            padding: 10px 20px;

            /* Top | Horizontal | Bottom */
            padding: 10px 20px 30px;

            /* Top | Right | Bottom | Left */
            padding: 10px 20px 30px 40px;

            /* Individual sides */
            padding-top: 10px;
            padding-right: 20px;
            padding-bottom: 30px;
            padding-left: 40px;
        </div>
    </section>

    <!-- ====== 3. BORDER ====== -->
    <section>
        <h2>3. Border</h2>
        <p>The <code>border</code> property is a shorthand for <code>border-width</code>, <code>border-style</code>, and <code>border-color</code>.</p>

        <h3>Border Styles</h3>
        <div class="demo-box">
            <div style="display: flex; flex-wrap: wrap; gap: 15px; justify-content: center;">
                <div class="border-solid">solid</div>
                <div class="border-dashed">dashed</div>
                <div class="border-dotted">dotted</div>
                <div class="border-double">double</div>
                <div class="border-groove">groove</div>
                <div class="border-ridge">ridge</div>
                <div class="border-inset">inset</div>
                <div class="border-outset">outset</div>
            </div>
        </div>

        <h3>Individual Sides</h3>
        <div class="demo-box">
            <div class="border-individual">
                Different border on each side
            </div>
        </div>

        <div class="code-block">
            /* Shorthand: width | style | color */
            border: 1px solid #000;
            border: 2px dashed red;
            border: 3px dotted blue;
            border: 5px double green;
            border: 5px groove purple;
            border: 5px ridge orange;

            /* Individual sides */
            border-top: 2px solid blue;
            border-right: 3px dashed green;
            border-bottom: 4px dotted orange;
            border-left: 5px double purple;

            /* Individual properties */
            border-width: 2px;
            border-style: solid;
            border-color: #000;
        </div>
    </section>

    <!-- ====== 4. VISUAL BOX MODEL ====== -->
    <section>
        <h2>4. Visual Box Model</h2>
        <p>Compare the same box with different margin, padding, and border values.</p>

        <div class="box-model-demo">
            <div class="box-model-item">
                <h4>No Extra Space</h4>
                <div class="box">150 × 100</div>
                <p><small>margin: 0; padding: 0; border: none</small></p>
            </div>

            <div class="box-model-item">
                <h4>With Margin</h4>
                <div class="box with-margin">150 × 100</div>
                <p><small>margin: 30px</small></p>
            </div>

            <div class="box-model-item">
                <h4>With Padding</h4>
                <div class="box with-padding">150 × 100</div>
                <p><small>padding: 30px (content-box)</small></p>
            </div>

            <div class="box-model-item">
                <h4>With Border</h4>
                <div class="box with-border">150 × 100</div>
                <p><small>border: 8px solid #333</small></p>
            </div>
        </div>

        <div class="code-block">
            /* No extra space */
            .box {
                width: 150px;
                height: 100px;
                margin: 0;
                padding: 0;
                border: none;
            }

            /* With margin */
            .box {
                margin: 30px;
            }

            /* With padding */
            .box {
                padding: 30px;
                box-sizing: content-box; /* Padding adds to total size */
            }

            /* With border */
            .box {
                border: 8px solid #333;
            }
        </div>
    </section>

    <!-- ====== 5. REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>Shorthand Order</h3>
        <table class="reference-table">
            <tr>
                <th>Values</th>
                <th>Top</th>
                <th>Right</th>
                <th>Bottom</th>
                <th>Left</th>
            </tr>
            <tr>
                <td><code>margin: 20px;</code></td>
                <td>20px</td>
                <td>20px</td>
                <td>20px</td>
                <td>20px</td>
            </tr>
            <tr>
                <td><code>margin: 10px 20px;</code></td>
                <td>10px</td>
                <td>20px</td>
                <td>10px</td>
                <td>20px</td>
            </tr>
            <tr>
                <td><code>margin: 10px 20px 30px;</code></td>
                <td>10px</td>
                <td>20px</td>
                <td>30px</td>
                <td>20px</td>
            </tr>
            <tr>
                <td><code>margin: 10px 20px 30px 40px;</code></td>
                <td>10px</td>
                <td>20px</td>
                <td>30px</td>
                <td>40px</td>
            </tr>
        </table>

        <h3>Border Styles</h3>
        <table class="reference-table">
            <tr>
                <th>Style</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>solid</code></td>
                <td>Single solid line</td>
                <td><code>border: 2px solid black;</code></td>
            </tr>
            <tr>
                <td><code>dashed</code></td>
                <td>Dashed line</td>
                <td><code>border: 2px dashed red;</code></td>
            </tr>
            <tr>
                <td><code>dotted</code></td>
                <td>Dotted line</td>
                <td><code>border: 2px dotted blue;</code></td>
            </tr>
            <tr>
                <td><code>double</code></td>
                <td>Double line</td>
                <td><code>border: 4px double green;</code></td>
            </tr>
            <tr>
                <td><code>groove</code></td>
                <td>3D grooved effect</td>
                <td><code>border: 4px groove gray;</code></td>
            </tr>
            <tr>
                <td><code>ridge</code></td>
                <td>3D ridged effect</td>
                <td><code>border: 4px ridge gray;</code></td>
            </tr>
            <tr>
                <td><code>inset</code></td>
                <td>3D inset effect</td>
                <td><code>border: 4px inset gray;</code></td>
            </tr>
            <tr>
                <td><code>outset</code></td>
                <td>3D outset effect</td>
                <td><code>border: 4px outset gray;</code></td>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>No border</td>
                <td><code>border: none;</code></td>
            </tr>
        </table>

        <h3>Border Width Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>thin</code></td>
                <td>Thin border (1px)</td>
                <td><code>border-width: thin;</code></td>
            </tr>
            <tr>
                <td><code>medium</code></td>
                <td>Medium border (3px)</td>
                <td><code>border-width: medium;</code></td>
            </tr>
            <tr>
                <td><code>thick</code></td>
                <td>Thick border (5px)</td>
                <td><code>border-width: thick;</code></td>
            </tr>
            <tr>
                <td><code>length</code></td>
                <td>Custom width</td>
                <td><code>border-width: 2px;</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>margin</code> for spacing between elements</li>
                <li>Use <code>padding</code> for spacing inside elements</li>
                <li>Use shorthand properties to write cleaner code</li>
                <li>Use <code>margin: 0 auto</code> to center block elements</li>
                <li>Use <code>box-sizing: border-box</code> for predictable sizing</li>
                <li>Use <code>border-radius</code> to round corners</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use <code>margin</code> for internal spacing (use padding)</li>
                <li>Don't use <code>padding</code> for external spacing (use margin)</li>
                <li>Don't forget that padding adds to the total size (standard box model)</li>
                <li>Don't use negative padding (not allowed)</li>
                <li>Don't mix up margin and padding — they serve different purposes</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionWhere It Applies
marginSpace outside the borderBetween the element and its neighbors
paddingSpace inside the borderBetween the content and the border
borderLine around the padding and contentSurrounds the element

Shorthand Order

ValuesTopRightBottomLeft
property: A;AAAA
property: A B;ABAB
property: A B C;ABCB
property: A B C D;ABCD

Best Practices

Do This:

/* Use margin for external spacing */
.card {
    margin-bottom: 20px;
}

/* Use padding for internal spacing */
.card {
    padding: 20px;
}

/* Center block elements */
.container {
    margin: 0 auto;
    max-width: 1200px;
}

/* Apply border-box globally */
*, *::before, *::after {
    box-sizing: border-box;
}

Don’t Do This:

/* Don't use padding for external spacing */
.card {
    padding-bottom: 20px; /* Creates space inside, not outside */
}

/* Don't forget box-sizing */
.box {
    width: 100%;
    padding: 20px;
    border: 5px solid black;
    /* Total width exceeds 100%! */
}

/* Don't use negative padding */
.box {
    padding: -10px; /* Invalid! */
}

Pro Tip: Remember: margin is outside, padding is inside. Use margin to space elements apart, and padding to give content room to breathe. Always use box-sizing: border-box to make sizing more predictable. Use margin: 0 auto to center block elements horizontally!

18. Grid Layout Introduction

CSS Grid is a two-dimensional layout system introduced in CSS3. It provides a powerful and flexible way to create complex, responsive layouts by defining rows and columns.


What is CSS Grid?

CSS Grid allows you to arrange elements into rows and columns, giving you precise control over the layout of your web page. Unlike Flexbox (which is one-dimensional), Grid works in two dimensions simultaneously.

Key Benefits:

BenefitDescription
Two-dimensionalControls both rows and columns at the same time
Precise controlExact placement of items in the grid
ResponsiveEasily adapts to different screen sizes
FlexibleSupports fractions, min/max sizes, and repeat patterns
Clean markupNo need for extra wrapper divs

Basic Grid Setup

<div class="grid-container">
    <div class="grid-item">Grid Item 1</div>
    <div class="grid-item">Grid Item 2</div>
    <div class="grid-item">Grid Item 3</div>
    <div class="grid-item">Grid Item 4</div>
    <div class="grid-item">Grid Item 5</div>
    <div class="grid-item">Grid Item 6</div>
</div>
.grid-container {
    display: grid;
    grid-template-columns: 100px 200px 100px;
    grid-gap: 10px;
}

What happens:

  • display: grid; — Turns the element into a grid container
  • grid-template-columns: 100px 200px 100px; — Creates three columns with specific widths
  • grid-gap: 10px; — Sets the gap between rows and columns
  • Children automatically flow into the grid cells

1. grid-template-columns

Defines the number and size of columns in the grid.

/* Three fixed-width columns */
.grid-container {
    grid-template-columns: 100px 200px 100px;
}

/* Two equal columns */
.grid-container {
    grid-template-columns: 1fr 1fr;
}

/* Mixed units */
.grid-container {
    grid-template-columns: 100px 1fr 200px;
}

2. grid-template-rows

Defines the number and size of rows in the grid.

/* Three fixed-height rows */
.grid-container {
    grid-template-rows: 100px 200px 100px;
}

/* Two equal rows */
.grid-container {
    grid-template-rows: 1fr 1fr;
}

3. The fr Unit (Fraction of Available Space)

The fr unit represents a fraction of the available space. The total space is divided equally among all fractional units.

/* 1fr : 2fr : 3fr ratio */
.grid-container {
    grid-template-columns: 1fr 2fr 3fr;
}

Calculation:

  • Total = 1 + 2 + 3 = 6 parts
  • Column 1 = 1/6 of available space
  • Column 2 = 2/6 (1/3) of available space
  • Column 3 = 3/6 (1/2) of available space

4. Value Keywords

Grid columns and rows also accept keyword values for more flexible sizing.

KeywordDescriptionExample
max-contentTakes up the maximum possible spacegrid-template-columns: max-content;
min-contentTakes up the minimum possible spacegrid-template-columns: min-content;
minmax(min, max)Sets minimum and maximum dimensionsgrid-template-columns: minmax(100px, 200px);
autoTakes up remaining spacegrid-template-columns: auto;
repeat(n, size)Repeats a patterngrid-template-columns: repeat(3, 100px);

5. minmax()

The minmax() function specifies the minimum and maximum possible dimensions for a grid track.

.grid-container {
    grid-template-columns: minmax(100px, 200px) auto;
}

What happens:

  • First column: minimum 100px, maximum 200px
  • Second column: takes up any remaining space

6. repeat()

The repeat() function creates columns or rows by repeating a pattern.

/* Three equal columns */
.grid-container {
    grid-template-columns: repeat(3, 100px);
}

/* Three equal fractional columns */
.grid-container {
    grid-template-columns: repeat(3, 1fr);
}

/* Repeating pattern */
.grid-container {
    grid-template-columns: repeat(3, 100px 200px);
}

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS Grid Layout Introduction</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== GRID DEMOS ====== */
        .grid-container {
            display: grid;
            gap: 10px;
            margin: 15px 0;
            background: #e9ecef;
            padding: 10px;
            border-radius: 8px;
        }

        .grid-item {
            background: #007bff;
            color: white;
            padding: 20px;
            border-radius: 6px;
            text-align: center;
            font-weight: bold;
        }

        .grid-item:nth-child(even) {
            background: #28a745;
        }

        .grid-item:nth-child(3n) {
            background: #dc3545;
        }

        /* Fixed columns */
        .grid-fixed {
            grid-template-columns: 100px 200px 100px;
        }

        /* Fractional columns */
        .grid-fr {
            grid-template-columns: 1fr 2fr 1fr;
        }

        /* Equal columns */
        .grid-equal {
            grid-template-columns: repeat(3, 1fr);
        }

        /* Repeat pattern */
        .grid-repeat {
            grid-template-columns: repeat(3, 100px);
        }

        /* minmax */
        .grid-minmax {
            grid-template-columns: minmax(100px, 200px) auto;
        }

        /* Rows */
        .grid-rows {
            grid-template-columns: 1fr 1fr;
            grid-template-rows: 100px 150px;
        }

        /* Responsive grid */
        .grid-responsive {
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }
    </style>
</head>
<body>

    <h1>CSS Grid Layout Introduction</h1>

    <!-- ====== 1. BASIC GRID ====== -->
    <section>
        <h2>1. Basic Grid (Fixed Columns)</h2>
        <p>Three columns with fixed widths: <code>100px 200px 100px</code></p>

        <div class="grid-container grid-fixed">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
            <div class="grid-item">4</div>
            <div class="grid-item">5</div>
            <div class="grid-item">6</div>
        </div>

        <div class="code-block">
            .grid-container {
                display: grid;
                grid-template-columns: 100px 200px 100px;
                gap: 10px;
            }
        </div>
    </section>

    <!-- ====== 2. FRACTIONAL COLUMNS ====== -->
    <section>
        <h2>2. Fractional Columns (fr)</h2>
        <p>Columns in ratio <code>1fr 2fr 1fr</code> — the middle column is twice as wide.</p>

        <div class="grid-container grid-fr">
            <div class="grid-item">1fr</div>
            <div class="grid-item">2fr</div>
            <div class="grid-item">1fr</div>
            <div class="grid-item">1fr</div>
            <div class="grid-item">2fr</div>
            <div class="grid-item">1fr</div>
        </div>

        <div class="code-block">
            .grid-container {
                display: grid;
                grid-template-columns: 1fr 2fr 1fr;
                gap: 10px;
            }
        </div>
    </section>

    <!-- ====== 3. EQUAL COLUMNS ====== -->
    <section>
        <h2>3. Equal Columns (repeat)</h2>
        <p>Three equal columns using <code>repeat(3, 1fr)</code>.</p>

        <div class="grid-container grid-equal">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
            <div class="grid-item">4</div>
            <div class="grid-item">5</div>
            <div class="grid-item">6</div>
        </div>

        <div class="code-block">
            .grid-container {
                display: grid;
                grid-template-columns: repeat(3, 1fr);
                gap: 10px;
            }
        </div>
    </section>

    <!-- ====== 4. REPEAT WITH FIXED SIZE ====== -->
    <section>
        <h2>4. Repeat with Fixed Size</h2>
        <p>Three columns of exactly 100px each using <code>repeat(3, 100px)</code>.</p>

        <div class="grid-container grid-repeat">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
            <div class="grid-item">4</div>
            <div class="grid-item">5</div>
            <div class="grid-item">6</div>
        </div>

        <div class="code-block">
            .grid-container {
                display: grid;
                grid-template-columns: repeat(3, 100px);
                gap: 10px;
            }
        </div>
    </section>

    <!-- ====== 5. MINMAX ====== -->
    <section>
        <h2>5. minmax()</h2>
        <p>First column: <code>minmax(100px, 200px)</code>, second column: <code>auto</code>.</p>

        <div class="grid-container grid-minmax">
            <div class="grid-item">minmax(100px, 200px)</div>
            <div class="grid-item">auto (remaining space)</div>
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
        </div>

        <div class="code-block">
            .grid-container {
                display: grid;
                grid-template-columns: minmax(100px, 200px) auto;
                gap: 10px;
            }
        </div>
    </section>

    <!-- ====== 6. ROWS ====== -->
    <section>
        <h2>6. Grid with Rows</h2>
        <p>Two columns and two rows with different heights.</p>

        <div class="grid-container grid-rows">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
            <div class="grid-item">4</div>
        </div>

        <div class="code-block">
            .grid-container {
                display: grid;
                grid-template-columns: 1fr 1fr;
                grid-template-rows: 100px 150px;
                gap: 10px;
            }
        </div>
    </section>

    <!-- ====== 7. RESPONSIVE GRID ====== -->
    <section>
        <h2>7. Responsive Grid (auto-fit)</h2>
        <p>Columns automatically wrap based on available space using <code>repeat(auto-fit, minmax(150px, 1fr))</code>.</p>

        <div class="grid-container grid-responsive">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
            <div class="grid-item">4</div>
            <div class="grid-item">5</div>
            <div class="grid-item">6</div>
            <div class="grid-item">7</div>
            <div class="grid-item">8</div>
        </div>

        <div class="code-block">
            .grid-container {
                display: grid;
                grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
                gap: 10px;
            }
        </div>
        <p class="note">Resize the browser to see the columns wrap automatically.</p>
    </section>

    <!-- ====== REFERENCE TABLES ====== -->
    <section>
        <h2>8. Reference Tables</h2>

        <h3>Grid Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>display</code></td>
                <td>Enables grid layout</td>
                <td><code>display: grid;</code></td>
            </tr>
            <tr>
                <td><code>grid-template-columns</code></td>
                <td>Defines columns</td>
                <td><code>grid-template-columns: 1fr 1fr;</code></td>
            </tr>
            <tr>
                <td><code>grid-template-rows</code></td>
                <td>Defines rows</td>
                <td><code>grid-template-rows: 100px auto;</code></td>
            </tr>
            <tr>
                <td><code>gap</code> / <code>grid-gap</code></td>
                <td>Sets gap between rows and columns</td>
                <td><code>gap: 10px;</code></td>
            </tr>
        </table>

        <h3>Grid Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>length</code></td>
                <td>Fixed size (px, em, rem)</td>
                <td><code>100px</code></td>
            </tr>
            <tr>
                <td><code>percentage</code></td>
                <td>Percentage of container</td>
                <td><code>50%</code></td>
            </tr>
            <tr>
                <td><code>fr</code></td>
                <td>Fraction of available space</td>
                <td><code>1fr</code>, <code>2fr</code></td>
            </tr>
            <tr>
                <td><code>auto</code></td>
                <td>Remaining space</td>
                <td><code>auto</code></td>
            </tr>
            <tr>
                <td><code>min-content</code></td>
                <td>Minimum possible space</td>
                <td><code>min-content</code></td>
            </tr>
            <tr>
                <td><code>max-content</code></td>
                <td>Maximum possible space</td>
                <td><code>max-content</code></td>
            </tr>
            <tr>
                <td><code>minmax(min, max)</code></td>
                <td>Minimum and maximum dimensions</td>
                <td><code>minmax(100px, 200px)</code></td>
            </tr>
            <tr>
                <td><code>repeat(n, size)</code></td>
                <td>Repeats a pattern</td>
                <td><code>repeat(3, 1fr)</code></td>
            </tr>
        </table>

        <h3>repeat() Variations</h3>
        <table class="reference-table">
            <tr>
                <th>Example</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>repeat(3, 1fr)</code></td>
                <td>Three equal fractional columns</td>
            </tr>
            <tr>
                <td><code>repeat(3, 100px)</code></td>
                <td>Three fixed 100px columns</td>
            </tr>
            <tr>
                <td><code>repeat(auto-fit, minmax(150px, 1fr))</code></td>
                <td>Responsive columns that wrap</td>
            </tr>
            <tr>
                <td><code>repeat(auto-fill, minmax(150px, 1fr))</code></td>
                <td>Like auto-fit, but keeps empty tracks</td>
            </tr>
        </table>
    </section>

    <!-- ====== BEST PRACTICES ====== -->
    <section>
        <h2>9. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>fr</code> units for flexible, responsive columns</li>
                <li>Use <code>repeat()</code> to avoid repetitive code</li>
                <li>Use <code>minmax()</code> with <code>auto-fit</code> for responsive grids</li>
                <li>Use <code>gap</code> instead of margins on grid items</li>
                <li>Use <code>grid-template-areas</code> for complex layouts (next lesson)</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use fixed pixel widths for responsive layouts</li>
                <li>Don't use margins on grid items (use gap instead)</li>
                <li>Don't forget <code>display: grid</code> — nothing will work without it</li>
                <li>Don't overcomplicate — Grid is powerful but start simple</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionExample
display: gridEnables grid layoutdisplay: grid;
grid-template-columnsDefines columnsgrid-template-columns: 1fr 2fr 1fr;
grid-template-rowsDefines rowsgrid-template-rows: 100px auto;
gap / grid-gapGap between cellsgap: 10px;

Grid Values

ValueDescriptionExample
lengthFixed size100px
percentagePercentage of container50%
frFraction of available space1fr, 2fr
autoRemaining spaceauto
min-contentMinimum possible spacemin-content
max-contentMaximum possible spacemax-content
minmax(min, max)Min and max dimensionsminmax(100px, 200px)
repeat(n, size)Repeats a patternrepeat(3, 1fr)

Best Practices

Do This:

/* Responsive grid that wraps automatically */
.grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 20px;
}

/* Use fr for flexible columns */
.layout {
    display: grid;
    grid-template-columns: 200px 1fr;
    gap: 15px;
}

Don’t Do This:

/* Don't use fixed widths for responsive layouts */
.grid {
    grid-template-columns: 300px 300px 300px;
    /* Breaks on smaller screens */
}

/* Don't use margins on grid items */
.grid-item {
    margin: 10px; /* Use gap on the container instead */
}

Pro Tip: CSS Grid is the most powerful layout system in CSS. Start with display: grid and grid-template-columns, then add rows and gaps. Use repeat(auto-fit, minmax(250px, 1fr)) for a responsive grid that automatically adjusts to the screen size. In the next lesson, you’ll learn about grid-template-areas for even more complex layouts!

19. grid-template-areas, grid-area, and grid-template

These three properties take CSS Grid to the next level, allowing you to create named grid areas, precisely position items, and use a shorthand for the entire grid definition.


Overview of Properties

PropertyDescription
grid-template-areasDefines named grid areas using a visual map
grid-areaPositions a grid item in the grid (or assigns it to a named area)
grid-templateShorthand for grid-template-columns, grid-template-rows, and grid-template-areas

1. grid-template-areas

The grid-template-areas property defines named grid areas using a visual map of strings. Each string represents a row, and each word represents a cell.

.grid-container {
    display: grid;
    grid-template-columns: repeat(3, 200px);
    grid-template-rows: 50px auto 70px;
    grid-template-areas:
        "header header header"
        "sidebar main content"
        "footer footer footer";
    gap: 10px;
    padding: 10px;
}

Visual Map:

┌─────────────────────────────────────┐
│              header                  │
├──────────┬──────────┬───────────────┤
│ sidebar  │   main   │   content     │
├──────────┴──────────┴───────────────┤
│              footer                  │
└─────────────────────────────────────┘

Assigning Items to Areas

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.content { grid-area: content; }
.footer  { grid-area: footer; }

Null Tokens

Use a sequence of full stops (.) to represent empty cells:

.grid-container {
    grid-template-areas:
        "header header header"
        "sidebar . content"
        "footer footer footer";
}

The middle cell (between sidebar and content) is empty.


2. grid-area

The grid-area property positions a grid item using either:

  • A named area (from grid-template-areas)
  • Row/column start and end positions

Syntax (Numeric):

grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
PositionRequired?Description
1st valueOptionalStart row
2nd valueOptionalStart column
3rd valueRequiredEnd row
4th valueOptionalEnd column

Examples:

/* Spans 3 rows, 1 column (starts at row 1, col 1) */
.item1 {
    grid-area: 1 / 1 / span 3 / 2;
}

/* Spans 2 rows, 2 columns (starts at row 1, col 3) */
.item2 {
    grid-area: 1 / 3 / span 2 / span 2;
}

/* Spans 1 row, 2 columns (starts at row 2, col 1) */
.item3 {
    grid-area: 2 / 1 / 3 / 3;
}

Using span:

  • span 3 — spans 3 tracks from the start position
  • span 2 — spans 2 tracks from the start position

3. grid-template (Shorthand)

The grid-template property is a shorthand for:

  • grid-template-columns
  • grid-template-rows
  • grid-template-areas
.grid-container-template {
    display: grid;
    grid-template:
        "header header" auto
        "sidebar main" 200px / 1fr 3fr;
    gap: 10px;
    padding: 10px;
}

Syntax:

grid-template: 
    "area area" <row-size>
    "area area" <row-size> / <column-sizes>;

Breaking It Down:

PartDescription
"header header" autoFirst row: header spans 2 columns, row height is auto
"sidebar main" 200pxSecond row: sidebar and main, row height is 200px
/ 1fr 3frColumn sizes: 1fr for sidebar, 3fr for main

Visual Layout:

┌──────────────┬─────────────────────────┐
│        header (auto)                    │
├──────────────┼─────────────────────────┤
│   sidebar    │         main            │
│    (1fr)     │         (3fr)           │
│   (200px)    │        (200px)          │
└──────────────┴─────────────────────────┘

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>grid-template-areas, grid-area, grid-template</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== GRID AREA DEMO ====== */
        .grid-container {
            display: grid;
            grid-template-columns: repeat(3, 200px);
            grid-template-rows: 50px auto 70px;
            grid-template-areas:
                "header header header"
                "sidebar main content"
                "footer footer footer";
            gap: 10px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px auto;
            max-width: 650px;
        }

        .cell {
            border: 2px solid #333;
            padding: 15px;
            border-radius: 4px;
            font-weight: bold;
            text-align: center;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .header  { grid-area: header;  background-color: #f0e68c; }
        .sidebar { grid-area: sidebar; background-color: #add8e6; }
        .main    { grid-area: main;    background-color: #90ee90; }
        .content { grid-area: content; background-color: #b0c4de; }
        .footer  { grid-area: footer;  background-color: #f5deb3; }

        /* ====== GRID AREA NUMERIC DEMO ====== */
        .grid-container-area {
            display: grid;
            grid-template-columns: repeat(3, 200px);
            grid-template-rows: 50px auto 70px;
            gap: 10px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px auto;
            max-width: 650px;
        }

        .item1 {
            grid-area: 1 / 1 / span 3 / 2;
            background-color: #f0e68c;
        }

        .item2 {
            grid-area: 1 / 3 / span 2 / span 2;
            background-color: #add8e6;
        }

        .item3 {
            grid-area: 2 / 1 / 3 / 3;
            background-color: #90ee90;
        }

        /* ====== GRID TEMPLATE SHORTHAND ====== */
        .grid-container-template {
            display: grid;
            grid-template:
                "header header" auto
                "sidebar main" 200px / 1fr 3fr;
            gap: 10px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px auto;
            max-width: 650px;
        }

        .header, .sidebar {
            background-color: #f0e68c;
        }

        .main {
            background-color: #add8e6;
        }

        /* ====== NULL TOKEN DEMO ====== */
        .grid-null {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            grid-template-rows: repeat(3, 80px);
            grid-template-areas:
                "header header header"
                "sidebar . content"
                "footer footer footer";
            gap: 10px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px auto;
            max-width: 650px;
        }

        .grid-null .header  { grid-area: header;  background-color: #f0e68c; }
        .grid-null .sidebar { grid-area: sidebar; background-color: #add8e6; }
        .grid-null .content { grid-area: content; background-color: #b0c4de; }
        .grid-null .footer  { grid-area: footer;  background-color: #f5deb3; }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
            text-align: center;
        }
    </style>
</head>
<body>

    <h1>grid-template-areas, grid-area, and grid-template</h1>

    <!-- ====== 1. GRID-TEMPLATE-AREAS ====== -->
    <section>
        <h2>1. grid-template-areas (Named Areas)</h2>
        <p>Define a visual map of your layout using named areas in double quotes.</p>

        <div class="grid-container">
            <div class="cell header">Header</div>
            <div class="cell sidebar">Sidebar</div>
            <div class="cell main">Main Content</div>
            <div class="cell content">Additional Content</div>
            <div class="cell footer">Footer</div>
        </div>

        <div class="code-block">
            .grid-container {
                display: grid;
                grid-template-columns: repeat(3, 200px);
                grid-template-rows: 50px auto 70px;
                grid-template-areas:
                    "header header header"
                    "sidebar main content"
                    "footer footer footer";
                gap: 10px;
            }

            .header  { grid-area: header; }
            .sidebar { grid-area: sidebar; }
            .main    { grid-area: main; }
            .content { grid-area: content; }
            .footer  { grid-area: footer; }
        </div>
    </section>

    <!-- ====== 2. NULL TOKENS ====== -->
    <section>
        <h2>2. Null Tokens (Empty Cells)</h2>
        <p>Use full stops (<code>.</code>) to represent empty cells in the grid.</p>

        <div class="grid-null">
            <div class="cell header">Header</div>
            <div class="cell sidebar">Sidebar</div>
            <div class="cell content">Content</div>
            <div class="cell footer">Footer</div>
        </div>

        <p class="note">The middle cell (between sidebar and content) is empty.</p>

        <div class="code-block">
            .grid-null {
                grid-template-areas:
                    "header header header"
                    "sidebar . content"      /* . = empty cell */
                    "footer footer footer";
            }
        </div>
    </section>

    <!-- ====== 3. GRID-AREA (NUMERIC) ====== -->
    <section>
        <h2>3. grid-area (Numeric Positioning)</h2>
        <p>Position items using row/column start and end values.</p>

        <div class="grid-container-area">
            <div class="cell item1">Item 1 (spans 3 rows)</div>
            <div class="cell item2">Item 2 (spans 2 rows × 2 cols)</div>
            <div class="cell item3">Item 3 (spans 1 row × 2 cols)</div>
        </div>

        <div class="code-block">
            /* Starts at row 1, col 1 — spans 3 rows, 1 column */
            .item1 { grid-area: 1 / 1 / span 3 / 2; }

            /* Starts at row 1, col 3 — spans 2 rows, 2 columns */
            .item2 { grid-area: 1 / 3 / span 2 / span 2; }

            /* Starts at row 2, col 1 — spans 1 row, 2 columns */
            .item3 { grid-area: 2 / 1 / 3 / 3; }
        </div>
    </section>

    <!-- ====== 4. GRID-TEMPLATE (SHORTHAND) ====== -->
    <section>
        <h2>4. grid-template (Shorthand)</h2>
        <p>Combines columns, rows, and areas into a single declaration.</p>

        <div class="grid-container-template">
            <div class="cell header">Header</div>
            <div class="cell sidebar">Sidebar</div>
            <div class="cell main">Main Content</div>
        </div>

        <div class="code-block">
            .grid-container-template {
                display: grid;
                grid-template:
                    "header header" auto
                    "sidebar main" 200px / 1fr 3fr;
                gap: 10px;
            }
        </div>
    </section>

    <!-- ====== 5. REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>Grid Area Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>grid-template-areas</code></td>
                <td>Defines named grid areas</td>
                <td><code>"header header" "sidebar main"</code></td>
            </tr>
            <tr>
                <td><code>grid-area</code></td>
                <td>Positions an item (named or numeric)</td>
                <td><code>grid-area: header;</code></td>
            </tr>
            <tr>
                <td><code>grid-area</code></td>
                <td>Positions an item (numeric)</td>
                <td><code>grid-area: 1 / 1 / span 3 / 2;</code></td>
            </tr>
            <tr>
                <td><code>grid-template</code></td>
                <td>Shorthand for columns, rows, and areas</td>
                <td><code>grid-template: "header" auto / 1fr 2fr;</code></td>
            </tr>
        </table>

        <h3>grid-area Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Position</th>
                <th>Required?</th>
            </tr>
            <tr>
                <td>1st value</td>
                <td>Start row</td>
                <td>Optional</td>
            </tr>
            <tr>
                <td>2nd value</td>
                <td>Start column</td>
                <td>Optional</td>
            </tr>
            <tr>
                <td>3rd value</td>
                <td>End row</td>
                <td>Required</td>
            </tr>
            <tr>
                <td>4th value</td>
                <td>End column</td>
                <td>Optional</td>
            </tr>
        </table>

        <h3>grid-template Shorthand Breakdown</h3>
        <table class="reference-table">
            <tr>
                <th>Part</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>"header header" auto</code></td>
                <td>Row 1: named areas + row height</td>
                <td>Header spans 2 columns, auto height</td>
            </tr>
            <tr>
                <td><code>"sidebar main" 200px</code></td>
                <td>Row 2: named areas + row height</td>
                <td>Sidebar and main, 200px height</td>
            </tr>
            <tr>
                <td><code>/ 1fr 3fr</code></td>
                <td>Column sizes</td>
                <td>Column 1 = 1fr, Column 2 = 3fr</td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>grid-template-areas</code> for clear, readable layouts</li>
                <li>Use meaningful area names (header, sidebar, main, footer)</li>
                <li>Use <code>grid-template</code> shorthand for concise code</li>
                <li>Use null tokens (<code>.</code>) for empty cells</li>
                <li>Use <code>span</code> for spanning multiple tracks</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use numeric <code>grid-area</code> when named areas would be clearer</li>
                <li>Don't forget that <code>grid-template-areas</code> must form a complete rectangle</li>
                <li>Don't use <code>grid-template</code> shorthand without understanding the order</li>
                <li>Don't mix named and numeric <code>grid-area</code> on the same item</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionExample
grid-template-areasDefines named grid areas"header header" "sidebar main"
grid-area (named)Assigns item to a named areagrid-area: header;
grid-area (numeric)Positions item by row/columngrid-area: 1 / 1 / span 3 / 2;
grid-templateShorthand for columns, rows, areasgrid-template: "header" auto / 1fr 2fr;

grid-area Numeric Syntax

grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
PositionRequired?Description
1stOptionalStart row
2ndOptionalStart column
3rdRequiredEnd row
4thOptionalEnd column

Best Practices

Do This:

/* Named areas — clear and readable */
.layout {
    display: grid;
    grid-template-areas:
        "header header"
        "sidebar main"
        "footer footer";
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }

/* Numeric positioning for precise control */
.item {
    grid-area: 1 / 2 / span 2 / span 3;
}

Don’t Do This:

/* Don't use incomplete area maps */
.layout {
    grid-template-areas:
        "header header"
        "sidebar main"
        "footer";  /* Invalid! Must form a complete rectangle */
}

/* Don't mix named and numeric on the same item */
.item {
    grid-area: header;  /* Named */
    grid-area: 1 / 1 / 2 / 2;  /* Numeric — overrides the named area */
}

Pro Tip: grid-template-areas is the most readable way to create complex layouts. Name your areas semantically (header, sidebar, main, footer) so the layout is self-documenting. Use null tokens (.) for empty cells. The grid-template shorthand combines everything into one declaration, but use it only when you’re comfortable with the syntax — it can be harder to read and maintain than separate properties!

20. grid-auto-columns, grid-auto-rows, and grid-auto-flow

These three properties control how auto-placed grid items are sized and positioned. They’re essential for handling grids where the number of items isn’t known in advance or where you want automatic sizing rules.


Overview of Properties

PropertyDescription
grid-auto-columnsSets the default size for auto-placed columns
grid-auto-rowsSets the default size for auto-placed rows
grid-auto-flowControls how auto-placed items flow into the grid

1. grid-auto-columns

The grid-auto-columns property defines the default size for auto-placed columns — columns that are created implicitly when items are placed outside the explicitly defined grid.

.grid-container {
    display: grid;
    grid-template-rows: 50px auto 70px;
    grid-auto-columns: 200px;
}

What happens:

  • The grid has 3 explicit rows
  • No explicit columns are defined
  • Items are auto-placed, creating implicit columns
  • Each implicit column is 200px wide

Values

ValueDescriptionExample
lengthFixed size (px, cm, em)grid-auto-columns: 200px;
percentagePercentage of containergrid-auto-columns: 25%;
frFraction of available spacegrid-auto-columns: 1fr;
minmax(min, max)Min and max dimensionsgrid-auto-columns: minmax(100px, 1fr);
min-contentMinimum possible spacegrid-auto-columns: min-content;
max-contentMaximum possible spacegrid-auto-columns: max-content;
fit-contentFits content within limitsgrid-auto-columns: fit-content(200px);
autoAutomatic sizinggrid-auto-columns: auto;

Important: This property only applies to auto-placed items, not to items that are explicitly positioned.


2. grid-auto-rows

The grid-auto-rows property defines the default size for auto-placed rows — rows that are created implicitly when items are placed outside the explicitly defined grid.

.grid-container-rows {
    display: grid;
    grid-template-columns: 200px auto;
    grid-auto-rows: 50px;
}

What happens:

  • The grid has 2 explicit columns
  • No explicit rows are defined
  • Items are auto-placed, creating implicit rows
  • Each implicit row is 50px tall

Values

Same as grid-auto-columns:
length, percentage, fr, minmax(), min-content, max-content, fit-content(), auto


3. grid-auto-flow

The grid-auto-flow property specifies how auto-placed items are placed in the grid.

.grid-container-flow {
    display: grid;
    grid-template-rows: repeat(3, 50px);
    grid-template-columns: repeat(2, 200px);
    grid-auto-flow: row dense;
}

Values

ValueDescription
rowItems fill rows first (default)
columnItems fill columns first
row denseFills rows, and “dense” packs items to fill holes
column denseFills columns, and “dense” packs items to fill holes

row vs column

grid-auto-flow: row (default):

Item 1  Item 2  Item 3
Item 4  Item 5  Item 6

grid-auto-flow: column:

Item 1  Item 3  Item 5
Item 2  Item 4  Item 6

The dense Keyword

The dense keyword tells the grid to fill in holes left by items that span multiple tracks. Without dense, gaps may remain.

Without dense:

┌─────┬─────┬─────┐
│  1  │  2  │  3  │
├─────┼─────┴─────┤
│  4  │    5      │
├─────┼─────┬─────┤
│  6  │     │     │
└─────┴─────┴─────┘
   ↑ gap remains

With dense:

┌─────┬─────┬─────┐
│  1  │  2  │  3  │
├─────┼─────┴─────┤
│  4  │    5      │
├─────┼─────┬─────┤
│  6  │  7  │  8  │
└─────┴─────┴─────┘
   ↑ holes filled

Note: dense can change the visual order of items, which may affect accessibility. Use it carefully.


Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>grid-auto-columns, grid-auto-rows, grid-auto-flow</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        /* ====== GRID DEMOS ====== */
        .cell {
            border: 2px solid #333;
            padding: 15px;
            border-radius: 4px;
            font-weight: bold;
            text-align: center;
            display: flex;
            align-items: center;
            justify-content: center;
            background: #007bff;
            color: white;
        }

        .cell:nth-child(even) {
            background: #28a745;
        }

        .cell:nth-child(3n) {
            background: #dc3545;
        }

        /* grid-auto-columns demo */
        .grid-auto-cols {
            display: grid;
            grid-template-rows: 50px auto 70px;
            grid-auto-columns: 200px;
            gap: 10px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
        }

        /* grid-auto-rows demo */
        .grid-auto-rows {
            display: grid;
            grid-template-columns: 200px auto;
            grid-auto-rows: 50px;
            gap: 10px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
        }

        /* grid-auto-flow: row */
        .grid-flow-row {
            display: grid;
            grid-template-rows: repeat(3, 50px);
            grid-template-columns: repeat(3, 1fr);
            grid-auto-flow: row;
            gap: 10px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
        }

        /* grid-auto-flow: column */
        .grid-flow-column {
            display: grid;
            grid-template-rows: repeat(3, 50px);
            grid-template-columns: repeat(3, 1fr);
            grid-auto-flow: column;
            gap: 10px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
        }

        /* grid-auto-flow: row dense */
        .grid-flow-dense {
            display: grid;
            grid-template-rows: repeat(3, 60px);
            grid-template-columns: repeat(3, 1fr);
            grid-auto-flow: row dense;
            gap: 10px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
        }

        .grid-flow-dense .span-2 {
            grid-column: span 2;
        }

        .grid-flow-dense .span-3 {
            grid-column: span 3;
        }

        /* Non-dense for comparison */
        .grid-flow-no-dense {
            display: grid;
            grid-template-rows: repeat(3, 60px);
            grid-template-columns: repeat(3, 1fr);
            grid-auto-flow: row;
            gap: 10px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
        }

        .grid-flow-no-dense .span-2 {
            grid-column: span 2;
        }

        .grid-flow-no-dense .span-3 {
            grid-column: span 3;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }
    </style>
</head>
<body>

    <h1>grid-auto-columns, grid-auto-rows, and grid-auto-flow</h1>

    <!-- ====== 1. GRID-AUTO-COLUMNS ====== -->
    <section>
        <h2>1. grid-auto-columns</h2>
        <p>Defines the default size for <strong>auto-placed columns</strong>. Only one explicit property is set: <code>grid-template-rows</code>.</p>

        <div class="grid-auto-cols">
            <div class="cell">Item 1</div>
            <div class="cell">Item 2</div>
            <div class="cell">Item 3</div>
            <div class="cell">Item 4</div>
            <div class="cell">Item 5</div>
            <div class="cell">Item 6</div>
        </div>

        <p class="note">Each auto-created column is <span class="highlight">200px</span> wide.</p>

        <div class="code-block">
            .grid-auto-cols {
                display: grid;
                grid-template-rows: 50px auto 70px;
                grid-auto-columns: 200px;
                gap: 10px;
            }
        </div>
    </section>

    <!-- ====== 2. GRID-AUTO-ROWS ====== -->
    <section>
        <h2>2. grid-auto-rows</h2>
        <p>Defines the default size for <strong>auto-placed rows</strong>. Only one explicit property is set: <code>grid-template-columns</code>.</p>

        <div class="grid-auto-rows">
            <div class="cell">Item 1</div>
            <div class="cell">Item 2</div>
            <div class="cell">Item 3</div>
            <div class="cell">Item 4</div>
            <div class="cell">Item 5</div>
            <div class="cell">Item 6</div>
        </div>

        <p class="note">Each auto-created row is <span class="highlight">50px</span> tall.</p>

        <div class="code-block">
            .grid-auto-rows {
                display: grid;
                grid-template-columns: 200px auto;
                grid-auto-rows: 50px;
                gap: 10px;
            }
        </div>
    </section>

    <!-- ====== 3. GRID-AUTO-FLOW: ROW ====== -->
    <section>
        <h2>3. grid-auto-flow: row (default)</h2>
        <p>Items fill <strong>rows first</strong>, then wrap to the next row.</p>

        <div class="grid-flow-row">
            <div class="cell">1</div>
            <div class="cell">2</div>
            <div class="cell">3</div>
            <div class="cell">4</div>
            <div class="cell">5</div>
            <div class="cell">6</div>
        </div>

        <div class="code-block">
            .grid-flow-row {
                display: grid;
                grid-template-rows: repeat(3, 50px);
                grid-template-columns: repeat(3, 1fr);
                grid-auto-flow: row;  /* Default */
                gap: 10px;
            }
        </div>
    </section>

    <!-- ====== 4. GRID-AUTO-FLOW: COLUMN ====== -->
    <section>
        <h2>4. grid-auto-flow: column</h2>
        <p>Items fill <strong>columns first</strong>, then wrap to the next column.</p>

        <div class="grid-flow-column">
            <div class="cell">1</div>
            <div class="cell">2</div>
            <div class="cell">3</div>
            <div class="cell">4</div>
            <div class="cell">5</div>
            <div class="cell">6</div>
        </div>

        <div class="code-block">
            .grid-flow-column {
                display: grid;
                grid-template-rows: repeat(3, 50px);
                grid-template-columns: repeat(3, 1fr);
                grid-auto-flow: column;  /* Fills columns first */
                gap: 10px;
            }
        </div>
    </section>

    <!-- ====== 5. GRID-AUTO-FLOW: DENSE ====== -->
    <section>
        <h2>5. grid-auto-flow: row dense</h2>
        <p>When items span multiple tracks, <code>dense</code> fills in the gaps left behind.</p>

        <h3>Without dense (gaps remain):</h3>
        <div class="grid-flow-no-dense">
            <div class="cell span-2">1 (span 2)</div>
            <div class="cell">2</div>
            <div class="cell">3</div>
            <div class="cell span-3">4 (span 3)</div>
            <div class="cell">5</div>
            <div class="cell">6</div>
        </div>
        <p class="note">Gap remains in the first row because item 3 doesn't fit.</p>

        <h3>With dense (gaps filled):</h3>
        <div class="grid-flow-dense">
            <div class="cell span-2">1 (span 2)</div>
            <div class="cell">2</div>
            <div class="cell">3</div>
            <div class="cell span-3">4 (span 3)</div>
            <div class="cell">5</div>
            <div class="cell">6</div>
        </div>
        <p class="note">Item 3 moves up to fill the gap, making the grid more compact.</p>

        <div class="code-block">
            /* Without dense — gaps may remain */
            .grid {
                grid-auto-flow: row;
            }

            /* With dense — fills in holes */
            .grid {
                grid-auto-flow: row dense;
            }

            /* Column dense */
            .grid {
                grid-auto-flow: column dense;
            }
        </div>
    </section>

    <!-- ====== 6. COMPARISON: ROW vs COLUMN ====== -->
    <section>
        <h2>6. Side-by-Side Comparison</h2>

        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 30px;">
            <div>
                <h4>grid-auto-flow: row</h4>
                <div class="grid-flow-row" style="grid-template-rows: repeat(2, 50px); grid-template-columns: repeat(3, 1fr);">
                    <div class="cell">1</div>
                    <div class="cell">2</div>
                    <div class="cell">3</div>
                    <div class="cell">4</div>
                    <div class="cell">5</div>
                    <div class="cell">6</div>
                </div>
                <p class="note">Order: 1, 2, 3, 4, 5, 6 (left to right, top to bottom)</p>
            </div>

            <div>
                <h4>grid-auto-flow: column</h4>
                <div class="grid-flow-column" style="grid-template-rows: repeat(2, 50px); grid-template-columns: repeat(3, 1fr);">
                    <div class="cell">1</div>
                    <div class="cell">2</div>
                    <div class="cell">3</div>
                    <div class="cell">4</div>
                    <div class="cell">5</div>
                    <div class="cell">6</div>
                </div>
                <p class="note">Order: 1, 2, 3, 4, 5, 6 (top to bottom, left to right)</p>
            </div>
        </div>
    </section>

    <!-- ====== 7. REFERENCE TABLES ====== -->
    <section>
        <h2>7. Reference Tables</h2>

        <h3>Auto Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>grid-auto-columns</code></td>
                <td>Default size for auto-placed columns</td>
                <td><code>grid-auto-columns: 200px;</code></td>
            </tr>
            <tr>
                <td><code>grid-auto-rows</code></td>
                <td>Default size for auto-placed rows</td>
                <td><code>grid-auto-rows: 50px;</code></td>
            </tr>
            <tr>
                <td><code>grid-auto-flow</code></td>
                <td>How auto-placed items flow</td>
                <td><code>grid-auto-flow: row dense;</code></td>
            </tr>
        </table>

        <h3>grid-auto-flow Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>row</code></td>
                <td>Items fill rows first (default)</td>
            </tr>
            <tr>
                <td><code>column</code></td>
                <td>Items fill columns first</td>
            </tr>
            <tr>
                <td><code>row dense</code></td>
                <td>Fills rows and packs items to fill holes</td>
            </tr>
            <tr>
                <td><code>column dense</code></td>
                <td>Fills columns and packs items to fill holes</td>
            </tr>
        </table>

        <h3>Values for grid-auto-columns and grid-auto-rows</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>length</code></td>
                <td>Fixed size (px, cm, em)</td>
                <td><code>200px</code></td>
            </tr>
            <tr>
                <td><code>percentage</code></td>
                <td>Percentage of container</td>
                <td><code>25%</code></td>
            </tr>
            <tr>
                <td><code>fr</code></td>
                <td>Fraction of available space</td>
                <td><code>1fr</code></td>
            </tr>
            <tr>
                <td><code>minmax(min, max)</code></td>
                <td>Min and max dimensions</td>
                <td><code>minmax(100px, 1fr)</code></td>
            </tr>
            <tr>
                <td><code>min-content</code></td>
                <td>Minimum possible space</td>
                <td><code>min-content</code></td>
            </tr>
            <tr>
                <td><code>max-content</code></td>
                <td>Maximum possible space</td>
                <td><code>max-content</code></td>
            </tr>
            <tr>
                <td><code>fit-content(limit)</code></td>
                <td>Fits content within limits</td>
                <td><code>fit-content(200px)</code></td>
            </tr>
            <tr>
                <td><code>auto</code></td>
                <td>Automatic sizing</td>
                <td><code>auto</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 8. BEST PRACTICES ====== -->
    <section>
        <h2>8. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>grid-auto-rows</code> to control the height of auto-created rows</li>
                <li>Use <code>grid-auto-columns</code> to control the width of auto-created columns</li>
                <li>Use <code>grid-auto-flow: row dense</code> to fill gaps in complex layouts</li>
                <li>Use <code>grid-auto-flow: column</code> for vertical layouts (e.g., navigation)</li>
                <li>Test with different content sizes to ensure the grid behaves as expected</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use <code>grid-auto-columns</code> when you've defined all columns explicitly</li>
                <li>Don't use <code>dense</code> without considering the visual order change</li>
                <li>Don't forget that <code>grid-auto-flow</code> only affects <strong>auto-placed</strong> items</li>
                <li>Don't rely solely on <code>dense</code> for accessibility — visual order should match DOM order when possible</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionExample
grid-auto-columnsDefault size for auto-placed columnsgrid-auto-columns: 200px;
grid-auto-rowsDefault size for auto-placed rowsgrid-auto-rows: 50px;
grid-auto-flowHow auto-placed items flowgrid-auto-flow: row dense;

grid-auto-flow Values

ValueDescription
rowItems fill rows first (default)
columnItems fill columns first
row denseFills rows and packs items to fill holes
column denseFills columns and packs items to fill holes

Best Practices

Do This:

/* Control the height of auto-created rows */
.grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: 100px; /* Each auto row is 100px */
}

/* Fill gaps with dense */
.grid {
    grid-auto-flow: row dense;
}

/* Vertical layout with column flow */
.nav {
    display: grid;
    grid-auto-flow: column;
    gap: 10px;
}

Don’t Do This:

/* Don't use auto-columns when columns are defined */
.grid {
    grid-template-columns: 1fr 1fr;
    grid-auto-columns: 200px; /* Only affects extra columns */
}

/* Don't use dense without understanding the trade-offs */
.grid {
    grid-auto-flow: dense; /* Can change visual order */
}

Pro Tip: grid-auto-rows and grid-auto-columns are essential when you don’t know how many items your grid will contain (e.g., dynamic content from a database). Use grid-auto-flow: row dense to compact your grid and fill holes — but be aware that dense can change the visual order of items, which may confuse users relying on screen readers. Always test your grid with different content sizes!

21. grid-row-start, grid-column-start, grid-row-end, and grid-column-end

These four properties give you precise control over where grid items are placed and how many tracks they span. They are the individual longhand properties that grid-area and grid-row/grid-column shorthand properties are based on.


Overview of Properties

PropertyDescription
grid-row-startSpecifies where a grid item starts within a row
grid-row-endSpecifies where a grid item ends within a row
grid-column-startSpecifies where a grid item starts within a column
grid-column-endSpecifies where a grid item ends within a column

1. grid-row-start

Specifies the starting row line for a grid item.

.first-item {
    grid-row-start: 1; /* Starts at row line 1 */
}

Values

ValueDescriptionExample
autoNext available row (default)grid-row-start: auto;
integerSpecific row line numbergrid-row-start: 2;
span #nSpans n rows from the startgrid-row-start: span 2;

2. grid-row-end

Specifies the ending row line for a grid item.

.first-item {
    grid-row-start: 1;
    grid-row-end: 3; /* Ends at row line 3 (spans rows 1 and 2) */
}

Values

ValueDescriptionExample
autoNext available row (default)grid-row-end: auto;
integerSpecific row line numbergrid-row-end: 4;
span #nSpans n rows from the startgrid-row-end: span 2;

Important: The end line is exclusivegrid-row-end: 3 means the item ends before line 3 (i.e., it occupies rows 1 and 2).


3. grid-column-start

Specifies the starting column line for a grid item.

.second-item {
    grid-column-start: 2; /* Starts at column line 2 */
}

Values

ValueDescriptionExample
autoNext available column (default)grid-column-start: auto;
integerSpecific column line numbergrid-column-start: 3;
span #nSpans n columns from the startgrid-column-start: span 2;

4. grid-column-end

Specifies the ending column line for a grid item.

.second-item {
    grid-column-start: 2;
    grid-column-end: 4; /* Ends at column line 4 (spans columns 2 and 3) */
}

Values

ValueDescriptionExample
autoNext available column (default)grid-column-end: auto;
integerSpecific column line numbergrid-column-end: 4;
span #nSpans n columns from the startgrid-column-end: span 2;

Visualizing Grid Lines

In a 3×2 grid, there are 4 column lines and 3 row lines:

Column Lines:  1        2        3        4
              │        │        │        │
Row Line 1 ───┼────────┼────────┼────────┤
              │ Cell 1 │ Cell 2 │ Cell 3 │
Row Line 2 ───┼────────┼────────┼────────┤
              │ Cell 4 │ Cell 5 │ Cell 6 │
Row Line 3 ───┴────────┴────────┴────────┘
  • A cell that starts at row line 1 and ends at row line 2 occupies 1 row
  • A cell that starts at row line 1 and ends at row line 3 occupies 2 rows

Using span

Instead of specifying the end line, you can use span to indicate how many tracks the item should cover.

/* These two are equivalent */
.item {
    grid-row-start: 1;
    grid-row-end: 3;
}

.item {
    grid-row-start: 1;
    grid-row-end: span 2; /* Spans 2 rows from row line 1 */
}

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>grid-row-start, grid-column-start, grid-row-end, grid-column-end</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== GRID DEMOS ====== */
        .grid-container {
            display: grid;
            grid-template-columns: repeat(3, 100px);
            grid-template-rows: repeat(2, 100px);
            gap: 5px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px auto;
            width: fit-content;
        }

        .cell {
            border: 2px solid #333;
            padding: 10px;
            border-radius: 4px;
            display: flex;
            align-items: center;
            justify-content: center;
            text-align: center;
            font-weight: bold;
            font-size: 0.85rem;
            background: #007bff;
            color: white;
        }

        .cell:nth-child(even) {
            background: #28a745;
        }

        .cell:nth-child(3n) {
            background: #dc3545;
        }

        /* Demo 1: grid-row-start / grid-row-end */
        .grid-rows {
            display: grid;
            grid-template-columns: repeat(3, 100px);
            grid-template-rows: repeat(3, 100px);
            gap: 5px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px auto;
            width: fit-content;
        }

        .grid-rows .span-2-rows {
            grid-row-start: 1;
            grid-row-end: 3;
            background: #6c5ce7;
        }

        /* Demo 2: grid-column-start / grid-column-end */
        .grid-columns {
            display: grid;
            grid-template-columns: repeat(3, 100px);
            grid-template-rows: repeat(3, 100px);
            gap: 5px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px auto;
            width: fit-content;
        }

        .grid-columns .span-2-cols {
            grid-column-start: 2;
            grid-column-end: 4;
            background: #e17055;
        }

        /* Demo 3: Both row and column */
        .grid-both {
            display: grid;
            grid-template-columns: repeat(3, 100px);
            grid-template-rows: repeat(3, 100px);
            gap: 5px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px auto;
            width: fit-content;
        }

        .grid-both .span-both {
            grid-row-start: 1;
            grid-row-end: 3;
            grid-column-start: 2;
            grid-column-end: 4;
            background: #00b894;
        }

        /* Demo 4: span keyword */
        .grid-span {
            display: grid;
            grid-template-columns: repeat(4, 80px);
            grid-template-rows: repeat(2, 80px);
            gap: 5px;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px auto;
            width: fit-content;
        }

        .grid-span .span-2 {
            grid-column-start: 1;
            grid-column-end: span 2;
            background: #6c5ce7;
        }

        .grid-span .span-3 {
            grid-column-start: 3;
            grid-column-end: span 2;
            background: #e17055;
        }

        /* Grid lines visualization */
        .grid-lines {
            display: grid;
            grid-template-columns: repeat(3, 100px);
            grid-template-rows: repeat(2, 100px);
            gap: 0;
            padding: 0;
            background: #fff;
            border: 2px solid #333;
            margin: 15px auto;
            width: fit-content;
            position: relative;
        }

        .grid-lines .cell {
            border: 1px dashed #999;
            border-radius: 0;
            background: #f8f9fa;
            color: #333;
            font-size: 0.8rem;
        }

        .grid-lines .cell.line-label {
            background: #ffc107;
            font-weight: bold;
        }
    </style>
</head>
<body>

    <h1>grid-row-start, grid-column-start, grid-row-end, grid-column-end</h1>

    <!-- ====== 1. GRID-ROW-START / GRID-ROW-END ====== -->
    <section>
        <h2>1. grid-row-start & grid-row-end</h2>
        <p>Control where an item <strong>starts</strong> and <strong>ends</strong> within rows.</p>

        <div class="grid-rows">
            <div class="cell span-2-rows">Spans 2 Rows<br>(start: 1, end: 3)</div>
            <div class="cell">2</div>
            <div class="cell">3</div>
            <div class="cell">4</div>
            <div class="cell">5</div>
            <div class="cell">6</div>
            <div class="cell">7</div>
        </div>

        <div class="code-block">
            .span-2-rows {
                grid-row-start: 1;   /* Starts at row line 1 */
                grid-row-end: 3;     /* Ends at row line 3 (spans rows 1 & 2) */
            }
        </div>
    </section>

    <!-- ====== 2. GRID-COLUMN-START / GRID-COLUMN-END ====== -->
    <section>
        <h2>2. grid-column-start & grid-column-end</h2>
        <p>Control where an item <strong>starts</strong> and <strong>ends</strong> within columns.</p>

        <div class="grid-columns">
            <div class="cell">1</div>
            <div class="cell span-2-cols">Spans 2 Columns<br>(start: 2, end: 4)</div>
            <div class="cell">4</div>
            <div class="cell">5</div>
            <div class="cell">6</div>
            <div class="cell">7</div>
            <div class="cell">8</div>
        </div>

        <div class="code-block">
            .span-2-cols {
                grid-column-start: 2;  /* Starts at column line 2 */
                grid-column-end: 4;    /* Ends at column line 4 (spans cols 2 & 3) */
            }
        </div>
    </section>

    <!-- ====== 3. BOTH ROW AND COLUMN ====== -->
    <section>
        <h2>3. Combining Row and Column</h2>
        <p>Use all four properties to position an item precisely.</p>

        <div class="grid-both">
            <div class="cell">1</div>
            <div class="cell span-both">Spans 2 Rows × 2 Columns<br>(row: 1→3, col: 2→4)</div>
            <div class="cell">3</div>
            <div class="cell">4</div>
            <div class="cell">5</div>
            <div class="cell">6</div>
            <div class="cell">7</div>
        </div>

        <div class="code-block">
            .span-both {
                grid-row-start: 1;
                grid-row-end: 3;
                grid-column-start: 2;
                grid-column-end: 4;
            }
        </div>
    </section>

    <!-- ====== 4. THE span KEYWORD ====== -->
    <section>
        <h2>4. Using the <code>span</code> Keyword</h2>
        <p>Instead of specifying the end line, use <code>span</code> to indicate how many tracks to cover.</p>

        <div class="grid-span">
            <div class="cell span-2">span 2</div>
            <div class="cell span-3">span 2</div>
            <div class="cell">3</div>
            <div class="cell">4</div>
            <div class="cell">5</div>
            <div class="cell">6</div>
        </div>

        <div class="code-block">
            /* These two are equivalent */
            .item {
                grid-column-start: 1;
                grid-column-end: span 2;  /* Spans 2 columns from start */
            }

            .item {
                grid-column-start: 1;
                grid-column-end: 3;       /* Same result */
            }
        </div>
    </section>

    <!-- ====== 5. GRID LINES VISUALIZATION ====== -->
    <section>
        <h2>5. Understanding Grid Lines</h2>
        <p>In a 3×2 grid, there are <strong>4 column lines</strong> and <strong>3 row lines</strong>.</p>

        <div style="display: flex; flex-direction: column; align-items: center;">
            <!-- Column line labels -->
            <div style="display: flex; gap: 0; margin-bottom: 5px; padding-left: 40px;">
                <div style="width: 100px; text-align: center; font-weight: bold; color: #007bff;">Line 1</div>
                <div style="width: 100px; text-align: center; font-weight: bold; color: #007bff;">Line 2</div>
                <div style="width: 100px; text-align: center; font-weight: bold; color: #007bff;">Line 3</div>
                <div style="width: 100px; text-align: center; font-weight: bold; color: #007bff;">Line 4</div>
            </div>

            <div style="display: flex; align-items: center;">
                <!-- Row line labels -->
                <div style="display: flex; flex-direction: column; margin-right: 5px;">
                    <div style="height: 100px; display: flex; align-items: center; font-weight: bold; color: #28a745;">Line 1</div>
                    <div style="height: 100px; display: flex; align-items: center; font-weight: bold; color: #28a745;">Line 2</div>
                    <div style="height: 100px; display: flex; align-items: center; font-weight: bold; color: #28a745;">Line 3</div>
                </div>

                <div class="grid-lines">
                    <div class="cell">Cell 1</div>
                    <div class="cell">Cell 2</div>
                    <div class="cell">Cell 3</div>
                    <div class="cell">Cell 4</div>
                    <div class="cell">Cell 5</div>
                    <div class="cell">Cell 6</div>
                </div>
            </div>
        </div>

        <p class="note" style="text-align: center; margin-top: 15px;">
            <span class="highlight">Column lines</span> run vertically between columns (1, 2, 3, 4).<br>
            <span class="highlight">Row lines</span> run horizontally between rows (1, 2, 3).
        </p>
    </section>

    <!-- ====== 6. REFERENCE TABLES ====== -->
    <section>
        <h2>6. Reference Tables</h2>

        <h3>Grid Placement Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>grid-row-start</code></td>
                <td>Starting row line</td>
                <td><code>grid-row-start: 1;</code></td>
            </tr>
            <tr>
                <td><code>grid-row-end</code></td>
                <td>Ending row line</td>
                <td><code>grid-row-end: 3;</code></td>
            </tr>
            <tr>
                <td><code>grid-column-start</code></td>
                <td>Starting column line</td>
                <td><code>grid-column-start: 2;</code></td>
            </tr>
            <tr>
                <td><code>grid-column-end</code></td>
                <td>Ending column line</td>
                <td><code>grid-column-end: 4;</code></td>
            </tr>
        </table>

        <h3>Values for All Four Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>auto</code></td>
                <td>Next available track (default)</td>
                <td><code>grid-row-start: auto;</code></td>
            </tr>
            <tr>
                <td><code>integer</code></td>
                <td>Specific line number</td>
                <td><code>grid-row-start: 2;</code></td>
            </tr>
            <tr>
                <td><code>span #n</code></td>
                <td>Spans n tracks from start</td>
                <td><code>grid-row-end: span 2;</code></td>
            </tr>
        </table>

        <h3>Shorthand Equivalents</h3>
        <table class="reference-table">
            <tr>
                <th>Longhand</th>
                <th>Shorthand</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>grid-row-start</code> + <code>grid-row-end</code></td>
                <td><code>grid-row</code></td>
                <td><code>grid-row: 1 / 3;</code></td>
            </tr>
            <tr>
                <td><code>grid-column-start</code> + <code>grid-column-end</code></td>
                <td><code>grid-column</code></td>
                <td><code>grid-column: 2 / 4;</code></td>
            </tr>
            <tr>
                <td>All four</td>
                <td><code>grid-area</code></td>
                <td><code>grid-area: 1 / 2 / 3 / 4;</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 7. BEST PRACTICES ====== -->
    <section>
        <h2>7. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>span</code> when you only care about how many tracks an item covers</li>
                <li>Use specific line numbers when you need exact placement</li>
                <li>Combine row and column properties for precise positioning</li>
                <li>Use shorthand <code>grid-row</code>, <code>grid-column</code>, or <code>grid-area</code> for cleaner code</li>
                <li>Remember that end lines are <strong>exclusive</strong> (end: 3 means rows 1 and 2)</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't confuse line numbers with track numbers (lines are between tracks)</li>
                <li>Don't forget that grid lines start at 1, not 0</li>
                <li>Don't use explicit placement when auto-placement would work</li>
                <li>Don't mix up <code>start</code> and <code>end</code> — start must be less than end</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionExample
grid-row-startStarting row linegrid-row-start: 1;
grid-row-endEnding row linegrid-row-end: 3;
grid-column-startStarting column linegrid-column-start: 2;
grid-column-endEnding column linegrid-column-end: 4;

Values

ValueDescriptionExample
autoNext available track (default)grid-row-start: auto;
integerSpecific line numbergrid-row-start: 2;
span #nSpans n tracks from startgrid-row-end: span 2;

Shorthand Equivalents

LonghandShorthandExample
grid-row-start + grid-row-endgrid-rowgrid-row: 1 / 3;
grid-column-start + grid-column-endgrid-columngrid-column: 2 / 4;
All fourgrid-areagrid-area: 1 / 2 / 3 / 4;

Best Practices

Do This:

/* Use span when you only care about coverage */
.item {
    grid-column: 1 / span 2;  /* Spans 2 columns from line 1 */
}

/* Use specific lines for precise placement */
.item {
    grid-row: 2 / 4;  /* Starts at line 2, ends at line 4 */
}

/* Combine row and column for full control */
.item {
    grid-area: 1 / 2 / 3 / 4;
}

Don’t Do This:

/* Don't confuse lines with tracks */
.item {
    grid-row-start: 0;  /* Invalid! Lines start at 1 */
}

/* Don't mix up start and end */
.item {
    grid-row-start: 3;
    grid-row-end: 1;  /* Invalid! Start must be less than end */
}

/* Don't use explicit placement unnecessarily */
.item {
    grid-row: 1 / 2;  /* Auto-placement would work fine */
}

Pro Tip: Think of grid lines as the borders between cells, not the cells themselves. In a 3-column grid, there are 4 column lines (1, 2, 3, 4). The grid-row-start and grid-column-start properties specify which line the item starts at, while grid-row-end and grid-column-end specify which line it ends before. Use the shorthand properties (grid-row, grid-column, grid-area) for cleaner, more readable code!

22. grid-row and grid-column Properties

The grid-row and grid-column properties are shorthand for the four longhand properties you learned in the previous lesson. They let you control where a grid item starts and ends in both rows and columns.


Overview of Properties

PropertyDescriptionShorthand For
grid-rowSpecifies start and end row linesgrid-row-start + grid-row-end
grid-columnSpecifies start and end column linesgrid-column-start + grid-column-end

1. grid-row

The grid-row property specifies where a grid item starts and ends within the grid rows.

.item1 {
    grid-row: 1 / 3; /* Starts at row line 1, ends at row line 3 */
}

Syntax

grid-row: <start> / <end>;
grid-row: <start> / span <n>;
grid-row: <start>;  /* Only start, end is auto */

Values

ValueDescriptionExample
autoAuto placement (default)grid-row: auto;
integer / integerStart line / End linegrid-row: 1 / 3;
integer / span #nStart line / Span n rowsgrid-row: 1 / span 2;
span #n / integerSpan n rows / End linegrid-row: span 2 / 4;
integerStart line onlygrid-row: 2;

2. grid-column

The grid-column property specifies where a grid item starts and ends within the grid columns.

.item1 {
    grid-column: 2 / 4; /* Starts at column line 2, ends at column line 4 */
}

Syntax

grid-column: <start> / <end>;
grid-column: <start> / span <n>;
grid-column: <start>;  /* Only start, end is auto */

Values

ValueDescriptionExample
autoAuto placement (default)grid-column: auto;
integer / integerStart line / End linegrid-column: 2 / 4;
integer / span #nStart line / Span n columnsgrid-column: 2 / span 2;
span #n / integerSpan n columns / End linegrid-column: span 2 / 4;
integerStart line onlygrid-column: 2;

How It Works

Remember: Grid lines are the borders between cells, not the cells themselves.

In a 4-column grid:

Column Lines:  1        2        3        4        5
              │        │        │        │        │
              │ Cell 1 │ Cell 2 │ Cell 3 │ Cell 4 │
              │        │        │        │        │
  • grid-column: 2 / 4 → Starts at line 2, ends at line 4 (spans columns 2 and 3)
  • grid-column: 2 / span 2 → Starts at line 2, spans 2 columns (same result)

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>grid-row and grid-column Properties</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== GRID DEMOS ====== */
        .grid-container {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            grid-template-rows: repeat(4, 80px);
            gap: 10px;
            padding: 15px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
        }

        .cell {
            border: 2px solid #333;
            padding: 10px;
            border-radius: 4px;
            display: flex;
            align-items: center;
            justify-content: center;
            text-align: center;
            font-weight: bold;
            font-size: 0.85rem;
            background: #007bff;
            color: white;
        }

        .cell:nth-child(even) {
            background: #28a745;
        }

        .cell:nth-child(3n) {
            background: #dc3545;
        }

        /* Demo 1: grid-row */
        .item-row {
            grid-row: 1 / 3;
            background: #6c5ce7 !important;
        }

        /* Demo 2: grid-column */
        .item-col {
            grid-column: 2 / 4;
            background: #e17055 !important;
        }

        /* Demo 3: Both */
        .item-both {
            grid-row: 2 / 5;
            grid-column: 1 / 3;
            background: #00b894 !important;
        }

        /* Demo 4: span keyword */
        .item-span-row {
            grid-row: 1 / span 2;
            background: #6c5ce7 !important;
        }

        .item-span-col {
            grid-column: 2 / span 2;
            background: #e17055 !important;
        }

        /* Demo 5: multiple items */
        .grid-multi {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            grid-template-rows: repeat(3, 80px);
            gap: 10px;
            padding: 15px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
        }

        .header-item {
            grid-column: 1 / 5;
            background: #007bff !important;
        }

        .sidebar-item {
            grid-row: 2 / 4;
            grid-column: 1 / 2;
            background: #6c5ce7 !important;
        }

        .main-item {
            grid-row: 2 / 4;
            grid-column: 2 / 5;
            background: #00b894 !important;
        }

        .footer-item {
            grid-column: 1 / 5;
            grid-row: 4 / 5;
            background: #e17055 !important;
        }

        /* Grid lines visualization */
        .grid-lines {
            display: grid;
            grid-template-columns: repeat(4, 80px);
            grid-template-rows: repeat(3, 80px);
            gap: 0;
            background: #fff;
            border: 2px solid #333;
            margin: 15px auto;
            width: fit-content;
            position: relative;
        }

        .grid-lines .cell {
            border: 1px dashed #999;
            border-radius: 0;
            background: #f8f9fa;
            color: #333;
            font-size: 0.75rem;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }

        .grid-lines .cell .line-num {
            font-size: 0.6rem;
            color: #007bff;
            font-weight: bold;
        }
    </style>
</head>
<body>

    <h1>grid-row and grid-column Properties</h1>

    <!-- ====== 1. GRID-ROW ====== -->
    <section>
        <h2>1. grid-row</h2>
        <p>Controls where an item starts and ends in <strong>rows</strong>.</p>

        <div class="grid-container">
            <div class="cell item-row">grid-row: 1 / 3</div>
            <div class="cell">2</div>
            <div class="cell">3</div>
            <div class="cell">4</div>
            <div class="cell">5</div>
            <div class="cell">6</div>
            <div class="cell">7</div>
            <div class="cell">8</div>
        </div>

        <div class="code-block">
            .item-row {
                grid-row: 1 / 3;  /* Starts at row line 1, ends at row line 3 */
            }
        </div>
    </section>

    <!-- ====== 2. GRID-COLUMN ====== -->
    <section>
        <h2>2. grid-column</h2>
        <p>Controls where an item starts and ends in <strong>columns</strong>.</p>

        <div class="grid-container">
            <div class="cell">1</div>
            <div class="cell item-col">grid-column: 2 / 4</div>
            <div class="cell">3</div>
            <div class="cell">4</div>
            <div class="cell">5</div>
            <div class="cell">6</div>
            <div class="cell">7</div>
            <div class="cell">8</div>
        </div>

        <div class="code-block">
            .item-col {
                grid-column: 2 / 4;  /* Starts at column line 2, ends at column line 4 */
            }
        </div>
    </section>

    <!-- ====== 3. BOTH ROW AND COLUMN ====== -->
    <section>
        <h2>3. Combining grid-row and grid-column</h2>
        <p>Use both properties to position an item precisely in the grid.</p>

        <div class="grid-container">
            <div class="cell">1</div>
            <div class="cell">2</div>
            <div class="cell">3</div>
            <div class="cell item-both">grid-row: 2 / 5<br>grid-column: 1 / 3</div>
            <div class="cell">5</div>
            <div class="cell">6</div>
            <div class="cell">7</div>
            <div class="cell">8</div>
        </div>

        <div class="code-block">
            .item-both {
                grid-row: 2 / 5;     /* Spans rows 2, 3, 4 */
                grid-column: 1 / 3;  /* Spans columns 1, 2 */
            }
        </div>
    </section>

    <!-- ====== 4. THE span KEYWORD ====== -->
    <section>
        <h2>4. Using <code>span</code></h2>
        <p>Instead of specifying the end line, use <code>span</code> to indicate how many tracks to cover.</p>

        <div class="grid-container">
            <div class="cell item-span-row">grid-row: 1 / span 2</div>
            <div class="cell">2</div>
            <div class="cell">3</div>
            <div class="cell">4</div>
            <div class="cell item-span-col">grid-column: 2 / span 2</div>
            <div class="cell">6</div>
            <div class="cell">7</div>
            <div class="cell">8</div>
        </div>

        <div class="code-block">
            .item-span-row {
                grid-row: 1 / span 2;     /* Starts at line 1, spans 2 rows */
            }

            .item-span-col {
                grid-column: 2 / span 2;  /* Starts at line 2, spans 2 columns */
            }

            /* These are equivalent to: */
            /* grid-row: 1 / 3; */
            /* grid-column: 2 / 4; */
        </div>
    </section>

    <!-- ====== 5. PRACTICAL LAYOUT ====== -->
    <section>
        <h2>5. Practical Layout Example</h2>
        <p>A classic header / sidebar / main / footer layout using <code>grid-row</code> and <code>grid-column</code>.</p>

        <div class="grid-multi">
            <div class="cell header-item">Header (grid-column: 1 / 5)</div>
            <div class="cell sidebar-item">Sidebar<br>(grid-row: 2 / 4)<br>(grid-column: 1 / 2)</div>
            <div class="cell main-item">Main Content<br>(grid-row: 2 / 4)<br>(grid-column: 2 / 5)</div>
            <div class="cell footer-item">Footer (grid-column: 1 / 5)</div>
        </div>

        <div class="code-block">
            .header-item {
                grid-column: 1 / 5;   /* Full width */
            }

            .sidebar-item {
                grid-row: 2 / 4;      /* Spans rows 2 and 3 */
                grid-column: 1 / 2;   /* First column */
            }

            .main-item {
                grid-row: 2 / 4;      /* Spans rows 2 and 3 */
                grid-column: 2 / 5;   /* Columns 2-4 */
            }

            .footer-item {
                grid-column: 1 / 5;   /* Full width */
            }
        </div>
    </section>

    <!-- ====== 6. GRID LINES VISUALIZATION ====== -->
    <section>
        <h2>6. Understanding Grid Lines</h2>
        <p>In a 4-column × 3-row grid, there are <strong>5 column lines</strong> and <strong>4 row lines</strong>.</p>

        <div style="display: flex; flex-direction: column; align-items: center;">
            <!-- Column line labels -->
            <div style="display: flex; gap: 0; margin-bottom: 5px; padding-left: 40px;">
                <div style="width: 80px; text-align: center; font-weight: bold; color: #007bff;">Line 1</div>
                <div style="width: 80px; text-align: center; font-weight: bold; color: #007bff;">Line 2</div>
                <div style="width: 80px; text-align: center; font-weight: bold; color: #007bff;">Line 3</div>
                <div style="width: 80px; text-align: center; font-weight: bold; color: #007bff;">Line 4</div>
                <div style="width: 80px; text-align: center; font-weight: bold; color: #007bff;">Line 5</div>
            </div>

            <div style="display: flex; align-items: center;">
                <!-- Row line labels -->
                <div style="display: flex; flex-direction: column; margin-right: 5px;">
                    <div style="height: 80px; display: flex; align-items: center; font-weight: bold; color: #28a745;">Line 1</div>
                    <div style="height: 80px; display: flex; align-items: center; font-weight: bold; color: #28a745;">Line 2</div>
                    <div style="height: 80px; display: flex; align-items: center; font-weight: bold; color: #28a745;">Line 3</div>
                    <div style="height: 80px; display: flex; align-items: center; font-weight: bold; color: #28a745;">Line 4</div>
                </div>

                <div class="grid-lines">
                    <div class="cell">Cell 1<br><span class="line-num">1,1 → 2,2</span></div>
                    <div class="cell">Cell 2<br><span class="line-num">2,1 → 3,2</span></div>
                    <div class="cell">Cell 3<br><span class="line-num">3,1 → 4,2</span></div>
                    <div class="cell">Cell 4<br><span class="line-num">4,1 → 5,2</span></div>
                    <div class="cell">Cell 5<br><span class="line-num">1,2 → 2,3</span></div>
                    <div class="cell">Cell 6<br><span class="line-num">2,2 → 3,3</span></div>
                    <div class="cell">Cell 7<br><span class="line-num">3,2 → 4,3</span></div>
                    <div class="cell">Cell 8<br><span class="line-num">4,2 → 5,3</span></div>
                    <div class="cell">Cell 9<br><span class="line-num">1,3 → 2,4</span></div>
                    <div class="cell">Cell 10<br><span class="line-num">2,3 → 3,4</span></div>
                    <div class="cell">Cell 11<br><span class="line-num">3,3 → 4,4</span></div>
                    <div class="cell">Cell 12<br><span class="line-num">4,3 → 5,4</span></div>
                </div>
            </div>
        </div>

        <p class="note" style="text-align: center; margin-top: 15px;">
            <span class="highlight">Column lines</span> run vertically between columns (1, 2, 3, 4, 5).<br>
            <span class="highlight">Row lines</span> run horizontally between rows (1, 2, 3, 4).<br>
            Each cell is defined by its start and end lines.
        </p>
    </section>

    <!-- ====== 7. REFERENCE TABLES ====== -->
    <section>
        <h2>7. Reference Tables</h2>

        <h3>grid-row and grid-column</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>grid-row</code></td>
                <td>Shorthand for row start + end</td>
                <td><code>grid-row: 1 / 3;</code></td>
            </tr>
            <tr>
                <td><code>grid-column</code></td>
                <td>Shorthand for column start + end</td>
                <td><code>grid-column: 2 / 4;</code></td>
            </tr>
        </table>

        <h3>Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>auto</code></td>
                <td>Auto placement (default)</td>
                <td><code>grid-row: auto;</code></td>
            </tr>
            <tr>
                <td><code>integer / integer</code></td>
                <td>Start line / End line</td>
                <td><code>grid-row: 1 / 3;</code></td>
            </tr>
            <tr>
                <td><code>integer / span #n</code></td>
                <td>Start line / Span n tracks</td>
                <td><code>grid-row: 1 / span 2;</code></td>
            </tr>
            <tr>
                <td><code>span #n / integer</code></td>
                <td>Span n tracks / End line</td>
                <td><code>grid-row: span 2 / 4;</code></td>
            </tr>
            <tr>
                <td><code>integer</code></td>
                <td>Start line only</td>
                <td><code>grid-row: 2;</code></td>
            </tr>
        </table>

        <h3>Longhand vs Shorthand</h3>
        <table class="reference-table">
            <tr>
                <th>Longhand</th>
                <th>Shorthand</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>grid-row-start: 1;<br>grid-row-end: 3;</code></td>
                <td><code>grid-row</code></td>
                <td><code>grid-row: 1 / 3;</code></td>
            </tr>
            <tr>
                <td><code>grid-column-start: 2;<br>grid-column-end: 4;</code></td>
                <td><code>grid-column</code></td>
                <td><code>grid-column: 2 / 4;</code></td>
            </tr>
            <tr>
                <td>All four</td>
                <td><code>grid-area</code></td>
                <td><code>grid-area: 1 / 2 / 3 / 4;</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 8. BEST PRACTICES ====== -->
    <section>
        <h2>8. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>grid-row</code> and <code>grid-column</code> shorthand instead of the four longhand properties</li>
                <li>Use <code>span</code> when you only care about how many tracks an item covers</li>
                <li>Use specific line numbers when you need exact placement</li>
                <li>Combine row and column properties for precise positioning</li>
                <li>Remember that end lines are <strong>exclusive</strong></li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't confuse line numbers with track numbers (lines are between tracks)</li>
                <li>Don't forget that grid lines start at 1, not 0</li>
                <li>Don't use explicit placement when auto-placement would work</li>
                <li>Don't mix up <code>start</code> and <code>end</code> — start must be less than end</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionExample
grid-rowShorthand for row start + endgrid-row: 1 / 3;
grid-columnShorthand for column start + endgrid-column: 2 / 4;

Values

ValueDescriptionExample
autoAuto placement (default)grid-row: auto;
integer / integerStart line / End linegrid-row: 1 / 3;
integer / span #nStart line / Span n tracksgrid-row: 1 / span 2;
span #n / integerSpan n tracks / End linegrid-row: span 2 / 4;
integerStart line onlygrid-row: 2;

Longhand vs Shorthand

LonghandShorthandExample
grid-row-start + grid-row-endgrid-rowgrid-row: 1 / 3;
grid-column-start + grid-column-endgrid-columngrid-column: 2 / 4;
All fourgrid-areagrid-area: 1 / 2 / 3 / 4;

Best Practices

Do This:

/* Use span when you only care about coverage */
.item {
    grid-row: 1 / span 2;     /* Spans 2 rows from line 1 */
}

.item {
    grid-column: 2 / span 2;  /* Spans 2 columns from line 2 */
}

/* Use specific lines for precise placement */
.item {
    grid-row: 2 / 4;          /* Starts at line 2, ends at line 4 */
}

/* Combine row and column for full control */
.item {
    grid-row: 1 / 3;
    grid-column: 2 / 4;
}

Don’t Do This:

/* Don't confuse lines with tracks */
.item {
    grid-row: 0 / 2;  /* Invalid! Lines start at 1 */
}

/* Don't mix up start and end */
.item {
    grid-row: 3 / 1;  /* Invalid! Start must be less than end */
}

/* Don't use explicit placement unnecessarily */
.item {
    grid-row: 1 / 2;  /* Auto-placement would work fine */
}

Pro Tip: The grid-row and grid-column shorthand properties are the most commonly used ways to position grid items. Use span when you want to say “cover this many tracks” without calculating the exact end line. Use specific line numbers when you need precise control. Remember: end lines are exclusivegrid-row: 1 / 3 means the item occupies rows 1 and 2, not rows 1, 2, and 3!

23. row-gap, column-gap, and gap Properties

These properties control the spacing between grid tracks (rows and columns). They’re essential for creating clean, well-spaced grid layouts without using margins on individual items.


Overview of Properties

PropertyDescription
row-gapSpace between rows
column-gapSpace between columns
gapShorthand for row-gap and column-gap

1. row-gap

The row-gap property specifies the space between each row in a grid.

.grid-container {
    display: grid;
    row-gap: 20px; /* 20px between each row */
}

Values

ValueDescriptionExample
lengthFixed size (px, em, rem)row-gap: 20px;
percentagePercentage of containerrow-gap: 5%;
calc()Calculated valuerow-gap: calc(10px + 2%);
normalBrowser default (usually 0)row-gap: normal;

2. column-gap

The column-gap property specifies the space between each column in a grid.

.grid-container {
    display: grid;
    column-gap: 10px; /* 10px between each column */
}

Values

Same as row-gap: length, percentage, calc(), normal


3. gap (Shorthand)

The gap property is a shorthand for row-gap and column-gap. It also applies to flex containers.

/* Both rows and columns */
.grid-container {
    gap: 20px; /* 20px for both row and column gaps */
}

/* Row gap | Column gap */
.grid-container {
    gap: 20px 10px; /* 20px row gap, 10px column gap */
}

Syntax

gap: <row-gap> <column-gap>;
gap: <row-gap>;  /* Same for both */

How It Works

┌─────────┐  ← row-gap
│  Item   │
├─────────┤  ← row-gap
│  Item   │
└─────────┘

┌────┬────┬────┐
│    │    │    │
│ It │ It │ It │  ← column-gap between columns
│    │    │    │
└────┴────┴────┘
  • row-gap creates vertical space between rows
  • column-gap creates horizontal space between columns
  • gap combines both

gap in Flexbox

The gap property also works in flex containers, making it easier to space flex items without margins.

.flex-container {
    display: flex;
    gap: 20px; /* 20px between flex items */
}

Before gap (using margins):

.flex-item {
    margin-right: 20px;
}
.flex-item:last-child {
    margin-right: 0;
}

With gap:

.flex-container {
    display: flex;
    gap: 20px; /* Much cleaner! */
}

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>row-gap, column-gap, and gap Properties</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== GRID DEMOS ====== */
        .grid-container {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
        }

        .grid-item {
            background: #007bff;
            color: white;
            padding: 20px;
            border-radius: 5px;
            text-align: center;
            font-weight: bold;
        }

        .grid-item:nth-child(even) {
            background: #28a745;
        }

        .grid-item:nth-child(3n) {
            background: #dc3545;
        }

        /* Gap variations */
        .gap-both {
            gap: 20px;
        }

        .gap-different {
            row-gap: 30px;
            column-gap: 10px;
        }

        .gap-shorthand {
            gap: 30px 10px;
        }

        .gap-percentage {
            gap: 5%;
        }

        .gap-calc {
            gap: calc(10px + 2%);
        }

        /* Flexbox with gap */
        .flex-container {
            display: flex;
            gap: 20px;
            flex-wrap: wrap;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
        }

        .flex-item {
            background: #6c5ce7;
            color: white;
            padding: 20px;
            border-radius: 5px;
            text-align: center;
            font-weight: bold;
            flex: 1;
            min-width: 150px;
        }

        /* Visual gap indicators */
        .gap-visual {
            display: flex;
            justify-content: center;
            gap: 30px;
            margin: 20px 0;
            flex-wrap: wrap;
        }

        .gap-visual-item {
            text-align: center;
        }

        .gap-visual-item .box {
            width: 100px;
            height: 60px;
            background: #007bff;
            border-radius: 4px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
        }

        .gap-visual-item .arrow {
            font-size: 1.5rem;
            color: #dc3545;
            margin: 5px 0;
        }
    </style>
</head>
<body>

    <h1>row-gap, column-gap, and gap Properties</h1>

    <!-- ====== 1. ROW-GAP ====== -->
    <section>
        <h2>1. row-gap</h2>
        <p>Specifies the space between <strong>rows</strong> in a grid.</p>

        <div class="grid-container" style="row-gap: 20px;">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
            <div class="grid-item">4</div>
            <div class="grid-item">5</div>
            <div class="grid-item">6</div>
            <div class="grid-item">7</div>
            <div class="grid-item">8</div>
            <div class="grid-item">9</div>
            <div class="grid-item">10</div>
        </div>

        <div class="code-block">
            .grid-container {
                display: grid;
                grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
                row-gap: 20px;  /* 20px between rows */
            }
        </div>
    </section>

    <!-- ====== 2. COLUMN-GAP ====== -->
    <section>
        <h2>2. column-gap</h2>
        <p>Specifies the space between <strong>columns</strong> in a grid.</p>

        <div class="grid-container" style="column-gap: 30px;">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
            <div class="grid-item">4</div>
            <div class="grid-item">5</div>
            <div class="grid-item">6</div>
            <div class="grid-item">7</div>
            <div class="grid-item">8</div>
            <div class="grid-item">9</div>
            <div class="grid-item">10</div>
        </div>

        <div class="code-block">
            .grid-container {
                display: grid;
                grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
                column-gap: 30px;  /* 30px between columns */
            }
        </div>
    </section>

    <!-- ====== 3. GAP (SHORTHAND) ====== -->
    <section>
        <h2>3. gap (Shorthand)</h2>
        <p>Sets both row and column gaps in one declaration.</p>

        <h3>gap: 20px (same for both)</h3>
        <div class="grid-container gap-both">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
            <div class="grid-item">4</div>
            <div class="grid-item">5</div>
            <div class="grid-item">6</div>
            <div class="grid-item">7</div>
            <div class="grid-item">8</div>
            <div class="grid-item">9</div>
            <div class="grid-item">10</div>
        </div>

        <h3>gap: 30px 10px (row gap | column gap)</h3>
        <div class="grid-container gap-shorthand">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
            <div class="grid-item">4</div>
            <div class="grid-item">5</div>
            <div class="grid-item">6</div>
            <div class="grid-item">7</div>
            <div class="grid-item">8</div>
            <div class="grid-item">9</div>
            <div class="grid-item">10</div>
        </div>

        <div class="code-block">
            /* Same for both */
            gap: 20px;

            /* Row gap | Column gap */
            gap: 30px 10px;

            /* Equivalent to: */
            row-gap: 30px;
            column-gap: 10px;
        </div>
    </section>

    <!-- ====== 4. GAP IN FLEXBOX ====== -->
    <section>
        <h2>4. gap in Flexbox</h2>
        <p>The <code>gap</code> property also works in <strong>flex containers</strong>, eliminating the need for margins.</p>

        <div class="flex-container">
            <div class="flex-item">Flex Item 1</div>
            <div class="flex-item">Flex Item 2</div>
            <div class="flex-item">Flex Item 3</div>
            <div class="flex-item">Flex Item 4</div>
            <div class="flex-item">Flex Item 5</div>
        </div>

        <div class="code-block">
            /* Flexbox with gap */
            .flex-container {
                display: flex;
                flex-wrap: wrap;
                gap: 20px;  /* Space between items */
            }

            /* Before gap, you needed margins: */
            .flex-item {
                margin-right: 20px;
            }
            .flex-item:last-child {
                margin-right: 0;
            }
        </div>
    </section>

    <!-- ====== 5. VISUAL COMPARISON ====== -->
    <section>
        <h2>5. Visual Comparison</h2>

        <h3>row-gap vs column-gap</h3>
        <div class="gap-visual">
            <div class="gap-visual-item">
                <div class="box">Item 1</div>
                <div class="arrow">↕</div>
                <div class="box">Item 2</div>
                <div class="arrow">↕</div>
                <div class="box">Item 3</div>
                <p class="note">row-gap</p>
            </div>

            <div class="gap-visual-item" style="display: flex; gap: 20px; align-items: center;">
                <div class="box">Item 1</div>
                <div class="arrow" style="transform: rotate(90deg);">↔</div>
                <div class="box">Item 2</div>
                <div class="arrow" style="transform: rotate(90deg);">↔</div>
                <div class="box">Item 3</div>
                <p class="note">column-gap</p>
            </div>
        </div>
    </section>

    <!-- ====== 6. ADVANCED VALUES ====== -->
    <section>
        <h2>6. Advanced Values</h2>

        <h3>Percentage Gap</h3>
        <div class="grid-container" style="gap: 5%;">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
            <div class="grid-item">4</div>
            <div class="grid-item">5</div>
            <div class="grid-item">6</div>
            <div class="grid-item">7</div>
            <div class="grid-item">8</div>
        </div>

        <h3>calc() Gap</h3>
        <div class="grid-container" style="gap: calc(10px + 2%);">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
            <div class="grid-item">4</div>
            <div class="grid-item">5</div>
            <div class="grid-item">6</div>
            <div class="grid-item">7</div>
            <div class="grid-item">8</div>
        </div>

        <div class="code-block">
            /* Percentage gap */
            gap: 5%;

            /* calc() gap */
            gap: calc(10px + 2%);

            /* Different row and column gaps */
            gap: 30px 10px;
        </div>
    </section>

    <!-- ====== 7. REFERENCE TABLES ====== -->
    <section>
        <h2>7. Reference Tables</h2>

        <h3>Gap Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>row-gap</code></td>
                <td>Space between rows</td>
                <td><code>row-gap: 20px;</code></td>
            </tr>
            <tr>
                <td><code>column-gap</code></td>
                <td>Space between columns</td>
                <td><code>column-gap: 10px;</code></td>
            </tr>
            <tr>
                <td><code>gap</code></td>
                <td>Shorthand for both</td>
                <td><code>gap: 20px 10px;</code></td>
            </tr>
        </table>

        <h3>Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>length</code></td>
                <td>Fixed size (px, em, rem)</td>
                <td><code>gap: 20px;</code></td>
            </tr>
            <tr>
                <td><code>percentage</code></td>
                <td>Percentage of container</td>
                <td><code>gap: 5%;</code></td>
            </tr>
            <tr>
                <td><code>calc()</code></td>
                <td>Calculated value</td>
                <td><code>gap: calc(10px + 2%);</code></td>
            </tr>
            <tr>
                <td><code>normal</code></td>
                <td>Browser default (usually 0)</td>
                <td><code>gap: normal;</code></td>
            </tr>
        </table>

        <h3>gap Shorthand</h3>
        <table class="reference-table">
            <tr>
                <th>Syntax</th>
                <th>Row Gap</th>
                <th>Column Gap</th>
            </tr>
            <tr>
                <td><code>gap: 20px;</code></td>
                <td>20px</td>
                <td>20px</td>
            </tr>
            <tr>
                <td><code>gap: 30px 10px;</code></td>
                <td>30px</td>
                <td>10px</td>
            </tr>
        </table>
    </section>

    <!-- ====== 8. BEST PRACTICES ====== -->
    <section>
        <h2>8. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>gap</code> instead of margins on grid/flex items</li>
                <li>Use <code>gap</code> for consistent spacing in both grid and flexbox</li>
                <li>Use <code>row-gap</code> and <code>column-gap</code> for different spacing</li>
                <li>Use percentage or <code>calc()</code> gaps for responsive spacing</li>
                <li>Use <code>gap</code> to simplify your code — no more <code>:last-child</code> margin resets!</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use margins on grid items — use <code>gap</code> instead</li>
                <li>Don't forget that <code>gap</code> creates space <strong>between</strong> tracks, not around them</li>
                <li>Don't use <code>gap</code> on elements that aren't grid or flex containers</li>
                <li>Don't mix <code>gap</code> and margins unnecessarily — choose one approach</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionExample
row-gapSpace between rowsrow-gap: 20px;
column-gapSpace between columnscolumn-gap: 10px;
gapShorthand for bothgap: 20px 10px;

Values

ValueDescriptionExample
lengthFixed size (px, em, rem)gap: 20px;
percentagePercentage of containergap: 5%;
calc()Calculated valuegap: calc(10px + 2%);
normalBrowser default (usually 0)gap: normal;

gap Shorthand

SyntaxRow GapColumn Gap
gap: 20px;20px20px
gap: 30px 10px;30px10px

Best Practices

Do This:

/* Grid with gap */
.grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px; /* Much cleaner than margins! */
}

/* Flexbox with gap */
.flex {
    display: flex;
    gap: 15px;
}

/* Different row and column gaps */
.grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 30px 10px; /* 30px rows, 10px columns */
}

Don’t Do This:

/* Don't use margins on grid items */
.grid-item {
    margin: 10px; /* Use gap on the container instead */
}

/* Don't forget gap only works on grid/flex containers */
p {
    gap: 20px; /* Won't work — p is not a grid or flex container */
}

Pro Tip: The gap property is one of the best additions to CSS in recent years. It works in both Grid and Flexbox, eliminating the need for margin-based spacing hacks. Use gap on your grid and flex containers instead of margins on individual items — your code will be cleaner, more maintainable, and easier to reason about. Remember: gap creates space between tracks, not around the outer edges!

24. Flexbox Layout Introduction

Flexbox (Flexible Box Layout) is a one-dimensional layout system that allows you to arrange elements in rows or columns with flexible sizing and alignment. It’s perfect for responsive designs where items need to resize, reorder, or align based on available space.


What is Flexbox?

Flexbox is a layout model that distributes space among items in a container and provides powerful alignment capabilities. Unlike Grid (which is two-dimensional), Flexbox works in one dimension at a time — either a row or a column.

Key Benefits:

BenefitDescription
One-dimensionalLayout items in a row or column
Flexible sizingItems grow or shrink to fill space
Easy alignmentCenter, space-between, space-around, etc.
Order controlReorder items without changing HTML
ResponsiveAdapts to different screen sizes automatically

Flexbox Basics

<div class="container">
    <div class="item">Item 1</div>
    <div class="item">Item 2</div>
    <div class="item">Item 3</div>
    <div class="item">Item 4</div>
    <div class="item">Item 5</div>
</div>
.container {
    display: flex;
}

.item {
    background-color: lightblue;
    padding: 10px;
    margin: 5px;
    border: 2px solid black;
}

What happens:

  • The container becomes a flex container
  • The children become flex items
  • Items are laid out in a row (default direction)
  • Items are placed side by side

The Main Axis and Cross Axis

Every flex container has two axes:

AxisDescriptionDefault Direction
Main axisThe primary direction items are laid outHorizontal (row)
Cross axisPerpendicular to the main axisVertical (column)
Main Axis (row):
┌─────────────────────────────────────────────────┐
│  Item 1  │  Item 2  │  Item 3  │  Item 4        │
└─────────────────────────────────────────────────┘
     ↑ Cross Axis (column)

Important: The main and cross axes change when you change flex-direction.

flex-directionMain AxisCross Axis
row (default)HorizontalVertical
columnVerticalHorizontal
row-reverseHorizontal (reversed)Vertical
column-reverseVertical (reversed)Horizontal

Flexbox Properties Overview

PropertyApplies ToDescription
flex-directionContainerDefines the main axis (row or column)
flex-wrapContainerAllows items to wrap to the next line
justify-contentContainerAligns items along the main axis
align-itemsContainerAligns items along the cross axis
align-contentContainerAligns wrapped lines along the cross axis
flex-growItemHow much an item can grow
flex-shrinkItemHow much an item can shrink
flex-basisItemInitial size of an item
flexItemShorthand for grow, shrink, basis
orderItemChanges the order of items
align-selfItemOverrides align-items for one item

1. flex-direction

Defines the main axis — the direction items are laid out.

.container {
    display: flex;
    flex-direction: row; /* Default — left to right */
}

.container {
    display: flex;
    flex-direction: column; /* Top to bottom */
}

.container {
    display: flex;
    flex-direction: row-reverse; /* Right to left */
}

.container {
    display: flex;
    flex-direction: column-reverse; /* Bottom to top */
}

2. flex-wrap

Controls whether items wrap to the next line when there isn’t enough space.

.container {
    display: flex;
    flex-wrap: nowrap; /* Default — no wrapping */
}

.container {
    display: flex;
    flex-wrap: wrap; /* Items wrap to next line */
}

.container {
    display: flex;
    flex-wrap: wrap-reverse; /* Items wrap in reverse */
}

3. flex-grow, flex-shrink, flex-basis

These properties control how flex items grow, shrink, and their initial size.

.item {
    flex-grow: 0;    /* Default — no growth */
    flex-shrink: 1;  /* Default — can shrink */
    flex-basis: auto; /* Default — auto size */
}

/* Shorthand */
.item {
    flex: 1; /* grow: 1, shrink: 1, basis: 0 */
}

.item {
    flex: 1 1 200px; /* grow: 1, shrink: 1, basis: 200px */
}
PropertyDescriptionDefault
flex-growHow much an item can grow0
flex-shrinkHow much an item can shrink1
flex-basisInitial size before distributionauto

4. flex (Shorthand)

The flex property combines flex-grow, flex-shrink, and flex-basis into one declaration.

/* Common patterns */
.item {
    flex: 1;           /* grow: 1, shrink: 1, basis: 0 */
}

.item {
    flex: auto;        /* grow: 1, shrink: 1, basis: auto */
}

.item {
    flex: none;        /* grow: 0, shrink: 0, basis: auto */
}

.item {
    flex: 1 0 200px;   /* grow: 1, shrink: 0, basis: 200px */
}

5. justify-content

Aligns items along the main axis.

.container {
    display: flex;
    justify-content: flex-start;    /* Default — start */
    justify-content: flex-end;      /* End */
    justify-content: center;        /* Center */
    justify-content: space-between; /* Equal space between */
    justify-content: space-around;  /* Equal space around */
    justify-content: space-evenly;  /* Equal space everywhere */
}

6. align-items

Aligns items along the cross axis.

.container {
    display: flex;
    align-items: stretch;     /* Default — fill height */
    align-items: flex-start;  /* Top */
    align-items: flex-end;    /* Bottom */
    align-items: center;      /* Center */
    align-items: baseline;    /* Align to text baseline */
}

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flexbox Layout Introduction</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        /* ====== FLEX CONTAINERS ====== */
        .container {
            display: flex;
            background: #e9ecef;
            padding: 10px;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 80px;
        }

        .item {
            background: #007bff;
            color: white;
            padding: 15px 20px;
            border-radius: 6px;
            text-align: center;
            font-weight: bold;
            border: 2px solid #0056b3;
        }

        .item:nth-child(even) {
            background: #28a745;
            border-color: #1e7e34;
        }

        .item:nth-child(3n) {
            background: #dc3545;
            border-color: #a71d2a;
        }

        /* Direction demos */
        .dir-row {
            flex-direction: row;
        }

        .dir-column {
            flex-direction: column;
        }

        .dir-row-reverse {
            flex-direction: row-reverse;
        }

        .dir-column-reverse {
            flex-direction: column-reverse;
        }

        /* Wrap demos */
        .wrap-nowrap {
            flex-wrap: nowrap;
        }

        .wrap-wrap {
            flex-wrap: wrap;
        }

        .wrap-wrap .item {
            width: 200px;
        }

        /* Grow/shrink demos */
        .grow-demo .item.grow-1 {
            flex-grow: 1;
        }

        .grow-demo .item.grow-2 {
            flex-grow: 2;
        }

        /* Justify-content demos */
        .justify-start {
            justify-content: flex-start;
        }

        .justify-center {
            justify-content: center;
        }

        .justify-end {
            justify-content: flex-end;
        }

        .justify-between {
            justify-content: space-between;
        }

        .justify-around {
            justify-content: space-around;
        }

        .justify-evenly {
            justify-content: space-evenly;
        }

        /* Align-items demos */
        .align-demo {
            height: 150px;
        }

        .align-start {
            align-items: flex-start;
        }

        .align-center {
            align-items: center;
        }

        .align-end {
            align-items: flex-end;
        }

        .align-stretch {
            align-items: stretch;
        }

        .align-baseline {
            align-items: baseline;
        }

        /* Axis visualization */
        .axis-demo {
            position: relative;
            padding: 30px 20px;
        }

        .axis-demo .main-axis {
            position: absolute;
            top: 5px;
            left: 50%;
            transform: translateX(-50%);
            font-weight: bold;
            color: #dc3545;
            font-size: 0.85rem;
        }

        .axis-demo .cross-axis {
            position: absolute;
            right: 5px;
            top: 50%;
            transform: translateY(-50%);
            font-weight: bold;
            color: #6c5ce7;
            font-size: 0.85rem;
            writing-mode: vertical-rl;
        }
    </style>
</head>
<body>

    <h1>Flexbox Layout Introduction</h1>

    <!-- ====== 1. BASIC FLEXBOX ====== -->
    <section>
        <h2>1. Basic Flexbox</h2>
        <p>Setting <code>display: flex</code> on the container makes its children flex items, laid out in a row by default.</p>

        <div class="container axis-demo">
            <span class="main-axis">← Main Axis (row) →</span>
            <span class="cross-axis">↕ Cross Axis</span>
            <div class="item">Item 1</div>
            <div class="item">Item 2</div>
            <div class="item">Item 3</div>
            <div class="item">Item 4</div>
            <div class="item">Item 5</div>
        </div>

        <div class="code-block">
            .container {
                display: flex;  /* Makes this a flex container */
            }

            .item {
                /* Flex items are laid out in a row by default */
            }
        </div>
    </section>

    <!-- ====== 2. FLEX-DIRECTION ====== -->
    <section>
        <h2>2. flex-direction</h2>
        <p>Defines the main axis — the direction items are laid out.</p>

        <h3>flex-direction: row (default)</h3>
        <div class="container dir-row">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>

        <h3>flex-direction: column</h3>
        <div class="container dir-column" style="min-height: 250px;">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>

        <h3>flex-direction: row-reverse</h3>
        <div class="container dir-row-reverse">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>

        <h3>flex-direction: column-reverse</h3>
        <div class="container dir-column-reverse" style="min-height: 250px;">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>

        <div class="code-block">
            .container { flex-direction: row; }            /* Default — left to right */
            .container { flex-direction: column; }         /* Top to bottom */
            .container { flex-direction: row-reverse; }    /* Right to left */
            .container { flex-direction: column-reverse; } /* Bottom to top */
        </div>
    </section>

    <!-- ====== 3. FLEX-WRAP ====== -->
    <section>
        <h2>3. flex-wrap</h2>
        <p>Controls whether items wrap to the next line when there isn't enough space.</p>

        <h3>flex-wrap: nowrap (default — items shrink to fit)</h3>
        <div class="container wrap-nowrap">
            <div class="item">Item 1</div>
            <div class="item">Item 2</div>
            <div class="item">Item 3</div>
            <div class="item">Item 4</div>
            <div class="item">Item 5</div>
            <div class="item">Item 6</div>
            <div class="item">Item 7</div>
            <div class="item">Item 8</div>
        </div>

        <h3>flex-wrap: wrap (items wrap to next line)</h3>
        <div class="container wrap-wrap">
            <div class="item">Item 1</div>
            <div class="item">Item 2</div>
            <div class="item">Item 3</div>
            <div class="item">Item 4</div>
            <div class="item">Item 5</div>
            <div class="item">Item 6</div>
            <div class="item">Item 7</div>
            <div class="item">Item 8</div>
        </div>

        <div class="code-block">
            .container { flex-wrap: nowrap; }     /* Default — no wrapping */
            .container { flex-wrap: wrap; }       /* Items wrap */
            .container { flex-wrap: wrap-reverse; } /* Items wrap in reverse */
        </div>
    </section>

    <!-- ====== 4. FLEX-GROW ====== -->
    <section>
        <h2>4. flex-grow</h2>
        <p>Defines how much an item can grow relative to other items.</p>

        <div class="container grow-demo">
            <div class="item">flex-grow: 0 (default)</div>
            <div class="item grow-1">flex-grow: 1</div>
            <div class="item grow-2">flex-grow: 2</div>
        </div>

        <div class="code-block">
            .item { flex-grow: 0; }  /* Default — no growth */
            .item { flex-grow: 1; }  /* Grows to fill available space */
            .item { flex-grow: 2; }  /* Grows twice as much as flex-grow: 1 */
        </div>
    </section>

    <!-- ====== 5. JUSTIFY-CONTENT ====== -->
    <section>
        <h2>5. justify-content</h2>
        <p>Aligns items along the <strong>main axis</strong>.</p>

        <h3>flex-start (default)</h3>
        <div class="container justify-start">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
        </div>

        <h3>center</h3>
        <div class="container justify-center">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
        </div>

        <h3>flex-end</h3>
        <div class="container justify-end">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
        </div>

        <h3>space-between</h3>
        <div class="container justify-between">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
        </div>

        <h3>space-around</h3>
        <div class="container justify-around">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
        </div>

        <h3>space-evenly</h3>
        <div class="container justify-evenly">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
        </div>

        <div class="code-block">
            .container { justify-content: flex-start; }    /* Default — start */
            .container { justify-content: flex-end; }      /* End */
            .container { justify-content: center; }        /* Center */
            .container { justify-content: space-between; } /* Space between */
            .container { justify-content: space-around; }  /* Space around */
            .container { justify-content: space-evenly; }  /* Equal space */
        </div>
    </section>

    <!-- ====== 6. ALIGN-ITEMS ====== -->
    <section>
        <h2>6. align-items</h2>
        <p>Aligns items along the <strong>cross axis</strong>.</p>

        <h3>flex-start</h3>
        <div class="container align-demo align-start">
            <div class="item">1</div>
            <div class="item" style="height: 80px;">2 (taller)</div>
            <div class="item">3</div>
        </div>

        <h3>center</h3>
        <div class="container align-demo align-center">
            <div class="item">1</div>
            <div class="item" style="height: 80px;">2 (taller)</div>
            <div class="item">3</div>
        </div>

        <h3>flex-end</h3>
        <div class="container align-demo align-end">
            <div class="item">1</div>
            <div class="item" style="height: 80px;">2 (taller)</div>
            <div class="item">3</div>
        </div>

        <h3>stretch (default)</h3>
        <div class="container align-demo align-stretch">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
        </div>

        <div class="code-block">
            .container { align-items: stretch; }     /* Default — fill height */
            .container { align-items: flex-start; }  /* Top */
            .container { align-items: flex-end; }    /* Bottom */
            .container { align-items: center; }      /* Center */
            .container { align-items: baseline; }    /* Text baseline */
        </div>
    </section>

    <!-- ====== 7. FLEX SHORTHAND ====== -->
    <section>
        <h2>7. flex (Shorthand)</h2>
        <p>Combines <code>flex-grow</code>, <code>flex-shrink</code>, and <code>flex-basis</code>.</p>

        <div class="container">
            <div class="item" style="flex: 1;">flex: 1</div>
            <div class="item" style="flex: 2;">flex: 2</div>
            <div class="item" style="flex: 1;">flex: 1</div>
        </div>

        <div class="code-block">
            .item { flex: 1; }           /* grow: 1, shrink: 1, basis: 0 */
            .item { flex: auto; }        /* grow: 1, shrink: 1, basis: auto */
            .item { flex: none; }        /* grow: 0, shrink: 0, basis: auto */
            .item { flex: 1 0 200px; }   /* grow: 1, shrink: 0, basis: 200px */
        </div>
    </section>

    <!-- ====== 8. REFERENCE TABLES ====== -->
    <section>
        <h2>8. Reference Tables</h2>

        <h3>Container Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Values</th>
            </tr>
            <tr>
                <td><code>display</code></td>
                <td>Enables flexbox</td>
                <td><code>flex</code>, <code>inline-flex</code></td>
            </tr>
            <tr>
                <td><code>flex-direction</code></td>
                <td>Main axis direction</td>
                <td><code>row</code>, <code>column</code>, <code>row-reverse</code>, <code>column-reverse</code></td>
            </tr>
            <tr>
                <td><code>flex-wrap</code></td>
                <td>Wrapping behavior</td>
                <td><code>nowrap</code>, <code>wrap</code>, <code>wrap-reverse</code></td>
            </tr>
            <tr>
                <td><code>justify-content</code></td>
                <td>Align on main axis</td>
                <td><code>flex-start</code>, <code>flex-end</code>, <code>center</code>, <code>space-between</code>, <code>space-around</code>, <code>space-evenly</code></td>
            </tr>
            <tr>
                <td><code>align-items</code></td>
                <td>Align on cross axis</td>
                <td><code>stretch</code>, <code>flex-start</code>, <code>flex-end</code>, <code>center</code>, <code>baseline</code></td>
            </tr>
        </table>

        <h3>Item Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Default</th>
            </tr>
            <tr>
                <td><code>flex-grow</code></td>
                <td>How much an item can grow</td>
                <td><code>0</code></td>
            </tr>
            <tr>
                <td><code>flex-shrink</code></td>
                <td>How much an item can shrink</td>
                <td><code>1</code></td>
            </tr>
            <tr>
                <td><code>flex-basis</code></td>
                <td>Initial size</td>
                <td><code>auto</code></td>
            </tr>
            <tr>
                <td><code>flex</code></td>
                <td>Shorthand for grow, shrink, basis</td>
                <td>—</td>
            </tr>
            <tr>
                <td><code>order</code></td>
                <td>Visual order of items</td>
                <td><code>0</code></td>
            </tr>
            <tr>
                <td><code>align-self</code></td>
                <td>Override align-items for one item</td>
                <td><code>auto</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 9. BEST PRACTICES ====== -->
    <section>
        <h2>9. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>display: flex</code> for one-dimensional layouts</li>
                <li>Use <code>gap</code> instead of margins on flex items</li>
                <li>Use <code>justify-content</code> for main axis alignment</li>
                <li>Use <code>align-items</code> for cross axis alignment</li>
                <li>Use <code>flex-wrap: wrap</code> for responsive layouts</li>
                <li>Use the <code>flex</code> shorthand for concise code</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use Flexbox for two-dimensional layouts (use Grid instead)</li>
                <li>Don't use margins on flex items when gap works</li>
                <li>Don't forget that <code>align-items</code> only works on the cross axis</li>
                <li>Don't confuse <code>justify-content</code> (main axis) with <code>align-items</code> (cross axis)</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyApplies ToDescription
display: flexContainerEnables flexbox
flex-directionContainerMain axis (row/column)
flex-wrapContainerWrapping behavior
justify-contentContainerAlign on main axis
align-itemsContainerAlign on cross axis
flex-growItemGrowth factor
flex-shrinkItemShrink factor
flex-basisItemInitial size
flexItemShorthand for grow, shrink, basis

Main Axis vs Cross Axis

flex-directionMain AxisCross Axis
row (default)Horizontal →Vertical ↓
columnVertical ↓Horizontal →
row-reverseHorizontal ←Vertical ↓
column-reverseVertical ↑Horizontal →

Best Practices

Do This:

/* Center everything perfectly */
.container {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
}

/* Responsive flex with wrapping */
.container {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
}

/* Equal-width items */
.item {
    flex: 1;
}

Don’t Do This:

/* Don't use margins on flex items */
.item {
    margin-right: 20px; /* Use gap on the container instead */
}

/* Don't confuse justify-content and align-items */
.container {
    justify-content: center; /* Main axis */
    align-items: center;     /* Cross axis */
}

Pro Tip: Flexbox is perfect for one-dimensional layouts (rows or columns). Use display: flex on the container, then control alignment with justify-content (main axis) and align-items (cross axis). The flex: 1 shorthand makes items grow equally to fill available space. Remember: when you change flex-direction, the main and cross axes swap! In the next lessons, you’ll dive deeper into each Flexbox property.

25. flex-direction and flex-wrap Properties

These two container properties control the direction of the main axis and how items wrap when they exceed the container’s size. Together, they form the foundation of any Flexbox layout.


Overview of Properties

PropertyDescriptionValues
flex-directionSets the direction of the main axisrow, row-reverse, column, column-reverse
flex-wrapControls whether items wrapnowrap, wrap, wrap-reverse

1. flex-direction

The flex-direction property sets the direction of the main axis — which determines how items are laid out.

.container {
    display: flex;
    flex-direction: row; /* Default — left to right */
}

Values

ValueMain AxisDirectionVisual
rowHorizontalLeft → Right (default)[1] [2] [3]
row-reverseHorizontalRight → Left[3] [2] [1]
columnVerticalTop → Bottom[1]
[2]
[3]
column-reverseVerticalBottom → Top[3]
[2]
[1]

Important: Changing flex-direction also changes which axis is the main axis and which is the cross axis.

flex-directionMain AxisCross Axis
rowHorizontal →Vertical ↓
row-reverseHorizontal ←Vertical ↓
columnVertical ↓Horizontal →
column-reverseVertical ↑Horizontal →

2. flex-wrap

The flex-wrap property controls whether flex items wrap to the next line when they exceed the container’s size.

.container {
    display: flex;
    flex-wrap: nowrap; /* Default — no wrapping */
}

Values

ValueDescriptionVisual
nowrapAll items on one line (default) — items shrink to fit[1][2][3][4][5]
wrapItems wrap to multiple lines[1][2][3]
[4][5]
wrap-reverseItems wrap in reverse order (bottom to top)[4][5]
[1][2][3]

Key Points:

  • nowrap forces all items onto a single line (items may shrink)
  • wrap allows items to flow onto multiple lines
  • wrap-reverse inverts the cross-axis direction (lines stack in reverse)

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>flex-direction and flex-wrap</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        /* ====== FLEX CONTAINERS ====== */
        .container {
            display: flex;
            border: 2px solid #333;
            width: 200px;
            margin: 10px 0;
            padding: 5px;
            background: #e9ecef;
            border-radius: 8px;
        }

        .item {
            width: 100px;
            height: 50px;
            background: #007bff;
            margin: 5px;
            color: white;
            text-align: center;
            line-height: 50px;
            border-radius: 4px;
            font-weight: bold;
            flex-shrink: 0;
        }

        .item:nth-child(even) {
            background: #28a745;
        }

        .item:nth-child(3n) {
            background: #dc3545;
        }

        /* flex-direction demos */
        .dir-row {
            flex-direction: row;
        }

        .dir-row-reverse {
            flex-direction: row-reverse;
        }

        .dir-column {
            flex-direction: column;
            width: auto;
            min-width: 200px;
            min-height: 200px;
        }

        .dir-column-reverse {
            flex-direction: column-reverse;
            width: auto;
            min-width: 200px;
            min-height: 200px;
        }

        /* flex-wrap demos */
        .wrap-nowrap {
            flex-wrap: nowrap;
        }

        .wrap-wrap {
            flex-wrap: wrap;
        }

        .wrap-wrap-reverse {
            flex-wrap: wrap-reverse;
        }

        /* Wider container for wrap demos */
        .container-wide {
            width: 350px;
        }

        .container-wide .item {
            width: 100px;
        }

        /* Side-by-side comparison */
        .comparison-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
        }

        .comparison-item {
            text-align: center;
        }

        .comparison-item h4 {
            margin-bottom: 5px;
            color: #007bff;
        }

        /* Axis visualization */
        .axis-demo {
            position: relative;
            padding: 25px 15px 15px 15px;
        }

        .axis-demo .main-axis-label {
            position: absolute;
            top: 2px;
            left: 50%;
            transform: translateX(-50%);
            font-size: 0.75rem;
            font-weight: bold;
            color: #dc3545;
            white-space: nowrap;
        }

        .axis-demo .cross-axis-label {
            position: absolute;
            right: -5px;
            top: 50%;
            transform: translateY(-50%);
            font-size: 0.75rem;
            font-weight: bold;
            color: #6c5ce7;
            writing-mode: vertical-rl;
        }
    </style>
</head>
<body>

    <h1>flex-direction and flex-wrap Properties</h1>

    <!-- ====== 1. FLEX-DIRECTION: ROW ====== -->
    <section>
        <h2>1. flex-direction: row (default)</h2>
        <p>Main axis is horizontal, items flow from left to right.</p>

        <div class="container dir-row axis-demo">
            <span class="main-axis-label">← Main Axis →</span>
            <span class="cross-axis-label">↕ Cross</span>
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
        </div>

        <div class="code-block">
            .container {
                display: flex;
                flex-direction: row;  /* Default */
            }
        </div>
    </section>

    <!-- ====== 2. FLEX-DIRECTION: ROW-REVERSE ====== -->
    <section>
        <h2>2. flex-direction: row-reverse</h2>
        <p>Main axis is horizontal, but items flow from right to left.</p>

        <div class="container dir-row-reverse axis-demo">
            <span class="main-axis-label">← Main Axis →</span>
            <span class="cross-axis-label">↕ Cross</span>
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
        </div>

        <div class="code-block">
            .container {
                display: flex;
                flex-direction: row-reverse;
            }
        </div>
    </section>

    <!-- ====== 3. FLEX-DIRECTION: COLUMN ====== -->
    <section>
        <h2>3. flex-direction: column</h2>
        <p>Main axis is vertical, items flow from top to bottom.</p>

        <div class="container dir-column axis-demo">
            <span class="main-axis-label">↓ Main Axis ↓</span>
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
        </div>

        <div class="code-block">
            .container {
                display: flex;
                flex-direction: column;
            }
        </div>
    </section>

    <!-- ====== 4. FLEX-DIRECTION: COLUMN-REVERSE ====== -->
    <section>
        <h2>4. flex-direction: column-reverse</h2>
        <p>Main axis is vertical, but items flow from bottom to top.</p>

        <div class="container dir-column-reverse axis-demo">
            <span class="main-axis-label">↑ Main Axis ↑</span>
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
        </div>

        <div class="code-block">
            .container {
                display: flex;
                flex-direction: column-reverse;
            }
        </div>
    </section>

    <!-- ====== 5. FLEX-WRAP: NOWRAP ====== -->
    <section>
        <h2>5. flex-wrap: nowrap (default)</h2>
        <p>All items are forced onto a single line. If they don't fit, they overflow or shrink.</p>

        <div class="container container-wide wrap-nowrap">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
            <div class="item">5</div>
        </div>
        <p class="note">Items overflow the container because they don't wrap.</p>

        <div class="code-block">
            .container {
                display: flex;
                flex-wrap: nowrap;  /* Default */
            }
        </div>
    </section>

    <!-- ====== 6. FLEX-WRAP: WRAP ====== -->
    <section>
        <h2>6. flex-wrap: wrap</h2>
        <p>Items wrap to multiple lines when they exceed the container's size.</p>

        <div class="container container-wide wrap-wrap">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
            <div class="item">5</div>
        </div>
        <p class="note">Items wrap onto new lines when there's not enough space.</p>

        <div class="code-block">
            .container {
                display: flex;
                flex-wrap: wrap;
            }
        </div>
    </section>

    <!-- ====== 7. FLEX-WRAP: WRAP-REVERSE ====== -->
    <section>
        <h2>7. flex-wrap: wrap-reverse</h2>
        <p>Items wrap, but the lines are stacked in reverse order (bottom to top).</p>

        <div class="container container-wide wrap-wrap-reverse">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
            <div class="item">5</div>
        </div>
        <p class="note">The first line is at the bottom, the second line is at the top.</p>

        <div class="code-block">
            .container {
                display: flex;
                flex-wrap: wrap-reverse;
            }
        </div>
    </section>

    <!-- ====== 8. SIDE-BY-SIDE COMPARISON ====== -->
    <section>
        <h2>8. Side-by-Side Comparison</h2>

        <h3>flex-direction</h3>
        <div class="comparison-grid">
            <div class="comparison-item">
                <h4>row</h4>
                <div class="container" style="flex-direction: row;">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>row-reverse</h4>
                <div class="container" style="flex-direction: row-reverse;">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>column</h4>
                <div class="container" style="flex-direction: column; width: auto; min-width: 150px;">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>column-reverse</h4>
                <div class="container" style="flex-direction: column-reverse; width: auto; min-width: 150px;">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                </div>
            </div>
        </div>

        <h3 style="margin-top: 30px;">flex-wrap</h3>
        <div class="comparison-grid">
            <div class="comparison-item">
                <h4>nowrap</h4>
                <div class="container container-wide" style="flex-wrap: nowrap; width: 100%;">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                    <div class="item">4</div>
                    <div class="item">5</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>wrap</h4>
                <div class="container container-wide" style="flex-wrap: wrap; width: 100%;">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                    <div class="item">4</div>
                    <div class="item">5</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>wrap-reverse</h4>
                <div class="container container-wide" style="flex-wrap: wrap-reverse; width: 100%;">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                    <div class="item">4</div>
                    <div class="item">5</div>
                </div>
            </div>
        </div>
    </section>

    <!-- ====== 9. REFERENCE TABLES ====== -->
    <section>
        <h2>9. Reference Tables</h2>

        <h3>flex-direction Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Main Axis</th>
                <th>Direction</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>row</code></td>
                <td>Horizontal</td>
                <td>Left → Right (default)</td>
                <td><code>[1] [2] [3]</code></td>
            </tr>
            <tr>
                <td><code>row-reverse</code></td>
                <td>Horizontal</td>
                <td>Right → Left</td>
                <td><code>[3] [2] [1]</code></td>
            </tr>
            <tr>
                <td><code>column</code></td>
                <td>Vertical</td>
                <td>Top → Bottom</td>
                <td><code>[1]</code><br><code>[2]</code><br><code>[3]</code></td>
            </tr>
            <tr>
                <td><code>column-reverse</code></td>
                <td>Vertical</td>
                <td>Bottom → Top</td>
                <td><code>[3]</code><br><code>[2]</code><br><code>[1]</code></td>
            </tr>
        </table>

        <h3>flex-wrap Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Visual</th>
            </tr>
            <tr>
                <td><code>nowrap</code></td>
                <td>All items on one line (default)</td>
                <td><code>[1][2][3][4][5]</code></td>
            </tr>
            <tr>
                <td><code>wrap</code></td>
                <td>Items wrap to multiple lines</td>
                <td><code>[1][2][3]</code><br><code>[4][5]</code></td>
            </tr>
            <tr>
                <td><code>wrap-reverse</code></td>
                <td>Items wrap in reverse order (bottom to top)</td>
                <td><code>[4][5]</code><br><code>[1][2][3]</code></td>
            </tr>
        </table>

        <h3>Shorthand: flex-flow</h3>
        <table class="reference-table">
            <tr>
                <th>Shorthand</th>
                <th>Equivalent</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>flex-flow</code></td>
                <td><code>flex-direction</code> + <code>flex-wrap</code></td>
                <td><code>flex-flow: row wrap;</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 10. BEST PRACTICES ====== -->
    <section>
        <h2>10. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>flex-direction: row</code> for horizontal layouts</li>
                <li>Use <code>flex-direction: column</code> for vertical layouts</li>
                <li>Use <code>flex-wrap: wrap</code> for responsive layouts</li>
                <li>Use <code>flex-flow</code> shorthand to combine both properties</li>
                <li>Remember that changing <code>flex-direction</code> swaps the main and cross axes</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use <code>flex-wrap: wrap-reverse</code> without understanding the visual order change</li>
                <li>Don't forget that <code>justify-content</code> and <code>align-items</code> swap axes when you change <code>flex-direction</code></li>
                <li>Don't use <code>nowrap</code> when items might overflow on small screens</li>
                <li>Don't confuse <code>row-reverse</code> (visual order) with <code>order</code> (DOM order)</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyValuesDescription
flex-directionrow, row-reverse, column, column-reverseSets the main axis direction
flex-wrapnowrap, wrap, wrap-reverseControls wrapping behavior
flex-flow<flex-direction> <flex-wrap>Shorthand for both

flex-direction Values

ValueMain AxisDirection
rowHorizontalLeft → Right (default)
row-reverseHorizontalRight → Left
columnVerticalTop → Bottom
column-reverseVerticalBottom → Top

flex-wrap Values

ValueDescription
nowrapAll items on one line (default)
wrapItems wrap to multiple lines
wrap-reverseItems wrap in reverse order (bottom to top)

flex-flow Shorthand

/* Instead of: */
flex-direction: row;
flex-wrap: wrap;

/* Use: */
flex-flow: row wrap;

Best Practices

Do This:

/* Responsive flex layout */
.container {
    display: flex;
    flex-flow: row wrap;  /* Shorthand */
    gap: 20px;
}

/* Vertical layout */
.sidebar {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

Don’t Do This:

/* Don't use wrap-reverse without understanding it */
.container {
    flex-wrap: wrap-reverse; /* Lines stack from bottom to top */
}

/* Don't forget axis swap when changing direction */
.container {
    flex-direction: column;
    justify-content: center; /* Now controls vertical alignment! */
    align-items: center;     /* Now controls horizontal alignment! */
}

Pro Tip: flex-direction and flex-wrap are the two most fundamental Flexbox properties. Use flex-flow: row wrap as a shorthand for responsive layouts. Remember that changing flex-direction swaps the main and cross axes — which means justify-content and align-items swap their effects too! This is a common source of confusion for beginners.

26. flex-grow and flex-shrink Properties

These two properties control how flex items grow to fill available space and shrink when there isn’t enough space. They’re essential for creating flexible, responsive layouts.


Overview of Properties

PropertyDescriptionDefaultValues
flex-growHow much an item can grow relative to siblings0Number (e.g., 1, 2, 3)
flex-shrinkHow much an item can shrink relative to siblings1Number (e.g., 0, 1, 2)

1. flex-grow

The flex-grow property specifies the grow factor — how much an item can grow relative to its siblings when there’s available space.

.item1, .item3 {
    flex-grow: 1; /* Each takes 1 share */
}

.item2 {
    flex-grow: 2; /* Takes 2 shares */
}

How It Works

The available space is divided among items based on their grow factors:

Total grow factors = 1 + 2 + 1 = 4

Item 1: 1/4 of available space (25%)
Item 2: 2/4 of available space (50%)
Item 3: 1/4 of available space (25%)

Values

ValueDescriptionExample
0Item does not grow (default)flex-grow: 0;
1Item grows to fill available spaceflex-grow: 1;
2Item grows twice as much as flex-grow: 1flex-grow: 2;
3+Higher values grow moreflex-grow: 3;

Important: flex-grow only applies when there is extra space in the container. If items already fill the container, flex-grow has no effect.


2. flex-shrink

The flex-shrink property specifies the shrink factor — how much an item can shrink relative to its siblings when there isn’t enough space.

.item4, .item5 {
    flex-shrink: 1; /* Each shrinks by 1 share */
}

.item6 {
    flex-shrink: 2; /* Shrinks by 2 shares */
}

How It Works

When the total size of items exceeds the container, items shrink based on their shrink factors:

Total shrink factors = 1 + 1 + 2 = 4

Item 4: 1/4 of the overflow is removed (25% shrink)
Item 5: 1/4 of the overflow is removed (25% shrink)
Item 6: 2/4 of the overflow is removed (50% shrink)

Values

ValueDescriptionExample
0Item does not shrinkflex-shrink: 0;
1Item shrinks proportionally (default)flex-shrink: 1;
2Item shrinks twice as much as flex-shrink: 1flex-shrink: 2;
3+Higher values shrink moreflex-shrink: 3;

Important: flex-shrink only applies when items overflow the container. If there’s enough space, flex-shrink has no effect.


flex-grow vs flex-shrink

Aspectflex-growflex-shrink
When it appliesWhen there’s extra spaceWhen there’s not enough space
EffectItems get biggerItems get smaller
Default0 (no growth)1 (can shrink)
Higher valueGrows moreShrinks more
Value 0Won’t growWon’t shrink

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>flex-grow and flex-shrink Properties</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== FLEX CONTAINERS ====== */
        .container {
            display: flex;
            border: 2px solid #333;
            margin: 15px 0;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            gap: 10px;
        }

        .item {
            height: 100px;
            border: 3px solid #6c5ce7;
            border-radius: 6px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 1.2rem;
        }

        .item1 { background: #007bff; }
        .item2 { background: #28a745; }
        .item3 { background: #dc3545; }
        .item4 { background: #ffc107; color: #333; }
        .item5 { background: #17a2b8; }
        .item6 { background: #e17055; }

        /* Grow demos */
        .grow-demo-1 .item1,
        .grow-demo-1 .item3 {
            flex-grow: 1;
        }

        .grow-demo-1 .item2 {
            flex-grow: 2;
        }

        .grow-demo-2 .item1 {
            flex-grow: 0;
        }

        .grow-demo-2 .item2 {
            flex-grow: 1;
        }

        .grow-demo-2 .item3 {
            flex-grow: 1;
        }

        .grow-demo-3 .item1 {
            flex-grow: 3;
        }

        .grow-demo-3 .item2 {
            flex-grow: 1;
        }

        .grow-demo-3 .item3 {
            flex-grow: 1;
        }

        /* Shrink demos */
        .shrink-container {
            width: 500px;
        }

        .shrink-demo-1 .item4,
        .shrink-demo-1 .item5 {
            flex-shrink: 1;
            width: 200px;
        }

        .shrink-demo-1 .item6 {
            flex-shrink: 2;
            width: 200px;
        }

        .shrink-demo-2 .item4 {
            flex-shrink: 0;
            width: 200px;
        }

        .shrink-demo-2 .item5 {
            flex-shrink: 1;
            width: 200px;
        }

        .shrink-demo-2 .item6 {
            flex-shrink: 1;
            width: 200px;
        }

        /* Side-by-side comparison */
        .comparison-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
        }

        .comparison-item {
            text-align: center;
        }

        .comparison-item h4 {
            margin-bottom: 5px;
            color: #007bff;
        }

        .comparison-item .container {
            margin: 5px 0;
        }

        /* Visual explanation */
        .visual-explanation {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 20px;
            flex-wrap: wrap;
            margin: 20px 0;
        }

        .visual-box {
            text-align: center;
        }

        .visual-box .bar {
            height: 30px;
            background: #007bff;
            border-radius: 4px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 0.8rem;
            font-weight: bold;
            margin: 5px 0;
        }

        .visual-box .bar.grow-1 {
            background: #007bff;
            width: 60px;
        }

        .visual-box .bar.grow-2 {
            background: #28a745;
            width: 120px;
        }

        .visual-box .bar.grow-3 {
            background: #dc3545;
            width: 180px;
        }
    </style>
</head>
<body>

    <h1>flex-grow and flex-shrink Properties</h1>

    <!-- ====== 1. FLEX-GROW ====== -->
    <section>
        <h2>1. flex-grow</h2>
        <p>Specifies how much an item can <strong>grow</strong> relative to its siblings when there's available space.</p>

        <h3>flex-grow: 1 | 2 | 1</h3>
        <div class="container grow-demo-1">
            <div class="item item1">1 (grow: 1)</div>
            <div class="item item2">2 (grow: 2)</div>
            <div class="item item3">3 (grow: 1)</div>
        </div>
        <p class="note">Total grow factors = 4. Item 1 and 3 get 25% each, Item 2 gets 50%.</p>

        <h3>flex-grow: 0 | 1 | 1</h3>
        <div class="container grow-demo-2">
            <div class="item item1">1 (grow: 0)</div>
            <div class="item item2">2 (grow: 1)</div>
            <div class="item item3">3 (grow: 1)</div>
        </div>
        <p class="note">Item 1 doesn't grow. Items 2 and 3 share the available space equally.</p>

        <h3>flex-grow: 3 | 1 | 1</h3>
        <div class="container grow-demo-3">
            <div class="item item1">1 (grow: 3)</div>
            <div class="item item2">2 (grow: 1)</div>
            <div class="item item3">3 (grow: 1)</div>
        </div>
        <p class="note">Total grow factors = 5. Item 1 gets 60%, Items 2 and 3 get 20% each.</p>

        <div class="code-block">
            /* Item 1 and 3 grow equally, Item 2 grows twice as much */
            .item1, .item3 { flex-grow: 1; }
            .item2 { flex-grow: 2; }

            /* Item 1 doesn't grow, Items 2 and 3 grow equally */
            .item1 { flex-grow: 0; }
            .item2, .item3 { flex-grow: 1; }

            /* Item 1 grows 3x, Items 2 and 3 grow 1x each */
            .item1 { flex-grow: 3; }
            .item2, .item3 { flex-grow: 1; }
        </div>
    </section>

    <!-- ====== 2. FLEX-SHRINK ====== -->
    <section>
        <h2>2. flex-shrink</h2>
        <p>Specifies how much an item can <strong>shrink</strong> relative to its siblings when there isn't enough space.</p>

        <h3>flex-shrink: 1 | 1 | 2</h3>
        <div class="container shrink-container shrink-demo-1">
            <div class="item item4">4 (shrink: 1)</div>
            <div class="item item5">5 (shrink: 1)</div>
            <div class="item item6">6 (shrink: 2)</div>
        </div>
        <p class="note">Container is 500px wide. Items are 200px each (600px total). Item 6 shrinks twice as much.</p>

        <h3>flex-shrink: 0 | 1 | 1</h3>
        <div class="container shrink-container shrink-demo-2">
            <div class="item item4">4 (shrink: 0)</div>
            <div class="item item5">5 (shrink: 1)</div>
            <div class="item item6">6 (shrink: 1)</div>
        </div>
        <p class="note">Item 4 doesn't shrink. Items 5 and 6 share the overflow reduction equally.</p>

        <div class="code-block">
            /* Items 4 and 5 shrink equally, Item 6 shrinks twice as much */
            .item4, .item5 { flex-shrink: 1; width: 200px; }
            .item6 { flex-shrink: 2; width: 200px; }

            /* Item 4 doesn't shrink, Items 5 and 6 shrink equally */
            .item4 { flex-shrink: 0; width: 200px; }
            .item5, .item6 { flex-shrink: 1; width: 200px; }
        </div>
    </section>

    <!-- ====== 3. SIDE-BY-SIDE COMPARISON ====== -->
    <section>
        <h2>3. Side-by-Side Comparison</h2>

        <h3>flex-grow</h3>
        <div class="comparison-grid">
            <div class="comparison-item">
                <h4>grow: 1 | 1 | 1</h4>
                <div class="container" style="gap: 5px;">
                    <div class="item item1" style="flex-grow: 1; height: 60px; font-size: 0.8rem;">1</div>
                    <div class="item item2" style="flex-grow: 1; height: 60px; font-size: 0.8rem;">1</div>
                    <div class="item item3" style="flex-grow: 1; height: 60px; font-size: 0.8rem;">1</div>
                </div>
                <p class="note">Equal growth</p>
            </div>

            <div class="comparison-item">
                <h4>grow: 1 | 2 | 1</h4>
                <div class="container" style="gap: 5px;">
                    <div class="item item1" style="flex-grow: 1; height: 60px; font-size: 0.8rem;">1</div>
                    <div class="item item2" style="flex-grow: 2; height: 60px; font-size: 0.8rem;">2</div>
                    <div class="item item3" style="flex-grow: 1; height: 60px; font-size: 0.8rem;">1</div>
                </div>
                <p class="note">Middle grows more</p>
            </div>

            <div class="comparison-item">
                <h4>grow: 0 | 1 | 1</h4>
                <div class="container" style="gap: 5px;">
                    <div class="item item1" style="flex-grow: 0; height: 60px; font-size: 0.8rem;">0</div>
                    <div class="item item2" style="flex-grow: 1; height: 60px; font-size: 0.8rem;">1</div>
                    <div class="item item3" style="flex-grow: 1; height: 60px; font-size: 0.8rem;">1</div>
                </div>
                <p class="note">First doesn't grow</p>
            </div>
        </div>

        <h3 style="margin-top: 30px;">flex-shrink</h3>
        <div class="comparison-grid">
            <div class="comparison-item">
                <h4>shrink: 1 | 1 | 1</h4>
                <div class="container" style="width: 100%; gap: 5px;">
                    <div class="item item4" style="flex-shrink: 1; width: 200px; height: 60px; font-size: 0.8rem;">1</div>
                    <div class="item item5" style="flex-shrink: 1; width: 200px; height: 60px; font-size: 0.8rem;">1</div>
                    <div class="item item6" style="flex-shrink: 1; width: 200px; height: 60px; font-size: 0.8rem;">1</div>
                </div>
                <p class="note">Equal shrink</p>
            </div>

            <div class="comparison-item">
                <h4>shrink: 1 | 1 | 2</h4>
                <div class="container" style="width: 100%; gap: 5px;">
                    <div class="item item4" style="flex-shrink: 1; width: 200px; height: 60px; font-size: 0.8rem;">1</div>
                    <div class="item item5" style="flex-shrink: 1; width: 200px; height: 60px; font-size: 0.8rem;">1</div>
                    <div class="item item6" style="flex-shrink: 2; width: 200px; height: 60px; font-size: 0.8rem;">2</div>
                </div>
                <p class="note">Last shrinks more</p>
            </div>

            <div class="comparison-item">
                <h4>shrink: 0 | 1 | 1</h4>
                <div class="container" style="width: 100%; gap: 5px;">
                    <div class="item item4" style="flex-shrink: 0; width: 200px; height: 60px; font-size: 0.8rem;">0</div>
                    <div class="item item5" style="flex-shrink: 1; width: 200px; height: 60px; font-size: 0.8rem;">1</div>
                    <div class="item item6" style="flex-shrink: 1; width: 200px; height: 60px; font-size: 0.8rem;">1</div>
                </div>
                <p class="note">First doesn't shrink</p>
            </div>
        </div>
    </section>

    <!-- ====== 4. VISUAL EXPLANATION ====== -->
    <section>
        <h2>4. Visual Explanation</h2>

        <h3>How flex-grow works</h3>
        <div class="visual-explanation">
            <div class="visual-box">
                <div class="bar grow-1">grow: 1</div>
                <p class="note">1 share</p>
            </div>
            <div class="visual-box">
                <div class="bar grow-2">grow: 2</div>
                <p class="note">2 shares</p>
            </div>
            <div class="visual-box">
                <div class="bar grow-3">grow: 3</div>
                <p class="note">3 shares</p>
            </div>
        </div>
        <p class="note" style="text-align: center;">
            Total = 6 shares. The available space is divided proportionally: 1/6, 2/6, 3/6.
        </p>

        <div class="code-block">
            /* Available space is divided based on grow factors */
            .item1 { flex-grow: 1; }  /* Gets 1/6 of space */
            .item2 { flex-grow: 2; }  /* Gets 2/6 of space */
            .item3 { flex-grow: 3; }  /* Gets 3/6 of space */
        </div>
    </section>

    <!-- ====== 5. REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>flex-grow vs flex-shrink</h3>
        <table class="reference-table">
            <tr>
                <th>Aspect</th>
                <th>flex-grow</th>
                <th>flex-shrink</th>
            </tr>
            <tr>
                <td><strong>When it applies</strong></td>
                <td>When there's extra space</td>
                <td>When there's not enough space</td>
            </tr>
            <tr>
                <td><strong>Effect</strong></td>
                <td>Items get bigger</td>
                <td>Items get smaller</td>
            </tr>
            <tr>
                <td><strong>Default value</strong></td>
                <td><code>0</code></td>
                <td><code>1</code></td>
            </tr>
            <tr>
                <td><strong>Value 0</strong></td>
                <td>Won't grow</td>
                <td>Won't shrink</td>
            </tr>
            <tr>
                <td><strong>Higher value</strong></td>
                <td>Grows more</td>
                <td>Shrinks more</td>
            </tr>
        </table>

        <h3>Common Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>flex-grow</th>
                <th>flex-shrink</th>
            </tr>
            <tr>
                <td><code>0</code></td>
                <td>No growth</td>
                <td>No shrinking</td>
            </tr>
            <tr>
                <td><code>1</code></td>
                <td>Normal growth</td>
                <td>Normal shrinking (default)</td>
            </tr>
            <tr>
                <td><code>2</code></td>
                <td>Grows 2x more</td>
                <td>Shrinks 2x more</td>
            </tr>
            <tr>
                <td><code>3+</code></td>
                <td>Grows 3x+ more</td>
                <td>Shrinks 3x+ more</td>
            </tr>
        </table>

        <h3>flex Shorthand</h3>
        <table class="reference-table">
            <tr>
                <th>Shorthand</th>
                <th>Equivalent</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>flex: 1;</code></td>
                <td><code>flex-grow: 1; flex-shrink: 1; flex-basis: 0;</code></td>
                <td>Grow equally, shrink equally</td>
            </tr>
            <tr>
                <td><code>flex: auto;</code></td>
                <td><code>flex-grow: 1; flex-shrink: 1; flex-basis: auto;</code></td>
                <td>Grow and shrink based on content</td>
            </tr>
            <tr>
                <td><code>flex: none;</code></td>
                <td><code>flex-grow: 0; flex-shrink: 0; flex-basis: auto;</code></td>
                <td>Fixed size, no grow/shrink</td>
            </tr>
            <tr>
                <td><code>flex: 2 1 200px;</code></td>
                <td><code>flex-grow: 2; flex-shrink: 1; flex-basis: 200px;</code></td>
                <td>Grows 2x, shrinks 1x, base 200px</td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>flex-grow: 1</code> to make items fill available space equally</li>
                <li>Use <code>flex-shrink: 0</code> to prevent items from shrinking (e.g., icons, buttons)</li>
                <li>Use different grow factors to create proportional layouts</li>
                <li>Use the <code>flex</code> shorthand for concise code</li>
                <li>Test with different container sizes to ensure proper behavior</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use <code>flex-grow</code> when items should have fixed widths</li>
                <li>Don't forget that <code>flex-shrink: 0</code> can cause overflow on small screens</li>
                <li>Don't confuse <code>flex-grow</code> (extra space) with <code>flex-shrink</code> (overflow)</li>
                <li>Don't use large grow factors without understanding the proportional distribution</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionDefaultValues
flex-growHow much an item grows0Number
flex-shrinkHow much an item shrinks1Number

flex-grow vs flex-shrink

Aspectflex-growflex-shrink
When it appliesExtra spaceNot enough space
EffectItems get biggerItems get smaller
Default0 (no growth)1 (can shrink)
Value 0Won’t growWon’t shrink
Higher valueGrows moreShrinks more

flex Shorthand

ShorthandEquivalentDescription
flex: 1;flex-grow: 1; flex-shrink: 1; flex-basis: 0;Grow equally
flex: auto;flex-grow: 1; flex-shrink: 1; flex-basis: auto;Based on content
flex: none;flex-grow: 0; flex-shrink: 0; flex-basis: auto;Fixed size
flex: 2 1 200px;flex-grow: 2; flex-shrink: 1; flex-basis: 200px;Custom

Best Practices

Do This:

/* Equal-width items */
.item {
    flex: 1; /* grow: 1, shrink: 1, basis: 0 */
}

/* Proportional widths */
.item1 { flex-grow: 1; }
.item2 { flex-grow: 2; } /* Twice as wide */
.item3 { flex-grow: 1; }

/* Prevent shrinking */
.icon {
    flex-shrink: 0; /* Won't shrink */
}

/* Fixed-size item */
.sidebar {
    flex: none; /* Won't grow or shrink */
    width: 250px;
}

Don’t Do This:

/* Don't use flex-grow without understanding distribution */
.item { flex-grow: 1; } /* Each gets equal share of extra space */

/* Don't prevent shrinking without considering small screens */
.item { flex-shrink: 0; } /* May overflow on mobile */

/* Don't confuse grow and shrink */
.item {
    flex-grow: 0;   /* Won't grow — applies when extra space */
    flex-shrink: 0; /* Won't shrink — applies when overflow */
}

Pro Tip: Think of flex-grow as “how much of the extra space do I get?” and flex-shrink as “how much of the overflow do I absorb?” Use flex: 1 for equal-width items, flex: none for fixed items, and different flex-grow values for proportional layouts. The flex shorthand is almost always cleaner than writing the three longhand properties separately!

27. flex-basis, flex, and flex-flow Properties

These three properties give you precise control over initial sizing, space distribution, and direction/wrapping in Flexbox. They’re essential for building sophisticated, responsive layouts.


Overview of Properties

PropertyDescriptionType
flex-basisSets the initial main size of a flex itemLonghand
flexShorthand for flex-grow, flex-shrink, flex-basisShorthand
flex-flowShorthand for flex-direction and flex-wrapShorthand

1. flex-basis

The flex-basis property specifies the initial main size of a flex item before any free space is distributed.

.item1 {
    flex-basis: 100px; /* Starts at 100px before growing/shrinking */
}

Values

ValueDescriptionExample
autoBased on content or width/height (default)flex-basis: auto;
lengthFixed size (px, em, rem)flex-basis: 100px;
percentagePercentage of containerflex-basis: 20%;
contentBased on content sizeflex-basis: content;
max-contentMaximum content sizeflex-basis: max-content;
min-contentMinimum content sizeflex-basis: min-content;
fit-contentFits content within limitsflex-basis: fit-content(200px);

Examples

/* Fixed size */
.item1 {
    flex-basis: 100px; /* Starts at 100px */
}

/* Percentage of container */
.item3 {
    flex-basis: 20%; /* Starts at 20% of container width */
}

/* Relative to font size */
.item4 {
    flex-basis: 5em; /* Starts at 5em */
}

/* Content-based */
.item {
    flex-basis: content; /* Size based on content */
}

Important: flex-basis is applied before flex-grow and flex-shrink come into play. It’s the starting point for space distribution.


2. flex (Shorthand)

The flex property is a shorthand for flex-grow, flex-shrink, and flex-basis.

.item {
    flex: 2 1 100px; /* grow: 2, shrink: 1, basis: 100px */
}

Syntax

flex: <flex-grow> <flex-shrink> <flex-basis>;
flex: <flex-grow> <flex-basis>;  /* shrink defaults to 1 */
flex: <flex-grow>;               /* shrink: 1, basis: 0 */

Common Values

ValueEquivalentDescription
flex: none;0 0 autoFixed size, no grow/shrink
flex: auto;1 1 autoBased on content, can grow/shrink
flex: 1;1 1 0%Equal distribution, ignores content
flex: 2;2 1 0%Grows 2x more than flex: 1
flex: 1 1 10em;1 1 10emGrow 1x, shrink 1x, base 10em
flex: 2 1 100px;2 1 100pxGrow 2x, shrink 1x, base 100px
flex: 1 2 auto;1 2 autoGrow 1x, shrink 2x, base auto

Special Values

ShorthandEquivalentDescription
flex: none0 0 autoNo flexibility at all
flex: auto1 1 autoFully flexible based on content
flex: initial0 1 autoDefault flex behavior

Two-Value Syntax

If you provide two values and both are integers, the second is flex-shrink:

flex: 2 2;    /* grow: 2, shrink: 2, basis: 0% */

If one is an integer and the other is a length, the integer is flex-grow and the length is flex-basis:

flex: 1 30px; /* grow: 1, shrink: 1, basis: 30px */

3. flex-flow (Shorthand)

The flex-flow property is a shorthand for flex-direction and flex-wrap.

.container {
    flex-flow: row wrap; /* direction: row, wrap: wrap */
}

Values

PartValues
flex-directionrow, row-reverse, column, column-reverse
flex-wrapnowrap, wrap, wrap-reverse

Examples

/* Row direction with wrapping */
.container {
    flex-flow: row wrap;
}

/* Column direction without wrapping */
.container {
    flex-flow: column nowrap;
}

/* Row reverse with wrapping */
.container {
    flex-flow: row-reverse wrap;
}

/* Only direction (wrap defaults to nowrap) */
.container {
    flex-flow: column;
}

/* Only wrap (direction defaults to row) */
.container {
    flex-flow: wrap;
}

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>flex-basis, flex, and flex-flow Properties</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== FLEX CONTAINERS ====== */
        .container {
            display: flex;
            border: 2px solid #333;
            width: 500px;
            height: 100px;
            padding: 5px;
            margin: 15px 0;
            background: #e9ecef;
            border-radius: 8px;
            gap: 5px;
        }

        .container-small {
            width: 300px;
        }

        .container-tall {
            height: 350px;
        }

        .item {
            border: 2px solid #dc3545;
            height: 50px;
            border-radius: 6px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.8rem;
            padding: 5px;
            background: #007bff;
        }

        .item:nth-child(even) {
            background: #28a745;
        }

        .item:nth-child(3n) {
            background: #6c5ce7;
        }

        /* flex-basis demos */
        .basis-100px {
            flex-basis: 100px;
        }

        .basis-20p {
            flex-basis: 20%;
        }

        .basis-5em {
            flex-basis: 5em;
        }

        .basis-auto {
            flex-basis: auto;
        }

        /* flex shorthand demos */
        .flex-1 {
            flex: 1;
        }

        .flex-2 {
            flex: 2;
        }

        .flex-none {
            flex: none;
        }

        .flex-auto {
            flex: auto;
        }

        .flex-2-1-100 {
            flex: 2 1 100px;
        }

        .flex-1-2-auto {
            flex: 1 2 auto;
        }

        .flex-1-1-5em {
            flex: 1 1 5em;
        }

        /* flex-flow demos */
        .flow-row-wrap {
            flex-flow: row wrap;
        }

        .flow-column-nowrap {
            flex-flow: column nowrap;
        }

        .flow-row-reverse-wrap {
            flex-flow: row-reverse wrap;
        }

        .item-flow {
            border: 2px solid #dc3545;
            flex: 0 0 100px;
            height: 60px;
            border-radius: 6px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.8rem;
            background: #007bff;
        }

        .item-flow:nth-child(even) {
            background: #28a745;
        }

        /* Side-by-side comparison */
        .comparison-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
        }

        .comparison-item {
            text-align: center;
        }

        .comparison-item h4 {
            margin-bottom: 5px;
            color: #007bff;
        }

        /* Visual explanation */
        .visual-explanation {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 20px;
            flex-wrap: wrap;
            margin: 20px 0;
        }

        .visual-box {
            text-align: center;
        }

        .visual-box .bar {
            height: 30px;
            border-radius: 4px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 0.8rem;
            font-weight: bold;
            margin: 5px 0;
        }

        .visual-box .bar.basis-100 {
            background: #007bff;
            width: 100px;
        }

        .visual-box .bar.basis-50 {
            background: #28a745;
            width: 50px;
        }

        .visual-box .bar.basis-150 {
            background: #dc3545;
            width: 150px;
        }
    </style>
</head>
<body>

    <h1>flex-basis, flex, and flex-flow Properties</h1>

    <!-- ====== 1. FLEX-BASIS ====== -->
    <section>
        <h2>1. flex-basis</h2>
        <p>Specifies the <strong>initial main size</strong> of a flex item before any space is distributed.</p>

        <div class="container">
            <div class="item basis-100px">basis: 100px</div>
            <div class="item basis-20p">basis: 20%</div>
            <div class="item basis-5em">basis: 5em</div>
        </div>

        <p class="note">Each item starts at its <code>flex-basis</code> value. The remaining space is distributed based on <code>flex-grow</code>.</p>

        <div class="code-block">
            .item1 { flex-basis: 100px; }  /* Starts at 100px */
            .item2 { flex-basis: 20%; }    /* Starts at 20% of container */
            .item3 { flex-basis: 5em; }    /* Starts at 5em */
            .item4 { flex-basis: auto; }   /* Based on content (default) */
        </div>
    </section>

    <!-- ====== 2. FLEX SHORTHAND ====== -->
    <section>
        <h2>2. flex (Shorthand)</h2>
        <p>Combines <code>flex-grow</code>, <code>flex-shrink</code>, and <code>flex-basis</code>.</p>

        <h3>flex: 2 1 100px | 1 2 auto | 1 1 5em</h3>
        <div class="container">
            <div class="item flex-2-1-100">flex: 2 1 100px</div>
            <div class="item flex-1-2-auto">flex: 1 2 auto</div>
            <div class="item flex-1-1-5em">flex: 1 1 5em</div>
        </div>

        <h3>flex: 1 | 2 | none | auto</h3>
        <div class="container">
            <div class="item flex-1">flex: 1</div>
            <div class="item flex-2">flex: 2</div>
            <div class="item flex-none">flex: none</div>
            <div class="item flex-auto">flex: auto</div>
        </div>

        <div class="code-block">
            /* Longhand version */
            .item {
                flex-grow: 2;
                flex-shrink: 1;
                flex-basis: 100px;
            }

            /* Shorthand version */
            .item {
                flex: 2 1 100px;
            }

            /* Common shorthand values */
            .item { flex: 1; }      /* grow: 1, shrink: 1, basis: 0% */
            .item { flex: 2; }      /* grow: 2, shrink: 1, basis: 0% */
            .item { flex: none; }   /* grow: 0, shrink: 0, basis: auto */
            .item { flex: auto; }   /* grow: 1, shrink: 1, basis: auto */
            .item { flex: 1 30px; } /* grow: 1, shrink: 1, basis: 30px */
        </div>
    </section>

    <!-- ====== 3. FLEX-FLOW ====== -->
    <section>
        <h2>3. flex-flow (Shorthand)</h2>
        <p>Combines <code>flex-direction</code> and <code>flex-wrap</code>.</p>

        <h3>flex-flow: row wrap</h3>
        <div class="container container-small container-tall flow-row-wrap">
            <div class="item-flow">1</div>
            <div class="item-flow">2</div>
            <div class="item-flow">3</div>
            <div class="item-flow">4</div>
        </div>

        <h3>flex-flow: column nowrap</h3>
        <div class="container container-small container-tall flow-column-nowrap" style="width: auto; height: 300px;">
            <div class="item-flow" style="flex: 0 0 50px;">1</div>
            <div class="item-flow" style="flex: 0 0 50px;">2</div>
            <div class="item-flow" style="flex: 0 0 50px;">3</div>
            <div class="item-flow" style="flex: 0 0 50px;">4</div>
        </div>

        <h3>flex-flow: row-reverse wrap</h3>
        <div class="container container-small container-tall flow-row-reverse-wrap">
            <div class="item-flow">1</div>
            <div class="item-flow">2</div>
            <div class="item-flow">3</div>
            <div class="item-flow">4</div>
        </div>

        <div class="code-block">
            /* Row direction with wrapping */
            .container { flex-flow: row wrap; }

            /* Column direction without wrapping */
            .container { flex-flow: column nowrap; }

            /* Row reverse with wrapping */
            .container { flex-flow: row-reverse wrap; }

            /* Only direction (wrap defaults to nowrap) */
            .container { flex-flow: column; }

            /* Only wrap (direction defaults to row) */
            .container { flex-flow: wrap; }
        </div>
    </section>

    <!-- ====== 4. SIDE-BY-SIDE COMPARISON ====== -->
    <section>
        <h2>4. Side-by-Side Comparison</h2>

        <h3>flex-basis vs flex-grow</h3>
        <div class="comparison-grid">
            <div class="comparison-item">
                <h4>flex-basis: 100px | 100px | 100px</h4>
                <div class="container" style="width: 100%;">
                    <div class="item basis-100px">100px</div>
                    <div class="item basis-100px">100px</div>
                    <div class="item basis-100px">100px</div>
                </div>
                <p class="note">All start at 100px, no growth</p>
            </div>

            <div class="comparison-item">
                <h4>flex: 1 | 1 | 1</h4>
                <div class="container" style="width: 100%;">
                    <div class="item flex-1">flex: 1</div>
                    <div class="item flex-1">flex: 1</div>
                    <div class="item flex-1">flex: 1</div>
                </div>
                <p class="note">All grow equally to fill space</p>
            </div>

            <div class="comparison-item">
                <h4>flex: 1 | 2 | 1</h4>
                <div class="container" style="width: 100%;">
                    <div class="item flex-1">flex: 1</div>
                    <div class="item flex-2">flex: 2</div>
                    <div class="item flex-1">flex: 1</div>
                </div>
                <p class="note">Middle grows twice as much</p>
            </div>
        </div>
    </section>

    <!-- ====== 5. VISUAL EXPLANATION ====== -->
    <section>
        <h2>5. Visual Explanation: flex-basis</h2>
        <p>Think of <code>flex-basis</code> as the starting point before any space is distributed.</p>

        <div class="visual-explanation">
            <div class="visual-box">
                <div class="bar basis-50">50px</div>
                <p class="note">flex-basis: 50px</p>
            </div>
            <div class="visual-box">
                <div class="bar basis-100">100px</div>
                <p class="note">flex-basis: 100px</p>
            </div>
            <div class="visual-box">
                <div class="bar basis-150">150px</div>
                <p class="note">flex-basis: 150px</p>
            </div>
        </div>

        <div class="code-block">
            /* flex-basis sets the starting size */
            .item1 { flex-basis: 50px; }
            .item2 { flex-basis: 100px; }
            .item3 { flex-basis: 150px; }

            /* Then flex-grow distributes remaining space */
            .item { flex-grow: 1; }
        </div>
    </section>

    <!-- ====== 6. REFERENCE TABLES ====== -->
    <section>
        <h2>6. Reference Tables</h2>

        <h3>flex-basis Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>auto</code></td>
                <td>Based on content or width/height (default)</td>
                <td><code>flex-basis: auto;</code></td>
            </tr>
            <tr>
                <td><code>length</code></td>
                <td>Fixed size (px, em, rem)</td>
                <td><code>flex-basis: 100px;</code></td>
            </tr>
            <tr>
                <td><code>percentage</code></td>
                <td>Percentage of container</td>
                <td><code>flex-basis: 20%;</code></td>
            </tr>
            <tr>
                <td><code>content</code></td>
                <td>Based on content size</td>
                <td><code>flex-basis: content;</code></td>
            </tr>
            <tr>
                <td><code>max-content</code></td>
                <td>Maximum content size</td>
                <td><code>flex-basis: max-content;</code></td>
            </tr>
            <tr>
                <td><code>min-content</code></td>
                <td>Minimum content size</td>
                <td><code>flex-basis: min-content;</code></td>
            </tr>
            <tr>
                <td><code>fit-content</code></td>
                <td>Fits content within limits</td>
                <td><code>flex-basis: fit-content(200px);</code></td>
            </tr>
        </table>

        <h3>flex Shorthand Values</h3>
        <table class="reference-table">
            <tr>
                <th>Shorthand</th>
                <th>Equivalent</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>flex: none;</code></td>
                <td><code>0 0 auto</code></td>
                <td>Fixed size, no grow/shrink</td>
            </tr>
            <tr>
                <td><code>flex: auto;</code></td>
                <td><code>1 1 auto</code></td>
                <td>Based on content, can grow/shrink</td>
            </tr>
            <tr>
                <td><code>flex: 1;</code></td>
                <td><code>1 1 0%</code></td>
                <td>Equal distribution, ignores content</td>
            </tr>
            <tr>
                <td><code>flex: 2;</code></td>
                <td><code>2 1 0%</code></td>
                <td>Grows 2x more than flex: 1</td>
            </tr>
            <tr>
                <td><code>flex: 1 1 10em;</code></td>
                <td><code>1 1 10em</code></td>
                <td>Grow 1x, shrink 1x, base 10em</td>
            </tr>
            <tr>
                <td><code>flex: 2 1 100px;</code></td>
                <td><code>2 1 100px</code></td>
                <td>Grow 2x, shrink 1x, base 100px</td>
            </tr>
            <tr>
                <td><code>flex: 1 2 auto;</code></td>
                <td><code>1 2 auto</code></td>
                <td>Grow 1x, shrink 2x, base auto</td>
            </tr>
        </table>

        <h3>flex-flow Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>row wrap</code></td>
                <td>Row direction with wrapping</td>
                <td><code>flex-flow: row wrap;</code></td>
            </tr>
            <tr>
                <td><code>column nowrap</code></td>
                <td>Column direction without wrapping</td>
                <td><code>flex-flow: column nowrap;</code></td>
            </tr>
            <tr>
                <td><code>row-reverse wrap</code></td>
                <td>Row reverse with wrapping</td>
                <td><code>flex-flow: row-reverse wrap;</code></td>
            </tr>
            <tr>
                <td><code>column</code></td>
                <td>Column direction (wrap defaults to nowrap)</td>
                <td><code>flex-flow: column;</code></td>
            </tr>
            <tr>
                <td><code>wrap</code></td>
                <td>Wrapping (direction defaults to row)</td>
                <td><code>flex-flow: wrap;</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 7. BEST PRACTICES ====== -->
    <section>
        <h2>7. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>flex: 1</code> for equal-width items that fill available space</li>
                <li>Use <code>flex: none</code> for fixed-size items that shouldn't grow or shrink</li>
                <li>Use <code>flex-basis</code> to set a starting size before distribution</li>
                <li>Use <code>flex-flow</code> to combine direction and wrapping</li>
                <li>Use the shorthand properties for cleaner, more readable code</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't confuse <code>flex-basis</code> with <code>width</code> — they behave differently</li>
                <li>Don't use <code>flex: 1</code> when you want items to be based on their content (use <code>flex: auto</code>)</li>
                <li>Don't forget that <code>flex-basis: auto</code> looks at <code>width</code>/<code>height</code> first</li>
                <li>Don't write all three longhand properties when <code>flex</code> shorthand works</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionExample
flex-basisInitial main sizeflex-basis: 100px;
flexShorthand for grow, shrink, basisflex: 2 1 100px;
flex-flowShorthand for direction and wrapflex-flow: row wrap;

flex-basis Values

ValueDescription
autoBased on content or width/height (default)
lengthFixed size (px, em, rem)
percentagePercentage of container
contentBased on content size
max-contentMaximum content size
min-contentMinimum content size
fit-content(limit)Fits content within limits

flex Shorthand Values

ShorthandEquivalentDescription
flex: none;0 0 autoFixed size, no grow/shrink
flex: auto;1 1 autoBased on content
flex: 1;1 1 0%Equal distribution
flex: 2;2 1 0%Grows 2x more
flex: 1 1 10em;1 1 10emGrow 1x, shrink 1x, base 10em
flex: 2 1 100px;2 1 100pxGrow 2x, shrink 1x, base 100px

flex-flow Values

ValueDescription
row wrapRow direction with wrapping
column nowrapColumn direction without wrapping
row-reverse wrapRow reverse with wrapping
columnColumn direction (wrap defaults to nowrap)
wrapWrapping (direction defaults to row)

Best Practices

Do This:

/* Equal-width items */
.item {
    flex: 1; /* grow: 1, shrink: 1, basis: 0% */
}

/* Fixed-size item */
.sidebar {
    flex: none; /* grow: 0, shrink: 0, basis: auto */
}

/* Content-based item */
.content {
    flex: auto; /* grow: 1, shrink: 1, basis: auto */
}

/* Custom sizing */
.item {
    flex: 2 1 200px; /* grow: 2, shrink: 1, basis: 200px */
}

/* Direction + wrap */
.container {
    flex-flow: row wrap;
}

Don’t Do This:

/* Don't confuse flex-basis with width */
.item {
    flex-basis: 100px; /* Initial size before distribution */
    width: 100px;      /* Ignored in flex context (mostly) */
}

/* Don't use flex: 1 when you want content-based sizing */
.item {
    flex: 1; /* Ignores content, uses 0% basis */
    /* Use flex: auto for content-based sizing */
}

/* Don't write longhand when shorthand works */
.item {
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: 0%;
    /* Just write: flex: 1; */
}

Pro Tip: flex-basis is the starting point for a flex item before any space is distributed. Think of it as “how big should this item be before we start sharing the extra space?” Use flex: 1 for equal-width items that ignore content size, and flex: auto for items that respect their content size. The flex shorthand is almost always cleaner than writing the three longhand properties separately. And flex-flow is a convenient way to set both direction and wrapping in one line!

28. justify-content and align-items Properties

These two properties are the alignment powerhouses of Flexbox. They control how items are distributed and aligned within a flex container along the main and cross axes.


Overview of Properties

PropertyAxisDescription
justify-contentMain axisDistributes extra space between/around items
align-itemsCross axisAligns items within the container

1. justify-content

The justify-content property specifies how extra space is distributed between and around items along the main axis.

.container {
    display: flex;
    justify-content: space-between;
}

Values

ValueDescriptionVisual
flex-startItems packed at the start (default)[1][2][3]__________
flex-endItems packed at the end__________[1][2][3]
centerItems centered_____[1][2][3]_____
space-betweenFirst at start, last at end, equal space between[1]___[2]___[3]
space-aroundEqual space around each item_[1]__[2]__[3]_
space-evenlyEqual space everywhere__[1]__[2]__[3]__
stretchItems stretch to fill space[1][2][3] (stretched)

Visual Comparison

flex-start:        [1][2][3]__________
flex-end:          __________[1][2][3]
center:            _____[1][2][3]_____
space-between:     [1]___[2]___[3]
space-around:      _[1]__[2]__[3]_
space-evenly:      __[1]__[2]__[3]__

Key Difference:

  • space-between — no space at the edges
  • space-around — half space at the edges
  • space-evenly — equal space everywhere

2. align-items

The align-items property specifies how items are aligned along the cross axis.

.container {
    display: flex;
    align-items: center;
}

Values

ValueDescriptionVisual
stretchItems stretch to fill the container height (default)Items fill height
flex-startItems aligned to the top[1][2][3]
flex-endItems aligned to the bottom
[1][2][3]
centerItems centered vertically
[1][2][3]
baselineItems aligned to their text baselineText baselines align
startLogical start of cross axisSame as flex-start (for LTR)
endLogical end of cross axisSame as flex-end (for LTR)

Visual Comparison

stretch:      [1][2][3]  (tall items)
flex-start:   [1][2][3]
              
flex-end:     
              [1][2][3]
center:       
              [1][2][3]
              
baseline:     [1][2][3]  (text baselines align)

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>justify-content and align-items Properties</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== FLEX CONTAINERS ====== */
        .container {
            display: flex;
            border: 2px dashed #dc3545;
            margin: 10px 0;
            padding: 10px;
            background: #e9ecef;
            border-radius: 8px;
            min-height: 80px;
        }

        .container-tall {
            min-height: 150px;
        }

        .item {
            background: #007bff;
            color: white;
            padding: 15px 20px;
            margin: 5px;
            border: 2px dashed #0056b3;
            border-radius: 6px;
            font-weight: bold;
            text-align: center;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .item:nth-child(even) {
            background: #28a745;
            border-color: #1e7e34;
        }

        .item:nth-child(3n) {
            background: #6c5ce7;
            border-color: #4a2a9e;
        }

        /* justify-content demos */
        .jc-start {
            justify-content: flex-start;
        }

        .jc-end {
            justify-content: flex-end;
        }

        .jc-center {
            justify-content: center;
        }

        .jc-between {
            justify-content: space-between;
        }

        .jc-around {
            justify-content: space-around;
        }

        .jc-evenly {
            justify-content: space-evenly;
        }

        /* align-items demos */
        .ai-start {
            align-items: flex-start;
        }

        .ai-end {
            align-items: flex-end;
        }

        .ai-center {
            align-items: center;
        }

        .ai-baseline {
            align-items: baseline;
        }

        .ai-stretch {
            align-items: stretch;
        }

        .ai-stretch .item {
            padding: 10px;
        }

        /* Baseline demo items */
        .baseline-item-1 {
            font-size: 14px;
            padding: 5px 15px;
        }

        .baseline-item-2 {
            font-size: 28px;
            padding: 5px 15px;
        }

        .baseline-item-3 {
            font-size: 20px;
            padding: 5px 15px;
        }

        .baseline-item-4 {
            font-size: 16px;
            padding: 5px 15px;
        }

        /* Side-by-side comparison */
        .comparison-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
        }

        .comparison-item {
            text-align: center;
        }

        .comparison-item h4 {
            margin-bottom: 5px;
            color: #007bff;
        }

        .comparison-item .container {
            margin: 5px 0;
        }

        /* Visual explanation */
        .visual-explanation {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 15px;
            margin: 20px 0;
        }

        .visual-row {
            display: flex;
            align-items: center;
            gap: 10px;
            width: 100%;
            max-width: 600px;
        }

        .visual-label {
            font-weight: bold;
            color: #007bff;
            min-width: 130px;
            text-align: right;
            font-size: 0.85rem;
        }

        .visual-bar {
            flex: 1;
            height: 40px;
            background: #e9ecef;
            border-radius: 6px;
            position: relative;
            display: flex;
            align-items: center;
            padding: 0 5px;
            border: 1px solid #ddd;
        }

        .visual-bar .dot {
            width: 30px;
            height: 30px;
            background: #007bff;
            border-radius: 4px;
            margin: 0 3px;
        }

        .visual-bar .dot:nth-child(even) {
            background: #28a745;
        }

        .visual-bar .dot:nth-child(3n) {
            background: #6c5ce7;
        }
    </style>
</head>
<body>

    <h1>justify-content and align-items Properties</h1>

    <!-- ====== 1. JUSTIFY-CONTENT ====== -->
    <section>
        <h2>1. justify-content</h2>
        <p>Distributes extra space between and around items along the <strong>main axis</strong>.</p>

        <h3>flex-start (default)</h3>
        <div class="container jc-start">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>

        <h3>flex-end</h3>
        <div class="container jc-end">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>

        <h3>center</h3>
        <div class="container jc-center">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>

        <h3>space-between</h3>
        <div class="container jc-between">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>
        <p class="note">First item at start, last item at end, equal space between.</p>

        <h3>space-around</h3>
        <div class="container jc-around">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>
        <p class="note">Equal space around each item. Half space at the edges.</p>

        <h3>space-evenly</h3>
        <div class="container jc-evenly">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>
        <p class="note">Equal space everywhere — between items and at the edges.</p>

        <div class="code-block">
            .container { justify-content: flex-start; }    /* Default — start */
            .container { justify-content: flex-end; }      /* End */
            .container { justify-content: center; }        /* Center */
            .container { justify-content: space-between; } /* Space between */
            .container { justify-content: space-around; }  /* Space around */
            .container { justify-content: space-evenly; }  /* Equal space */
        </div>
    </section>

    <!-- ====== 2. ALIGN-ITEMS ====== -->
    <section>
        <h2>2. align-items</h2>
        <p>Aligns items along the <strong>cross axis</strong>.</p>

        <h3>flex-start</h3>
        <div class="container container-tall ai-start">
            <div class="item">1</div>
            <div class="item" style="padding: 30px 20px;">2 (taller)</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>

        <h3>flex-end</h3>
        <div class="container container-tall ai-end">
            <div class="item">1</div>
            <div class="item" style="padding: 30px 20px;">2 (taller)</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>

        <h3>center</h3>
        <div class="container container-tall ai-center">
            <div class="item">1</div>
            <div class="item" style="padding: 30px 20px;">2 (taller)</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>

        <h3>baseline</h3>
        <div class="container container-tall ai-baseline">
            <div class="item baseline-item-1">Small</div>
            <div class="item baseline-item-2">LARGE</div>
            <div class="item baseline-item-3">Medium</div>
            <div class="item baseline-item-4">Normal</div>
        </div>
        <p class="note">Items align to their text baselines, regardless of font size.</p>

        <h3>stretch (default)</h3>
        <div class="container container-tall ai-stretch">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
            <div class="item">4</div>
        </div>
        <p class="note">Items stretch to fill the container's height.</p>

        <div class="code-block">
            .container { align-items: flex-start; }  /* Top */
            .container { align-items: flex-end; }    /* Bottom */
            .container { align-items: center; }      /* Center */
            .container { align-items: baseline; }    /* Text baseline */
            .container { align-items: stretch; }     /* Fill height (default) */
        </div>
    </section>

    <!-- ====== 3. COMBINING BOTH ====== -->
    <section>
        <h2>3. Combining justify-content and align-items</h2>
        <p>Use both properties together for perfect alignment.</p>

        <h3>Perfect Centering: justify-content: center + align-items: center</h3>
        <div class="container container-tall" style="justify-content: center; align-items: center;">
            <div class="item" style="padding: 30px 40px;">Centered</div>
        </div>

        <h3>Space Between + Center</h3>
        <div class="container container-tall" style="justify-content: space-between; align-items: center;">
            <div class="item">1</div>
            <div class="item">2</div>
            <div class="item">3</div>
        </div>

        <h3>Space Evenly + Flex-End</h3>
        <div class="container container-tall" style="justify-content: space-evenly; align-items: flex-end;">
            <div class="item">1</div>
            <div class="item" style="padding: 25px 20px;">2</div>
            <div class="item">3</div>
        </div>

        <div class="code-block">
            /* Perfect centering */
            .container {
                display: flex;
                justify-content: center;  /* Main axis */
                align-items: center;      /* Cross axis */
            }

            /* Space between + center */
            .container {
                justify-content: space-between;
                align-items: center;
            }

            /* Space evenly + flex-end */
            .container {
                justify-content: space-evenly;
                align-items: flex-end;
            }
        </div>
    </section>

    <!-- ====== 4. SIDE-BY-SIDE COMPARISON ====== -->
    <section>
        <h2>4. Side-by-Side Comparison</h2>

        <h3>justify-content</h3>
        <div class="comparison-grid">
            <div class="comparison-item">
                <h4>flex-start</h4>
                <div class="container jc-start" style="min-height: 60px;">
                    <div class="item" style="padding: 5px 10px;">1</div>
                    <div class="item" style="padding: 5px 10px;">2</div>
                    <div class="item" style="padding: 5px 10px;">3</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>center</h4>
                <div class="container jc-center" style="min-height: 60px;">
                    <div class="item" style="padding: 5px 10px;">1</div>
                    <div class="item" style="padding: 5px 10px;">2</div>
                    <div class="item" style="padding: 5px 10px;">3</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>space-between</h4>
                <div class="container jc-between" style="min-height: 60px;">
                    <div class="item" style="padding: 5px 10px;">1</div>
                    <div class="item" style="padding: 5px 10px;">2</div>
                    <div class="item" style="padding: 5px 10px;">3</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>space-around</h4>
                <div class="container jc-around" style="min-height: 60px;">
                    <div class="item" style="padding: 5px 10px;">1</div>
                    <div class="item" style="padding: 5px 10px;">2</div>
                    <div class="item" style="padding: 5px 10px;">3</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>space-evenly</h4>
                <div class="container jc-evenly" style="min-height: 60px;">
                    <div class="item" style="padding: 5px 10px;">1</div>
                    <div class="item" style="padding: 5px 10px;">2</div>
                    <div class="item" style="padding: 5px 10px;">3</div>
                </div>
            </div>
        </div>

        <h3 style="margin-top: 30px;">align-items</h3>
        <div class="comparison-grid">
            <div class="comparison-item">
                <h4>flex-start</h4>
                <div class="container ai-start" style="min-height: 100px;">
                    <div class="item" style="padding: 5px 10px;">1</div>
                    <div class="item" style="padding: 20px 10px;">2</div>
                    <div class="item" style="padding: 5px 10px;">3</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>center</h4>
                <div class="container ai-center" style="min-height: 100px;">
                    <div class="item" style="padding: 5px 10px;">1</div>
                    <div class="item" style="padding: 20px 10px;">2</div>
                    <div class="item" style="padding: 5px 10px;">3</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>flex-end</h4>
                <div class="container ai-end" style="min-height: 100px;">
                    <div class="item" style="padding: 5px 10px;">1</div>
                    <div class="item" style="padding: 20px 10px;">2</div>
                    <div class="item" style="padding: 5px 10px;">3</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>stretch</h4>
                <div class="container ai-stretch" style="min-height: 100px;">
                    <div class="item" style="padding: 5px 10px;">1</div>
                    <div class="item" style="padding: 5px 10px;">2</div>
                    <div class="item" style="padding: 5px 10px;">3</div>
                </div>
            </div>
        </div>
    </section>

    <!-- ====== 5. VISUAL EXPLANATION ====== -->
    <section>
        <h2>5. Visual Explanation</h2>
        <p>See how different <code>justify-content</code> values distribute space.</p>

        <div class="visual-explanation">
            <div class="visual-row">
                <div class="visual-label">flex-start:</div>
                <div class="visual-bar" style="justify-content: flex-start;">
                    <div class="dot"></div>
                    <div class="dot"></div>
                    <div class="dot"></div>
                </div>
            </div>
            <div class="visual-row">
                <div class="visual-label">flex-end:</div>
                <div class="visual-bar" style="justify-content: flex-end;">
                    <div class="dot"></div>
                    <div class="dot"></div>
                    <div class="dot"></div>
                </div>
            </div>
            <div class="visual-row">
                <div class="visual-label">center:</div>
                <div class="visual-bar" style="justify-content: center;">
                    <div class="dot"></div>
                    <div class="dot"></div>
                    <div class="dot"></div>
                </div>
            </div>
            <div class="visual-row">
                <div class="visual-label">space-between:</div>
                <div class="visual-bar" style="justify-content: space-between;">
                    <div class="dot"></div>
                    <div class="dot"></div>
                    <div class="dot"></div>
                </div>
            </div>
            <div class="visual-row">
                <div class="visual-label">space-around:</div>
                <div class="visual-bar" style="justify-content: space-around;">
                    <div class="dot"></div>
                    <div class="dot"></div>
                    <div class="dot"></div>
                </div>
            </div>
            <div class="visual-row">
                <div class="visual-label">space-evenly:</div>
                <div class="visual-bar" style="justify-content: space-evenly;">
                    <div class="dot"></div>
                    <div class="dot"></div>
                    <div class="dot"></div>
                </div>
            </div>
        </div>
    </section>

    <!-- ====== 6. REFERENCE TABLES ====== -->
    <section>
        <h2>6. Reference Tables</h2>

        <h3>justify-content Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Space at Edges</th>
            </tr>
            <tr>
                <td><code>flex-start</code></td>
                <td>Items packed at start (default)</td>
                <td>No</td>
            </tr>
            <tr>
                <td><code>flex-end</code></td>
                <td>Items packed at end</td>
                <td>No</td>
            </tr>
            <tr>
                <td><code>center</code></td>
                <td>Items centered</td>
                <td>No</td>
            </tr>
            <tr>
                <td><code>space-between</code></td>
                <td>Equal space between items</td>
                <td>No</td>
            </tr>
            <tr>
                <td><code>space-around</code></td>
                <td>Equal space around items</td>
                <td>Half space</td>
            </tr>
            <tr>
                <td><code>space-evenly</code></td>
                <td>Equal space everywhere</td>
                <td>Full space</td>
            </tr>
            <tr>
                <td><code>stretch</code></td>
                <td>Items stretch to fill space</td>
                <td>—</td>
            </tr>
        </table>

        <h3>align-items Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>stretch</code></td>
                <td>Items stretch to fill container (default)</td>
            </tr>
            <tr>
                <td><code>flex-start</code> / <code>start</code></td>
                <td>Items aligned to the start</td>
            </tr>
            <tr>
                <td><code>flex-end</code> / <code>end</code></td>
                <td>Items aligned to the end</td>
            </tr>
            <tr>
                <td><code>center</code></td>
                <td>Items centered</td>
            </tr>
            <tr>
                <td><code>baseline</code></td>
                <td>Items aligned to text baseline</td>
            </tr>
        </table>

        <h3>Common Combinations</h3>
        <table class="reference-table">
            <tr>
                <th>Combination</th>
                <th>Effect</th>
            </tr>
            <tr>
                <td><code>justify-content: center;<br>align-items: center;</code></td>
                <td>Perfect centering</td>
            </tr>
            <tr>
                <td><code>justify-content: space-between;<br>align-items: center;</code></td>
                <td>Items spread out, vertically centered</td>
            </tr>
            <tr>
                <td><code>justify-content: center;<br>align-items: flex-end;</code></td>
                <td>Horizontally centered, aligned to bottom</td>
            </tr>
        </table>
    </section>

    <!-- ====== 7. BEST PRACTICES ====== -->
    <section>
        <h2>7. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>justify-content: center; align-items: center;</code> for perfect centering</li>
                <li>Use <code>space-between</code> for navigation bars and toolbars</li>
                <li>Use <code>space-evenly</code> for evenly distributed items</li>
                <li>Use <code>align-items: baseline</code> for text of different sizes</li>
                <li>Remember that <code>justify-content</code> works on the main axis and <code>align-items</code> on the cross axis</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't confuse <code>justify-content</code> (main axis) with <code>align-items</code> (cross axis)</li>
                <li>Don't forget that the axes swap when you change <code>flex-direction</code></li>
                <li>Don't use <code>space-between</code> when you need space at the edges</li>
                <li>Don't use <code>align-items</code> on a single item (use <code>align-self</code> instead)</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyAxisValues
justify-contentMain axisflex-start, flex-end, center, space-between, space-around, space-evenly
align-itemsCross axisstretch, flex-start, flex-end, center, baseline

Space Distribution Comparison

ValueSpace Between ItemsSpace at Edges
flex-startNoneAll at end
flex-endNoneAll at start
centerNoneEqual at both ends
space-betweenEqualNone
space-aroundEqualHalf space
space-evenlyEqualFull space

Best Practices

Do This:

/* Perfect centering */
.container {
    display: flex;
    justify-content: center;
    align-items: center;
}

/* Navigation bar */
.nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* Evenly distributed items */
.toolbar {
    display: flex;
    justify-content: space-evenly;
}

/* Baseline alignment for mixed font sizes */
.baseline-demo {
    display: flex;
    align-items: baseline;
}

Don’t Do This:

/* Don't confuse the axes */
.container {
    justify-content: center; /* Main axis */
    align-items: center;     /* Cross axis */
}

/* Don't forget axes swap with flex-direction */
.container {
    flex-direction: column;
    justify-content: center; /* Now controls VERTICAL alignment */
    align-items: center;     /* Now controls HORIZONTAL alignment */
}

/* Don't use align-items for single item */
.item {
    align-items: center; /* Invalid — use align-self */
}

Pro Tip: The combination justify-content: center; align-items: center; is the classic “perfect centering” trick that works in both Flexbox and Grid. Remember: justify-content works on the main axis (controlled by flex-direction), while align-items works on the cross axis. When you change flex-direction to column, these two properties swap their visual effects — justify-content now controls vertical alignment, and align-items controls horizontal alignment!

29. align-content and align-self Properties

These two properties complete the Flexbox alignment toolkit. align-content controls how multiple lines are distributed along the cross axis, while align-self lets you override the container’s align-items for individual items.


Overview of Properties

PropertyApplies ToDescription
align-contentContainerAligns multiple lines along the cross axis
align-selfItemOverrides align-items for a single item

1. align-content

The align-content property controls the alignment of flex lines along the cross axis. It only works when:

  • The container has flex-wrap: wrap (or wrap-reverse)
  • There are multiple lines of items
  • There is extra space in the container
.container {
    display: flex;
    flex-wrap: wrap;
    height: 400px;
    align-content: center;
}

Values

ValueDescriptionVisual
stretchLines stretch to fill container (default)Lines fill height
flex-startLines packed at start[1][2]
[3][4]
flex-endLines packed at end
[1][2]
[3][4]
centerLines centered
[1][2]
[3][4]
space-betweenFirst at start, last at end[1][2]

[3][4]
space-aroundEqual space around each line
[1][2]

[3][4]
space-evenlyEqual space everywhere
[1][2]

[3][4]

Important: align-content has no effect if:

  • flex-wrap: nowrap (single line)
  • There’s only one line of items
  • There’s no extra space in the container

2. align-self

The align-self property allows an individual flex item to override the container’s align-items value.

.item2 {
    align-self: flex-start; /* This item aligns differently */
}

Values

Same as align-items:

ValueDescription
autoInherits from parent’s align-items (default)
stretchStretches to fill container
flex-startAligns to the start
flex-endAligns to the end
centerCenters the item
baselineAligns to text baseline

align-content vs align-items

Aspectalign-contentalign-items
Applies toMultiple linesItems within a line
When it worksflex-wrap: wrap + multiple linesAlways (single or multi-line)
AxisCross axisCross axis
ControlsDistribution of linesAlignment of items
Number of linesOnly multi-lineSingle or multi-line

Visual difference:

align-items: center          align-content: center
┌─────────────────┐          ┌─────────────────┐
│                 │          │                 │
│  [1] [2] [3]    │          │  [1] [2] [3]    │
│                 │          │  [4] [5] [6]    │
│                 │          │                 │
└─────────────────┘          └─────────────────┘
   Items centered             Lines centered
   within each line           as a group

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>align-content and align-self Properties</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== FLEX CONTAINERS ====== */
        .container {
            display: flex;
            flex-wrap: wrap;
            height: 300px;
            border: 2px solid #333;
            margin: 10px 0;
            padding: 5px;
            background: #e9ecef;
            border-radius: 8px;
            gap: 5px;
        }

        .item {
            background: #007bff;
            color: white;
            padding: 15px;
            margin: 3px;
            text-align: center;
            width: 200px;
            border-radius: 6px;
            font-weight: bold;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .item:nth-child(even) {
            background: #28a745;
        }

        .item:nth-child(3n) {
            background: #6c5ce7;
        }

        /* align-content demos */
        .ac-stretch {
            align-content: stretch;
        }

        .ac-start {
            align-content: flex-start;
        }

        .ac-end {
            align-content: flex-end;
        }

        .ac-center {
            align-content: center;
        }

        .ac-between {
            align-content: space-between;
        }

        .ac-around {
            align-content: space-around;
        }

        .ac-evenly {
            align-content: space-evenly;
        }

        /* align-self demo */
        .container-self {
            display: flex;
            height: 300px;
            border: 2px solid #333;
            margin: 10px 0;
            padding: 5px;
            background: #e9ecef;
            border-radius: 8px;
            gap: 5px;
        }

        .container-self .item {
            width: auto;
            flex: 1;
            min-width: 80px;
        }

        .container-self .item1 {
            align-self: stretch;
            background: #007bff;
        }

        .container-self .item2 {
            align-self: flex-start;
            background: #28a745;
        }

        .container-self .item3 {
            align-self: flex-end;
            background: #dc3545;
        }

        .container-self .item4 {
            align-self: center;
            background: #ffc107;
            color: #333;
        }

        .container-self .item5 {
            align-self: baseline;
            background: #17a2b8;
        }

        /* Comparison grid */
        .comparison-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
        }

        .comparison-item {
            text-align: center;
        }

        .comparison-item h4 {
            margin-bottom: 5px;
            color: #007bff;
        }

        .comparison-item .container {
            margin: 5px 0;
            height: 200px;
        }

        .comparison-item .item {
            width: auto;
            flex: 1;
            min-width: 60px;
            font-size: 0.8rem;
            padding: 10px 5px;
        }

        /* Visual explanation */
        .visual-explanation {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 15px;
            margin: 20px 0;
        }

        .visual-row {
            display: flex;
            align-items: center;
            gap: 10px;
            width: 100%;
            max-width: 700px;
        }

        .visual-label {
            font-weight: bold;
            color: #007bff;
            min-width: 160px;
            text-align: right;
            font-size: 0.85rem;
        }

        .visual-bar {
            flex: 1;
            height: 120px;
            background: #e9ecef;
            border-radius: 6px;
            position: relative;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            padding: 10px;
            border: 1px solid #ddd;
            gap: 5px;
        }

        .visual-bar .line {
            display: flex;
            gap: 5px;
            padding: 5px 10px;
            background: #007bff;
            border-radius: 4px;
            color: white;
            font-size: 0.7rem;
            font-weight: bold;
        }

        .visual-bar .line:nth-child(even) {
            background: #28a745;
        }
    </style>
</head>
<body>

    <h1>align-content and align-self Properties</h1>

    <!-- ====== 1. ALIGN-CONTENT ====== -->
    <section>
        <h2>1. align-content</h2>
        <p>Aligns <strong>multiple lines</strong> along the cross axis. Only works with <code>flex-wrap: wrap</code> and multiple lines.</p>

        <h3>align-content: stretch (default)</h3>
        <div class="container ac-stretch">
            <div class="item">Item 1</div>
            <div class="item">Item 2</div>
            <div class="item">Item 3</div>
            <div class="item">Item 4</div>
            <div class="item">Item 5</div>
        </div>
        <p class="note">Lines stretch to fill the container's height.</p>

        <h3>align-content: flex-start</h3>
        <div class="container ac-start">
            <div class="item">Item 1</div>
            <div class="item">Item 2</div>
            <div class="item">Item 3</div>
            <div class="item">Item 4</div>
            <div class="item">Item 5</div>
        </div>

        <h3>align-content: flex-end</h3>
        <div class="container ac-end">
            <div class="item">Item 1</div>
            <div class="item">Item 2</div>
            <div class="item">Item 3</div>
            <div class="item">Item 4</div>
            <div class="item">Item 5</div>
        </div>

        <h3>align-content: center</h3>
        <div class="container ac-center">
            <div class="item">Item 1</div>
            <div class="item">Item 2</div>
            <div class="item">Item 3</div>
            <div class="item">Item 4</div>
            <div class="item">Item 5</div>
        </div>

        <h3>align-content: space-between</h3>
        <div class="container ac-between">
            <div class="item">Item 1</div>
            <div class="item">Item 2</div>
            <div class="item">Item 3</div>
            <div class="item">Item 4</div>
            <div class="item">Item 5</div>
        </div>

        <h3>align-content: space-around</h3>
        <div class="container ac-around">
            <div class="item">Item 1</div>
            <div class="item">Item 2</div>
            <div class="item">Item 3</div>
            <div class="item">Item 4</div>
            <div class="item">Item 5</div>
        </div>

        <h3>align-content: space-evenly</h3>
        <div class="container ac-evenly">
            <div class="item">Item 1</div>
            <div class="item">Item 2</div>
            <div class="item">Item 3</div>
            <div class="item">Item 4</div>
            <div class="item">Item 5</div>
        </div>

        <div class="code-block">
            .container {
                display: flex;
                flex-wrap: wrap;
                height: 300px;
                align-content: stretch;      /* Default — fills height */
                align-content: flex-start;   /* Packed at start */
                align-content: flex-end;     /* Packed at end */
                align-content: center;       /* Centered */
                align-content: space-between;/* First at start, last at end */
                align-content: space-around; /* Equal space around lines */
                align-content: space-evenly; /* Equal space everywhere */
            }
        </div>
    </section>

    <!-- ====== 2. ALIGN-SELF ====== -->
    <section>
        <h2>2. align-self</h2>
        <p>Overrides <code>align-items</code> for an <strong>individual item</strong>.</p>

        <div class="container-self">
            <div class="item item1">align-self: stretch</div>
            <div class="item item2">align-self: flex-start</div>
            <div class="item item3">align-self: flex-end</div>
            <div class="item item4">align-self: center</div>
            <div class="item item5">align-self: baseline</div>
        </div>

        <p class="note">Each item has a different <code>align-self</code> value, overriding the container's default alignment.</p>

        <div class="code-block">
            .item1 { align-self: stretch; }     /* Stretches to fill */
            .item2 { align-self: flex-start; }  /* Top */
            .item3 { align-self: flex-end; }    /* Bottom */
            .item4 { align-self: center; }      /* Center */
            .item5 { align-self: baseline; }    /* Text baseline */
        </div>
    </section>

    <!-- ====== 3. SIDE-BY-SIDE COMPARISON ====== -->
    <section>
        <h2>3. Side-by-Side Comparison</h2>

        <h3>align-content (multi-line distribution)</h3>
        <div class="comparison-grid">
            <div class="comparison-item">
                <h4>stretch (default)</h4>
                <div class="container ac-stretch">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                    <div class="item">4</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>flex-start</h4>
                <div class="container ac-start">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                    <div class="item">4</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>center</h4>
                <div class="container ac-center">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                    <div class="item">4</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>space-between</h4>
                <div class="container ac-between">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                    <div class="item">4</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>space-around</h4>
                <div class="container ac-around">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                    <div class="item">4</div>
                </div>
            </div>
            <div class="comparison-item">
                <h4>space-evenly</h4>
                <div class="container ac-evenly">
                    <div class="item">1</div>
                    <div class="item">2</div>
                    <div class="item">3</div>
                    <div class="item">4</div>
                </div>
            </div>
        </div>
    </section>

    <!-- ====== 4. VISUAL EXPLANATION ====== -->
    <section>
        <h2>4. Visual Explanation</h2>
        <p>See how <code>align-content</code> distributes multiple lines.</p>

        <div class="visual-explanation">
            <div class="visual-row">
                <div class="visual-label">flex-start:</div>
                <div class="visual-bar" style="justify-content: flex-start;">
                    <div class="line">Line 1</div>
                    <div class="line">Line 2</div>
                    <div class="line">Line 3</div>
                </div>
            </div>
            <div class="visual-row">
                <div class="visual-label">center:</div>
                <div class="visual-bar" style="justify-content: center;">
                    <div class="line">Line 1</div>
                    <div class="line">Line 2</div>
                    <div class="line">Line 3</div>
                </div>
            </div>
            <div class="visual-row">
                <div class="visual-label">flex-end:</div>
                <div class="visual-bar" style="justify-content: flex-end;">
                    <div class="line">Line 1</div>
                    <div class="line">Line 2</div>
                    <div class="line">Line 3</div>
                </div>
            </div>
            <div class="visual-row">
                <div class="visual-label">space-between:</div>
                <div class="visual-bar" style="justify-content: space-between;">
                    <div class="line">Line 1</div>
                    <div class="line">Line 2</div>
                    <div class="line">Line 3</div>
                </div>
            </div>
            <div class="visual-row">
                <div class="visual-label">space-around:</div>
                <div class="visual-bar" style="justify-content: space-around;">
                    <div class="line">Line 1</div>
                    <div class="line">Line 2</div>
                    <div class="line">Line 3</div>
                </div>
            </div>
            <div class="visual-row">
                <div class="visual-label">space-evenly:</div>
                <div class="visual-bar" style="justify-content: space-evenly;">
                    <div class="line">Line 1</div>
                    <div class="line">Line 2</div>
                    <div class="line">Line 3</div>
                </div>
            </div>
        </div>
    </section>

    <!-- ====== 5. REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>align-content Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Space at Edges</th>
            </tr>
            <tr>
                <td><code>stretch</code></td>
                <td>Lines stretch to fill container (default)</td>
                <td>—</td>
            </tr>
            <tr>
                <td><code>flex-start</code></td>
                <td>Lines packed at start</td>
                <td>No</td>
            </tr>
            <tr>
                <td><code>flex-end</code></td>
                <td>Lines packed at end</td>
                <td>No</td>
            </tr>
            <tr>
                <td><code>center</code></td>
                <td>Lines centered</td>
                <td>Equal at both ends</td>
            </tr>
            <tr>
                <td><code>space-between</code></td>
                <td>Equal space between lines</td>
                <td>No</td>
            </tr>
            <tr>
                <td><code>space-around</code></td>
                <td>Equal space around lines</td>
                <td>Half space</td>
            </tr>
            <tr>
                <td><code>space-evenly</code></td>
                <td>Equal space everywhere</td>
                <td>Full space</td>
            </tr>
        </table>

        <h3>align-self Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>auto</code></td>
                <td>Inherits from parent's align-items (default)</td>
            </tr>
            <tr>
                <td><code>stretch</code></td>
                <td>Stretches to fill container</td>
            </tr>
            <tr>
                <td><code>flex-start</code></td>
                <td>Aligns to the start</td>
            </tr>
            <tr>
                <td><code>flex-end</code></td>
                <td>Aligns to the end</td>
            </tr>
            <tr>
                <td><code>center</code></td>
                <td>Centers the item</td>
            </tr>
            <tr>
                <td><code>baseline</code></td>
                <td>Aligns to text baseline</td>
            </tr>
        </table>

        <h3>align-content vs align-items</h3>
        <table class="reference-table">
            <tr>
                <th>Aspect</th>
                <th>align-content</th>
                <th>align-items</th>
            </tr>
            <tr>
                <td><strong>Applies to</strong></td>
                <td>Multiple lines</td>
                <td>Items within a line</td>
            </tr>
            <tr>
                <td><strong>When it works</strong></td>
                <td><code>flex-wrap: wrap</code> + multiple lines</td>
                <td>Always</td>
            </tr>
            <tr>
                <td><strong>Controls</strong></td>
                <td>Distribution of lines</td>
                <td>Alignment of items</td>
            </tr>
            <tr>
                <td><strong>Number of lines</strong></td>
                <td>Multi-line only</td>
                <td>Single or multi-line</td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>align-content</code> only with <code>flex-wrap: wrap</code></li>
                <li>Use <code>align-self</code> to override alignment for specific items</li>
                <li>Use <code>align-content: center</code> to center multiple lines vertically</li>
                <li>Use <code>align-self: flex-start</code> for items that need to stick to the top</li>
                <li>Remember that <code>align-content</code> has no effect with a single line</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use <code>align-content</code> without <code>flex-wrap: wrap</code></li>
                <li>Don't confuse <code>align-content</code> (lines) with <code>align-items</code> (items)</li>
                <li>Don't forget that <code>align-self</code> overrides <code>align-items</code> for one item</li>
                <li>Don't use <code>align-content</code> on single-line containers</li>
            </ul>
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyApplies ToDescription
align-contentContainerAligns multiple lines along the cross axis
align-selfItemOverrides align-items for one item

align-content Values

ValueDescription
stretchLines stretch to fill container (default)
flex-startLines packed at start
flex-endLines packed at end
centerLines centered
space-betweenFirst at start, last at end
space-aroundEqual space around lines
space-evenlyEqual space everywhere

align-content vs align-items

Aspectalign-contentalign-items
Applies toMultiple linesItems within a line
When it worksflex-wrap: wrap + multiple linesAlways
ControlsDistribution of linesAlignment of items
Single lineNo effectWorks

Best Practices

Do This:

/* Center multiple lines vertically */
.container {
    display: flex;
    flex-wrap: wrap;
    height: 400px;
    align-content: center; /* Centers lines as a group */
}

/* Override alignment for one item */
.special-item {
    align-self: flex-start; /* This item aligns to the top */
}

/* Distribute lines evenly */
.container {
    display: flex;
    flex-wrap: wrap;
    align-content: space-between;
}

Don’t Do This:

/* Don't use align-content without wrap */
.container {
    display: flex;
    flex-wrap: nowrap; /* align-content has NO effect */
    align-content: center;
}

/* Don't confuse align-content and align-items */
.container {
    align-content: center; /* Centers LINES, not items */
    align-items: center;   /* Centers ITEMS within lines */
}

Pro Tip: align-content is often confused with align-items. The key difference: align-items aligns items within each line, while align-content aligns the lines themselves as a group. Remember: align-content only works when you have multiple lines (i.e., flex-wrap: wrap and enough items to wrap). And align-self is your escape hatch — it lets a single item break away from the container’s align-items rule and align itself independently!

30. Media Queries Introduction

Media queries are the foundation of responsive web design. They allow you to apply different styles based on the user’s device characteristics — screen size, orientation, resolution, and more.


What are Media Queries?

A media query is a CSS technique that applies styles conditionally based on the characteristics of the device or viewport. They’re defined using the @media rule.

@media screen and (min-width: 780px) {
    div {
        display: flex;
    }
}

What happens:

  • The styles inside the block are applied only when the condition is true
  • The condition is: screen device AND viewport width ≥ 780px
  • On smaller screens, the styles are ignored

Media Types

TypeDescription
allAll devices (default)
printPrint preview mode and printed pages
screenScreens (desktops, laptops, tablets, phones)
/* All devices */
@media all {
    body { margin: 0; }
}

/* Print only */
@media print {
    div {
        background-color: white;
        color: black;
    }
}

/* Screen only */
@media screen {
    body { background: #f8f9fa; }
}

Logical Operators

OperatorDescriptionExample
andCombines multiple conditions (all must be true)screen and (min-width: 780px)
notNegates a conditionnot (hover: hover)
onlyPrevents older browsers from applying stylesonly screen and (min-width: 780px)
, (or)Either condition can be truescreen, print
/* AND — both conditions must be true */
@media screen and (min-width: 780px) {
    div { display: flex; }
}

/* NOT — condition must be false */
@media not (hover: hover) {
    .no-hover { display: none; }
}

/* ONLY — for older browsers */
@media only screen and (min-width: 780px) {
    div { display: flex; }
}

/* OR — either condition can be true */
@media screen, print {
    body { font-family: Arial, sans-serif; }
}

Common Media Features (Descriptors)

FeatureDescriptionExample
widthViewport width(min-width: 768px)
heightViewport height(min-height: 600px)
aspect-ratioAspect ratio of viewport(aspect-ratio: 16/9)
orientationPortrait or landscape(orientation: landscape)
resolutionPixel density(min-resolution: 2dppx)
hoverHover capability(hover: hover)
pointerPointer accuracy(pointer: fine)
prefers-color-schemeLight or dark mode(prefers-color-scheme: dark)
prefers-reduced-motionReduced motion preference(prefers-reduced-motion: reduce)
/* Width-based */
@media (min-width: 768px) and (max-width: 1024px) {
    body { font-size: 16px; }
}

/* Orientation-based */
@media (orientation: landscape) {
    body { background-color: lightblue; }
}

/* Hover capability */
@media not (hover: hover) {
    .no-hover { display: none; }
}

/* Dark mode preference */
@media (prefers-color-scheme: dark) {
    body { background: #1a1a1a; color: #fff; }
}

/* Reduced motion preference */
@media (prefers-reduced-motion: reduce) {
    * { animation: none; transition: none; }
}

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Media Queries Introduction</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
            transition: background 0.3s, color 0.3s;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
            transition: background 0.3s, color 0.3s;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== RESPONSIVE DEMO ====== */
        .responsive-demo {
            display: block;
            padding: 20px;
            border: 2px dashed #007bff;
            border-radius: 8px;
            margin: 15px 0;
            background: #e9ecef;
            text-align: center;
        }

        .responsive-demo .icon {
            font-size: 3rem;
            display: block;
            margin-bottom: 10px;
        }

        .responsive-demo .label {
            font-weight: bold;
            color: #007bff;
        }

        /* Default: Mobile (small screens) */
        .responsive-demo {
            background: #ff6b6b;
            color: white;
        }
        .responsive-demo .label::before {
            content: "📱 Mobile";
        }

        /* Tablet: 768px and up */
        @media (min-width: 768px) {
            .responsive-demo {
                background: #ffc107;
                color: #333;
            }
            .responsive-demo .label::before {
                content: "📟 Tablet";
            }
        }

        /* Desktop: 1024px and up */
        @media (min-width: 1024px) {
            .responsive-demo {
                background: #28a745;
                color: white;
            }
            .responsive-demo .label::before {
                content: "💻 Desktop";
            }
        }

        /* Large Desktop: 1400px and up */
        @media (min-width: 1400px) {
            .responsive-demo {
                background: #6c5ce7;
                color: white;
            }
            .responsive-demo .label::before {
                content: "🖥️ Large Desktop";
            }
        }

        /* ====== ORIENTATION DEMO ====== */
        .orientation-demo {
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            background: #17a2b8;
            color: white;
            margin: 15px 0;
        }

        .orientation-demo::before {
            content: "🔄 Portrait Mode";
        }

        @media (orientation: landscape) {
            .orientation-demo {
                background: #fd7e14;
            }
            .orientation-demo::before {
                content: "🔄 Landscape Mode";
            }
        }

        /* ====== DARK MODE ====== */
        @media (prefers-color-scheme: dark) {
            body {
                background: #1a1a1a;
                color: #f8f9fa;
            }
            section {
                background: #2d2d2d;
                color: #f8f9fa;
            }
            h1 {
                color: #4dabf7;
                border-bottom-color: #4dabf7;
            }
            h2 {
                color: #69db7c;
                border-left-color: #69db7c;
            }
            h3 {
                color: #f8f9fa;
            }
            .reference-table th {
                background: #4dabf7;
            }
            .reference-table tr:nth-child(even) {
                background: #3d3d3d;
            }
            .reference-table td {
                border-color: #555;
            }
            .responsive-demo {
                background: #364fc7;
                color: white;
            }
            .code-block {
                background: #0d0d0d;
            }
            .note {
                color: #adb5bd;
            }
        }

        /* ====== HOVER CAPABILITY ====== */
        .hover-demo {
            padding: 15px;
            background: #007bff;
            color: white;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            margin: 15px 0;
        }

        @media not (hover: hover) {
            .hover-demo {
                background: #dc3545;
            }
            .hover-demo::before {
                content: "📱 Touch device — hover not available";
            }
        }

        @media (hover: hover) {
            .hover-demo:hover {
                background: #28a745;
                transform: scale(1.02);
                transition: all 0.3s;
            }
        }

        /* ====== REDUCED MOTION ====== */
        .motion-demo {
            padding: 20px;
            background: #6c5ce7;
            color: white;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            animation: pulse 2s infinite;
            margin: 15px 0;
        }

        @keyframes pulse {
            0%, 100% { transform: scale(1); }
            50% { transform: scale(1.05); }
        }

        @media (prefers-reduced-motion: reduce) {
            .motion-demo {
                animation: none;
            }
            .motion-demo::after {
                content: " (animation disabled)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* ====== PRINT STYLES ====== */
        @media print {
            body {
                background: white;
                color: black;
                font-size: 12pt;
            }
            section {
                box-shadow: none;
                border: 1px solid #ccc;
                page-break-inside: avoid;
            }
            .code-block {
                background: #f4f4f4;
                color: #333;
                border: 1px solid #ddd;
            }
            .no-print {
                display: none;
            }
        }

        /* ====== BREAKPOINT VISUALIZATION ====== */
        .breakpoint-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #007bff;
            color: white;
            padding: 10px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.9rem;
            box-shadow: 0 4px 15px rgba(0,123,255,0.4);
            z-index: 1000;
        }

        .breakpoint-indicator::before {
            content: "📱 < 768px";
        }

        @media (min-width: 768px) {
            .breakpoint-indicator {
                background: #ffc107;
                color: #333;
            }
            .breakpoint-indicator::before {
                content: "📟 768px - 1023px";
            }
        }

        @media (min-width: 1024px) {
            .breakpoint-indicator {
                background: #28a745;
                color: white;
            }
            .breakpoint-indicator::before {
                content: "💻 1024px - 1399px";
            }
        }

        @media (min-width: 1400px) {
            .breakpoint-indicator {
                background: #6c5ce7;
                color: white;
            }
            .breakpoint-indicator::before {
                content: "🖥️ ≥ 1400px";
            }
        }
    </style>
</head>
<body>

    <h1>Media Queries Introduction</h1>

    <!-- ====== 1. RESPONSIVE DEMO ====== -->
    <section>
        <h2>1. Responsive Breakpoints</h2>
        <p>Resize your browser to see the breakpoint change!</p>

        <div class="responsive-demo">
            <span class="icon">📱</span>
            <span class="label"></span>
            <p>Current breakpoint: <span class="highlight" id="current-breakpoint">Resize to see</span></p>
        </div>

        <div class="code-block">
            /* Mobile first — default styles */
            .responsive-demo {
                background: #ff6b6b;
            }

            /* Tablet: 768px and up */
            @media (min-width: 768px) {
                .responsive-demo {
                    background: #ffc107;
                }
            }

            /* Desktop: 1024px and up */
            @media (min-width: 1024px) {
                .responsive-demo {
                    background: #28a745;
                }
            }

            /* Large Desktop: 1400px and up */
            @media (min-width: 1400px) {
                .responsive-demo {
                    background: #6c5ce7;
                }
            }
        </div>
    </section>

    <!-- ====== 2. ORIENTATION ====== -->
    <section>
        <h2>2. Orientation</h2>
        <p>Rotate your device or resize your browser to change orientation.</p>

        <div class="orientation-demo"></div>

        <div class="code-block">
            /* Portrait (default) */
            .orientation-demo::before {
                content: "Portrait Mode";
            }

            /* Landscape */
            @media (orientation: landscape) {
                .orientation-demo {
                    background: #fd7e14;
                }
                .orientation-demo::before {
                    content: "Landscape Mode";
                }
            }
        </div>
    </section>

    <!-- ====== 3. DARK MODE ====== -->
    <section>
        <h2>3. Dark Mode (prefers-color-scheme)</h2>
        <p>This page automatically adapts to your system's dark mode preference.</p>

        <div class="code-block">
            @media (prefers-color-scheme: dark) {
                body {
                    background: #1a1a1a;
                    color: #f8f9fa;
                }
                section {
                    background: #2d2d2d;
                }
            }
        </div>
    </section>

    <!-- ====== 4. HOVER CAPABILITY ====== -->
    <section>
        <h2>4. Hover Capability</h2>
        <p>This element changes style on hover (desktop) or shows a message (touch devices).</p>

        <div class="hover-demo">
            <span class="no-hover-text">Hover over me (if you can!)</span>
        </div>

        <div class="code-block">
            /* For devices with hover capability */
            @media (hover: hover) {
                .hover-demo:hover {
                    background: #28a745;
                }
            }

            /* For touch devices without hover */
            @media not (hover: hover) {
                .hover-demo {
                    background: #dc3545;
                }
            }
        </div>
    </section>

    <!-- ====== 5. REDUCED MOTION ====== -->
    <section>
        <h2>5. Reduced Motion</h2>
        <p>This element respects your system's reduced motion preference.</p>

        <div class="motion-demo">
            ⚡ Animated Element
        </div>

        <div class="code-block">
            @keyframes pulse {
                0%, 100% { transform: scale(1); }
                50% { transform: scale(1.05); }
            }

            .motion-demo {
                animation: pulse 2s infinite;
            }

            @media (prefers-reduced-motion: reduce) {
                .motion-demo {
                    animation: none;
                }
            }
        </div>
    </section>

    <!-- ====== 6. PRINT STYLES ====== -->
    <section>
        <h2>6. Print Styles</h2>
        <p>Print this page to see the print-specific styles in action.</p>

        <div class="code-block no-print">
            @media print {
                body {
                    background: white;
                    color: black;
                }
                .no-print {
                    display: none;
                }
            }
        </div>
        <p class="note">This entire section is styled differently when printed.</p>
    </section>

    <!-- ====== 7. REFERENCE TABLES ====== -->
    <section>
        <h2>7. Reference Tables</h2>

        <h3>Media Types</h3>
        <table class="reference-table">
            <tr>
                <th>Type</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>all</code></td>
                <td>All devices (default)</td>
            </tr>
            <tr>
                <td><code>print</code></td>
                <td>Print preview mode and printed pages</td>
            </tr>
            <tr>
                <td><code>screen</code></td>
                <td>Screens (desktops, laptops, tablets, phones)</td>
            </tr>
        </table>

        <h3>Logical Operators</h3>
        <table class="reference-table">
            <tr>
                <th>Operator</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>and</code></td>
                <td>Both conditions must be true</td>
                <td><code>screen and (min-width: 780px)</code></td>
            </tr>
            <tr>
                <td><code>not</code></td>
                <td>Negates a condition</td>
                <td><code>not (hover: hover)</code></td>
            </tr>
            <tr>
                <td><code>only</code></td>
                <td>For older browsers</td>
                <td><code>only screen and (min-width: 780px)</code></td>
            </tr>
            <tr>
                <td><code>,</code></td>
                <td>Either condition can be true</td>
                <td><code>screen, print</code></td>
            </tr>
        </table>

        <h3>Common Media Features</h3>
        <table class="reference-table">
            <tr>
                <th>Feature</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>width</code></td>
                <td>Viewport width</td>
                <td><code>(min-width: 768px)</code></td>
            </tr>
            <tr>
                <td><code>height</code></td>
                <td>Viewport height</td>
                <td><code>(min-height: 600px)</code></td>
            </tr>
            <tr>
                <td><code>orientation</code></td>
                <td>Portrait or landscape</td>
                <td><code>(orientation: landscape)</code></td>
            </tr>
            <tr>
                <td><code>aspect-ratio</code></td>
                <td>Aspect ratio of viewport</td>
                <td><code>(aspect-ratio: 16/9)</code></td>
            </tr>
            <tr>
                <td><code>resolution</code></td>
                <td>Pixel density</td>
                <td><code>(min-resolution: 2dppx)</code></td>
            </tr>
            <tr>
                <td><code>hover</code></td>
                <td>Hover capability</td>
                <td><code>(hover: hover)</code></td>
            </tr>
            <tr>
                <td><code>pointer</code></td>
                <td>Pointer accuracy</td>
                <td><code>(pointer: fine)</code></td>
            </tr>
            <tr>
                <td><code>prefers-color-scheme</code></td>
                <td>Light or dark mode</td>
                <td><code>(prefers-color-scheme: dark)</code></td>
            </tr>
            <tr>
                <td><code>prefers-reduced-motion</code></td>
                <td>Reduced motion preference</td>
                <td><code>(prefers-reduced-motion: reduce)</code></td>
            </tr>
        </table>

        <h3>Common Breakpoints</h3>
        <table class="reference-table">
            <tr>
                <th>Device</th>
                <th>Breakpoint</th>
                <th>Example</th>
            </tr>
            <tr>
                <td>Mobile</td>
                <td>< 768px</td>
                <td><code>@media (max-width: 767px)</code></td>
            </tr>
            <tr>
                <td>Tablet</td>
                <td>768px – 1023px</td>
                <td><code>@media (min-width: 768px) and (max-width: 1023px)</code></td>
            </tr>
            <tr>
                <td>Desktop</td>
                <td>1024px – 1399px</td>
                <td><code>@media (min-width: 1024px)</code></td>
            </tr>
            <tr>
                <td>Large Desktop</td>
                <td>≥ 1400px</td>
                <td><code>@media (min-width: 1400px)</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 8. BEST PRACTICES ====== -->
    <section>
        <h2>8. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li><strong>Mobile First</strong> — Start with the smallest screen and build up</li>
                <li>Use <strong>relative units</strong> (em, rem, %) instead of fixed pixels</li>
                <li>Aim for a <strong>breakpoint every 50–70 pixels</strong> or so</li>
                <li><strong>Test thoroughly</strong> on various devices and screen sizes</li>
                <li>Use <code>prefers-color-scheme</code> for dark mode support</li>
                <li>Use <code>prefers-reduced-motion</code> for accessibility</li>
                <li>Use <code>@media print</code> to optimize for printing</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't <strong>overuse media queries</strong> — too many can slow down your site</li>
                <li>Don't use <strong>fixed units</strong> (px) for everything</li>
                <li>Don't ignore <strong>accessibility</strong> features like reduced motion</li>
                <li>Don't forget to include the <strong>viewport meta tag</strong></li>
                <li>Don't design only for one device — test everywhere</li>
            </ul>
        </div>
    </section>

    <!-- ====== BREAKPOINT INDICATOR ====== -->
    <div class="breakpoint-indicator"></div>

    <!-- ====== SCRIPT FOR BREAKPOINT DISPLAY ====== -->
    <script>
        function updateBreakpoint() {
            const width = window.innerWidth;
            const el = document.getElementById('current-breakpoint');
            if (width < 768) {
                el.textContent = '📱 Mobile (< 768px) — ' + width + 'px';
            } else if (width < 1024) {
                el.textContent = '📟 Tablet (768–1023px) — ' + width + 'px';
            } else if (width < 1400) {
                el.textContent = '💻 Desktop (1024–1399px) — ' + width + 'px';
            } else {
                el.textContent = '🖥️ Large Desktop (≥ 1400px) — ' + width + 'px';
            }
        }

        window.addEventListener('resize', updateBreakpoint);
        window.addEventListener('load', updateBreakpoint);
        updateBreakpoint();
    </script>

</body>
</html>

Quick Reference

ConceptDescriptionExample
@mediaMedia query rule@media screen and (min-width: 768px)
allAll devices@media all
printPrint styles@media print
screenScreen devices@media screen
andBoth conditionsscreen and (min-width: 768px)
notNegationnot (hover: hover)
onlyLegacy browser supportonly screen and (min-width: 768px)
,OR conditionscreen, print

Common Media Features

FeatureDescriptionExample
widthViewport width(min-width: 768px)
heightViewport height(min-height: 600px)
orientationPortrait/landscape(orientation: landscape)
aspect-ratioViewport aspect ratio(aspect-ratio: 16/9)
resolutionPixel density(min-resolution: 2dppx)
hoverHover capability(hover: hover)
prefers-color-schemeDark/light mode(prefers-color-scheme: dark)
prefers-reduced-motionReduced motion(prefers-reduced-motion: reduce)

Best Practices

Do This:

/* Mobile First approach */
/* Base styles for mobile */
.container {
    display: block;
    padding: 10px;
}

/* Tablet and up */
@media (min-width: 768px) {
    .container {
        display: flex;
        padding: 20px;
    }
}

/* Desktop and up */
@media (min-width: 1024px) {
    .container {
        max-width: 1200px;
        margin: 0 auto;
    }
}

Don’t Do This:

/* Don't use too many breakpoints */
@media (min-width: 320px) { }
@media (min-width: 375px) { }
@media (min-width: 414px) { }
@media (min-width: 480px) { }
@media (min-width: 640px) { }
/* Too many — aim for 3-5 major breakpoints */

/* Don't forget the viewport meta tag */
/* <meta name="viewport" content="width=device-width, initial-scale=1.0"> */

Pro Tip: Mobile First is the recommended approach — start with styles for the smallest screens and add complexity as the screen gets larger. Use min-width for breakpoints. Don’t forget the viewport meta tag — without it, media queries won’t work correctly on mobile devices! And always respect user preferences like prefers-color-scheme and prefers-reduced-motion for a more accessible experience.

31. any-hover and any-pointer Media Features

These two media features let you detect the input capabilities of a user’s device — whether they have a mouse that can hover, a touch screen, or both. This is crucial for creating interfaces that work well across all device types.


Overview of Features

FeatureDescriptionValues
any-hoverDetects if any pointing device can hovernone, hover
any-pointerDetects the accuracy of any pointing devicenone, coarse, fine

1. any-hover

The any-hover media feature detects whether any available pointing device can hover over elements.

@media (any-hover: none) {
    .container {
        background-color: lightcoral;
    }
}

Values

ValueDescription
noneNo pointing device can hover
hoverAt least one pointing device can hover

Key Points:

  • Desktop browsers with a mouse → any-hover: hover
  • Mobile browsers with touch input → any-hover: none
  • Devices with both mouse and touch → any-hover: hover (because the mouse can hover)

2. any-pointer

The any-pointer media feature detects the accuracy of any available pointing device.

@media (any-pointer: none) {
    .container {
        background-color: lightcoral;
    }
}

Values

ValueDescription
noneNo pointing device available
coarsePointing device with limited accuracy (e.g., touch, stylus)
finePointing device with fine accuracy (e.g., mouse, trackpad)

Key Points:

  • Desktop with mouse → any-pointer: fine
  • Mobile with touch → any-pointer: coarse
  • Devices with both → any-pointer: fine (because at least one device is fine)

any-hover vs hover

FeatureDescription
hoverDetects the primary pointing device’s hover capability
any-hoverDetects if any pointing device can hover

Example:

  • A laptop with a touchscreen and a mouse:
    • hover: hover (primary device is mouse)
    • any-hover: hover (at least one device can hover)
  • A tablet with a Bluetooth mouse:
    • hover: none (primary device is touch)
    • any-hover: hover (mouse can hover)

any-pointer vs pointer

FeatureDescription
pointerDetects the primary pointing device’s accuracy
any-pointerDetects the best accuracy among all pointing devices

Example:

  • A laptop with a touchscreen and a mouse:
    • pointer: fine (primary device is mouse)
    • any-pointer: fine (at least one device is fine)
  • A tablet with a Bluetooth mouse:
    • pointer: coarse (primary device is touch)
    • any-pointer: fine (mouse is fine)

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>any-hover and any-pointer Media Features</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DEMO CONTAINER ====== */
        .container {
            width: 200px;
            height: 200px;
            background-color: lightblue;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            font-size: 18px;
            border-radius: 12px;
            margin: 20px auto;
            cursor: pointer;
            transition: all 0.3s;
            text-align: center;
            padding: 20px;
        }

        .container:hover {
            background-color: lightgreen;
            transform: scale(1.05);
        }

        .container .status {
            font-size: 0.8rem;
            margin-top: 10px;
            font-weight: normal;
        }

        /* ====== DETECTION BADGES ====== */
        .detection-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .detection-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            background: #e9ecef;
            border: 2px solid #ddd;
        }

        .detection-card .feature-name {
            font-size: 0.85rem;
            color: #666;
            display: block;
            margin-bottom: 5px;
        }

        .detection-card .feature-value {
            font-size: 1.1rem;
            color: #007bff;
        }

        /* ====== HOVER CAPABILITY ====== */
        .hover-capable {
            background: #d4edda;
            border-color: #28a745;
            color: #155724;
        }

        .hover-capable .feature-value {
            color: #28a745;
        }

        .hover-not-capable {
            background: #f8d7da;
            border-color: #dc3545;
            color: #721c24;
        }

        .hover-not-capable .feature-value {
            color: #dc3545;
        }

        /* ====== POINTER CAPABILITY ====== */
        .pointer-fine {
            background: #cce5ff;
            border-color: #007bff;
            color: #004085;
        }

        .pointer-fine .feature-value {
            color: #007bff;
        }

        .pointer-coarse {
            background: #fff3cd;
            border-color: #ffc107;
            color: #856404;
        }

        .pointer-coarse .feature-value {
            color: #856404;
        }

        .pointer-none {
            background: #f8d7da;
            border-color: #dc3545;
            color: #721c24;
        }

        .pointer-none .feature-value {
            color: #dc3545;
        }

        /* ====== MEDIA QUERY DEMOS ====== */
        @media (any-hover: none) {
            .container {
                background-color: lightcoral;
            }
            .container:hover {
                background-color: lightcoral;
                transform: none;
            }
            .container .status::after {
                content: " (no hover available)";
                font-style: italic;
            }
        }

        @media (any-hover: hover) {
            .container .status::after {
                content: " (hover available!)";
                font-style: italic;
            }
        }

        @media (any-pointer: none) {
            .pointer-demo {
                background-color: #dc3545;
                color: white;
            }
            .pointer-demo::after {
                content: " — No pointing device detected";
            }
        }

        @media (any-pointer: coarse) {
            .pointer-demo {
                background-color: #ffc107;
                color: #333;
            }
            .pointer-demo::after {
                content: " — Coarse pointer (touch)";
            }
        }

        @media (any-pointer: fine) {
            .pointer-demo {
                background-color: #28a745;
                color: white;
            }
            .pointer-demo::after {
                content: " — Fine pointer (mouse)";
            }
        }

        /* ====== INTERACTIVE DEMO ====== */
        .interactive-demo {
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
            justify-content: center;
            margin: 20px 0;
        }

        .interactive-box {
            width: 150px;
            height: 100px;
            background: #007bff;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 8px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
        }

        .interactive-box:hover {
            background: #28a745;
            transform: scale(1.05);
        }

        /* ====== BEST PRACTICE DEMO ====== */
        .best-practice-card {
            background: white;
            border: 2px solid #ddd;
            border-radius: 12px;
            padding: 20px;
            max-width: 400px;
            margin: 20px auto;
            text-align: center;
            box-shadow: 0 4px 15px rgba(0,0,0,0.1);
        }

        .best-practice-card h3 {
            margin-top: 0;
            color: #007bff;
        }

        .best-practice-card .btn {
            display: inline-block;
            padding: 12px 30px;
            background: #007bff;
            color: white;
            border-radius: 8px;
            text-decoration: none;
            font-weight: bold;
            margin-top: 10px;
            transition: all 0.3s;
        }

        .best-practice-card .btn:hover {
            background: #28a745;
            transform: scale(1.02);
        }

        /* Hide hover-only elements on touch devices */
        @media (any-hover: none) {
            .hover-only {
                display: none;
            }
        }

        @media (any-hover: hover) {
            .hover-only {
                display: inline;
            }
        }
    </style>
</head>
<body>

    <h1>any-hover and any-pointer Media Features</h1>

    <!-- ====== 1. ANY-HOVER DEMO ====== -->
    <section>
        <h2>1. any-hover</h2>
        <p>Detects whether <strong>any</strong> pointing device can hover over elements.</p>

        <div class="container">
            <strong>Hover over me!</strong>
            <span class="status">Testing any-hover</span>
        </div>

        <p class="note">On desktop, the box turns green on hover. On touch devices with no hover, it stays coral.</p>

        <div class="code-block">
            /* Default state */
            .container {
                background-color: lightblue;
            }

            .container:hover {
                background-color: lightgreen;
            }

            /* No hover capability */
            @media (any-hover: none) {
                .container {
                    background-color: lightcoral;
                }
                .container:hover {
                    background-color: lightcoral; /* Disable hover effect */
                    transform: none;
                }
            }
        </div>
    </section>

    <!-- ====== 2. ANY-POINTER DEMO ====== -->
    <section>
        <h2>2. any-pointer</h2>
        <p>Detects the <strong>accuracy</strong> of any available pointing device.</p>

        <div class="pointer-demo" style="padding: 20px; border-radius: 8px; text-align: center; font-weight: bold; margin: 15px 0;">
            Pointer Detection
        </div>

        <div class="code-block">
            /* No pointing device */
            @media (any-pointer: none) {
                .pointer-demo {
                    background-color: #dc3545;
                    color: white;
                }
            }

            /* Coarse pointer (touch) */
            @media (any-pointer: coarse) {
                .pointer-demo {
                    background-color: #ffc107;
                    color: #333;
                }
            }

            /* Fine pointer (mouse) */
            @media (any-pointer: fine) {
                .pointer-demo {
                    background-color: #28a745;
                    color: white;
                }
            }
        </div>
    </section>

    <!-- ====== 3. DETECTION SUMMARY ====== -->
    <section>
        <h2>3. Your Device's Capabilities</h2>
        <p>Below is a live detection of your device's input capabilities.</p>

        <div class="detection-grid">
            <div class="detection-card" id="any-hover-card">
                <span class="feature-name">any-hover</span>
                <span class="feature-value" id="any-hover-value">Detecting...</span>
            </div>
            <div class="detection-card" id="any-pointer-card">
                <span class="feature-name">any-pointer</span>
                <span class="feature-value" id="any-pointer-value">Detecting...</span>
            </div>
            <div class="detection-card" id="hover-card">
                <span class="feature-name">hover (primary)</span>
                <span class="feature-value" id="hover-value">Detecting...</span>
            </div>
            <div class="detection-card" id="pointer-card">
                <span class="feature-name">pointer (primary)</span>
                <span class="feature-value" id="pointer-value">Detecting...</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect any-hover */
            @media (any-hover: hover) { /* At least one device can hover */ }
            @media (any-hover: none) { /* No device can hover */ }

            /* Detect any-pointer */
            @media (any-pointer: fine) { /* At least one fine pointer */ }
            @media (any-pointer: coarse) { /* At least one coarse pointer */ }
            @media (any-pointer: none) { /* No pointer available */ }
        </div>
    </section>

    <!-- ====== 4. PRACTICAL USE CASE ====== -->
    <section>
        <h2>4. Practical Use Case: Hover-Only Elements</h2>
        <p>Some UI elements only make sense with a mouse. Here's how to handle them.</p>

        <div class="best-practice-card">
            <h3>📱 Touch-Friendly Card</h3>
            <p>
                This card shows a "hover to see more" message
                <span class="hover-only"> — hover over the button to see the effect!</span>
            </p>
            <a href="#" class="btn">Learn More</a>
        </div>

        <p class="note">On touch devices, hover-only elements are hidden or replaced with tap-friendly alternatives.</p>

        <div class="code-block">
            /* Hide hover-only elements on touch devices */
            @media (any-hover: none) {
                .hover-only {
                    display: none;
                }
            }

            @media (any-hover: hover) {
                .hover-only {
                    display: inline;
                }
            }
        </div>
    </section>

    <!-- ====== 5. SIDE-BY-SIDE COMPARISON ====== -->
    <section>
        <h2>5. Side-by-Side Comparison</h2>

        <h3>any-hover vs hover</h3>
        <table class="reference-table">
            <tr>
                <th>Feature</th>
                <th>Description</th>
                <th>Use Case</th>
            </tr>
            <tr>
                <td><code>hover</code></td>
                <td>Primary pointing device can hover</td>
                <td>Optimizing for the main input method</td>
            </tr>
            <tr>
                <td><code>any-hover</code></td>
                <td>At least one pointing device can hover</td>
                <td>Detecting if hover effects are possible at all</td>
            </tr>
        </table>

        <h3>any-pointer vs pointer</h3>
        <table class="reference-table">
            <tr>
                <th>Feature</th>
                <th>Description</th>
                <th>Use Case</th>
            </tr>
            <tr>
                <td><code>pointer</code></td>
                <td>Primary pointing device accuracy</td>
                <td>Optimizing for the main input method</td>
            </tr>
            <tr>
                <td><code>any-pointer</code></td>
                <td>Best accuracy among all pointing devices</td>
                <td>Detecting if precise input is possible</td>
            </tr>
        </table>

        <h3>Detection Scenarios</h3>
        <table class="reference-table">
            <tr>
                <th>Device</th>
                <th>hover</th>
                <th>any-hover</th>
                <th>pointer</th>
                <th>any-pointer</th>
            </tr>
            <tr>
                <td>Desktop with mouse</td>
                <td><code>hover</code></td>
                <td><code>hover</code></td>
                <td><code>fine</code></td>
                <td><code>fine</code></td>
            </tr>
            <tr>
                <td>Mobile phone (touch)</td>
                <td><code>none</code></td>
                <td><code>none</code></td>
                <td><code>coarse</code></td>
                <td><code>coarse</code></td>
            </tr>
            <tr>
                <td>Tablet with stylus</td>
                <td><code>none</code></td>
                <td><code>hover</code></td>
                <td><code>coarse</code></td>
                <td><code>fine</code></td>
            </tr>
            <tr>
                <td>Laptop with touchscreen</td>
                <td><code>hover</code></td>
                <td><code>hover</code></td>
                <td><code>fine</code></td>
                <td><code>fine</code></td>
            </tr>
            <tr>
                <td>Tablet with Bluetooth mouse</td>
                <td><code>none</code></td>
                <td><code>hover</code></td>
                <td><code>coarse</code></td>
                <td><code>fine</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>any-hover</code> to detect if hover effects are possible at all</li>
                <li>Use <code>any-pointer</code> to detect if precise input is available</li>
                <li>Provide tap-friendly alternatives for touch devices</li>
                <li>Hide hover-only UI elements on touch devices</li>
                <li>Test on both desktop and mobile devices</li>
                <li>Use <code>hover: hover</code> for primary input optimization</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't rely solely on hover for critical functionality</li>
                <li>Don't confuse <code>hover</code> with <code>any-hover</code></li>
                <li>Don't forget that touch devices have no hover capability</li>
                <li>Don't hide important content on touch devices</li>
                <li>Don't assume all desktops have a mouse (some use touch)</li>
            </ul>
        </div>
    </section>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        // Detect any-hover
        function updateAnyHover() {
            const card = document.getElementById('any-hover-card');
            const value = document.getElementById('any-hover-value');
            if (window.matchMedia('(any-hover: hover)').matches) {
                value.textContent = 'hover ✅';
                card.className = 'detection-card hover-capable';
            } else {
                value.textContent = 'none ❌';
                card.className = 'detection-card hover-not-capable';
            }
        }

        // Detect any-pointer
        function updateAnyPointer() {
            const card = document.getElementById('any-pointer-card');
            const value = document.getElementById('any-pointer-value');
            if (window.matchMedia('(any-pointer: fine)').matches) {
                value.textContent = 'fine 🖱️';
                card.className = 'detection-card pointer-fine';
            } else if (window.matchMedia('(any-pointer: coarse)').matches) {
                value.textContent = 'coarse 👆';
                card.className = 'detection-card pointer-coarse';
            } else {
                value.textContent = 'none ❌';
                card.className = 'detection-card pointer-none';
            }
        }

        // Detect hover (primary)
        function updateHover() {
            const card = document.getElementById('hover-card');
            const value = document.getElementById('hover-value');
            if (window.matchMedia('(hover: hover)').matches) {
                value.textContent = 'hover ✅';
                card.className = 'detection-card hover-capable';
            } else {
                value.textContent = 'none ❌';
                card.className = 'detection-card hover-not-capable';
            }
        }

        // Detect pointer (primary)
        function updatePointer() {
            const card = document.getElementById('pointer-card');
            const value = document.getElementById('pointer-value');
            if (window.matchMedia('(pointer: fine)').matches) {
                value.textContent = 'fine 🖱️';
                card.className = 'detection-card pointer-fine';
            } else if (window.matchMedia('(pointer: coarse)').matches) {
                value.textContent = 'coarse 👆';
                card.className = 'detection-card pointer-coarse';
            } else {
                value.textContent = 'none ❌';
                card.className = 'detection-card pointer-none';
            }
        }

        // Update all on load and resize
        function updateAll() {
            updateAnyHover();
            updateAnyPointer();
            updateHover();
            updatePointer();
        }

        window.addEventListener('load', updateAll);
        window.addEventListener('resize', updateAll);
        updateAll();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionValues
any-hoverAny pointing device can hovernone, hover
any-pointerAccuracy of any pointing devicenone, coarse, fine

any-hover vs hover

FeatureDescription
hoverPrimary pointing device’s hover capability
any-hoverAny pointing device’s hover capability

any-pointer vs pointer

FeatureDescription
pointerPrimary pointing device’s accuracy
any-pointerBest accuracy among all pointing devices

Detection Scenarios

Devicehoverany-hoverpointerany-pointer
Desktop with mousehoverhoverfinefine
Mobile phone (touch)nonenonecoarsecoarse
Tablet with stylusnonehovercoarsefine
Laptop with touchscreenhoverhoverfinefine
Tablet with Bluetooth mousenonehovercoarsefine

Best Practices

Do This:

/* Hide hover-only elements on touch devices */
@media (any-hover: none) {
    .hover-only {
        display: none;
    }
}

/* Provide tap-friendly alternatives */
@media (any-hover: hover) {
    .tooltip:hover .tooltip-text {
        display: block;
    }
}

/* Detect fine pointers for precision UI */
@media (any-pointer: fine) {
    .color-picker {
        display: block;
    }
}

@media (any-pointer: coarse) {
    .color-picker {
        display: none; /* Hide precision UI on touch */
    }
}

Don’t Do This:

/* Don't rely on hover for critical functionality */
.delete-btn {
    display: none; /* Only visible on hover — bad for touch! */
}
.item:hover .delete-btn {
    display: block;
}

/* Don't confuse hover with any-hover */
@media (hover: none) {
    /* Only checks primary device — may miss secondary devices */
}

/* Don't assume all desktops have a mouse */
@media (min-width: 1024px) {
    .hover-effect { /* May fail on touchscreen laptops */ }
}

Pro Tip: Use any-hover and any-pointer to create input-aware interfaces. The key insight is that hover/pointer check the primary input device, while any-hover/any-pointer check all available devices. For example, a tablet with a Bluetooth mouse has hover: none (primary is touch) but any-hover: hover (mouse can hover). Use any-hover to detect if hover effects are possible at all, and any-pointer to detect if precise input is available. Always provide tap-friendly alternatives for touch devices!

32. aspect-ratio and color Media Features

These two media features let you adapt styles based on the shape of the viewport and the color capabilities of the output device — useful for responsive design and print optimization.


Overview of Features

FeatureDescriptionValues
aspect-ratioRatio of viewport width to height16/9, 4/3, 1/1
colorBits per color component (RGB)Integer (e.g., 8, 32)

1. aspect-ratio

The aspect-ratio media feature applies styles based on the ratio of the viewport’s width to its height.

@media (aspect-ratio: 16/9) {
    .box {
        width: 500px;
        height: auto;
        background-color: #ffcccc;
    }
}

Syntax

aspect-ratio: <width> / <height>

Variations

FeatureDescriptionExample
aspect-ratioExact ratio@media (aspect-ratio: 16/9)
min-aspect-ratioMinimum ratio@media (min-aspect-ratio: 4/3)
max-aspect-ratioMaximum ratio@media (max-aspect-ratio: 3/2)

Common Aspect Ratios

RatioDescriptionTypical Use
16/9WidescreenModern monitors, TVs
4/3TraditionalOlder monitors, tablets
21/9Ultra-wideCinematic displays
1/1SquareMobile portrait
9/16VerticalMobile landscape

Key Points:

  • The viewport’s aspect ratio changes when the user rotates their device or resizes their browser
  • Useful for adapting layouts to portrait vs. landscape orientations
  • You can use min-aspect-ratio and max-aspect-ratio for range-based queries

2. color

The color media feature applies styles based on the number of bits per color component (red, green, blue) of the output device.

@media (color) {
    p {
        color: blue;
    }
}

@media (min-color: 32) {
    p {
        color: red;
    }
}

Syntax

color: <integer>
color: < 12
color: >= 24

Variations

FeatureDescriptionExample
colorDevice has color@media (color)
min-colorMinimum bits per component@media (min-color: 8)
max-colorMaximum bits per component@media (max-color: 32)

Common Color Depths

Bits per ComponentTotal ColorsDescription
0MonochromeNo color (e.g., e-ink)
816.7 millionStandard color (24-bit total)
101.07 billionHDR displays
1268.7 billionProfessional displays
16High-end displays

Key Points:

  • color: 0 means the device is monochrome (no color)
  • color without a value applies if the device has any color capability
  • min-color: 8 means at least 8 bits per component (24-bit color)
  • The value is per component (red, green, or blue), not total bits

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>aspect-ratio and color Media Features</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            margin: 0;
            padding: 20px;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: #f8f9fa;
            line-height: 1.6;
            min-height: 100vh;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== ASPECT RATIO DEMO ====== */
        .container {
            width: 100%;
            min-height: 50vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            padding: 20px;
            transition: background 0.3s;
        }

        .box {
            width: 300px;
            height: 200px;
            background-color: #dc3545;
            border-radius: 8px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            text-align: center;
            padding: 20px;
            transition: all 0.3s;
            box-shadow: 0 4px 15px rgba(0,0,0,0.2);
        }

        .box .ratio-label {
            font-size: 0.8rem;
            opacity: 0.8;
            margin-top: 5px;
        }

        /* Aspect ratio: 16/9 */
        @media (aspect-ratio: 16/9) {
            .box {
                width: 500px;
                height: auto;
                background-color: #ffcccc;
                color: #333;
            }
            .box .ratio-label::after {
                content: " (16:9 detected!)";
                font-weight: bold;
            }
        }

        /* Aspect ratio: 4/3 */
        @media (aspect-ratio: 4/3) {
            .box {
                width: 400px;
                height: 300px;
                background-color: #ffc107;
                color: #333;
            }
            .box .ratio-label::after {
                content: " (4:3 detected!)";
                font-weight: bold;
            }
        }

        /* Aspect ratio: 1/1 (square) */
        @media (aspect-ratio: 1/1) {
            .box {
                width: 300px;
                height: 300px;
                background-color: #6c5ce7;
                border-radius: 50%;
            }
            .box .ratio-label::after {
                content: " (1:1 square detected!)";
                font-weight: bold;
            }
        }

        /* Portrait orientation */
        @media (max-aspect-ratio: 1/1) {
            .container {
                background: #d4edda;
            }
        }

        /* Landscape orientation */
        @media (min-aspect-ratio: 1/1) {
            .container {
                background: #cce5ff;
            }
        }

        /* ====== COLOR DEMO ====== */
        .color-demo {
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            font-size: 1.2rem;
            background: #e9ecef;
            margin: 15px 0;
            border: 2px solid #ddd;
        }

        /* Monochrome device */
        @media (color: 0) {
            .color-demo {
                background: #000;
                color: #fff;
                border-color: #fff;
            }
            .color-demo::after {
                content: " (monochrome device detected)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Any color device */
        @media (color) {
            .color-demo {
                background: linear-gradient(135deg, #007bff, #6c5ce7);
                color: white;
                border-color: #007bff;
            }
            .color-demo::after {
                content: " (color device detected)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* High color depth */
        @media (min-color: 32) {
            .color-demo {
                background: linear-gradient(135deg, #ff6b6b, #ffc107, #28a745);
                border-color: #ffc107;
            }
            .color-demo::after {
                content: " (high color depth ≥ 32 bits)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* ====== COLOR DETECTION GRID ====== */
        .color-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .color-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            border: 2px solid #ddd;
            background: #f8f9fa;
        }

        .color-card .label {
            font-size: 0.85rem;
            color: #666;
            display: block;
            margin-bottom: 5px;
        }

        .color-card .value {
            font-size: 1.2rem;
            font-weight: bold;
            color: #007bff;
        }

        /* Color depth indicators */
        .color-card.depth-0 {
            background: #000;
            color: #fff;
            border-color: #333;
        }
        .color-card.depth-0 .value { color: #fff; }

        .color-card.depth-8 {
            background: #cce5ff;
            border-color: #007bff;
        }
        .color-card.depth-8 .value { color: #007bff; }

        .color-card.depth-16 {
            background: #d4edda;
            border-color: #28a745;
        }
        .color-card.depth-16 .value { color: #28a745; }

        .color-card.depth-32 {
            background: #fff3cd;
            border-color: #ffc107;
        }
        .color-card.depth-32 .value { color: #856404; }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #007bff;
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px rgba(0,123,255,0.4);
            z-index: 1000;
            transition: all 0.3s;
        }

        .live-indicator::before {
            content: "📐 Aspect Ratio: ";
        }

        /* ====== PRACTICAL EXAMPLE ====== */
        .video-container {
            position: relative;
            width: 100%;
            max-width: 800px;
            margin: 20px auto;
            background: #000;
            border-radius: 8px;
            overflow: hidden;
        }

        .video-container .video-placeholder {
            aspect-ratio: 16/9;
            background: linear-gradient(135deg, #1e1e1e, #2d2d2d);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
        }

        .video-container .video-placeholder .play-icon {
            font-size: 3rem;
            margin-bottom: 10px;
        }

        @media (max-aspect-ratio: 4/3) {
            .video-container .video-placeholder {
                aspect-ratio: 4/3;
                background: linear-gradient(135deg, #2d1b4e, #1e1e1e);
            }
            .video-container .video-placeholder::after {
                content: " (4:3 mode)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }
    </style>
</head>
<body>

    <h1>aspect-ratio and color Media Features</h1>

    <!-- ====== 1. ASPECT-RATIO DEMO ====== -->
    <section>
        <h2>1. aspect-ratio</h2>
        <p>Applies styles based on the <strong>viewport's width-to-height ratio</strong>.</p>
        <p>Resize your browser or rotate your device to see the changes!</p>

        <div class="container">
            <div class="box">
                <span>Aspect Ratio Demo</span>
                <span class="ratio-label">Default (no ratio matched)</span>
            </div>
        </div>

        <div class="code-block">
            /* Default state */
            .box {
                width: 300px;
                height: 200px;
                background-color: #dc3545;
            }

            /* 16:9 widescreen */
            @media (aspect-ratio: 16/9) {
                .box {
                    width: 500px;
                    height: auto;
                    background-color: #ffcccc;
                }
            }

            /* 4:3 traditional */
            @media (aspect-ratio: 4/3) {
                .box {
                    width: 400px;
                    height: 300px;
                    background-color: #ffc107;
                }
            }

            /* 1:1 square */
            @media (aspect-ratio: 1/1) {
                .box {
                    width: 300px;
                    height: 300px;
                    background-color: #6c5ce7;
                    border-radius: 50%;
                }
            }

            /* Portrait orientation */
            @media (max-aspect-ratio: 1/1) {
                .container { background: #d4edda; }
            }

            /* Landscape orientation */
            @media (min-aspect-ratio: 1/1) {
                .container { background: #cce5ff; }
            }
        </div>
    </section>

    <!-- ====== 2. COLOR DEMO ====== -->
    <section>
        <h2>2. color</h2>
        <p>Applies styles based on the <strong>number of bits per color component</strong>.</p>

        <div class="color-demo">
            Color Device Detection
        </div>

        <div class="code-block">
            /* Monochrome device (no color) */
            @media (color: 0) {
                .color-demo {
                    background: #000;
                    color: #fff;
                }
            }

            /* Any color device */
            @media (color) {
                .color-demo {
                    background: linear-gradient(135deg, #007bff, #6c5ce7);
                    color: white;
                }
            }

            /* High color depth (≥ 32 bits) */
            @media (min-color: 32) {
                .color-demo {
                    background: linear-gradient(135deg, #ff6b6b, #ffc107, #28a745);
                }
            }
        </div>
    </section>

    <!-- ====== 3. COLOR DEPTH DETECTION ====== -->
    <section>
        <h2>3. Color Depth Detection</h2>
        <p>Your device's color capabilities are detected below.</p>

        <div class="color-grid">
            <div class="color-card" id="color-monochrome">
                <span class="label">color: 0</span>
                <span class="value">Monochrome</span>
            </div>
            <div class="color-card" id="color-any">
                <span class="label">color (any)</span>
                <span class="value">Color</span>
            </div>
            <div class="color-card" id="color-8">
                <span class="label">min-color: 8</span>
                <span class="value">Standard</span>
            </div>
            <div class="color-card" id="color-16">
                <span class="label">min-color: 16</span>
                <span class="value">High</span>
            </div>
            <div class="color-card" id="color-32">
                <span class="label">min-color: 32</span>
                <span class="value">Ultra</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect monochrome */
            @media (color: 0) { /* No color */ }

            /* Detect any color */
            @media (color) { /* Has color */ }

            /* Detect color depth */
            @media (min-color: 8) { /* At least 8 bits per component */ }
            @media (min-color: 16) { /* At least 16 bits per component */ }
            @media (min-color: 32) { /* At least 32 bits per component */ }
        </div>
    </section>

    <!-- ====== 4. PRACTICAL EXAMPLE ====== -->
    <section>
        <h2>4. Practical Example: Responsive Video Container</h2>
        <p>A video container that adapts to different aspect ratios.</p>

        <div class="video-container">
            <div class="video-placeholder">
                <span class="play-icon">▶️</span>
                <span>Video Player</span>
            </div>
        </div>

        <div class="code-block">
            /* 16:9 aspect ratio (widescreen) */
            .video-placeholder {
                aspect-ratio: 16/9;
            }

            /* 4:3 aspect ratio (traditional) */
            @media (max-aspect-ratio: 4/3) {
                .video-placeholder {
                    aspect-ratio: 4/3;
                }
            }
        </div>
    </section>

    <!-- ====== 5. REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>aspect-ratio Values</h3>
        <table class="reference-table">
            <tr>
                <th>Feature</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>aspect-ratio</code></td>
                <td>Exact aspect ratio</td>
                <td><code>@media (aspect-ratio: 16/9)</code></td>
            </tr>
            <tr>
                <td><code>min-aspect-ratio</code></td>
                <td>Minimum aspect ratio</td>
                <td><code>@media (min-aspect-ratio: 4/3)</code></td>
            </tr>
            <tr>
                <td><code>max-aspect-ratio</code></td>
                <td>Maximum aspect ratio</td>
                <td><code>@media (max-aspect-ratio: 3/2)</code></td>
            </tr>
        </table>

        <h3>Common Aspect Ratios</h3>
        <table class="reference-table">
            <tr>
                <th>Ratio</th>
                <th>Description</th>
                <th>Typical Use</th>
            </tr>
            <tr>
                <td><code>16/9</code></td>
                <td>Widescreen</td>
                <td>Modern monitors, TVs, video</td>
            </tr>
            <tr>
                <td><code>4/3</code></td>
                <td>Traditional</td>
                <td>Older monitors, tablets</td>
            </tr>
            <tr>
                <td><code>21/9</code></td>
                <td>Ultra-wide</td>
                <td>Cinematic displays</td>
            </tr>
            <tr>
                <td><code>1/1</code></td>
                <td>Square</td>
                <td>Mobile portrait, avatars</td>
            </tr>
            <tr>
                <td><code>9/16</code></td>
                <td>Vertical</td>
                <td>Mobile landscape, stories</td>
            </tr>
        </table>

        <h3>color Values</h3>
        <table class="reference-table">
            <tr>
                <th>Feature</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>color</code></td>
                <td>Device has color</td>
                <td><code>@media (color)</code></td>
            </tr>
            <tr>
                <td><code>min-color</code></td>
                <td>Minimum bits per component</td>
                <td><code>@media (min-color: 8)</code></td>
            </tr>
            <tr>
                <td><code>max-color</code></td>
                <td>Maximum bits per component</td>
                <td><code>@media (max-color: 32)</code></td>
            </tr>
            <tr>
                <td><code>color: 0</code></td>
                <td>Monochrome device</td>
                <td><code>@media (color: 0)</code></td>
            </tr>
        </table>

        <h3>Common Color Depths</h3>
        <table class="reference-table">
            <tr>
                <th>Bits per Component</th>
                <th>Total Colors</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>0</code></td>
                <td>Monochrome</td>
                <td>No color (e-ink, braille)</td>
            </tr>
            <tr>
                <td><code>8</code></td>
                <td>16.7 million</td>
                <td>Standard color (24-bit total)</td>
            </tr>
            <tr>
                <td><code>10</code></td>
                <td>1.07 billion</td>
                <td>HDR displays</td>
            </tr>
            <tr>
                <td><code>12</code></td>
                <td>68.7 billion</td>
                <td>Professional displays</td>
            </tr>
            <tr>
                <td><code>16</code></td>
                <td>—</td>
                <td>High-end displays</td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>aspect-ratio</code> to adapt layouts to different screen shapes</li>
                <li>Use <code>max-aspect-ratio</code> and <code>min-aspect-ratio</code> for range queries</li>
                <li>Use <code>color</code> to detect monochrome devices and provide fallbacks</li>
                <li>Use <code>min-color</code> to detect high color depth displays</li>
                <li>Test on different devices and orientations</li>
                <li>Combine with <code>orientation</code> for comprehensive device detection</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't rely solely on aspect-ratio for responsive design</li>
                <li>Don't forget that aspect-ratio changes with orientation</li>
                <li>Don't assume all devices have color (e-ink readers exist)</li>
                <li>Don't use <code>color</code> for critical functionality — use it for enhancements</li>
                <li>Don't confuse bits per component with total bits</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator" id="live-indicator">Detecting...</div>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        function updateIndicators() {
            // Aspect ratio indicator
            const indicator = document.getElementById('live-indicator');
            const w = window.innerWidth;
            const h = window.innerHeight;
            const ratio = (w / h).toFixed(2);
            let ratioName = '';
            const exactRatio = w / h;

            if (Math.abs(exactRatio - 16/9) < 0.05) ratioName = '16:9';
            else if (Math.abs(exactRatio - 4/3) < 0.05) ratioName = '4:3';
            else if (Math.abs(exactRatio - 1) < 0.05) ratioName = '1:1';
            else if (exactRatio > 1) ratioName = 'Landscape';
            else ratioName = 'Portrait';

            indicator.textContent = '📐 ' + ratioName + ' (' + w + '×' + h + ' = ' + ratio + ')';

            // Color depth detection
            const colorCards = {
                monochrome: document.getElementById('color-monochrome'),
                any: document.getElementById('color-any'),
                c8: document.getElementById('color-8'),
                c16: document.getElementById('color-16'),
                c32: document.getElementById('color-32')
            };

            // Reset classes
            Object.values(colorCards).forEach(card => {
                if (card) card.className = 'color-card';
            });

            // Check color: 0 (monochrome)
            if (window.matchMedia('(color: 0)').matches) {
                colorCards.monochrome.className = 'color-card depth-0';
                colorCards.monochrome.querySelector('.value').textContent = 'Detected ✅';
            } else {
                colorCards.monochrome.querySelector('.value').textContent = 'Not monochrome';
            }

            // Check any color
            if (window.matchMedia('(color)').matches) {
                colorCards.any.className = 'color-card depth-8';
                colorCards.any.querySelector('.value').textContent = 'Detected ✅';
            }

            // Check min-color: 8
            if (window.matchMedia('(min-color: 8)').matches) {
                colorCards.c8.className = 'color-card depth-8';
                colorCards.c8.querySelector('.value').textContent = '≥ 8 bits ✅';
            }

            // Check min-color: 16
            if (window.matchMedia('(min-color: 16)').matches) {
                colorCards.c16.className = 'color-card depth-16';
                colorCards.c16.querySelector('.value').textContent = '≥ 16 bits ✅';
            }

            // Check min-color: 32
            if (window.matchMedia('(min-color: 32)').matches) {
                colorCards.c32.className = 'color-card depth-32';
                colorCards.c32.querySelector('.value').textContent = '≥ 32 bits ✅';
            }
        }

        window.addEventListener('resize', updateIndicators);
        window.addEventListener('load', updateIndicators);
        updateIndicators();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionValues
aspect-ratioViewport width-to-height ratio16/9, 4/3, 1/1
colorBits per color componentInteger (0, 8, 16, 32)

aspect-ratio Variations

FeatureDescriptionExample
aspect-ratioExact ratio@media (aspect-ratio: 16/9)
min-aspect-ratioMinimum ratio@media (min-aspect-ratio: 4/3)
max-aspect-ratioMaximum ratio@media (max-aspect-ratio: 3/2)

Common Aspect Ratios

RatioDescriptionTypical Use
16/9WidescreenModern monitors, TVs
4/3TraditionalOlder monitors, tablets
21/9Ultra-wideCinematic displays
1/1SquareMobile portrait
9/16VerticalMobile landscape

color Variations

FeatureDescriptionExample
colorDevice has color@media (color)
min-colorMinimum bits per component@media (min-color: 8)
max-colorMaximum bits per component@media (max-color: 32)
color: 0Monochrome device@media (color: 0)

Common Color Depths

Bits per ComponentTotal ColorsDescription
0MonochromeNo color (e-ink)
816.7 millionStandard color
101.07 billionHDR displays
1268.7 billionProfessional displays
16High-end displays

Best Practices

Do This:

/* Adapt layout to different aspect ratios */
@media (aspect-ratio: 16/9) {
    .video-container {
        aspect-ratio: 16/9;
    }
}

@media (max-aspect-ratio: 4/3) {
    .video-container {
        aspect-ratio: 4/3;
    }
}

/* Provide fallbacks for monochrome devices */
@media (color: 0) {
    .chart {
        /* Use patterns instead of colors */
        background-image: repeating-linear-gradient(...);
    }
}

/* Enhance for high color depth */
@media (min-color: 32) {
    .hero {
        background: linear-gradient(135deg, #ff6b6b, #ffc107, #28a745);
    }
}

Don’t Do This:

/* Don't rely solely on aspect-ratio for responsiveness */
@media (aspect-ratio: 16/9) {
    /* This won't catch all widescreen devices */
}

/* Don't assume all devices have color */
.chart {
    color: #ff0000; /* May not be visible on monochrome */
}

/* Don't forget that aspect-ratio changes with orientation */
/* A 16:9 landscape device becomes 9:16 in portrait */

Pro Tip: aspect-ratio is great for adapting to device orientation and screen shape. Use it to switch between portrait and landscape layouts or to adjust video player dimensions. color is useful for accessibility — providing fallbacks for monochrome e-ink devices. Remember that aspect-ratio changes when the user rotates their device, so you might want to use both aspect-ratio and orientation together for precise control!

33. color-gamut and color-index Media Features

These two advanced media features let you adapt styles based on the color capabilities of the display — from the range of colors it can reproduce to the size of its color lookup table.


Overview of Features

FeatureDescriptionValues
color-gamutApproximate color gamut of the displaysrgb, p3, rec2020
color-indexNumber of entries in the color lookup tableInteger (e.g., 1, 8, 256)

1. color-gamut

The color-gamut media feature queries the approximate range of colors (gamut) that the output device can display.

@media (color-gamut: p3) {
    .display-p3 {
        background-color: oklch(69% 0.27 140);
    }
}

Values

ValueDescription
srgbStandard sRGB color space (most common)
p3DCI-P3 or Adobe RGB (1988) — wider than sRGB
rec2020Rec. 2020 — widest color space
display-p3Alias for p3

Color Space Comparison

┌─────────────────────────────────────────────────────┐
│                    rec2020                          │
│  ┌─────────────────────────────────────────────┐   │
│  │                   p3                         │   │
│  │  ┌───────────────────────────────────────┐  │   │
│  │  │                srgb                    │  │   │
│  │  │  (Standard — most devices)             │  │   │
│  │  └───────────────────────────────────────┘  │   │
│  └─────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────┘

Key Points:

  • srgb — Standard for most monitors, phones, and the web
  • p3 — Wider gamut found on modern Apple devices and high-end displays
  • rec2020 — Widest gamut, used in HDR and professional video
  • A device that supports p3 also supports srgb (it’s a superset)
  • A device that supports rec2020 also supports p3 and srgb

Important: color-gamut tells you what the display can reproduce, not what it’s currently set to. You still need to use wide-gamut color values (like oklch(), color(display-p3 ...)) for the wider gamut to be visible.


2. color-index

The color-index media feature queries the number of entries in the output device’s color lookup table (CLUT). This is primarily relevant for devices with indexed color, like older displays or certain embedded systems.

@media (min-color-index: 1) {
    body {
        background-color: lightgray;
    }
}

Syntax

color-index: <integer>
color-index: >= 8
min-color-index: 1
max-color-index: 8

Variations

FeatureDescriptionExample
color-indexExact number of entries@media (color-index: 256)
min-color-indexMinimum entries@media (min-color-index: 1)
max-color-indexMaximum entries@media (max-color-index: 8)

Key Points:

  • color-index: 0 means the device does not use a color lookup table
  • Most modern devices use direct color (not indexed), so color-index: 0
  • Indexed color was common in older systems (e.g., 256-color VGA)
  • min-color-index is equivalent to color-index >= value
  • max-color-index is equivalent to color-index <= value

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>color-gamut and color-index Media Features</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            padding: 20px;
            background: #f8f9fa;
            max-width: 1200px;
            margin: 0 auto;
            transition: background 0.3s;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
            transition: background 0.3s;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== COLOR GAMUT DEMO ====== */
        .color-box {
            width: 200px;
            height: 200px;
            display: inline-block;
            margin: 10px;
            border-radius: 12px;
            transition: all 0.3s;
            box-shadow: 0 4px 15px rgba(0,0,0,0.15);
            position: relative;
            overflow: hidden;
        }

        .color-box::after {
            content: attr(data-label);
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            background: rgba(0,0,0,0.6);
            color: white;
            padding: 8px;
            text-align: center;
            font-size: 0.85rem;
            font-weight: bold;
            backdrop-filter: blur(4px);
        }

        /* Default: srgb */
        .color-box {
            background-color: rgb(85, 85, 85);
        }

        /* sRGB gamut */
        @media (color-gamut: srgb) {
            .srgb {
                background-color: rgb(85, 85, 85);
            }
        }

        /* P3 gamut */
        @media (color-gamut: p3) {
            .display-p3 {
                background-color: oklch(69% 0.27 140);
            }
        }

        /* Rec. 2020 gamut */
        @media (color-gamut: rec2020) {
            .rec2020 {
                background-color: rgb(15, 15, 15);
            }
        }

        /* ====== COLOR INDEX DEMO ====== */
        @media (min-color-index: 1) {
            body {
                background-color: lightgray;
            }
            .content {
                max-width: 80%;
                margin: auto;
                padding: 20px;
                border: 1px solid #ccc;
                box-shadow: 2px 2px 10px rgba(0,0,0,0.1);
            }
        }

        @media (max-color-index: 8) {
            body {
                background-color: lightblue;
            }
            .content {
                max-width: 60%;
                margin: auto;
                padding: 10px;
                border: 1px solid #aaa;
                box-shadow: none;
            }
        }

        /* ====== DETECTION CARDS ====== */
        .detection-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .detection-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            border: 2px solid #ddd;
            background: #f8f9fa;
            transition: all 0.3s;
        }

        .detection-card .label {
            font-size: 0.85rem;
            color: #666;
            display: block;
            margin-bottom: 5px;
        }

        .detection-card .value {
            font-size: 1.1rem;
            font-weight: bold;
            color: #007bff;
        }

        /* Gamut cards */
        .gamut-card.srgb {
            background: #cce5ff;
            border-color: #007bff;
        }
        .gamut-card.srgb .value { color: #007bff; }

        .gamut-card.p3 {
            background: #d4edda;
            border-color: #28a745;
        }
        .gamut-card.p3 .value { color: #28a745; }

        .gamut-card.rec2020 {
            background: #fff3cd;
            border-color: #ffc107;
        }
        .gamut-card.rec2020 .value { color: #856404; }

        /* Color index cards */
        .index-card {
            background: #e9ecef;
            border-color: #6c757d;
        }
        .index-card .value { color: #6c757d; }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #007bff;
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px rgba(0,123,255,0.4);
            z-index: 1000;
            transition: all 0.3s;
        }

        /* ====== PRACTICAL EXAMPLE ====== */
        .hero-image {
            width: 100%;
            height: 300px;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 1.5rem;
            font-weight: bold;
            text-shadow: 0 2px 10px rgba(0,0,0,0.3);
            margin: 20px 0;
            transition: all 0.3s;
            /* Default: sRGB */
            background: linear-gradient(135deg, #007bff, #6c5ce7);
        }

        /* Enhanced for P3 displays */
        @media (color-gamut: p3) {
            .hero-image {
                background: linear-gradient(135deg, oklch(69% 0.27 240), oklch(69% 0.27 300));
            }
        }

        /* Enhanced for Rec. 2020 displays */
        @media (color-gamut: rec2020) {
            .hero-image {
                background: linear-gradient(135deg, oklch(69% 0.27 30), oklch(69% 0.27 120), oklch(69% 0.27 240));
            }
        }

        /* ====== CONTENT BOX ====== */
        .content {
            background: white;
            padding: 20px;
            border-radius: 8px;
            margin: 20px 0;
            transition: all 0.3s;
        }
    </style>
</head>
<body>

    <h1>color-gamut and color-index Media Features</h1>

    <!-- ====== 1. COLOR-GAMUT DEMO ====== -->
    <section>
        <h2>1. color-gamut</h2>
        <p>Queries the <strong>approximate color gamut</strong> of the display.</p>

        <div style="text-align: center;">
            <div class="color-box srgb" data-label="sRGB (Standard)"></div>
            <div class="color-box display-p3" data-label="Display P3 (Wide)"></div>
            <div class="color-box rec2020" data-label="Rec. 2020 (Widest)"></div>
        </div>

        <p class="note" style="text-align: center;">Each box uses a color from its respective gamut. On a standard sRGB display, they'll all look similar. On a wide-gamut display, the P3 and Rec. 2020 colors will appear more vibrant.</p>

        <div class="code-block">
            /* Default: sRGB */
            .color-box {
                background-color: rgb(85, 85, 85);
            }

            /* sRGB gamut */
            @media (color-gamut: srgb) {
                .srgb {
                    background-color: rgb(85, 85, 85);
                }
            }

            /* P3 gamut (DCI-P3 / Adobe RGB) */
            @media (color-gamut: p3) {
                .display-p3 {
                    background-color: oklch(69% 0.27 140);
                }
            }

            /* Rec. 2020 gamut (widest) */
            @media (color-gamut: rec2020) {
                .rec2020 {
                    background-color: rgb(15, 15, 15);
                }
            }
        </div>
    </section>

    <!-- ====== 2. COLOR-INDEX DEMO ====== -->
    <section>
        <h2>2. color-index</h2>
        <p>Queries the <strong>number of entries</strong> in the output device's color lookup table.</p>

        <div class="content">
            <h3>Welcome to Our Website!</h3>
            <p>This is a simple example of using the <code>color-index</code> media feature in CSS.</p>
            <p>The styles on this page adapt based on your device's color index capability.</p>
        </div>

        <div class="code-block">
            /* At least 1 color index */
            @media (min-color-index: 1) {
                body {
                    background-color: lightgray;
                }
                .content {
                    max-width: 80%;
                    padding: 20px;
                    border: 1px solid #ccc;
                    box-shadow: 2px 2px 10px rgba(0,0,0,0.1);
                }
            }

            /* At most 8 color indices */
            @media (max-color-index: 8) {
                body {
                    background-color: lightblue;
                }
                .content {
                    max-width: 60%;
                    padding: 10px;
                    border: 1px solid #aaa;
                    box-shadow: none;
                }
            }
        </div>
    </section>

    <!-- ====== 3. DETECTION SUMMARY ====== -->
    <section>
        <h2>3. Your Display's Capabilities</h2>
        <p>Below is a live detection of your display's color capabilities.</p>

        <div class="detection-grid">
            <div class="detection-card" id="gamut-srgb">
                <span class="label">color-gamut: srgb</span>
                <span class="value" id="gamut-srgb-value">Detecting...</span>
            </div>
            <div class="detection-card" id="gamut-p3">
                <span class="label">color-gamut: p3</span>
                <span class="value" id="gamut-p3-value">Detecting...</span>
            </div>
            <div class="detection-card" id="gamut-rec2020">
                <span class="label">color-gamut: rec2020</span>
                <span class="value" id="gamut-rec2020-value">Detecting...</span>
            </div>
            <div class="detection-card" id="index-any">
                <span class="label">color-index</span>
                <span class="value" id="index-any-value">Detecting...</span>
            </div>
            <div class="detection-card" id="index-min">
                <span class="label">min-color-index: 1</span>
                <span class="value" id="index-min-value">Detecting...</span>
            </div>
            <div class="detection-card" id="index-max">
                <span class="label">max-color-index: 8</span>
                <span class="value" id="index-max-value">Detecting...</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect sRGB */
            @media (color-gamut: srgb) { /* Standard color gamut */ }

            /* Detect P3 */
            @media (color-gamut: p3) { /* Wide color gamut */ }

            /* Detect Rec. 2020 */
            @media (color-gamut: rec2020) { /* Widest color gamut */ }

            /* Detect color index */
            @media (min-color-index: 1) { /* At least 1 color index */ }
            @media (max-color-index: 8) { /* At most 8 color indices */ }
        </div>
    </section>

    <!-- ====== 4. PRACTICAL EXAMPLE ====== -->
    <section>
        <h2>4. Practical Example: Enhanced Hero Image</h2>
        <p>This hero image uses wider-gamut colors on displays that support them.</p>

        <div class="hero-image">
            🎨 Enhanced for Wide-Gamut Displays
        </div>

        <div class="code-block">
            /* Default: sRGB gradient */
            .hero-image {
                background: linear-gradient(135deg, #007bff, #6c5ce7);
            }

            /* Enhanced for P3 displays */
            @media (color-gamut: p3) {
                .hero-image {
                    background: linear-gradient(135deg, oklch(69% 0.27 240), oklch(69% 0.27 300));
                }
            }

            /* Enhanced for Rec. 2020 displays */
            @media (color-gamut: rec2020) {
                .hero-image {
                    background: linear-gradient(135deg, oklch(69% 0.27 30), oklch(69% 0.27 120), oklch(69% 0.27 240));
                }
            }
        </div>
    </section>

    <!-- ====== 5. REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>color-gamut Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Typical Devices</th>
            </tr>
            <tr>
                <td><code>srgb</code></td>
                <td>Standard sRGB color space</td>
                <td>Most monitors, phones, laptops</td>
            </tr>
            <tr>
                <td><code>p3</code></td>
                <td>DCI-P3 or Adobe RGB (1988)</td>
                <td>Modern Apple devices, high-end displays</td>
            </tr>
            <tr>
                <td><code>rec2020</code></td>
                <td>Rec. 2020 color space</td>
                <td>HDR displays, professional video</td>
            </tr>
            <tr>
                <td><code>display-p3</code></td>
                <td>Alias for <code>p3</code></td>
                <td>Same as <code>p3</code></td>
            </tr>
        </table>

        <h3>color-index Values</h3>
        <table class="reference-table">
            <tr>
                <th>Feature</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>color-index</code></td>
                <td>Exact number of entries</td>
                <td><code>@media (color-index: 256)</code></td>
            </tr>
            <tr>
                <td><code>min-color-index</code></td>
                <td>Minimum entries</td>
                <td><code>@media (min-color-index: 1)</code></td>
            </tr>
            <tr>
                <td><code>max-color-index</code></td>
                <td>Maximum entries</td>
                <td><code>@media (max-color-index: 8)</code></td>
            </tr>
        </table>

        <h3>Color Space Comparison</h3>
        <table class="reference-table">
            <tr>
                <th>Color Space</th>
                <th>Coverage</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>sRGB</code></td>
                <td>~35% of visible colors</td>
                <td>Standard for web and most devices</td>
            </tr>
            <tr>
                <td><code>DCI-P3</code></td>
                <td>~45% of visible colors</td>
                <td>Wider than sRGB, used in cinema and modern displays</td>
            </tr>
            <tr>
                <td><code>Rec. 2020</code></td>
                <td>~75% of visible colors</td>
                <td>Widest standard, used in HDR and 8K video</td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>color-gamut</code> to provide enhanced colors on capable displays</li>
                <li>Always provide an sRGB fallback for devices that don't support wider gamuts</li>
                <li>Use modern color functions like <code>oklch()</code> and <code>color(display-p3 ...)</code></li>
                <li>Use <code>color-index</code> only for legacy or specialized devices</li>
                <li>Test on both standard and wide-gamut displays</li>
                <li>Remember that wider gamut ≠ better design — use it purposefully</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't assume all displays support wide gamuts</li>
                <li>Don't use <code>color-index</code> for modern devices (most use direct color)</li>
                <li>Don't forget to provide sRGB fallbacks</li>
                <li>Don't use wide-gamut colors without testing on standard displays</li>
                <li>Don't rely on color-gamut for critical functionality</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator" id="live-indicator">Detecting...</div>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        function updateIndicators() {
            // Gamut detection
            const srgbCard = document.getElementById('gamut-srgb');
            const p3Card = document.getElementById('gamut-p3');
            const rec2020Card = document.getElementById('gamut-rec2020');
            const indicator = document.getElementById('live-indicator');

            let gamutName = 'Unknown';

            if (window.matchMedia('(color-gamut: rec2020)').matches) {
                srgbCard.className = 'detection-card gamut-card rec2020';
                srgbCard.querySelector('.value').textContent = 'Supported ✅';
                p3Card.className = 'detection-card gamut-card rec2020';
                p3Card.querySelector('.value').textContent = 'Supported ✅';
                rec2020Card.className = 'detection-card gamut-card rec2020';
                rec2020Card.querySelector('.value').textContent = 'Supported ✅';
                gamutName = 'Rec. 2020';
            } else if (window.matchMedia('(color-gamut: p3)').matches) {
                srgbCard.className = 'detection-card gamut-card p3';
                srgbCard.querySelector('.value').textContent = 'Supported ✅';
                p3Card.className = 'detection-card gamut-card p3';
                p3Card.querySelector('.value').textContent = 'Supported ✅';
                rec2020Card.querySelector('.value').textContent = 'Not supported ❌';
                gamutName = 'Display P3';
            } else if (window.matchMedia('(color-gamut: srgb)').matches) {
                srgbCard.className = 'detection-card gamut-card srgb';
                srgbCard.querySelector('.value').textContent = 'Supported ✅';
                p3Card.querySelector('.value').textContent = 'Not supported ❌';
                rec2020Card.querySelector('.value').textContent = 'Not supported ❌';
                gamutName = 'sRGB';
            } else {
                srgbCard.querySelector('.value').textContent = 'Not supported ❌';
                p3Card.querySelector('.value').textContent = 'Not supported ❌';
                rec2020Card.querySelector('.value').textContent = 'Not supported ❌';
            }

            // Color index detection
            const indexAnyCard = document.getElementById('index-any');
            const indexMinCard = document.getElementById('index-min');
            const indexMaxCard = document.getElementById('index-max');

            if (window.matchMedia('(color-index: 0)').matches) {
                indexAnyCard.querySelector('.value').textContent = 'Direct color (0)';
            } else if (window.matchMedia('(min-color-index: 1)').matches) {
                indexAnyCard.querySelector('.value').textContent = 'Indexed color ✅';
            } else {
                indexAnyCard.querySelector('.value').textContent = 'Unknown';
            }

            if (window.matchMedia('(min-color-index: 1)').matches) {
                indexMinCard.className = 'detection-card index-card';
                indexMinCard.querySelector('.value').textContent = '≥ 1 ✅';
            } else {
                indexMinCard.querySelector('.value').textContent = 'Not detected';
            }

            if (window.matchMedia('(max-color-index: 8)').matches) {
                indexMaxCard.className = 'detection-card index-card';
                indexMaxCard.querySelector('.value').textContent = '≤ 8 ✅';
            } else {
                indexMaxCard.querySelector('.value').textContent = 'Not detected';
            }

            // Update live indicator
            indicator.textContent = '🎨 ' + gamutName;
            indicator.style.background = gamutName === 'Rec. 2020' ? '#6c5ce7' :
                                         gamutName === 'Display P3' ? '#28a745' :
                                         gamutName === 'sRGB' ? '#007bff' : '#6c757d';
        }

        window.addEventListener('load', updateIndicators);
        updateIndicators();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionValues
color-gamutApproximate color gamut of displaysrgb, p3, rec2020
color-indexColor lookup table entriesInteger

color-gamut Values

ValueDescriptionTypical Devices
srgbStandard sRGBMost monitors, phones
p3DCI-P3 or Adobe RGBModern Apple devices, high-end displays
rec2020Rec. 2020HDR displays, professional video
display-p3Alias for p3Same as p3

color-index Variations

FeatureDescriptionExample
color-indexExact entries@media (color-index: 256)
min-color-indexMinimum entries@media (min-color-index: 1)
max-color-indexMaximum entries@media (max-color-index: 8)

Color Space Comparison

Color SpaceCoverageDescription
sRGB~35% of visible colorsStandard for web
DCI-P3~45% of visible colorsWider, used in cinema
Rec. 2020~75% of visible colorsWidest, used in HDR

Best Practices

Do This:

/* Provide sRGB fallback first */
.hero {
    background: linear-gradient(135deg, #007bff, #6c5ce7);
}

/* Enhance for P3 displays */
@media (color-gamut: p3) {
    .hero {
        background: linear-gradient(135deg, oklch(69% 0.27 240), oklch(69% 0.27 300));
    }
}

/* Further enhance for Rec. 2020 displays */
@media (color-gamut: rec2020) {
    .hero {
        background: linear-gradient(135deg, oklch(69% 0.27 30), oklch(69% 0.27 120), oklch(69% 0.27 240));
    }
}

/* Handle indexed color devices */
@media (max-color-index: 8) {
    .image {
        /* Reduce color complexity */
    }
}

Don’t Do This:

/* Don't use wide-gamut colors without fallbacks */
.hero {
    background: oklch(69% 0.27 240); /* May look wrong on sRGB */
}

/* Don't assume all devices support wide gamuts */
@media (color-gamut: p3) {
    /* This is fine, but always provide sRGB fallback */
}

/* Don't use color-index for modern devices */
@media (color-index: 256) {
    /* Most modern devices use direct color, not indexed */
}

Pro Tip: color-gamut is your key to vibrant, modern web design. Always provide an sRGB fallback first, then enhance for P3 and Rec. 2020 displays using modern color functions like oklch() or color(display-p3 ...). color-index is mostly relevant for legacy or specialized devices — modern devices use direct color rather than indexed color. Remember: wider gamut is about quality, not quantity — use it to make your colors more vivid and lifelike, not to change your design completely!

34. display-mode and dynamic-range Media Features

These two media features let you adapt styles based on how the app is displayed and the visual capabilities of the screen — from standalone PWA mode to HDR displays.


Overview of Features

FeatureDescriptionValues
display-modeHow the document is displayedbrowser, standalone, minimal-ui, fullscreen, picture-in-picture
dynamic-rangeBrightness, contrast, and color depthstandard, high

1. display-mode

The display-mode media feature queries how the document is being displayed — whether it’s in a browser tab, installed as an app, in fullscreen, etc.

@media (display-mode: standalone) {
    body {
        background-color: #f0f8ff;
        color: #036;
    }
}

Values

ValueDescription
browserIn a normal browser tab or window
standaloneInstalled as a standalone app (PWA)
minimal-uiLike standalone, but with minimal browser UI
fullscreenUses the full screen (no browser chrome)
picture-in-pictureIn a picture-in-picture window
window-controls-overlayPWA with window controls overlay (desktop)

How It’s Set

The display mode is controlled by:

  1. The manifest file’s display property (for PWAs)
  2. The Fullscreen API (requestFullscreen())
  3. The Picture-in-Picture API

Manifest example:

{
    "display": "standalone",
    "name": "My PWA",
    "short_name": "PWA"
}

JavaScript example:

// Enter fullscreen
document.documentElement.requestFullscreen();

// Check current display mode
if (window.matchMedia('(display-mode: standalone)').matches) {
    console.log('Running as standalone app');
}

2. dynamic-range

The dynamic-range media feature queries the combination of brightness, contrast, and color depth capabilities of the display.

@media (dynamic-range: high) {
    body {
        background-color: #f5f5f5;
        color: #000;
    }
}

Values

ValueDescription
standardStandard dynamic range (SDR) — typical displays
highHigh dynamic range (HDR) — supports HDR content

HDR requirements:

  • Color depth greater than 24-bit (usually 30-bit or 36-bit)
  • High contrast ratio
  • High peak brightness (typically 1000+ nits)

Key Points:

  • A device that matches high also matches standard (HDR is a superset)
  • A device that matches standard may or may not support high
  • Use high to enhance visuals on capable displays
  • Always provide a standard fallback

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>display-mode and dynamic-range Media Features</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
            transition: background 0.3s, color 0.3s;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
            transition: background 0.3s;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DISPLAY MODE DEMOS ====== */
        @media (display-mode: browser) {
            .display-browser {
                background: #cce5ff;
                border-color: #007bff;
            }
            .display-browser .value {
                color: #007bff;
            }
        }

        @media (display-mode: standalone) {
            body {
                background-color: #f0f8ff;
                color: #036;
            }
            a {
                color: #00f;
            }
            .display-standalone {
                background: #d4edda;
                border-color: #28a745;
            }
            .display-standalone .value {
                color: #28a745;
            }
        }

        @media (display-mode: minimal-ui) {
            .display-minimal-ui {
                background: #fff3cd;
                border-color: #ffc107;
            }
            .display-minimal-ui .value {
                color: #856404;
            }
        }

        @media (display-mode: fullscreen) {
            body {
                background-color: #fff;
                color: #000;
            }
            a {
                color: #03f;
            }
            .display-fullscreen {
                background: #f8d7da;
                border-color: #dc3545;
            }
            .display-fullscreen .value {
                color: #dc3545;
            }
        }

        @media (display-mode: picture-in-picture) {
            .display-pip {
                background: #e2d9f3;
                border-color: #6c5ce7;
            }
            .display-pip .value {
                color: #6c5ce7;
            }
        }

        /* ====== DYNAMIC RANGE DEMOS ====== */
        @media (dynamic-range: standard) {
            body {
                background-color: #e5e5e5;
                color: #333;
            }
            p {
                font-size: 1em;
            }
            .dynamic-standard {
                background: #e9ecef;
                border-color: #6c757d;
            }
            .dynamic-standard .value {
                color: #6c757d;
            }
        }

        @media (dynamic-range: high) {
            body {
                background-color: #f5f5f5;
                color: #000;
            }
            p {
                font-size: 1.2em;
            }
            .dynamic-high {
                background: #fff3cd;
                border-color: #ffc107;
            }
            .dynamic-high .value {
                color: #856404;
            }
        }

        /* ====== DETECTION CARDS ====== */
        .detection-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .detection-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            border: 2px solid #ddd;
            background: #f8f9fa;
            transition: all 0.3s;
        }

        .detection-card .label {
            font-size: 0.85rem;
            color: #666;
            display: block;
            margin-bottom: 5px;
        }

        .detection-card .value {
            font-size: 1.1rem;
            font-weight: bold;
            color: #007bff;
        }

        /* ====== BUTTONS ====== */
        .btn-group {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin: 15px 0;
        }

        .btn {
            padding: 10px 20px;
            border: none;
            border-radius: 8px;
            font-size: 1em;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
            color: white;
        }

        .btn-primary {
            background: #007bff;
        }
        .btn-primary:hover {
            background: #0056b3;
            transform: translateY(-2px);
        }

        .btn-success {
            background: #28a745;
        }
        .btn-success:hover {
            background: #1e7e34;
            transform: translateY(-2px);
        }

        .btn-danger {
            background: #dc3545;
        }
        .btn-danger:hover {
            background: #a71d2a;
            transform: translateY(-2px);
        }

        .btn-warning {
            background: #ffc107;
            color: #333;
        }
        .btn-warning:hover {
            background: #d39e00;
            transform: translateY(-2px);
        }

        /* ====== HDR VISUAL DEMO ====== */
        .hdr-demo {
            border-radius: 12px;
            overflow: hidden;
            margin: 20px 0;
            position: relative;
        }

        .hdr-demo .image-container {
            width: 100%;
            height: 300px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.5rem;
            font-weight: bold;
            color: white;
            text-shadow: 0 2px 10px rgba(0,0,0,0.3);
            transition: all 0.3s;
            /* Standard dynamic range */
            background: linear-gradient(135deg, #007bff, #6c5ce7);
        }

        /* High dynamic range enhancement */
        @media (dynamic-range: high) {
            .hdr-demo .image-container {
                background: linear-gradient(135deg, 
                    oklch(69% 0.27 240), 
                    oklch(69% 0.27 300),
                    oklch(69% 0.27 30));
                box-shadow: 0 0 40px rgba(108, 92, 231, 0.5);
            }
            .hdr-demo .image-container::after {
                content: " (HDR Enhanced ✨)";
                font-size: 1rem;
                font-weight: normal;
            }
        }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #007bff;
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px rgba(0,123,255,0.4);
            z-index: 1000;
            transition: all 0.3s;
        }

        /* ====== PWA MANIFEST NOTE ====== */
        .manifest-note {
            background: #e2d9f3;
            padding: 20px;
            border-radius: 8px;
            border-left: 4px solid #6c5ce7;
            margin: 15px 0;
        }

        .manifest-note code {
            background: rgba(0,0,0,0.08);
            padding: 2px 6px;
            border-radius: 4px;
            font-family: 'Courier New', monospace;
        }
    </style>
</head>
<body>

    <h1>display-mode and dynamic-range Media Features</h1>

    <!-- ====== 1. DISPLAY-MODE DEMO ====== -->
    <section>
        <h2>1. display-mode</h2>
        <p>Queries how the document is being <strong>displayed</strong> — browser tab, standalone app, fullscreen, etc.</p>

        <div class="btn-group">
            <button class="btn btn-primary" onclick="enterFullscreen()">🖥️ Enter Fullscreen</button>
            <button class="btn btn-danger" onclick="exitFullscreen()">🚪 Exit Fullscreen</button>
            <button class="btn btn-success" onclick="showDisplayMode()">📱 Detect Display Mode</button>
            <button class="btn btn-warning" onclick="requestPiP()">📺 Picture-in-Picture</button>
        </div>

        <div id="display-mode-result" class="detection-card" style="margin: 15px 0;">
            <span class="label">Current display mode:</span>
            <span class="value" id="current-display-mode">Click "Detect Display Mode"</span>
        </div>

        <div class="code-block">
            /* Browser tab or window */
            @media (display-mode: browser) {
                body { background-color: #f8f9fa; }
            }

            /* Installed as a standalone PWA */
            @media (display-mode: standalone) {
                body { background-color: #f0f8ff; }
            }

            /* Minimal UI (browser controls hidden) */
            @media (display-mode: minimal-ui) {
                body { background-color: #fff3cd; }
            }

            /* Fullscreen (no browser chrome) */
            @media (display-mode: fullscreen) {
                body { background-color: #fff; }
            }

            /* Picture-in-Picture window */
            @media (display-mode: picture-in-picture) {
                body { background-color: #e2d9f3; }
            }
        </div>

        <div class="manifest-note">
            <strong>📋 How display-mode is set:</strong>
            <ul>
                <li>In a <strong>manifest.json</strong> file: <code>"display": "standalone"</code></li>
                <li>With the <strong>Fullscreen API</strong>: <code>document.documentElement.requestFullscreen()</code></li>
                <li>With the <strong>Picture-in-Picture API</strong>: <code>video.requestPictureInPicture()</code></li>
            </ul>
        </div>
    </section>

    <!-- ====== 2. DYNAMIC-RANGE DEMO ====== -->
    <section>
        <h2>2. dynamic-range</h2>
        <p>Queries the <strong>brightness, contrast, and color depth</strong> capabilities of the display.</p>

        <div class="hdr-demo">
            <div class="image-container">
                🎨 Dynamic Range Demo
            </div>
        </div>

        <div id="dynamic-range-result" class="detection-card" style="margin: 15px 0;">
            <span class="label">Current dynamic range:</span>
            <span class="value" id="current-dynamic-range">Detecting...</span>
        </div>

        <div class="code-block">
            /* Standard Dynamic Range (SDR) — most displays */
            @media (dynamic-range: standard) {
                body {
                    background-color: #e5e5e5;
                    color: #333;
                }
                p {
                    font-size: 1em;
                }
            }

            /* High Dynamic Range (HDR) — HDR displays */
            @media (dynamic-range: high) {
                body {
                    background-color: #f5f5f5;
                    color: #000;
                }
                p {
                    font-size: 1.2em;
                }
            }
        </div>

        <p class="note"><strong>Note:</strong> HDR requires color depth > 24-bit, high contrast, and high peak brightness (1000+ nits). A device that matches <code>high</code> also matches <code>standard</code>.</p>
    </section>

    <!-- ====== 3. DETECTION SUMMARY ====== -->
    <section>
        <h2>3. Your Device's Capabilities</h2>
        <p>Below is a live detection of your display's capabilities.</p>

        <div class="detection-grid">
            <div class="detection-card" id="dm-browser">
                <span class="label">display-mode: browser</span>
                <span class="value" id="dm-browser-value">Detecting...</span>
            </div>
            <div class="detection-card" id="dm-standalone">
                <span class="label">display-mode: standalone</span>
                <span class="value" id="dm-standalone-value">Detecting...</span>
            </div>
            <div class="detection-card" id="dm-minimal-ui">
                <span class="label">display-mode: minimal-ui</span>
                <span class="value" id="dm-minimal-ui-value">Detecting...</span>
            </div>
            <div class="detection-card" id="dm-fullscreen">
                <span class="label">display-mode: fullscreen</span>
                <span class="value" id="dm-fullscreen-value">Detecting...</span>
            </div>
            <div class="detection-card" id="dm-pip">
                <span class="label">display-mode: picture-in-picture</span>
                <span class="value" id="dm-pip-value">Detecting...</span>
            </div>
            <div class="detection-card" id="dr-standard">
                <span class="label">dynamic-range: standard</span>
                <span class="value" id="dr-standard-value">Detecting...</span>
            </div>
            <div class="detection-card" id="dr-high">
                <span class="label">dynamic-range: high</span>
                <span class="value" id="dr-high-value">Detecting...</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect display-mode */
            @media (display-mode: browser) { /* Normal browser tab */ }
            @media (display-mode: standalone) { /* Installed PWA */ }
            @media (display-mode: fullscreen) { /* Fullscreen */ }
            @media (display-mode: picture-in-picture) { /* PiP */ }

            /* Detect dynamic-range */
            @media (dynamic-range: standard) { /* SDR display */ }
            @media (dynamic-range: high) { /* HDR display */ }
        </div>
    </section>

    <!-- ====== 4. PRACTICAL EXAMPLE ====== -->
    <section>
        <h2>4. Practical Example: PWA-Aware Styling</h2>
        <p>Styles that adapt when your site is installed as a standalone app.</p>

        <div class="detection-card" id="pwa-status" style="background: #e9ecef; border-color: #6c757d;">
            <span class="label">PWA Status</span>
            <span class="value" id="pwa-status-value">Checking...</span>
        </div>

        <div class="code-block">
            /* Hide browser-specific UI in standalone mode */
            @media (display-mode: standalone) {
                .browser-only {
                    display: none;
                }
                .standalone-only {
                    display: block;
                }
            }

            @media (display-mode: browser) {
                .standalone-only {
                    display: none;
                }
            }
        </div>

        <p class="browser-only" style="display: block; padding: 15px; background: #cce5ff; border-radius: 8px; margin-top: 15px;">
            🌐 You're viewing this in a <strong>browser tab</strong>. Install this site as a PWA to see standalone styles!
        </p>
        <p class="standalone-only" style="display: none; padding: 15px; background: #d4edda; border-radius: 8px; margin-top: 15px;">
            📱 You're viewing this as a <strong>standalone app</strong>! Enjoy the app-like experience.
        </p>
    </section>

    <!-- ====== 5. REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>display-mode Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>How to Set</th>
            </tr>
            <tr>
                <td><code>browser</code></td>
                <td>Normal browser tab or window</td>
                <td>Default</td>
            </tr>
            <tr>
                <td><code>standalone</code></td>
                <td>Installed as a standalone app (PWA)</td>
                <td>Manifest: <code>"display": "standalone"</code></td>
            </tr>
            <tr>
                <td><code>minimal-ui</code></td>
                <td>Standalone with minimal browser UI</td>
                <td>Manifest: <code>"display": "minimal-ui"</code></td>
            </tr>
            <tr>
                <td><code>fullscreen</code></td>
                <td>Full screen (no browser chrome)</td>
                <td>Fullscreen API</td>
            </tr>
            <tr>
                <td><code>picture-in-picture</code></td>
                <td>Picture-in-Picture window</td>
                <td>PiP API</td>
            </tr>
            <tr>
                <td><code>window-controls-overlay</code></td>
                <td>PWA with window controls overlay</td>
                <td>Manifest: <code>"display_override"</code></td>
            </tr>
        </table>

        <h3>dynamic-range Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Requirements</th>
            </tr>
            <tr>
                <td><code>standard</code></td>
                <td>Standard Dynamic Range (SDR)</td>
                <td>Typical displays (8-bit color)</td>
            </tr>
            <tr>
                <td><code>high</code></td>
                <td>High Dynamic Range (HDR)</td>
                <td>Color depth > 24-bit, high contrast, high peak brightness</td>
            </tr>
        </table>

        <h3>HDR Requirements</h3>
        <table class="reference-table">
            <tr>
                <th>Requirement</th>
                <th>Minimum</th>
                <th>Typical HDR</th>
            </tr>
            <tr>
                <td>Color depth</td>
                <td>> 24-bit</td>
                <td>30-bit or 36-bit</td>
            </tr>
            <tr>
                <td>Peak brightness</td>
                <td>—</td>
                <td>1000+ nits</td>
            </tr>
            <tr>
                <td>Contrast ratio</td>
                <td>—</td>
                <td>High (10000:1+)</td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>display-mode</code> to adapt your PWA's UI in standalone mode</li>
                <li>Hide browser-specific UI (like "Add to Home Screen" prompts) in standalone mode</li>
                <li>Use <code>dynamic-range</code> to enhance visuals on HDR displays</li>
                <li>Always provide a <code>standard</code> fallback for SDR displays</li>
                <li>Test your PWA in both browser and standalone modes</li>
                <li>Use the Fullscreen API to test <code>fullscreen</code> mode</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't assume all users are in <code>browser</code> mode</li>
                <li>Don't forget to handle the <code>standalone</code> case for PWAs</li>
                <li>Don't use HDR colors without a <code>standard</code> fallback</li>
                <li>Don't rely on <code>display-mode</code> for critical functionality</li>
                <li>Don't confuse <code>dynamic-range</code> with <code>color-gamut</code> (they're different!)</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator" id="live-indicator">Detecting...</div>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        // Display mode detection
        const displayModes = [
            { id: 'dm-browser', value: 'browser' },
            { id: 'dm-standalone', value: 'standalone' },
            { id: 'dm-minimal-ui', value: 'minimal-ui' },
            { id: 'dm-fullscreen', value: 'fullscreen' },
            { id: 'dm-pip', value: 'picture-in-picture' }
        ];

        function updateDisplayModes() {
            displayModes.forEach(mode => {
                const card = document.getElementById(mode.id);
                const valueEl = card.querySelector('.value');
                const query = `(display-mode: ${mode.value})`;

                if (window.matchMedia(query).matches) {
                    valueEl.textContent = 'Active ✅';
                    card.style.background = '#d4edda';
                    card.style.borderColor = '#28a745';
                    valueEl.style.color = '#28a745';
                } else {
                    valueEl.textContent = 'Inactive';
                    card.style.background = '#e9ecef';
                    card.style.borderColor = '#6c757d';
                    valueEl.style.color = '#6c757d';
                }
            });
        }

        // Dynamic range detection
        function updateDynamicRange() {
            const standardCard = document.getElementById('dr-standard');
            const highCard = document.getElementById('dr-high');
            const indicator = document.getElementById('live-indicator');

            const isStandard = window.matchMedia('(dynamic-range: standard)').matches;
            const isHigh = window.matchMedia('(dynamic-range: high)').matches;

            if (isStandard) {
                standardCard.querySelector('.value').textContent = 'Supported ✅';
                standardCard.style.background = '#cce5ff';
                standardCard.style.borderColor = '#007bff';
                standardCard.querySelector('.value').style.color = '#007bff';
            }

            if (isHigh) {
                highCard.querySelector('.value').textContent = 'Supported ✅';
                highCard.style.background = '#fff3cd';
                highCard.style.borderColor = '#ffc107';
                highCard.querySelector('.value').style.color = '#856404';
                indicator.textContent = '✨ HDR Display';
                indicator.style.background = '#ffc107';
                indicator.style.color = '#333';
            } else {
                highCard.querySelector('.value').textContent = 'Not supported';
                highCard.style.background = '#e9ecef';
                highCard.style.borderColor = '#6c757d';
                highCard.querySelector('.value').style.color = '#6c757d';
                indicator.textContent = '🎨 SDR Display';
                indicator.style.background = '#007bff';
                indicator.style.color = 'white';
            }
        }

        // Current display mode detection
        function showDisplayMode() {
            const modes = ['browser', 'standalone', 'minimal-ui', 'fullscreen', 'picture-in-picture'];
            let current = 'unknown';
            for (const mode of modes) {
                if (window.matchMedia(`(display-mode: ${mode})`).matches) {
                    current = mode;
                    break;
                }
            }
            document.getElementById('current-display-mode').textContent = current;
        }

        // Fullscreen API
        function enterFullscreen() {
            document.documentElement.requestFullscreen().catch(err => {
                alert('Fullscreen not supported or denied: ' + err.message);
            });
        }

        function exitFullscreen() {
            if (document.fullscreenElement) {
                document.exitFullscreen();
            }
        }

        // Picture-in-Picture (needs a video element)
        function requestPiP() {
            alert('Picture-in-Picture requires a video element. Open a video in PiP mode to see this display mode!');
        }

        // PWA status
        function updatePWAStatus() {
            const el = document.getElementById('pwa-status-value');
            if (window.matchMedia('(display-mode: standalone)').matches) {
                el.textContent = '📱 Standalone (Installed)';
                el.style.color = '#28a745';
            } else {
                el.textContent = '🌐 Browser Tab';
                el.style.color = '#007bff';
            }
        }

        // Update all
        function updateAll() {
            updateDisplayModes();
            updateDynamicRange();
            updatePWAStatus();
            showDisplayMode();
        }

        window.addEventListener('load', updateAll);
        window.addEventListener('resize', updateAll);

        // Listen for fullscreen changes
        document.addEventListener('fullscreenchange', updateAll);

        // Listen for PiP changes
        document.addEventListener('enterpictureinpicture', updateAll);
        document.addEventListener('leavepictureinpicture', updateAll);

        updateAll();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionValues
display-modeHow the document is displayedbrowser, standalone, minimal-ui, fullscreen, picture-in-picture
dynamic-rangeBrightness, contrast, color depthstandard, high

display-mode Values

ValueDescriptionHow to Set
browserNormal browser tabDefault
standaloneInstalled PWAManifest: "display": "standalone"
minimal-uiStandalone with minimal UIManifest: "display": "minimal-ui"
fullscreenFull screenFullscreen API
picture-in-picturePiP windowPiP API

dynamic-range Values

ValueDescriptionRequirements
standardStandard Dynamic Range (SDR)Typical displays (8-bit)
highHigh Dynamic Range (HDR)Color depth > 24-bit, high contrast, high brightness

Best Practices

Do This:

/* Adapt PWA UI in standalone mode */
@media (display-mode: standalone) {
    .browser-only {
        display: none;
    }
    .standalone-only {
        display: block;
    }
}

/* Enhance visuals on HDR displays */
@media (dynamic-range: high) {
    .hero {
        background: linear-gradient(135deg, oklch(69% 0.27 240), oklch(69% 0.27 300));
    }
}

/* Standard fallback */
.hero {
    background: linear-gradient(135deg, #007bff, #6c5ce7);
}

Don’t Do This:

/* Don't assume all users are in browser mode */
.browser-only {
    display: block; /* May show in standalone too */
}

/* Don't use HDR without fallback */
.hero {
    background: oklch(69% 0.27 240); /* May look wrong on SDR */
}

/* Don't confuse dynamic-range with color-gamut */
@media (dynamic-range: high) {
    /* HDR is about brightness/contrast, not just color */
}

Pro Tip: display-mode is essential for Progressive Web Apps (PWAs). Use it to hide browser-specific UI (like “Add to Home Screen” prompts) when your app is installed as a standalone app. dynamic-range is your key to HDR-enhanced visuals — but remember, HDR is about brightness and contrast, not just color. Always provide a standard fallback first, then enhance for high dynamic range displays. The two features work great together: one for app-like experiences, the other for visually stunning displays!

35. forced-colors and grid Media Features

These two media features let you adapt styles for accessibility (high-contrast mode) and legacy devices (grid-based screens).


Overview of Features

FeatureDescriptionValues
forced-colorsDetects forced colors mode (e.g., Windows High Contrast)none, active
gridDetects if the device uses a grid-based screen0, 1

1. forced-colors

The forced-colors media feature detects when the user agent has forced colors mode enabled — such as Windows High Contrast mode or similar accessibility features.

@media (forced-colors: active) {
    button {
        border: 1px solid ButtonBorder;
    }
}

Values

ValueDescription
noneForced colors mode is not active (default)
activeForced colors mode is active

What Happens in Forced Colors Mode

When forced colors mode is active, the browser overrides many CSS properties:

PropertyForced To
box-shadownone
text-shadownone
background-imagenone
color-schemelight dark
scrollbar-colorauto
colorSystem color
background-colorSystem color
border-colorSystem color
outline-colorSystem color
text-decoration-colorSystem color
column-rule-colorSystem color

System Colors

You can use system colors that adapt to the user’s forced colors theme:

System ColorDescription
CanvasBackground of the document
CanvasTextText color
LinkTextLink color
ButtonFaceButton background
ButtonTextButton text
ButtonBorderButton border
HighlightSelected item background
HighlightTextSelected item text
GrayTextDisabled text
FieldInput field background
FieldTextInput field text
/* Use system colors in forced colors mode */
@media (forced-colors: active) {
    button {
        border: 1px solid ButtonBorder;
        background: ButtonFace;
        color: ButtonText;
    }
}

2. grid

The grid media feature checks whether the output device uses a grid-based screen (like old text-only terminals) or a bitmap-based screen (like modern computers and smartphones).

@media (grid: 0) {
    .text {
        color: red;
    }
}

@media (grid: 1) {
    .text {
        color: black;
    }
}

Values

ValueDescription
0Bitmap-based screen (modern devices)
1Grid-based screen (text-only terminals)

Grid vs Bitmap

Screen TypeDescriptionExamples
BitmapPixel-based, can display any imageComputers, smartphones, tablets
GridCharacter-based, fixed grid of charactersText-only terminals, old phones, braille displays

Key Points:

  • Modern devices almost always match grid: 0
  • Grid-based devices are rare (legacy or specialized)
  • Use grid: 1 to optimize for text-only terminals
  • Most developers will never need this feature — it’s for extreme edge cases

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>forced-colors and grid Media Features</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
            transition: background 0.3s, color 0.3s;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
            transition: background 0.3s;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== BUTTON STYLES ====== */
        button {
            padding: 12px 24px;
            color: white;
            background-color: #007bff;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-size: 1em;
            font-weight: bold;
            transition: all 0.3s;
            margin: 5px;
        }

        button:hover {
            background-color: #0056b3;
            transform: translateY(-2px);
        }

        button.btn-danger {
            background-color: #dc3545;
        }
        button.btn-danger:hover {
            background-color: #a71d2a;
        }

        button.btn-success {
            background-color: #28a745;
        }
        button.btn-success:hover {
            background-color: #1e7e34;
        }

        button.btn-warning {
            background-color: #ffc107;
            color: #333;
        }
        button.btn-warning:hover {
            background-color: #d39e00;
        }

        /* ====== FORCED COLORS DEMO ====== */
        .forced-colors-demo {
            padding: 20px;
            border-radius: 8px;
            background: #e9ecef;
            margin: 15px 0;
            border: 2px solid #ddd;
            transition: all 0.3s;
        }

        .forced-colors-demo .demo-box {
            padding: 15px;
            background: #007bff;
            color: white;
            border-radius: 8px;
            margin: 10px 0;
            text-align: center;
            font-weight: bold;
            transition: all 0.3s;
        }

        /* Forced colors mode styles */
        @media (forced-colors: active) {
            body {
                background: Canvas;
                color: CanvasText;
            }
            section {
                background: Canvas;
                border: 1px solid CanvasText;
            }
            h1, h2, h3 {
                color: CanvasText;
            }
            h1 {
                border-bottom-color: CanvasText;
            }
            h2 {
                border-left-color: CanvasText;
            }
            .forced-colors-demo {
                background: Canvas;
                border: 1px solid CanvasText;
            }
            .forced-colors-demo .demo-box {
                background: ButtonFace;
                color: ButtonText;
                border: 1px solid ButtonBorder;
            }
            button {
                border: 1px solid ButtonBorder;
                background: ButtonFace;
                color: ButtonText;
            }
            button:hover {
                background: Highlight;
                color: HighlightText;
            }
            .code-block {
                background: Canvas;
                color: CanvasText;
                border: 1px solid CanvasText;
            }
            .reference-table th {
                background: ButtonFace;
                color: ButtonText;
                border: 1px solid ButtonBorder;
            }
            .reference-table td {
                border: 1px solid CanvasText;
            }
            .reference-table tr:nth-child(even) {
                background: Canvas;
            }
            a {
                color: LinkText;
            }
            .highlight {
                background: Highlight;
                color: HighlightText;
            }
        }

        /* ====== GRID DEMO ====== */
        .grid-demo {
            padding: 20px;
            border-radius: 8px;
            background: #e9ecef;
            margin: 15px 0;
            border: 2px solid #ddd;
            transition: all 0.3s;
        }

        .grid-demo .header {
            font-size: 1.2rem;
            font-weight: bold;
            margin-bottom: 10px;
            transition: color 0.3s;
        }

        .grid-demo .text {
            transition: color 0.3s;
        }

        /* Bitmap-based screen (modern devices) */
        @media (grid: 0) {
            .grid-demo .header {
                color: #6c757d;
            }
            .grid-demo .text {
                color: #dc3545;
            }
        }

        /* Grid-based screen (text-only terminals) */
        @media (grid: 1) {
            .grid-demo .header {
                color: #6c757d;
            }
            .grid-demo .text {
                color: #000;
            }
        }

        /* ====== DETECTION CARDS ====== */
        .detection-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .detection-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            border: 2px solid #ddd;
            background: #f8f9fa;
            transition: all 0.3s;
        }

        .detection-card .label {
            font-size: 0.85rem;
            color: #666;
            display: block;
            margin-bottom: 5px;
        }

        .detection-card .value {
            font-size: 1.1rem;
            font-weight: bold;
            color: #007bff;
        }

        /* ====== SYSTEM COLORS DEMO ====== */
        .system-colors-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 10px;
            margin: 15px 0;
        }

        .system-color-box {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            border: 2px solid #ddd;
            transition: all 0.3s;
        }

        /* Default colors */
        .sys-canvas { background: #ffffff; color: #000000; }
        .sys-canvastext { background: #f0f0f0; color: #000000; }
        .sys-linktext { background: #e0e0ff; color: #0000ff; }
        .sys-buttonface { background: #e9ecef; color: #333; }
        .sys-buttontext { background: #007bff; color: #ffffff; }
        .sys-buttonborder { background: #e9ecef; color: #333; border: 3px solid #007bff; }
        .sys-highlight { background: #ffc107; color: #333; }
        .sys-highlighttext { background: #fff3cd; color: #856404; }
        .sys-graytext { background: #e9ecef; color: #999; }
        .sys-field { background: #ffffff; color: #333; border: 2px solid #ccc; }
        .sys-fieldtext { background: #ffffff; color: #333; }

        /* Forced colors mode: use system colors */
        @media (forced-colors: active) {
            .sys-canvas { background: Canvas; color: CanvasText; }
            .sys-canvastext { background: Canvas; color: CanvasText; }
            .sys-linktext { background: Canvas; color: LinkText; }
            .sys-buttonface { background: ButtonFace; color: ButtonText; }
            .sys-buttontext { background: ButtonFace; color: ButtonText; }
            .sys-buttonborder { background: ButtonFace; color: ButtonText; border-color: ButtonBorder; }
            .sys-highlight { background: Highlight; color: HighlightText; }
            .sys-highlighttext { background: Highlight; color: HighlightText; }
            .sys-graytext { background: Canvas; color: GrayText; }
            .sys-field { background: Field; color: FieldText; }
            .sys-fieldtext { background: Field; color: FieldText; }
        }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #007bff;
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px rgba(0,123,255,0.4);
            z-index: 1000;
            transition: all 0.3s;
        }

        @media (forced-colors: active) {
            .live-indicator {
                background: Highlight;
                color: HighlightText;
                border: 1px solid ButtonBorder;
                box-shadow: none;
            }
        }

        /* ====== BEST PRACTICE DEMO ====== */
        .best-practice-card {
            background: white;
            border: 2px solid #ddd;
            border-radius: 12px;
            padding: 20px;
            max-width: 400px;
            margin: 20px auto;
            text-align: center;
            box-shadow: 0 4px 15px rgba(0,0,0,0.1);
            transition: all 0.3s;
        }

        .best-practice-card h3 {
            margin-top: 0;
            color: #007bff;
        }

        .best-practice-card .btn {
            display: inline-block;
            padding: 12px 30px;
            background: #007bff;
            color: white;
            border-radius: 8px;
            text-decoration: none;
            font-weight: bold;
            margin-top: 10px;
            transition: all 0.3s;
        }

        .best-practice-card .btn:hover {
            background: #28a745;
            transform: scale(1.02);
        }

        @media (forced-colors: active) {
            .best-practice-card {
                background: Canvas;
                border: 1px solid CanvasText;
                box-shadow: none;
            }
            .best-practice-card h3 {
                color: CanvasText;
            }
            .best-practice-card .btn {
                background: ButtonFace;
                color: ButtonText;
                border: 1px solid ButtonBorder;
            }
            .best-practice-card .btn:hover {
                background: Highlight;
                color: HighlightText;
            }
        }
    </style>
</head>
<body>

    <h1>forced-colors and grid Media Features</h1>

    <!-- ====== 1. FORCED-COLORS DEMO ====== -->
    <section>
        <h2>1. forced-colors</h2>
        <p>Detects when the user has <strong>forced colors mode</strong> enabled (e.g., Windows High Contrast).</p>

        <div class="forced-colors-demo">
            <h3>Forced Colors Demo</h3>
            <p>This box adapts to forced colors mode:</p>
            <div class="demo-box">
                I change colors in forced colors mode!
            </div>

            <div style="margin-top: 15px;">
                <button>Primary Button</button>
                <button class="btn-danger">Danger Button</button>
                <button class="btn-success">Success Button</button>
                <button class="btn-warning">Warning Button</button>
            </div>
        </div>

        <p class="note">
            <strong>Try it:</strong> Enable Windows High Contrast mode or a similar accessibility feature to see these styles change.
        </p>

        <div class="code-block">
            /* Detect forced colors mode */
            @media (forced-colors: active) {
                button {
                    border: 1px solid ButtonBorder;
                    background: ButtonFace;
                    color: ButtonText;
                }
                button:hover {
                    background: Highlight;
                    color: HighlightText;
                }
            }
        </div>
    </section>

    <!-- ====== 2. SYSTEM COLORS DEMO ====== -->
    <section>
        <h2>2. System Colors</h2>
        <p>System colors adapt to the user's forced colors theme.</p>

        <div class="system-colors-grid">
            <div class="system-color-box sys-canvas">Canvas</div>
            <div class="system-color-box sys-canvastext">CanvasText</div>
            <div class="system-color-box sys-linktext">LinkText</div>
            <div class="system-color-box sys-buttonface">ButtonFace</div>
            <div class="system-color-box sys-buttontext">ButtonText</div>
            <div class="system-color-box sys-buttonborder">ButtonBorder</div>
            <div class="system-color-box sys-highlight">Highlight</div>
            <div class="system-color-box sys-highlighttext">HighlightText</div>
            <div class="system-color-box sys-graytext">GrayText</div>
            <div class="system-color-box sys-field">Field</div>
            <div class="system-color-box sys-fieldtext">FieldText</div>
        </div>

        <div class="code-block">
            /* System colors adapt automatically */
            .button {
                background: ButtonFace;
                color: ButtonText;
                border: 1px solid ButtonBorder;
            }

            .selected {
                background: Highlight;
                color: HighlightText;
            }

            .disabled {
                color: GrayText;
            }

            input {
                background: Field;
                color: FieldText;
            }
        </div>
    </section>

    <!-- ====== 3. GRID DEMO ====== -->
    <section>
        <h2>3. grid</h2>
        <p>Detects whether the device uses a <strong>grid-based screen</strong> (text-only terminal) or <strong>bitmap-based screen</strong> (modern device).</p>

        <div class="grid-demo">
            <div class="header">Header (always gray)</div>
            <div class="text">
                This text is <span class="highlight">red</span> on bitmap screens and <span class="highlight">black</span> on grid-based screens.
            </div>
        </div>

        <div id="grid-detection" class="detection-card" style="margin: 15px 0;">
            <span class="label">Current screen type:</span>
            <span class="value" id="grid-value">Detecting...</span>
        </div>

        <div class="code-block">
            /* Bitmap-based screen (modern devices) */
            @media (grid: 0) {
                .text {
                    color: red;
                }
            }

            /* Grid-based screen (text-only terminals) */
            @media (grid: 1) {
                .text {
                    color: black;
                }
            }
        </div>

        <p class="note"><strong>Note:</strong> Modern devices almost always match <code>grid: 0</code>. Grid-based devices are rare (legacy terminals, braille displays).</p>
    </section>

    <!-- ====== 4. DETECTION SUMMARY ====== -->
    <section>
        <h2>4. Your Device's Capabilities</h2>
        <p>Below is a live detection of your device's capabilities.</p>

        <div class="detection-grid">
            <div class="detection-card" id="fc-active">
                <span class="label">forced-colors: active</span>
                <span class="value" id="fc-active-value">Detecting...</span>
            </div>
            <div class="detection-card" id="fc-none">
                <span class="label">forced-colors: none</span>
                <span class="value" id="fc-none-value">Detecting...</span>
            </div>
            <div class="detection-card" id="grid-0">
                <span class="label">grid: 0 (bitmap)</span>
                <span class="value" id="grid-0-value">Detecting...</span>
            </div>
            <div class="detection-card" id="grid-1">
                <span class="label">grid: 1 (grid-based)</span>
                <span class="value" id="grid-1-value">Detecting...</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect forced colors */
            @media (forced-colors: active) { /* Forced colors ON */ }
            @media (forced-colors: none) { /* Forced colors OFF */ }

            /* Detect screen type */
            @media (grid: 0) { /* Bitmap screen */ }
            @media (grid: 1) { /* Grid-based screen */ }
        </div>
    </section>

    <!-- ====== 5. PRACTICAL EXAMPLE ====== -->
    <section>
        <h2>5. Practical Example: Accessible Card</h2>
        <p>This card is fully accessible in forced colors mode.</p>

        <div class="best-practice-card">
            <h3>📱 Accessible Card</h3>
            <p>This card uses system colors and proper borders to remain usable in forced colors mode.</p>
            <a href="#" class="btn">Learn More</a>
        </div>

        <div class="code-block">
            /* Default styles */
            .card {
                background: white;
                border: 2px solid #ddd;
            }

            /* Forced colors mode */
            @media (forced-colors: active) {
                .card {
                    background: Canvas;
                    border: 1px solid CanvasText;
                }
                .card .btn {
                    background: ButtonFace;
                    color: ButtonText;
                    border: 1px solid ButtonBorder;
                }
            }
        </div>
    </section>

    <!-- ====== 6. REFERENCE TABLES ====== -->
    <section>
        <h2>6. Reference Tables</h2>

        <h3>forced-colors Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>Forced colors mode is not active (default)</td>
            </tr>
            <tr>
                <td><code>active</code></td>
                <td>Forced colors mode is active</td>
            </tr>
        </table>

        <h3>Properties Forced in Forced Colors Mode</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Forced To</th>
            </tr>
            <tr>
                <td><code>box-shadow</code></td>
                <td><code>none</code></td>
            </tr>
            <tr>
                <td><code>text-shadow</code></td>
                <td><code>none</code></td>
            </tr>
            <tr>
                <td><code>background-image</code></td>
                <td><code>none</code></td>
            </tr>
            <tr>
                <td><code>color-scheme</code></td>
                <td><code>light dark</code></td>
            </tr>
            <tr>
                <td><code>scrollbar-color</code></td>
                <td><code>auto</code></td>
            </tr>
        </table>

        <h3>Common System Colors</h3>
        <table class="reference-table">
            <tr>
                <th>System Color</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>Canvas</code></td>
                <td>Background of the document</td>
            </tr>
            <tr>
                <td><code>CanvasText</code></td>
                <td>Text color</td>
            </tr>
            <tr>
                <td><code>LinkText</code></td>
                <td>Link color</td>
            </tr>
            <tr>
                <td><code>ButtonFace</code></td>
                <td>Button background</td>
            </tr>
            <tr>
                <td><code>ButtonText</code></td>
                <td>Button text</td>
            </tr>
            <tr>
                <td><code>ButtonBorder</code></td>
                <td>Button border</td>
            </tr>
            <tr>
                <td><code>Highlight</code></td>
                <td>Selected item background</td>
            </tr>
            <tr>
                <td><code>HighlightText</code></td>
                <td>Selected item text</td>
            </tr>
            <tr>
                <td><code>GrayText</code></td>
                <td>Disabled text</td>
            </tr>
            <tr>
                <td><code>Field</code></td>
                <td>Input field background</td>
            </tr>
            <tr>
                <td><code>FieldText</code></td>
                <td>Input field text</td>
            </tr>
        </table>

        <h3>grid Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Examples</th>
            </tr>
            <tr>
                <td><code>0</code></td>
                <td>Bitmap-based screen (modern)</td>
                <td>Computers, smartphones, tablets</td>
            </tr>
            <tr>
                <td><code>1</code></td>
                <td>Grid-based screen (character-based)</td>
                <td>Text-only terminals, braille displays</td>
            </tr>
        </table>
    </section>

    <!-- ====== 7. BEST PRACTICES ====== -->
    <section>
        <h2>7. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>forced-colors</code> to ensure your site is usable in high-contrast mode</li>
                <li>Use <strong>system colors</strong> (ButtonFace, CanvasText, etc.) for forced colors mode</li>
                <li>Add borders to elements that rely on background color for boundaries</li>
                <li>Test your site with Windows High Contrast mode enabled</li>
                <li>Use <code>grid</code> only if you need to support text-only terminals</li>
                <li>Provide meaningful content even without images or shadows</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't rely solely on background colors to convey meaning</li>
                <li>Don't use box-shadows as the only visual separator in forced colors mode</li>
                <li>Don't forget to test with accessibility features enabled</li>
                <li>Don't use <code>grid: 1</code> styles for modern devices (they won't match)</li>
                <li>Don't ignore forced colors mode — it affects millions of users</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator" id="live-indicator">Detecting...</div>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        function updateIndicators() {
            const indicator = document.getElementById('live-indicator');

            // Forced colors detection
            const fcActive = document.getElementById('fc-active');
            const fcNone = document.getElementById('fc-none');

            const isForcedColors = window.matchMedia('(forced-colors: active)').matches;

            if (isForcedColors) {
                fcActive.querySelector('.value').textContent = 'Active ✅';
                fcActive.style.background = '#fff3cd';
                fcActive.style.borderColor = '#ffc107';
                fcActive.querySelector('.value').style.color = '#856404';

                fcNone.querySelector('.value').textContent = 'Inactive';
                fcNone.style.background = '#e9ecef';
                fcNone.style.borderColor = '#6c757d';
                fcNone.querySelector('.value').style.color = '#6c757d';

                indicator.textContent = '♿ Forced Colors Active';
                indicator.style.background = '#ffc107';
                indicator.style.color = '#333';
            } else {
                fcActive.querySelector('.value').textContent = 'Not active';
                fcActive.style.background = '#e9ecef';
                fcActive.style.borderColor = '#6c757d';
                fcActive.querySelector('.value').style.color = '#6c757d';

                fcNone.querySelector('.value').textContent = 'Active (default) ✅';
                fcNone.style.background = '#d4edda';
                fcNone.style.borderColor = '#28a745';
                fcNone.querySelector('.value').style.color = '#28a745';

                indicator.textContent = '🎨 Normal Colors';
                indicator.style.background = '#007bff';
                indicator.style.color = 'white';
            }

            // Grid detection
            const grid0 = document.getElementById('grid-0');
            const grid1 = document.getElementById('grid-1');
            const gridValue = document.getElementById('grid-value');

            if (window.matchMedia('(grid: 0)').matches) {
                grid0.querySelector('.value').textContent = 'Bitmap ✅';
                grid0.style.background = '#cce5ff';
                grid0.style.borderColor = '#007bff';
                grid0.querySelector('.value').style.color = '#007bff';

                grid1.querySelector('.value').textContent = 'Not grid-based';
                grid1.style.background = '#e9ecef';
                grid1.style.borderColor = '#6c757d';
                grid1.querySelector('.value').style.color = '#6c757d';

                if (gridValue) gridValue.textContent = '🖥️ Bitmap-based screen (modern device)';
            } else if (window.matchMedia('(grid: 1)').matches) {
                grid1.querySelector('.value').textContent = 'Grid-based ✅';
                grid1.style.background = '#fff3cd';
                grid1.style.borderColor = '#ffc107';
                grid1.querySelector('.value').style.color = '#856404';

                grid0.querySelector('.value').textContent = 'Not bitmap';
                grid0.style.background = '#e9ecef';
                grid0.style.borderColor = '#6c757d';
                grid0.querySelector('.value').style.color = '#6c757d';

                if (gridValue) gridValue.textContent = '📟 Grid-based screen (text-only terminal)';
            }
        }

        window.addEventListener('load', updateIndicators);

        // Listen for forced colors changes
        window.matchMedia('(forced-colors: active)').addEventListener('change', updateIndicators);

        updateIndicators();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionValues
forced-colorsDetects forced colors modenone, active
gridDetects grid-based screens0, 1

forced-colors Values

ValueDescription
noneForced colors mode is not active (default)
activeForced colors mode is active

Properties Forced in Forced Colors Mode

PropertyForced To
box-shadownone
text-shadownone
background-imagenone
color-schemelight dark
scrollbar-colorauto

Common System Colors

System ColorDescription
CanvasBackground of the document
CanvasTextText color
LinkTextLink color
ButtonFaceButton background
ButtonTextButton text
ButtonBorderButton border
HighlightSelected item background
HighlightTextSelected item text
GrayTextDisabled text
FieldInput field background
FieldTextInput field text

grid Values

ValueDescriptionExamples
0Bitmap-based screen (modern)Computers, smartphones, tablets
1Grid-based screen (character-based)Text-only terminals, braille displays

Best Practices

Do This:

/* Support forced colors mode */
@media (forced-colors: active) {
    button {
        border: 1px solid ButtonBorder;
        background: ButtonFace;
        color: ButtonText;
    }
    button:hover {
        background: Highlight;
        color: HighlightText;
    }
}

/* Use system colors for accessibility */
.card {
    background: Canvas;
    color: CanvasText;
    border: 1px solid CanvasText;
}

/* Optimize for grid-based devices */
@media (grid: 1) {
    .text {
        color: black;
    }
}

Don’t Do This:

/* Don't rely on shadows for boundaries */
.card {
    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
    /* Shadow disappears in forced colors mode! */
}

/* Don't rely on background colors alone */
.error {
    background: #ff0000; /* May not be visible in high contrast */
}

/* Don't ignore forced colors mode */
/* Test with Windows High Contrast mode! */

Pro Tip: forced-colors is essential for accessibility. Millions of users rely on high-contrast modes due to visual impairments. Always test your site with Windows High Contrast mode or similar features. Use system colors (ButtonFace, CanvasText, etc.) and add borders to elements that rely on background colors for boundaries. grid is a legacy feature — modern devices almost always match grid: 0, but it’s good to know for extreme

36. height and width Media Features

These two media features are the cornerstones of responsive design. They let you apply styles based on the viewport’s dimensions, enabling layouts that adapt to any screen size.


Overview of Features

FeatureDescriptionValues
heightViewport heightExact, min-height, max-height
widthViewport widthExact, min-width, max-width

1. height

The height media feature applies styles based on the height of the viewport (or the dimensions of an embedded document).

@media (height: 1024px) {
    .container {
        background-color: pink;
    }
}

Variations

FeatureDescriptionExample
heightExact height@media (height: 1024px)
min-heightMinimum height@media (min-height: 1024px)
max-heightMaximum height@media (max-height: 1200px)

Syntax

height: <length>
height: >= 1024px
height: < 1200px
height: 1024px

Common Use Cases

Use CaseExample
Mobile landscape@media (max-height: 500px)
Tall screens@media (min-height: 900px)
Short screens@media (max-height: 600px)
Full-screen sections@media (min-height: 100vh)

2. width

The width media feature applies styles based on the width of the viewport.

@media (min-width: 780px) {
    .container {
        background-color: red;
    }
}

Variations

FeatureDescriptionExample
widthExact width@media (width: 780px)
min-widthMinimum width@media (min-width: 780px)
max-widthMaximum width@media (max-width: 1200px)

Syntax

width: <length>
width: >= 780px
width: < 1200px
width: 780px

Common Breakpoints

BreakpointDescription
320pxSmall phones
480pxLarger phones
768pxTablets
1024pxSmall laptops
1200pxDesktops
1440pxLarge desktops
1920pxFull HD displays

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>height and width Media Features</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== WIDTH DEMO ====== */
        .width-demo {
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            font-size: 1.2rem;
            margin: 15px 0;
            transition: all 0.3s;
            background: #e9ecef;
            border: 2px solid #ddd;
        }

        /* Mobile: < 480px */
        @media (max-width: 479px) {
            .width-demo {
                background: #ff6b6b;
                color: white;
                border-color: #c92a2a;
            }
            .width-demo::after {
                content: " 📱 Mobile (< 480px)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Large phones: 480px - 767px */
        @media (min-width: 480px) and (max-width: 767px) {
            .width-demo {
                background: #ffc107;
                color: #333;
                border-color: #d39e00;
            }
            .width-demo::after {
                content: " 📱 Large Phone (480-767px)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Tablets: 768px - 1023px */
        @media (min-width: 768px) and (max-width: 1023px) {
            .width-demo {
                background: #28a745;
                color: white;
                border-color: #1e7e34;
            }
            .width-demo::after {
                content: " 📟 Tablet (768-1023px)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Desktops: 1024px - 1439px */
        @media (min-width: 1024px) and (max-width: 1439px) {
            .width-demo {
                background: #007bff;
                color: white;
                border-color: #0056b3;
            }
            .width-demo::after {
                content: " 💻 Desktop (1024-1439px)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Large Desktops: ≥ 1440px */
        @media (min-width: 1440px) {
            .width-demo {
                background: #6c5ce7;
                color: white;
                border-color: #4a2a9e;
            }
            .width-demo::after {
                content: " 🖥️ Large Desktop (≥ 1440px)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* ====== HEIGHT DEMO ====== */
        .height-demo {
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            font-size: 1.2rem;
            margin: 15px 0;
            transition: all 0.3s;
            background: #e9ecef;
            border: 2px solid #ddd;
            min-height: 150px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }

        /* Short viewport: < 600px */
        @media (max-height: 599px) {
            .height-demo {
                background: #dc3545;
                color: white;
                border-color: #a71d2a;
            }
            .height-demo::after {
                content: " 📏 Short Viewport (< 600px)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Medium viewport: 600px - 899px */
        @media (min-height: 600px) and (max-height: 899px) {
            .height-demo {
                background: #ffc107;
                color: #333;
                border-color: #d39e00;
            }
            .height-demo::after {
                content: " 📏 Medium Viewport (600-899px)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Tall viewport: ≥ 900px */
        @media (min-height: 900px) {
            .height-demo {
                background: #28a745;
                color: white;
                border-color: #1e7e34;
            }
            .height-demo::after {
                content: " 📏 Tall Viewport (≥ 900px)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* ====== RESPONSIVE GRID DEMO ====== */
        .responsive-grid {
            display: grid;
            gap: 15px;
            margin: 20px 0;
        }

        /* Mobile: 1 column */
        .responsive-grid {
            grid-template-columns: 1fr;
        }

        /* Tablet: 2 columns */
        @media (min-width: 600px) {
            .responsive-grid {
                grid-template-columns: repeat(2, 1fr);
            }
        }

        /* Desktop: 3 columns */
        @media (min-width: 900px) {
            .responsive-grid {
                grid-template-columns: repeat(3, 1fr);
            }
        }

        /* Large Desktop: 4 columns */
        @media (min-width: 1200px) {
            .responsive-grid {
                grid-template-columns: repeat(4, 1fr);
            }
        }

        .responsive-card {
            background: white;
            border: 2px solid #ddd;
            border-radius: 8px;
            padding: 20px;
            text-align: center;
            transition: all 0.3s;
        }

        .responsive-card:hover {
            border-color: #007bff;
            transform: translateY(-3px);
            box-shadow: 0 4px 15px rgba(0,123,255,0.15);
        }

        .responsive-card .icon {
            font-size: 2.5rem;
            display: block;
            margin-bottom: 10px;
        }

        .responsive-card .title {
            font-weight: bold;
            color: #007bff;
            margin-bottom: 5px;
        }

        .responsive-card .desc {
            font-size: 0.85rem;
            color: #6c757d;
        }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #007bff;
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px rgba(0,123,255,0.4);
            z-index: 1000;
            transition: all 0.3s;
            display: flex;
            flex-direction: column;
            gap: 3px;
        }

        .live-indicator .dimension {
            font-size: 0.75rem;
            opacity: 0.9;
        }

        /* ====== VIEWPORT VISUALIZATION ====== */
        .viewport-viz {
            position: relative;
            background: #e9ecef;
            border: 2px dashed #007bff;
            border-radius: 8px;
            padding: 20px;
            margin: 20px 0;
            min-height: 200px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            text-align: center;
        }

        .viewport-viz .dimension-label {
            position: absolute;
            font-weight: bold;
            color: #007bff;
            font-size: 0.85rem;
        }

        .viewport-viz .width-label {
            top: -12px;
            left: 50%;
            transform: translateX(-50%);
            background: white;
            padding: 2px 10px;
            border-radius: 4px;
            border: 1px solid #007bff;
        }

        .viewport-viz .height-label {
            right: -12px;
            top: 50%;
            transform: translateY(-50%) rotate(90deg);
            background: white;
            padding: 2px 10px;
            border-radius: 4px;
            border: 1px solid #007bff;
            white-space: nowrap;
        }

        .viewport-viz .content {
            font-size: 1.1rem;
            font-weight: bold;
            color: #333;
        }

        /* ====== PRACTICAL: RESPONSIVE NAVBAR ====== */
        .navbar {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            padding: 15px;
            background: #007bff;
            border-radius: 8px;
            margin: 15px 0;
            transition: all 0.3s;
        }

        .navbar a {
            color: white;
            text-decoration: none;
            padding: 8px 16px;
            border-radius: 6px;
            transition: background 0.3s;
            font-weight: bold;
        }

        .navbar a:hover {
            background: rgba(255,255,255,0.2);
        }

        /* Mobile: vertical stack */
        @media (max-width: 599px) {
            .navbar {
                flex-direction: column;
                background: #dc3545;
            }
            .navbar a {
                text-align: center;
            }
        }

        /* Desktop: horizontal row */
        @media (min-width: 600px) {
            .navbar {
                flex-direction: row;
                justify-content: center;
            }
        }

        /* ====== BEST PRACTICE: MOBILE FIRST ====== */
        .mobile-first-demo {
            padding: 20px;
            border-radius: 8px;
            background: #ff6b6b;
            color: white;
            text-align: center;
            font-weight: bold;
            margin: 15px 0;
            transition: all 0.3s;
        }

        /* Mobile first — base styles */
        .mobile-first-demo::after {
            content: " 📱 Mobile First (base styles)";
            font-weight: normal;
            font-size: 0.85rem;
            display: block;
        }

        /* Tablet and up */
        @media (min-width: 768px) {
            .mobile-first-demo {
                background: #28a745;
            }
            .mobile-first-demo::after {
                content: " 📟 Tablet and up (min-width: 768px)";
            }
        }

        /* Desktop and up */
        @media (min-width: 1024px) {
            .mobile-first-demo {
                background: #007bff;
            }
            .mobile-first-demo::after {
                content: " 💻 Desktop and up (min-width: 1024px)";
            }
        }

        /* Large desktop and up */
        @media (min-width: 1440px) {
            .mobile-first-demo {
                background: #6c5ce7;
            }
            .mobile-first-demo::after {
                content: " 🖥️ Large Desktop and up (min-width: 1440px)";
            }
        }
    </style>
</head>
<body>

    <h1>height and width Media Features</h1>

    <!-- ====== 1. WIDTH DEMO ====== -->
    <section>
        <h2>1. width</h2>
        <p>Applies styles based on the <strong>viewport width</strong>. Resize your browser to see the changes!</p>

        <div class="width-demo">
            Current Width
        </div>

        <div class="viewport-viz">
            <span class="dimension-label width-label" id="width-label">Width: detecting...</span>
            <span class="dimension-label height-label" id="height-label">Height: detecting...</span>
            <div class="content">
                Resize your browser window
            </div>
        </div>

        <div class="code-block">
            /* Mobile: < 480px */
            @media (max-width: 479px) {
                .width-demo { background: #ff6b6b; }
            }

            /* Large phones: 480px - 767px */
            @media (min-width: 480px) and (max-width: 767px) {
                .width-demo { background: #ffc107; }
            }

            /* Tablets: 768px - 1023px */
            @media (min-width: 768px) and (max-width: 1023px) {
                .width-demo { background: #28a745; }
            }

            /* Desktops: 1024px - 1439px */
            @media (min-width: 1024px) and (max-width: 1439px) {
                .width-demo { background: #007bff; }
            }

            /* Large Desktops: ≥ 1440px */
            @media (min-width: 1440px) {
                .width-demo { background: #6c5ce7; }
            }
        </div>
    </section>

    <!-- ====== 2. HEIGHT DEMO ====== -->
    <section>
        <h2>2. height</h2>
        <p>Applies styles based on the <strong>viewport height</strong>. Resize your browser vertically to see the changes!</p>

        <div class="height-demo">
            Current Height
        </div>

        <div class="code-block">
            /* Short viewport: < 600px */
            @media (max-height: 599px) {
                .height-demo { background: #dc3545; }
            }

            /* Medium viewport: 600px - 899px */
            @media (min-height: 600px) and (max-height: 899px) {
                .height-demo { background: #ffc107; }
            }

            /* Tall viewport: ≥ 900px */
            @media (min-height: 900px) {
                .height-demo { background: #28a745; }
            }
        </div>
    </section>

    <!-- ====== 3. RESPONSIVE GRID ====== -->
    <section>
        <h2>3. Practical Example: Responsive Grid</h2>
        <p>This grid adapts from 1 to 4 columns based on the viewport width.</p>

        <div class="responsive-grid">
            <div class="responsive-card">
                <span class="icon">🎨</span>
                <div class="title">Design</div>
                <div class="desc">Beautiful interfaces</div>
            </div>
            <div class="responsive-card">
                <span class="icon">💻</span>
                <div class="title">Development</div>
                <div class="desc">Clean code</div>
            </div>
            <div class="responsive-card">
                <span class="icon">📱</span>
                <div class="title">Responsive</div>
                <div class="desc">Works everywhere</div>
            </div>
            <div class="responsive-card">
                <span class="icon">⚡</span>
                <div class="title">Performance</div>
                <div class="desc">Fast loading</div>
            </div>
        </div>

        <div class="code-block">
            /* Mobile: 1 column */
            .responsive-grid {
                grid-template-columns: 1fr;
            }

            /* Tablet: 2 columns */
            @media (min-width: 600px) {
                .responsive-grid {
                    grid-template-columns: repeat(2, 1fr);
                }
            }

            /* Desktop: 3 columns */
            @media (min-width: 900px) {
                .responsive-grid {
                    grid-template-columns: repeat(3, 1fr);
                }
            }

            /* Large Desktop: 4 columns */
            @media (min-width: 1200px) {
                .responsive-grid {
                    grid-template-columns: repeat(4, 1fr);
                }
            }
        </div>
    </section>

    <!-- ====== 4. RESPONSIVE NAVBAR ====== -->
    <section>
        <h2>4. Practical Example: Responsive Navbar</h2>
        <p>The navbar changes from vertical (mobile) to horizontal (desktop).</p>

        <div class="navbar">
            <a href="#">🏠 Home</a>
            <a href="#">📄 About</a>
            <a href="#">⚙️ Services</a>
            <a href="#">📞 Contact</a>
        </div>

        <div class="code-block">
            /* Mobile: vertical stack */
            @media (max-width: 599px) {
                .navbar {
                    flex-direction: column;
                }
            }

            /* Desktop: horizontal row */
            @media (min-width: 600px) {
                .navbar {
                    flex-direction: row;
                    justify-content: center;
                }
            }
        </div>
    </section>

    <!-- ====== 5. MOBILE FIRST DEMO ====== -->
    <section>
        <h2>5. Mobile First Approach</h2>
        <p>Start with mobile styles and add complexity as the screen gets larger.</p>

        <div class="mobile-first-demo">
            Mobile First Demo
        </div>

        <div class="code-block">
            /* Mobile first — base styles */
            .demo {
                background: #ff6b6b;
            }

            /* Tablet and up */
            @media (min-width: 768px) {
                .demo {
                    background: #28a745;
                }
            }

            /* Desktop and up */
            @media (min-width: 1024px) {
                .demo {
                    background: #007bff;
                }
            }

            /* Large desktop and up */
            @media (min-width: 1440px) {
                .demo {
                    background: #6c5ce7;
                }
            }
        </div>
    </section>

    <!-- ====== 6. REFERENCE TABLES ====== -->
    <section>
        <h2>6. Reference Tables</h2>

        <h3>width and height Variations</h3>
        <table class="reference-table">
            <tr>
                <th>Feature</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>width</code></td>
                <td>Exact viewport width</td>
                <td><code>@media (width: 780px)</code></td>
            </tr>
            <tr>
                <td><code>min-width</code></td>
                <td>Minimum viewport width</td>
                <td><code>@media (min-width: 780px)</code></td>
            </tr>
            <tr>
                <td><code>max-width</code></td>
                <td>Maximum viewport width</td>
                <td><code>@media (max-width: 1200px)</code></td>
            </tr>
            <tr>
                <td><code>height</code></td>
                <td>Exact viewport height</td>
                <td><code>@media (height: 1024px)</code></td>
            </tr>
            <tr>
                <td><code>min-height</code></td>
                <td>Minimum viewport height</td>
                <td><code>@media (min-height: 1024px)</code></td>
            </tr>
            <tr>
                <td><code>max-height</code></td>
                <td>Maximum viewport height</td>
                <td><code>@media (max-height: 1200px)</code></td>
            </tr>
        </table>

        <h3>Common Breakpoints</h3>
        <table class="reference-table">
            <tr>
                <th>Breakpoint</th>
                <th>Device</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>320px</code></td>
                <td>Small phones</td>
                <td><code>@media (min-width: 320px)</code></td>
            </tr>
            <tr>
                <td><code>480px</code></td>
                <td>Larger phones</td>
                <td><code>@media (min-width: 480px)</code></td>
            </tr>
            <tr>
                <td><code>768px</code></td>
                <td>Tablets</td>
                <td><code>@media (min-width: 768px)</code></td>
            </tr>
            <tr>
                <td><code>1024px</code></td>
                <td>Small laptops</td>
                <td><code>@media (min-width: 1024px)</code></td>
            </tr>
            <tr>
                <td><code>1200px</code></td>
                <td>Desktops</td>
                <td><code>@media (min-width: 1200px)</code></td>
            </tr>
            <tr>
                <td><code>1440px</code></td>
                <td>Large desktops</td>
                <td><code>@media (min-width: 1440px)</code></td>
            </tr>
            <tr>
                <td><code>1920px</code></td>
                <td>Full HD displays</td>
                <td><code>@media (min-width: 1920px)</code></td>
            </tr>
        </table>

        <h3>Common Height Breakpoints</h3>
        <table class="reference-table">
            <tr>
                <th>Breakpoint</th>
                <th>Device</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>500px</code></td>
                <td>Mobile landscape</td>
                <td><code>@media (max-height: 500px)</code></td>
            </tr>
            <tr>
                <td><code>600px</code></td>
                <td>Short viewport</td>
                <td><code>@media (max-height: 600px)</code></td>
            </tr>
            <tr>
                <td><code>900px</code></td>
                <td>Tall viewport</td>
                <td><code>@media (min-height: 900px)</code></td>
            </tr>
            <tr>
                <td><code>1080px</code></td>
                <td>Full HD height</td>
                <td><code>@media (min-height: 1080px)</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 7. BEST PRACTICES ====== -->
    <section>
        <h2>7. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li><strong>Mobile First</strong> — Start with smallest screen and build up</li>
                <li>Use <code>min-width</code> for breakpoints (mobile-first approach)</li>
                <li>Use <code>max-width</code> for desktop-first approach</li>
                <li>Use relative units (<code>em</code>, <code>rem</code>, <code>%</code>) for breakpoints</li>
                <li>Test on real devices, not just browser resizing</li>
                <li>Combine width and height for comprehensive responsiveness</li>
                <li>Use <code>min-height: 100vh</code> for full-screen sections</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use too many breakpoints — aim for 3–5 major ones</li>
                <li>Don't use exact <code>width</code> values (they're rarely useful)</li>
                <li>Don't forget about mobile landscape orientation</li>
                <li>Don't use fixed pixel values for everything</li>
                <li>Don't assume all screens are the same size</li>
                <li>Don't forget to test with the viewport meta tag</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator" id="live-indicator">
        <span id="indicator-width">Width: —</span>
        <span class="dimension" id="indicator-height">Height: —</span>
    </div>

    <!-- ====== SCRIPT FOR LIVE DIMENSIONS ====== -->
    <script>
        function updateDimensions() {
            const w = window.innerWidth;
            const h = window.innerHeight;

            // Update live indicator
            document.getElementById('indicator-width').textContent = 'Width: ' + w + 'px';
            document.getElementById('indicator-height').textContent = 'Height: ' + h + 'px';

            // Update viewport visualization labels
            const widthLabel = document.getElementById('width-label');
            const heightLabel = document.getElementById('height-label');
            if (widthLabel) widthLabel.textContent = 'Width: ' + w + 'px';
            if (heightLabel) heightLabel.textContent = 'Height: ' + h + 'px';

            // Update breakpoint indicator color
            const indicator = document.getElementById('live-indicator');
            if (w < 480) {
                indicator.style.background = '#ff6b6b';
            } else if (w < 768) {
                indicator.style.background = '#ffc107';
                indicator.style.color = '#333';
            } else if (w < 1024) {
                indicator.style.background = '#28a745';
                indicator.style.color = 'white';
            } else if (w < 1440) {
                indicator.style.background = '#007bff';
                indicator.style.color = 'white';
            } else {
                indicator.style.background = '#6c5ce7';
                indicator.style.color = 'white';
            }
        }

        window.addEventListener('resize', updateDimensions);
        window.addEventListener('load', updateDimensions);
        updateDimensions();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionExample
widthExact viewport width@media (width: 780px)
min-widthMinimum viewport width@media (min-width: 780px)
max-widthMaximum viewport width@media (max-width: 1200px)
heightExact viewport height@media (height: 1024px)
min-heightMinimum viewport height@media (min-height: 1024px)
max-heightMaximum viewport height@media (max-height: 1200px)

Common Breakpoints

BreakpointDevice
320pxSmall phones
480pxLarger phones
768pxTablets
1024pxSmall laptops
1200pxDesktops
1440pxLarge desktops
1920pxFull HD displays

Common Height Breakpoints

BreakpointDevice
500pxMobile landscape
600pxShort viewport
900pxTall viewport
1080pxFull HD height

Best Practices

Do This:

/* Mobile First approach */
.container {
    /* Base styles for mobile */
    display: block;
}

/* Tablet and up */
@media (min-width: 768px) {
    .container {
        display: flex;
    }
}

/* Desktop and up */
@media (min-width: 1024px) {
    .container {
        max-width: 1200px;
        margin: 0 auto;
    }
}

/* Handle mobile landscape */
@media (max-height: 500px) {
    .hero {
        min-height: 100vh;
    }
}

Don’t Do This:

/* Don't use exact width values */
@media (width: 780px) {
    /* Rarely useful — only matches exactly 780px */
}

/* Don't use too many breakpoints */
@media (min-width: 320px) { }
@media (min-width: 375px) { }
@media (min-width: 414px) { }
@media (min-width: 480px) { }
@media (min-width: 640px) { }
@media (min-width: 768px) { }
/* Too many — aim for 3-5 major breakpoints */

/* Don't forget the viewport meta tag */
/* <meta name="viewport" content="width=device-width, initial-scale=1.0"> */

Pro Tip: width and height are the most fundamental media features for responsive design. Use the Mobile First approach — start with styles for the smallest screens and add complexity as the screen gets larger. Use min-width for breakpoints (not max-width). Don’t forget the viewport meta tag — without it, mobile devices won’t respect your media queries! And remember: test on real devices, not just by resizing your browser window!

37. hover and inverted-colors Media Features

These two media features help you create input-aware and accessibility-friendly interfaces — one detects hover capability, the other detects inverted color schemes.


Overview of Features

FeatureDescriptionValues
hoverDetects if the primary pointing device can hovernone, hover
inverted-colorsDetects if the system uses inverted colorsnone, inverted

1. hover

The hover media feature applies styles when the primary pointing device can hover over elements.

@media (hover: hover) {
    button:hover {
        background-color: red;
    }
}

Values

ValueDescription
nonePrimary input cannot hover (e.g., touch screen)
hoverPrimary input can hover (e.g., mouse, trackpad)

Key Points:

  • hover checks the primary pointing device
  • any-hover checks any available pointing device
  • Use hover to ensure hover effects only apply when they make sense
  • On touch devices, :hover can be triggered accidentally — use @media (hover: hover) to prevent this

hover vs any-hover

FeatureDescription
hoverPrimary pointing device’s hover capability
any-hoverAny pointing device’s hover capability

Example:

  • Tablet with Bluetooth mouse:
    • hover: none (primary is touch)
    • any-hover: hover (mouse can hover)

2. inverted-colors

The inverted-colors media feature applies styles when the system’s display uses an inverted color scheme — where dark colors become bright and vice versa.

@media (inverted-colors: inverted) {
    body {
        background-color: black;
        color: white;
    }
}

Values

ValueDescription
noneColors are displayed normally
invertedDisplay uses inverted color scheme

Key Points:

  • Inverted colors are used for accessibility (poor visibility conditions)
  • Common on iOS (Accessibility > Display & Text Size > Classic Invert)
  • Images and media may be double-inverted — use filter: invert(1) to counter
  • Helps make content readable when inverted colors are enabled

Handling Images in Inverted Mode

@media (inverted-colors: inverted) {
    /* Re-invert images so they look normal */
    img, video {
        filter: invert(1);
    }
}

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>hover and inverted-colors Media Features</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
            transition: background 0.3s, color 0.3s;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
            transition: background 0.3s;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== BUTTON STYLES ====== */
        button {
            padding: 12px 24px;
            font-size: 16px;
            color: white;
            background-color: #007bff;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-weight: bold;
            transition: all 0.3s;
            margin: 5px;
        }

        /* Hover effect only for devices that can hover */
        @media (hover: hover) {
            button:hover {
                background-color: #dc3545;
                transform: translateY(-2px);
                box-shadow: 0 4px 15px rgba(220, 53, 69, 0.4);
            }
        }

        /* For touch devices — use :active instead */
        @media (hover: none) {
            button:active {
                background-color: #dc3545;
                transform: scale(0.98);
            }
            button::after {
                content: " (tap me)";
                font-weight: normal;
                font-size: 0.8rem;
                opacity: 0.8;
            }
        }

        /* ====== CARD STYLES ====== */
        .card {
            background: white;
            border: 2px solid #ddd;
            border-radius: 12px;
            padding: 20px;
            margin: 15px 0;
            transition: all 0.3s;
            cursor: pointer;
        }

        @media (hover: hover) {
            .card:hover {
                border-color: #007bff;
                box-shadow: 0 4px 20px rgba(0, 123, 255, 0.15);
                transform: translateY(-3px);
            }
        }

        @media (hover: none) {
            .card:active {
                border-color: #007bff;
                background: #f0f7ff;
            }
        }

        /* ====== TOOLTIP STYLES ====== */
        .tooltip-container {
            position: relative;
            display: inline-block;
            margin: 10px;
        }

        .tooltip-text {
            visibility: hidden;
            opacity: 0;
            background: #333;
            color: white;
            padding: 8px 12px;
            border-radius: 6px;
            position: absolute;
            bottom: 100%;
            left: 50%;
            transform: translateX(-50%);
            white-space: nowrap;
            font-size: 0.85rem;
            transition: all 0.3s;
            margin-bottom: 8px;
        }

        .tooltip-text::after {
            content: "";
            position: absolute;
            top: 100%;
            left: 50%;
            transform: translateX(-50%);
            border: 6px solid transparent;
            border-top-color: #333;
        }

        @media (hover: hover) {
            .tooltip-container:hover .tooltip-text {
                visibility: visible;
                opacity: 1;
            }
        }

        /* ====== INVERTED COLORS DEMO ====== */
        .invert-demo {
            padding: 20px;
            border-radius: 8px;
            background: #e9ecef;
            margin: 15px 0;
            border: 2px solid #ddd;
            transition: all 0.3s;
        }

        .invert-demo .box {
            padding: 15px;
            background: #007bff;
            color: white;
            border-radius: 8px;
            margin: 10px 0;
            text-align: center;
            font-weight: bold;
            transition: all 0.3s;
        }

        /* Inverted colors mode */
        @media (inverted-colors: inverted) {
            body {
                background: #000;
                color: #fff;
            }
            section {
                background: #1a1a1a;
                border: 1px solid #333;
            }
            h1, h2, h3 {
                color: #4dabf7;
            }
            h1 {
                border-bottom-color: #4dabf7;
            }
            h2 {
                border-left-color: #69db7c;
            }
            .invert-demo {
                background: #2d2d2d;
                border-color: #444;
            }
            .invert-demo .box {
                background: #4dabf7;
                color: #000;
            }
            .code-block {
                background: #0d0d0d;
                border: 1px solid #333;
            }
            .reference-table th {
                background: #4dabf7;
                color: #000;
            }
            .reference-table td {
                border-color: #444;
            }
            .reference-table tr:nth-child(even) {
                background: #1a1a1a;
            }
            button {
                background: #4dabf7;
                color: #000;
            }
            @media (hover: hover) {
                button:hover {
                    background: #ff6b6b;
                    color: #000;
                }
            }
            .card {
                background: #1a1a1a;
                border-color: #444;
            }
            /* Re-invert images so they look normal */
            img, video {
                filter: invert(1);
            }
            .tooltip-text {
                background: #fff;
                color: #000;
            }
            .tooltip-text::after {
                border-top-color: #fff;
            }
            .note {
                color: #adb5bd;
            }
            .highlight {
                background: #4dabf7;
                color: #000;
            }
        }

        /* ====== DETECTION CARDS ====== */
        .detection-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .detection-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            border: 2px solid #ddd;
            background: #f8f9fa;
            transition: all 0.3s;
        }

        .detection-card .label {
            font-size: 0.85rem;
            color: #666;
            display: block;
            margin-bottom: 5px;
        }

        .detection-card .value {
            font-size: 1.1rem;
            font-weight: bold;
            color: #007bff;
        }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #007bff;
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px rgba(0,123,255,0.4);
            z-index: 1000;
            transition: all 0.3s;
            display: flex;
            flex-direction: column;
            gap: 3px;
        }

        .live-indicator .detail {
            font-size: 0.75rem;
            opacity: 0.9;
        }

        /* ====== PRACTICAL: NAVIGATION ====== */
        .nav-menu {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            list-style: none;
            padding: 0;
            margin: 15px 0;
        }

        .nav-menu li a {
            display: block;
            padding: 10px 20px;
            background: #007bff;
            color: white;
            text-decoration: none;
            border-radius: 8px;
            transition: all 0.3s;
            font-weight: bold;
        }

        @media (hover: hover) {
            .nav-menu li a:hover {
                background: #28a745;
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(40, 167, 69, 0.3);
            }
        }

        @media (hover: none) {
            .nav-menu li a:active {
                background: #28a745;
                transform: scale(0.97);
            }
        }

        /* ====== INVERTED COLORS BUTTON ====== */
        .invert-toggle {
            background: #6c5ce7;
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 8px;
            font-size: 1em;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
            margin: 10px 5px;
        }

        @media (hover: hover) {
            .invert-toggle:hover {
                background: #4a2a9e;
                transform: translateY(-2px);
            }
        }

        /* ====== PRACTICAL: INVERTED IMAGE HANDLING ====== */
        .image-demo {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            align-items: center;
            margin: 15px 0;
        }

        .image-demo .img-box {
            width: 200px;
            height: 150px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 1.2rem;
            text-align: center;
            padding: 20px;
        }

        @media (inverted-colors: inverted) {
            .image-demo .img-box {
                filter: invert(1);
            }
        }
    </style>
</head>
<body>

    <h1>hover and inverted-colors Media Features</h1>

    <!-- ====== 1. HOVER DEMO ====== -->
    <section>
        <h2>1. hover</h2>
        <p>Applies styles when the <strong>primary pointing device</strong> can hover over elements.</p>

        <h3>Button Hover</h3>
        <button>Hover or Tap Me!</button>
        <p class="note">On desktop with a mouse, the button turns red on hover. On touch devices, it responds to tap (active state).</p>

        <h3>Card Hover</h3>
        <div class="card">
            <strong>Interactive Card</strong>
            <p>This card lifts up on hover (desktop) or changes on tap (mobile).</p>
        </div>

        <h3>Tooltip Hover</h3>
        <div class="tooltip-container">
            <button>Hover for tooltip</button>
            <span class="tooltip-text">This is a tooltip!</span>
        </div>
        <p class="note">Tooltips only appear on devices that can hover.</p>

        <div class="code-block">
            /* Hover effect only for devices that can hover */
            @media (hover: hover) {
                button:hover {
                    background-color: #dc3545;
                    transform: translateY(-2px);
                }
            }

            /* Touch-friendly alternative */
            @media (hover: none) {
                button:active {
                    background-color: #dc3545;
                    transform: scale(0.98);
                }
            }
        </div>
    </section>

    <!-- ====== 2. INVERTED-COLORS DEMO ====== -->
    <section>
        <h2>2. inverted-colors</h2>
        <p>Applies styles when the system uses an <strong>inverted color scheme</strong>.</p>

        <div class="invert-demo">
            <h3>Inverted Colors Demo</h3>
            <p>This box adapts to inverted colors mode:</p>
            <div class="box">
                I adapt to inverted colors!
            </div>
            <p class="note">Enable inverted colors in your OS accessibility settings to see the changes.</p>
        </div>

        <h3>Image Handling in Inverted Mode</h3>
        <div class="image-demo">
            <div class="img-box">🖼️ Image</div>
            <p>Images are re-inverted with <code>filter: invert(1)</code> so they look normal in inverted mode.</p>
        </div>

        <div class="code-block">
            /* Inverted colors mode */
            @media (inverted-colors: inverted) {
                body {
                    background: #000;
                    color: #fff;
                }
                section {
                    background: #1a1a1a;
                }
                /* Re-invert images so they look normal */
                img, video {
                    filter: invert(1);
                }
            }
        </div>
    </section>

    <!-- ====== 3. DETECTION SUMMARY ====== -->
    <section>
        <h2>3. Your Device's Capabilities</h2>
        <p>Below is a live detection of your device's capabilities.</p>

        <div class="detection-grid">
            <div class="detection-card" id="hover-hover">
                <span class="label">hover: hover</span>
                <span class="value" id="hover-hover-value">Detecting...</span>
            </div>
            <div class="detection-card" id="hover-none">
                <span class="label">hover: none</span>
                <span class="value" id="hover-none-value">Detecting...</span>
            </div>
            <div class="detection-card" id="any-hover-hover">
                <span class="label">any-hover: hover</span>
                <span class="value" id="any-hover-hover-value">Detecting...</span>
            </div>
            <div class="detection-card" id="invert-none">
                <span class="label">inverted-colors: none</span>
                <span class="value" id="invert-none-value">Detecting...</span>
            </div>
            <div class="detection-card" id="invert-inverted">
                <span class="label">inverted-colors: inverted</span>
                <span class="value" id="invert-inverted-value">Detecting...</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect hover capability */
            @media (hover: hover) { /* Primary device can hover */ }
            @media (hover: none) { /* Primary device cannot hover */ }

            /* Detect any hover capability */
            @media (any-hover: hover) { /* Any device can hover */ }

            /* Detect inverted colors */
            @media (inverted-colors: none) { /* Normal colors */ }
            @media (inverted-colors: inverted) { /* Inverted colors */ }
        </div>
    </section>

    <!-- ====== 4. PRACTICAL EXAMPLE: NAVIGATION ====== -->
    <section>
        <h2>4. Practical Example: Hover-Aware Navigation</h2>
        <p>A navigation menu that works well on both desktop and touch devices.</p>

        <ul class="nav-menu">
            <li><a href="#">🏠 Home</a></li>
            <li><a href="#">📄 About</a></li>
            <li><a href="#">⚙️ Services</a></li>
            <li><a href="#">📞 Contact</a></li>
        </ul>

        <div class="code-block">
            /* Desktop: hover effect */
            @media (hover: hover) {
                .nav-menu a:hover {
                    background: #28a745;
                    transform: translateY(-2px);
                    box-shadow: 0 4px 12px rgba(40, 167, 69, 0.3);
                }
            }

            /* Touch: active effect */
            @media (hover: none) {
                .nav-menu a:active {
                    background: #28a745;
                    transform: scale(0.97);
                }
            }
        </div>
    </section>

    <!-- ====== 5. REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>hover Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Typical Devices</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>Primary input cannot hover</td>
                <td>Touch screens, phones, tablets</td>
            </tr>
            <tr>
                <td><code>hover</code></td>
                <td>Primary input can hover</td>
                <td>Desktop with mouse, laptop with trackpad</td>
            </tr>
        </table>

        <h3>hover vs any-hover</h3>
        <table class="reference-table">
            <tr>
                <th>Feature</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>hover</code></td>
                <td>Primary pointing device's hover capability</td>
            </tr>
            <tr>
                <td><code>any-hover</code></td>
                <td>Any pointing device's hover capability</td>
            </tr>
        </table>

        <h3>inverted-colors Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>Colors are displayed normally (default)</td>
            </tr>
            <tr>
                <td><code>inverted</code></td>
                <td>Display uses an inverted color scheme</td>
            </tr>
        </table>

        <h3>Detection Scenarios</h3>
        <table class="reference-table">
            <tr>
                <th>Device</th>
                <th>hover</th>
                <th>any-hover</th>
            </tr>
            <tr>
                <td>Desktop with mouse</td>
                <td><code>hover</code></td>
                <td><code>hover</code></td>
            </tr>
            <tr>
                <td>Mobile phone (touch)</td>
                <td><code>none</code></td>
                <td><code>none</code></td>
            </tr>
            <tr>
                <td>Tablet with stylus</td>
                <td><code>none</code></td>
                <td><code>hover</code></td>
            </tr>
            <tr>
                <td>Laptop with touchscreen</td>
                <td><code>hover</code></td>
                <td><code>hover</code></td>
            </tr>
            <tr>
                <td>Tablet with Bluetooth mouse</td>
                <td><code>none</code></td>
                <td><code>hover</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>@media (hover: hover)</code> to apply hover effects only when they work</li>
                <li>Provide <code>:active</code> alternatives for touch devices</li>
                <li>Use <code>@media (inverted-colors: inverted)</code> to ensure readability in inverted mode</li>
                <li>Re-invert images with <code>filter: invert(1)</code> in inverted mode</li>
                <li>Test with actual touch devices and screen readers</li>
                <li>Combine <code>hover</code> with <code>any-hover</code> for comprehensive detection</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't rely solely on hover for critical functionality</li>
                <li>Don't forget that touch devices trigger <code>:hover</code> accidentally</li>
                <li>Don't ignore inverted colors — it affects users with visual impairments</li>
                <li>Don't assume all desktops have a mouse (touchscreen laptops exist)</li>
                <li>Don't use hover effects without touch alternatives</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator" id="live-indicator">
        <span id="indicator-text">Detecting...</span>
    </div>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        function updateIndicators() {
            // Hover detection
            const hoverHover = document.getElementById('hover-hover');
            const hoverNone = document.getElementById('hover-none');
            const anyHoverHover = document.getElementById('any-hover-hover');

            if (window.matchMedia('(hover: hover)').matches) {
                hoverHover.querySelector('.value').textContent = 'Supported ✅';
                hoverHover.style.background = '#d4edda';
                hoverHover.style.borderColor = '#28a745';
                hoverHover.querySelector('.value').style.color = '#28a745';

                hoverNone.querySelector('.value').textContent = 'Not applicable';
                hoverNone.style.background = '#e9ecef';
                hoverNone.style.borderColor = '#6c757d';
                hoverNone.querySelector('.value').style.color = '#6c757d';
            } else {
                hoverNone.querySelector('.value').textContent = 'Active ✅';
                hoverNone.style.background = '#fff3cd';
                hoverNone.style.borderColor = '#ffc107';
                hoverNone.querySelector('.value').style.color = '#856404';

                hoverHover.querySelector('.value').textContent = 'Not supported';
                hoverHover.style.background = '#e9ecef';
                hoverHover.style.borderColor = '#6c757d';
                hoverHover.querySelector('.value').style.color = '#6c757d';
            }

            if (window.matchMedia('(any-hover: hover)').matches) {
                anyHoverHover.querySelector('.value').textContent = 'Supported ✅';
                anyHoverHover.style.background = '#d4edda';
                anyHoverHover.style.borderColor = '#28a745';
                anyHoverHover.querySelector('.value').style.color = '#28a745';
            } else {
                anyHoverHover.querySelector('.value').textContent = 'Not supported';
                anyHoverHover.style.background = '#e9ecef';
                anyHoverHover.style.borderColor = '#6c757d';
                anyHoverHover.querySelector('.value').style.color = '#6c757d';
            }

            // Inverted colors detection
            const invertNone = document.getElementById('invert-none');
            const invertInverted = document.getElementById('invert-inverted');

            if (window.matchMedia('(inverted-colors: inverted)').matches) {
                invertInverted.querySelector('.value').textContent = 'Active ✅';
                invertInverted.style.background = '#fff3cd';
                invertInverted.style.borderColor = '#ffc107';
                invertInverted.querySelector('.value').style.color = '#856404';

                invertNone.querySelector('.value').textContent = 'Not active';
                invertNone.style.background = '#e9ecef';
                invertNone.style.borderColor = '#6c757d';
                invertNone.querySelector('.value').style.color = '#6c757d';
            } else {
                invertNone.querySelector('.value').textContent = 'Active (default) ✅';
                invertNone.style.background = '#d4edda';
                invertNone.style.borderColor = '#28a745';
                invertNone.querySelector('.value').style.color = '#28a745';

                invertInverted.querySelector('.value').textContent = 'Not active';
                invertInverted.style.background = '#e9ecef';
                invertInverted.style.borderColor = '#6c757d';
                invertInverted.querySelector('.value').style.color = '#6c757d';
            }

            // Live indicator
            const indicator = document.getElementById('indicator-text');
            const hasHover = window.matchMedia('(hover: hover)').matches;
            const isInverted = window.matchMedia('(inverted-colors: inverted)').matches;

            let text = '';
            if (hasHover) text += '🖱️ Hover: Yes';
            else text += '👆 Hover: No (Touch)';

            if (isInverted) text += ' | 🔄 Inverted: Yes';
            else text += ' | 🎨 Inverted: No';

            indicator.textContent = text;

            // Update live indicator color
            const liveIndicator = document.getElementById('live-indicator');
            if (isInverted) {
                liveIndicator.style.background = '#ffc107';
                liveIndicator.style.color = '#333';
            } else if (hasHover) {
                liveIndicator.style.background = '#007bff';
                liveIndicator.style.color = 'white';
            } else {
                liveIndicator.style.background = '#28a745';
                liveIndicator.style.color = 'white';
            }
        }

        window.addEventListener('load', updateIndicators);

        // Listen for changes
        window.matchMedia('(hover: hover)').addEventListener('change', updateIndicators);
        window.matchMedia('(inverted-colors: inverted)').addEventListener('change', updateIndicators);

        updateIndicators();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionValues
hoverPrimary device can hovernone, hover
inverted-colorsSystem uses inverted colorsnone, inverted

hover Values

ValueDescriptionTypical Devices
noneCannot hoverTouch screens, phones, tablets
hoverCan hoverDesktop with mouse, laptop with trackpad

hover vs any-hover

FeatureDescription
hoverPrimary pointing device’s hover capability
any-hoverAny pointing device’s hover capability

inverted-colors Values

ValueDescription
noneColors are displayed normally (default)
invertedDisplay uses an inverted color scheme

Best Practices

Do This:

/* Only apply hover effects when hover is possible */
@media (hover: hover) {
    button:hover {
        background-color: #dc3545;
        transform: translateY(-2px);
    }
}

/* Provide touch-friendly alternatives */
@media (hover: none) {
    button:active {
        background-color: #dc3545;
        transform: scale(0.98);
    }
}

/* Handle inverted colors mode */
@media (inverted-colors: inverted) {
    body {
        background: #000;
        color: #fff;
    }
    /* Re-invert images */
    img, video {
        filter: invert(1);
    }
}

Don’t Do This:

/* Don't apply hover effects unconditionally */
button:hover {
    background: red;
    /* On touch devices, this triggers on tap and sticks! */
}

/* Don't forget touch alternatives */
.menu-item:hover .submenu {
    display: block;
    /* Won't work on touch devices! */
}

/* Don't ignore inverted colors */
body {
    background: white;
    color: black;
    /* May be unreadable if user has inverted colors on */
}

Pro Tip: hover is essential for input-aware design. Always wrap hover effects in @media (hover: hover) — otherwise, touch devices will trigger hover styles on tap, and they’ll “stick” until you tap elsewhere. Provide :active alternatives for touch devices. inverted-colors is crucial for accessibility — users with visual impairments may enable inverted colors. Re-invert images with filter: invert(1) so they look normal, and ensure your text remains readable in inverted mode!

38. monochrome and orientation Media Features

These two media features let you adapt styles for monochrome displays and screen orientation — one for specialized devices, the other for everyday responsive design.


Overview of Features

FeatureDescriptionValues
monochromeBits per pixel for monochrome devicesInteger (0, 1, 8)
orientationPortrait or landscape orientationportrait, landscape

1. monochrome

The monochrome media feature tests the number of bits per pixel (bpp) on monochrome (non-color) devices.

@media (monochrome) {
    body {
        background-color: #f0f0f0;
        color: #000;
    }
}

Variations

FeatureDescriptionExample
monochromeAny monochrome device@media (monochrome)
monochrome: 0Non-monochrome device@media (monochrome: 0)
min-monochrome: 1At least 1 bpp@media (min-monochrome: 1)
max-monochrome: 8At most 8 bpp@media (max-monochrome: 8)

Common Values

Bits per PixelDescriptionDevice Example
0Not monochromeModern color displays
12 colors (black/white)Simple e-ink readers
24 shadesEarly e-ink
416 shadesGrayscale displays
8256 shadesAdvanced e-ink, medical displays

Key Points:

  • monochrome: 0 means the device is not monochrome (has color)
  • monochrome without a value matches any monochrome device (bpp > 0)
  • min-monochrome: 1 is equivalent to monochrome (any monochrome device)
  • Most modern devices match monochrome: 0
  • Useful for e-ink readers, braille displays, and specialized hardware

2. orientation

The orientation media feature applies styles based on whether the viewport is in portrait or landscape orientation.

@media screen and (orientation: portrait) {
    body {
        background-color: #f0f0f0;
    }
}

@media screen and (orientation: landscape) {
    body {
        background-color: #ccc;
    }
}

Values

ValueDescriptionCondition
portraitHeight ≥ WidthVertical orientation
landscapeWidth > HeightHorizontal orientation

Visual Representation

Portrait:              Landscape:
┌─────────┐            ┌───────────────────┐
│         │            │                   │
│         │            │                   │
│         │            │                   │
│         │            │                   │
│         │            │                   │
└─────────┘            └───────────────────┘
Height ≥ Width         Width > Height

Key Points:

  • orientation is about the viewport shape, not the physical device
  • It changes when the user rotates their device
  • It changes when the user resizes their browser window
  • A square viewport is considered portrait (height ≥ width)
  • Common use: adjusting layouts for mobile landscape vs. portrait

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>monochrome and orientation Media Features</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
            transition: background 0.3s, color 0.3s;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
            transition: all 0.3s;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== MONOCHROME DEMO ====== */
        .monochrome-demo {
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            font-size: 1.2rem;
            margin: 15px 0;
            transition: all 0.3s;
            background: #e9ecef;
            border: 2px solid #ddd;
        }

        /* Any monochrome device */
        @media (monochrome) {
            .monochrome-demo {
                background: #000;
                color: #fff;
                border-color: #fff;
            }
            .monochrome-demo::after {
                content: " (monochrome device detected)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Non-monochrome device */
        @media (monochrome: 0) {
            .monochrome-demo {
                background: #e9ecef;
                color: #333;
                border-color: #ddd;
            }
            .monochrome-demo::after {
                content: " (color device — monochrome: 0)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* ====== ORIENTATION DEMO ====== */
        .orientation-demo {
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            font-size: 1.2rem;
            margin: 15px 0;
            transition: all 0.3s;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            min-height: 150px;
        }

        /* Portrait orientation */
        @media screen and (orientation: portrait) {
            .orientation-demo {
                background: #ff6b6b;
                color: white;
                border: 2px solid #c92a2a;
            }
            .orientation-demo .icon {
                font-size: 3rem;
                display: block;
            }
            .orientation-demo .icon::before {
                content: "📱";
            }
            .orientation-demo .label::after {
                content: " Portrait";
                font-weight: bold;
            }
        }

        /* Landscape orientation */
        @media screen and (orientation: landscape) {
            .orientation-demo {
                background: #28a745;
                color: white;
                border: 2px solid #1e7e34;
            }
            .orientation-demo .icon {
                font-size: 3rem;
                display: block;
            }
            .orientation-demo .icon::before {
                content: "🖥️";
            }
            .orientation-demo .label::after {
                content: " Landscape";
                font-weight: bold;
            }
        }

        /* ====== RESPONSIVE LAYOUT DEMO ====== */
        .layout-demo {
            display: flex;
            gap: 15px;
            margin: 15px 0;
            transition: all 0.3s;
            flex-wrap: wrap;
        }

        .layout-demo .box {
            background: #007bff;
            color: white;
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            flex: 1;
            min-width: 100px;
            transition: all 0.3s;
        }

        /* Portrait: stack vertically */
        @media screen and (orientation: portrait) {
            .layout-demo {
                flex-direction: column;
            }
            .layout-demo .box {
                background: #ff6b6b;
            }
        }

        /* Landscape: horizontal row */
        @media screen and (orientation: landscape) {
            .layout-demo {
                flex-direction: row;
            }
            .layout-demo .box {
                background: #28a745;
            }
        }

        /* ====== MOBILE LANDSCAPE WARNING ====== */
        .landscape-warning {
            display: none;
            padding: 15px;
            background: #fff3cd;
            border: 2px solid #ffc107;
            border-radius: 8px;
            text-align: center;
            margin: 15px 0;
            font-weight: bold;
            color: #856404;
        }

        @media screen and (orientation: landscape) and (max-height: 500px) {
            .landscape-warning {
                display: block;
            }
        }

        /* ====== DETECTION CARDS ====== */
        .detection-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .detection-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            border: 2px solid #ddd;
            background: #f8f9fa;
            transition: all 0.3s;
        }

        .detection-card .label {
            font-size: 0.85rem;
            color: #666;
            display: block;
            margin-bottom: 5px;
        }

        .detection-card .value {
            font-size: 1.1rem;
            font-weight: bold;
            color: #007bff;
        }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #007bff;
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px rgba(0,123,255,0.4);
            z-index: 1000;
            transition: all 0.3s;
            display: flex;
            flex-direction: column;
            gap: 3px;
        }

        .live-indicator .detail {
            font-size: 0.75rem;
            opacity: 0.9;
        }

        /* ====== PRACTICAL: RESPONSIVE CARD ====== */
        .profile-card {
            display: flex;
            gap: 20px;
            padding: 20px;
            background: white;
            border: 2px solid #ddd;
            border-radius: 12px;
            margin: 15px 0;
            transition: all 0.3s;
            align-items: center;
        }

        .profile-card .avatar {
            width: 80px;
            height: 80px;
            background: #007bff;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 2rem;
            font-weight: bold;
            flex-shrink: 0;
        }

        .profile-card .info {
            flex: 1;
        }

        .profile-card .info h4 {
            margin: 0 0 5px 0;
            color: #007bff;
        }

        .profile-card .info p {
            margin: 0;
            color: #6c757d;
            font-size: 0.9rem;
        }

        /* Portrait: stack vertically */
        @media screen and (orientation: portrait) {
            .profile-card {
                flex-direction: column;
                text-align: center;
            }
        }

        /* Landscape: horizontal row */
        @media screen and (orientation: landscape) {
            .profile-card {
                flex-direction: row;
                text-align: left;
            }
        }

        /* ====== MONOCHROME STYLES ====== */
        @media (monochrome) {
            body {
                background: #fff;
                color: #000;
            }
            section {
                background: #fff;
                border: 1px solid #000;
                box-shadow: none;
            }
            h1, h2, h3 {
                color: #000;
            }
            h1 {
                border-bottom-color: #000;
            }
            h2 {
                border-left-color: #000;
            }
            .code-block {
                background: #f0f0f0;
                color: #000;
                border: 1px solid #ccc;
            }
            .reference-table th {
                background: #000;
                color: #fff;
            }
            .reference-table td {
                border-color: #999;
            }
            .detection-card {
                border-color: #000;
                background: #fff;
            }
            .profile-card {
                border-color: #000;
            }
            .profile-card .avatar {
                background: #000;
            }
            .highlight {
                background: #000;
                color: #fff;
            }
        }
    </style>
</head>
<body>

    <h1>monochrome and orientation Media Features</h1>

    <!-- ====== 1. MONOCHROME DEMO ====== -->
    <section>
        <h2>1. monochrome</h2>
        <p>Tests the <strong>number of bits per pixel</strong> on monochrome devices.</p>

        <div class="monochrome-demo">
            Monochrome Detection
        </div>

        <div class="code-block">
            /* Any monochrome device */
            @media (monochrome) {
                .demo {
                    background: #000;
                    color: #fff;
                }
            }

            /* Non-monochrome device */
            @media (monochrome: 0) {
                .demo {
                    background: #e9ecef;
                    color: #333;
                }
            }

            /* At least 1 bit per pixel */
            @media (min-monochrome: 1) {
                /* Monochrome device with ≥ 1 bpp */
            }

            /* At most 8 bits per pixel */
            @media (max-monochrome: 8) {
                /* Monochrome device with ≤ 8 bpp */
            }
        </div>
    </section>

    <!-- ====== 2. ORIENTATION DEMO ====== -->
    <section>
        <h2>2. orientation</h2>
        <p>Applies styles based on <strong>portrait</strong> or <strong>landscape</strong> orientation. Rotate your device or resize your browser!</p>

        <div class="orientation-demo">
            <span class="icon"></span>
            <span class="label">Current Orientation:</span>
        </div>

        <h3>Responsive Layout</h3>
        <div class="layout-demo">
            <div class="box">📦 Box 1</div>
            <div class="box">📦 Box 2</div>
            <div class="box">📦 Box 3</div>
        </div>

        <div class="landscape-warning">
            ⚠️ You're in mobile landscape mode — content may be cramped. Rotate to portrait for a better experience.
        </div>

        <div class="code-block">
            /* Portrait orientation (height ≥ width) */
            @media screen and (orientation: portrait) {
                .layout-demo {
                    flex-direction: column;
                }
            }

            /* Landscape orientation (width > height) */
            @media screen and (orientation: landscape) {
                .layout-demo {
                    flex-direction: row;
                }
            }

            /* Mobile landscape warning */
            @media screen and (orientation: landscape) and (max-height: 500px) {
                .landscape-warning {
                    display: block;
                }
            }
        </div>
    </section>

    <!-- ====== 3. PRACTICAL EXAMPLE ====== -->
    <section>
        <h2>3. Practical Example: Responsive Profile Card</h2>
        <p>This card adapts its layout based on orientation.</p>

        <div class="profile-card">
            <div class="avatar">👤</div>
            <div class="info">
                <h4>John Doe</h4>
                <p>Full-Stack Developer</p>
                <p>Passionate about creating responsive, accessible web experiences.</p>
            </div>
        </div>

        <div class="code-block">
            /* Portrait: stack vertically */
            @media screen and (orientation: portrait) {
                .profile-card {
                    flex-direction: column;
                    text-align: center;
                }
            }

            /* Landscape: horizontal row */
            @media screen and (orientation: landscape) {
                .profile-card {
                    flex-direction: row;
                    text-align: left;
                }
            }
        </div>
    </section>

    <!-- ====== 4. DETECTION SUMMARY ====== -->
    <section>
        <h2>4. Your Device's Capabilities</h2>
        <p>Below is a live detection of your device's capabilities.</p>

        <div class="detection-grid">
            <div class="detection-card" id="mono-any">
                <span class="label">monochrome</span>
                <span class="value" id="mono-any-value">Detecting...</span>
            </div>
            <div class="detection-card" id="mono-0">
                <span class="label">monochrome: 0</span>
                <span class="value" id="mono-0-value">Detecting...</span>
            </div>
            <div class="detection-card" id="mono-min-1">
                <span class="label">min-monochrome: 1</span>
                <span class="value" id="mono-min-1-value">Detecting...</span>
            </div>
            <div class="detection-card" id="orient-portrait">
                <span class="label">orientation: portrait</span>
                <span class="value" id="orient-portrait-value">Detecting...</span>
            </div>
            <div class="detection-card" id="orient-landscape">
                <span class="label">orientation: landscape</span>
                <span class="value" id="orient-landscape-value">Detecting...</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect monochrome */
            @media (monochrome) { /* Any monochrome device */ }
            @media (monochrome: 0) { /* Non-monochrome device */ }
            @media (min-monochrome: 1) { /* At least 1 bpp */ }

            /* Detect orientation */
            @media (orientation: portrait) { /* Height ≥ Width */ }
            @media (orientation: landscape) { /* Width > Height */ }
        </div>
    </section>

    <!-- ====== 5. REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>monochrome Values</h3>
        <table class="reference-table">
            <tr>
                <th>Feature</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>monochrome</code></td>
                <td>Any monochrome device (bpp > 0)</td>
                <td><code>@media (monochrome)</code></td>
            </tr>
            <tr>
                <td><code>monochrome: 0</code></td>
                <td>Non-monochrome device</td>
                <td><code>@media (monochrome: 0)</code></td>
            </tr>
            <tr>
                <td><code>min-monochrome: 1</code></td>
                <td>At least 1 bit per pixel</td>
                <td><code>@media (min-monochrome: 1)</code></td>
            </tr>
            <tr>
                <td><code>max-monochrome: 8</code></td>
                <td>At most 8 bits per pixel</td>
                <td><code>@media (max-monochrome: 8)</code></td>
            </tr>
        </table>

        <h3>Bits per Pixel Values</h3>
        <table class="reference-table">
            <tr>
                <th>Bits per Pixel</th>
                <th>Description</th>
                <th>Device Example</th>
            </tr>
            <tr>
                <td><code>0</code></td>
                <td>Not monochrome</td>
                <td>Modern color displays</td>
            </tr>
            <tr>
                <td><code>1</code></td>
                <td>2 colors (black/white)</td>
                <td>Simple e-ink readers</td>
            </tr>
            <tr>
                <td><code>2</code></td>
                <td>4 shades</td>
                <td>Early e-ink</td>
            </tr>
            <tr>
                <td><code>4</code></td>
                <td>16 shades</td>
                <td>Grayscale displays</td>
            </tr>
            <tr>
                <td><code>8</code></td>
                <td>256 shades</td>
                <td>Advanced e-ink, medical displays</td>
            </tr>
        </table>

        <h3>orientation Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Condition</th>
                <th>Visual</th>
            </tr>
            <tr>
                <td><code>portrait</code></td>
                <td>Height ≥ Width</td>
                <td>Vertical rectangle</td>
            </tr>
            <tr>
                <td><code>landscape</code></td>
                <td>Width > Height</td>
                <td>Horizontal rectangle</td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>orientation</code> to adapt layouts for portrait vs. landscape</li>
                <li>Use <code>monochrome</code> to provide grayscale fallbacks for specialized devices</li>
                <li>Combine <code>orientation</code> with <code>max-height</code> for mobile landscape warnings</li>
                <li>Test on real devices in both orientations</li>
                <li>Use <code>monochrome: 0</code> for modern color devices</li>
                <li>Provide meaningful content even on monochrome devices</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't rely on orientation alone for responsive design</li>
                <li>Don't assume all users have color displays</li>
                <li>Don't forget about mobile landscape (short height)</li>
                <li>Don't use monochrome for critical functionality — use it for enhancements</li>
                <li>Don't confuse viewport orientation with device orientation</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator" id="live-indicator">
        <span id="indicator-orientation">Orientation: —</span>
        <span class="detail" id="indicator-monochrome">Monochrome: —</span>
    </div>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        function updateIndicators() {
            // Monochrome detection
            const monoAny = document.getElementById('mono-any');
            const mono0 = document.getElementById('mono-0');
            const monoMin1 = document.getElementById('mono-min-1');

            const isMonochrome = window.matchMedia('(monochrome)').matches;
            const isMonochrome0 = window.matchMedia('(monochrome: 0)').matches;
            const isMinMono1 = window.matchMedia('(min-monochrome: 1)').matches;

            if (isMonochrome) {
                monoAny.querySelector('.value').textContent = 'Monochrome ✅';
                monoAny.style.background = '#e9ecef';
                monoAny.style.borderColor = '#333';
                monoAny.querySelector('.value').style.color = '#333';
            } else {
                monoAny.querySelector('.value').textContent = 'Not monochrome';
                monoAny.style.background = '#e9ecef';
                monoAny.style.borderColor = '#6c757d';
                monoAny.querySelector('.value').style.color = '#6c757d';
            }

            if (isMonochrome0) {
                mono0.querySelector('.value').textContent = 'Color device ✅';
                mono0.style.background = '#d4edda';
                mono0.style.borderColor = '#28a745';
                mono0.querySelector('.value').style.color = '#28a745';
            } else {
                mono0.querySelector('.value').textContent = 'Monochrome';
                mono0.style.background = '#e9ecef';
                mono0.style.borderColor = '#6c757d';
                mono0.querySelector('.value').style.color = '#6c757d';
            }

            if (isMinMono1) {
                monoMin1.querySelector('.value').textContent = '≥ 1 bpp ✅';
                monoMin1.style.background = '#e9ecef';
                monoMin1.style.borderColor = '#333';
                monoMin1.querySelector('.value').style.color = '#333';
            } else {
                monoMin1.querySelector('.value').textContent = 'Not detected';
                monoMin1.style.background = '#e9ecef';
                monoMin1.style.borderColor = '#6c757d';
                monoMin1.querySelector('.value').style.color = '#6c757d';
            }

            // Orientation detection
            const orientPortrait = document.getElementById('orient-portrait');
            const orientLandscape = document.getElementById('orient-landscape');
            const indicator = document.getElementById('live-indicator');
            const indicatorOrientation = document.getElementById('indicator-orientation');
            const indicatorMonochrome = document.getElementById('indicator-monochrome');

            const isPortrait = window.matchMedia('(orientation: portrait)').matches;
            const isLandscape = window.matchMedia('(orientation: landscape)').matches;

            if (isPortrait) {
                orientPortrait.querySelector('.value').textContent = 'Active ✅';
                orientPortrait.style.background = '#ff6b6b';
                orientPortrait.style.borderColor = '#c92a2a';
                orientPortrait.querySelector('.value').style.color = 'white';

                orientLandscape.querySelector('.value').textContent = 'Inactive';
                orientLandscape.style.background = '#e9ecef';
                orientLandscape.style.borderColor = '#6c757d';
                orientLandscape.querySelector('.value').style.color = '#6c757d';

                indicatorOrientation.textContent = '📱 Portrait';
                indicator.style.background = '#ff6b6b';
                indicator.style.color = 'white';
            } else if (isLandscape) {
                orientLandscape.querySelector('.value').textContent = 'Active ✅';
                orientLandscape.style.background = '#28a745';
                orientLandscape.style.borderColor = '#1e7e34';
                orientLandscape.querySelector('.value').style.color = 'white';

                orientPortrait.querySelector('.value').textContent = 'Inactive';
                orientPortrait.style.background = '#e9ecef';
                orientPortrait.style.borderColor = '#6c757d';
                orientPortrait.querySelector('.value').style.color = '#6c757d';

                indicatorOrientation.textContent = '🖥️ Landscape';
                indicator.style.background = '#28a745';
                indicator.style.color = 'white';
            }

            // Update monochrome indicator
            if (isMonochrome) {
                indicatorMonochrome.textContent = 'Monochrome: Yes';
            } else {
                indicatorMonochrome.textContent = 'Monochrome: No (Color)';
            }
        }

        window.addEventListener('resize', updateIndicators);
        window.addEventListener('load', updateIndicators);
        window.addEventListener('orientationchange', updateIndicators);

        // Listen for changes
        window.matchMedia('(orientation: portrait)').addEventListener('change', updateIndicators);
        window.matchMedia('(monochrome)').addEventListener('change', updateIndicators);

        updateIndicators();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionValues
monochromeBits per pixel on monochrome devicesInteger (0, 1, 8)
orientationPortrait or landscapeportrait, landscape

monochrome Values

FeatureDescriptionExample
monochromeAny monochrome device@media (monochrome)
monochrome: 0Non-monochrome device@media (monochrome: 0)
min-monochrome: 1At least 1 bpp@media (min-monochrome: 1)
max-monochrome: 8At most 8 bpp@media (max-monochrome: 8)

Bits per Pixel

Bits per PixelDescriptionDevice Example
0Not monochromeModern color displays
12 colorsSimple e-ink readers
24 shadesEarly e-ink
416 shadesGrayscale displays
8256 shadesAdvanced e-ink, medical displays

orientation Values

ValueConditionVisual
portraitHeight ≥ WidthVertical rectangle
landscapeWidth > HeightHorizontal rectangle

Best Practices

Do This:

/* Adapt layout for orientation */
@media screen and (orientation: portrait) {
    .container {
        flex-direction: column;
    }
}

@media screen and (orientation: landscape) {
    .container {
        flex-direction: row;
    }
}

/* Mobile landscape warning */
@media screen and (orientation: landscape) and (max-height: 500px) {
    .warning {
        display: block;
    }
}

/* Monochrome fallback */
@media (monochrome) {
    .image {
        filter: grayscale(100%);
    }
}

Don’t Do This:

/* Don't rely on orientation alone */
@media (orientation: portrait) {
    /* Use width/height for more precise control */
}

/* Don't assume all users have color displays */
.chart {
    color: #ff0000; /* May not be visible on monochrome */
}

/* Don't forget mobile landscape */
/* A phone in landscape has a very short viewport height */

Pro Tip: orientation is essential for responsive design — mobile users frequently rotate their devices, and layouts should adapt accordingly. Use it to switch between vertical and horizontal layouts, and combine it with max-height to detect mobile landscape mode (where the viewport is very short). monochrome is for specialized devices — e-ink readers, braille displays, and medical monitors. Most modern devices match monochrome: 0 (color). Always provide meaningful content regardless of color capability!

39. overflow-block and overflow-inline Media Features

These two media features describe how a device handles content overflow — whether it scrolls, paginates, or simply clips. They’re especially relevant for paged media (like print) and e-readers.


Overview of Features

FeatureDescriptionAxis
overflow-blockOverflow handling along the block axisVertical (in horizontal writing modes)
overflow-inlineOverflow handling along the inline axisHorizontal (in horizontal writing modes)

Understanding Block and Inline Axes

Before diving in, it’s important to understand the two axes:

AxisDescriptionDefault Direction
Block axisThe direction in which block-level elements are laid outVertical (top → bottom)
Inline axisThe direction in which inline content flowsHorizontal (left → right)

Note: These axes swap in vertical writing modes (e.g., writing-mode: vertical-rl).

Block Axis (vertical)
        ↑
        │  Inline Axis (horizontal)
        │  ────────────────────────→
        │

1. overflow-block

The overflow-block media feature checks how the device handles overflow along the block axis.

@media (overflow-block: scroll) {
    div {
        color: blue;
    }
}

Values

ValueDescription
noneContent that overflows is not displayed (clipped)
scrollContent that overflows can be scrolled
optional-pagedScrolling is available, but pages can also be triggered
pagedContent is broken into discrete pages

Real-World Examples

Device / Mediumoverflow-block Value
Computer screenscroll
Smartphonescroll
Printed pagepaged
E-readerpaged or optional-paged
Text-only terminalscroll or none
Projectionnone

2. overflow-inline

The overflow-inline media feature checks how the device handles overflow along the inline axis.

@media (overflow-inline: scroll) {
    div {
        color: blue;
    }
}

Values

ValueDescription
noneOverflowing content is not displayed (clipped)
scrollOverflowing content can be scrolled to

Real-World Examples

Device / Mediumoverflow-inline Value
Computer screenscroll
Smartphonescroll (horizontal swipe)
Printed pagenone (content is clipped or wraps)
Text-only terminalscroll or none

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>overflow-block and overflow-inline Media Features</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
            transition: background 0.3s, color 0.3s;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
            transition: all 0.3s;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== OVERFLOW-BLOCK DEMO ====== */
        .overflow-block-demo {
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            font-size: 1.2rem;
            margin: 15px 0;
            transition: all 0.3s;
            background: #e9ecef;
            border: 2px solid #ddd;
        }

        /* None — clipped */
        @media (overflow-block: none) {
            .overflow-block-demo {
                background: #dc3545;
                color: white;
                border-color: #a71d2a;
            }
            .overflow-block-demo::after {
                content: " (none — content clipped)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Scroll — scrollable */
        @media (overflow-block: scroll) {
            .overflow-block-demo {
                background: #007bff;
                color: white;
                border-color: #0056b3;
            }
            .overflow-block-demo::after {
                content: " (scroll — content scrollable)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Optional-paged */
        @media (overflow-block: optional-paged) {
            .overflow-block-demo {
                background: #ffc107;
                color: #333;
                border-color: #d39e00;
            }
            .overflow-block-demo::after {
                content: " (optional-paged — can paginate)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Paged */
        @media (overflow-block: paged) {
            .overflow-block-demo {
                background: #28a745;
                color: white;
                border-color: #1e7e34;
            }
            .overflow-block-demo::after {
                content: " (paged — discrete pages)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* ====== OVERFLOW-INLINE DEMO ====== */
        .overflow-inline-demo {
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            font-size: 1.2rem;
            margin: 15px 0;
            transition: all 0.3s;
            background: #e9ecef;
            border: 2px solid #ddd;
        }

        @media (overflow-inline: none) {
            .overflow-inline-demo {
                background: #dc3545;
                color: white;
                border-color: #a71d2a;
            }
            .overflow-inline-demo::after {
                content: " (none — inline overflow clipped)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        @media (overflow-inline: scroll) {
            .overflow-inline-demo {
                background: #007bff;
                color: white;
                border-color: #0056b3;
            }
            .overflow-inline-demo::after {
                content: " (scroll — inline overflow scrollable)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* ====== AXIS VISUALIZATION ====== */
        .axis-viz {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 15px;
            margin: 20px 0;
        }

        .axis-row {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .axis-label {
            font-weight: bold;
            color: #007bff;
            min-width: 120px;
            text-align: right;
        }

        .axis-arrow {
            font-size: 1.5rem;
            color: #dc3545;
        }

        .axis-description {
            color: #6c757d;
            font-size: 0.9rem;
        }

        /* ====== PRACTICAL: PAGED MEDIA ====== */
        .article {
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            background: white;
            border: 2px solid #ddd;
            border-radius: 8px;
        }

        .article h3 {
            color: #007bff;
            margin-top: 0;
        }

        .article p {
            text-align: justify;
            line-height: 1.8;
        }

        /* Print / paged media styles */
        @media (overflow-block: paged) {
            .article {
                border: none;
                padding: 0;
                background: transparent;
            }
            .article h3 {
                color: #000;
                page-break-after: avoid;
            }
            .article p {
                orphans: 3;
                widows: 3;
            }
            .no-print {
                display: none;
            }
        }

        /* Scrollable media styles */
        @media (overflow-block: scroll) {
            .article {
                box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            }
        }

        /* ====== CONTENT OVERFLOW DEMO ====== */
        .overflow-container {
            width: 100%;
            max-width: 600px;
            margin: 15px auto;
            border: 2px dashed #007bff;
            border-radius: 8px;
            overflow: auto;
            padding: 15px;
            background: #f8f9fa;
        }

        .overflow-container .long-content {
            white-space: nowrap;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            color: #333;
        }

        /* Inline overflow behavior */
        @media (overflow-inline: scroll) {
            .overflow-container {
                overflow-x: auto;
            }
        }

        @media (overflow-inline: none) {
            .overflow-container {
                overflow-x: hidden;
            }
        }

        /* ====== DETECTION CARDS ====== */
        .detection-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .detection-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            border: 2px solid #ddd;
            background: #f8f9fa;
            transition: all 0.3s;
        }

        .detection-card .label {
            font-size: 0.85rem;
            color: #666;
            display: block;
            margin-bottom: 5px;
        }

        .detection-card .value {
            font-size: 1.1rem;
            font-weight: bold;
            color: #007bff;
        }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #007bff;
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px rgba(0,123,255,0.4);
            z-index: 1000;
            transition: all 0.3s;
            display: flex;
            flex-direction: column;
            gap: 3px;
        }

        .live-indicator .detail {
            font-size: 0.75rem;
            opacity: 0.9;
        }

        /* ====== PRINT STYLES ====== */
        @media print {
            body {
                background: white;
                color: black;
                padding: 0;
            }
            section {
                box-shadow: none;
                border: 1px solid #ccc;
                page-break-inside: avoid;
            }
            .code-block {
                background: #f4f4f4;
                color: #333;
                border: 1px solid #ddd;
            }
            .no-print {
                display: none;
            }
            .live-indicator {
                display: none;
            }
        }
    </style>
</head>
<body>

    <h1>overflow-block and overflow-inline Media Features</h1>

    <!-- ====== 1. OVERFLOW-BLOCK DEMO ====== -->
    <section>
        <h2>1. overflow-block</h2>
        <p>Checks how the device handles overflow along the <strong>block axis</strong> (vertical in horizontal writing modes).</p>

        <div class="overflow-block-demo">
            Block Axis Overflow
        </div>

        <div class="axis-viz">
            <div class="axis-row">
                <span class="axis-label">Block Axis:</span>
                <span class="axis-arrow">↕</span>
                <span class="axis-description">Vertical (top → bottom)</span>
            </div>
        </div>

        <div class="code-block">
            /* Content is clipped */
            @media (overflow-block: none) {
                div { color: red; }
            }

            /* Content can be scrolled */
            @media (overflow-block: scroll) {
                div { color: blue; }
            }

            /* Can paginate or scroll */
            @media (overflow-block: optional-paged) {
                div { color: orange; }
            }

            /* Content is broken into pages */
            @media (overflow-block: paged) {
                div { color: green; }
            }
        </div>

        <p class="note"><strong>Try it:</strong> Print this page to see <code>overflow-block: paged</code> in action!</p>
    </section>

    <!-- ====== 2. OVERFLOW-INLINE DEMO ====== -->
    <section>
        <h2>2. overflow-inline</h2>
        <p>Checks how the device handles overflow along the <strong>inline axis</strong> (horizontal in horizontal writing modes).</p>

        <div class="overflow-inline-demo">
            Inline Axis Overflow
        </div>

        <div class="axis-viz">
            <div class="axis-row">
                <span class="axis-label">Inline Axis:</span>
                <span class="axis-arrow">↔</span>
                <span class="axis-description">Horizontal (left → right)</span>
            </div>
        </div>

        <div class="code-block">
            /* Inline overflow is clipped */
            @media (overflow-inline: none) {
                div { color: blue; }
            }

            /* Inline overflow can be scrolled */
            @media (overflow-inline: scroll) {
                div { color: blue; }
            }
        </div>
    </section>

    <!-- ====== 3. CONTENT OVERFLOW DEMO ====== -->
    <section>
        <h2>3. Content Overflow Demo</h2>
        <p>This container demonstrates inline overflow behavior.</p>

        <div class="overflow-container">
            <div class="long-content">
                This is a very long line of text that will overflow the container if it's too wide. On devices with <code>overflow-inline: scroll</code>, you can scroll horizontally to see the rest. On devices with <code>overflow-inline: none</code>, the text is clipped. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            </div>
        </div>

        <div class="code-block">
            .overflow-container {
                overflow: auto; /* Handles both axes */
            }

            /* Inline overflow behavior */
            @media (overflow-inline: scroll) {
                .overflow-container {
                    overflow-x: auto; /* Horizontal scroll */
                }
            }

            @media (overflow-inline: none) {
                .overflow-container {
                    overflow-x: hidden; /* Clip */
                }
            }
        </div>
    </section>

    <!-- ====== 4. PRACTICAL: PAGED MEDIA ====== -->
    <section class="no-print">
        <h2>4. Practical Example: Paged Media Styles</h2>
        <p>This article uses <code>overflow-block</code> to adapt to paged media.</p>
    </section>

    <div class="article">
        <h3>📄 Sample Article</h3>
        <p>
            This article demonstrates how to adapt styles for different overflow behaviors.
            On a screen (with <code>overflow-block: scroll</code>), it has a shadow and border.
            When printed (with <code>overflow-block: paged</code>), it becomes clean and borderless,
            with proper page-break controls.
        </p>
        <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
            incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
            exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
        </p>
        <p>
            Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
            fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
            culpa qui officia deserunt mollit anim id est laborum.
        </p>
        <p class="no-print" style="color: #6c757d; font-style: italic;">
            (This paragraph is hidden when printed.)
        </p>
    </div>

    <div class="code-block no-print">
        /* Paged media styles */
        @media (overflow-block: paged) {
            .article {
                border: none;
                padding: 0;
                background: transparent;
            }
            .article h3 {
                page-break-after: avoid;
            }
            .article p {
                orphans: 3;
                widows: 3;
            }
            .no-print {
                display: none;
            }
        }

        /* Scrollable media styles */
        @media (overflow-block: scroll) {
            .article {
                box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            }
        }
    </div>

    <!-- ====== 5. DETECTION SUMMARY ====== -->
    <section>
        <h2>5. Your Device's Overflow Handling</h2>
        <p>Below is a live detection of your device's overflow capabilities.</p>

        <div class="detection-grid">
            <div class="detection-card" id="ob-none">
                <span class="label">overflow-block: none</span>
                <span class="value" id="ob-none-value">Detecting...</span>
            </div>
            <div class="detection-card" id="ob-scroll">
                <span class="label">overflow-block: scroll</span>
                <span class="value" id="ob-scroll-value">Detecting...</span>
            </div>
            <div class="detection-card" id="ob-paged">
                <span class="label">overflow-block: paged</span>
                <span class="value" id="ob-paged-value">Detecting...</span>
            </div>
            <div class="detection-card" id="ob-optional-paged">
                <span class="label">overflow-block: optional-paged</span>
                <span class="value" id="ob-optional-paged-value">Detecting...</span>
            </div>
            <div class="detection-card" id="oi-none">
                <span class="label">overflow-inline: none</span>
                <span class="value" id="oi-none-value">Detecting...</span>
            </div>
            <div class="detection-card" id="oi-scroll">
                <span class="label">overflow-inline: scroll</span>
                <span class="value" id="oi-scroll-value">Detecting...</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect overflow-block */
            @media (overflow-block: none) { /* Clipped */ }
            @media (overflow-block: scroll) { /* Scrollable */ }
            @media (overflow-block: optional-paged) { /* Scroll or paginate */ }
            @media (overflow-block: paged) { /* Paginated */ }

            /* Detect overflow-inline */
            @media (overflow-inline: none) { /* Clipped */ }
            @media (overflow-inline: scroll) { /* Scrollable */ }
        </div>
    </section>

    <!-- ====== 6. REFERENCE TABLES ====== -->
    <section>
        <h2>6. Reference Tables</h2>

        <h3>overflow-block Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Device Example</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>Overflowing content is clipped</td>
                <td>Projection, some terminals</td>
            </tr>
            <tr>
                <td><code>scroll</code></td>
                <td>Content can be scrolled</td>
                <td>Computer screens, phones</td>
            </tr>
            <tr>
                <td><code>optional-paged</code></td>
                <td>Can scroll or paginate</td>
                <td>Some e-readers</td>
            </tr>
            <tr>
                <td><code>paged</code></td>
                <td>Content is broken into pages</td>
                <td>Print, e-readers</td>
            </tr>
        </table>

        <h3>overflow-inline Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Device Example</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>Overflowing content is clipped</td>
                <td>Print, some terminals</td>
            </tr>
            <tr>
                <td><code>scroll</code></td>
                <td>Content can be scrolled horizontally</td>
                <td>Computer screens, phones</td>
            </tr>
        </table>

        <h3>Block vs Inline Axis</h3>
        <table class="reference-table">
            <tr>
                <th>Axis</th>
                <th>Description</th>
                <th>Default Direction</th>
            </tr>
            <tr>
                <td><strong>Block axis</strong></td>
                <td>Direction of block-level layout</td>
                <td>Vertical (top → bottom)</td>
            </tr>
            <tr>
                <td><strong>Inline axis</strong></td>
                <td>Direction of inline content flow</td>
                <td>Horizontal (left → right)</td>
            </tr>
        </table>

        <h3>Device Detection Summary</h3>
        <table class="reference-table">
            <tr>
                <th>Device</th>
                <th>overflow-block</th>
                <th>overflow-inline</th>
            </tr>
            <tr>
                <td>Computer screen</td>
                <td><code>scroll</code></td>
                <td><code>scroll</code></td>
            </tr>
            <tr>
                <td>Smartphone</td>
                <td><code>scroll</code></td>
                <td><code>scroll</code></td>
            </tr>
            <tr>
                <td>Printed page</td>
                <td><code>paged</code></td>
                <td><code>none</code></td>
            </tr>
            <tr>
                <td>E-reader</td>
                <td><code>paged</code></td>
                <td><code>none</code></td>
            </tr>
            <tr>
                <td>Text terminal</td>
                <td><code>scroll</code></td>
                <td><code>scroll</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 7. BEST PRACTICES ====== -->
    <section>
        <h2>7. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>overflow-block</code> to adapt styles for paged media (print, e-readers)</li>
                <li>Use <code>overflow-inline</code> to handle horizontal overflow on different devices</li>
                <li>Provide print-friendly styles with <code>overflow-block: paged</code></li>
                <li>Use <code>orphans</code> and <code>widows</code> for paged media</li>
                <li>Test your print styles with the browser's print preview</li>
                <li>Hide non-essential elements (like navigation) in paged media</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't rely on <code>overflow-block</code> for critical functionality — it's for enhancements</li>
                <li>Don't forget that axes swap in vertical writing modes</li>
                <li>Don't assume all devices support the same overflow behavior</li>
                <li>Don't use <code>overflow-inline: none</code> for essential content</li>
                <li>Don't ignore paged media — many users print web pages</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator no-print" id="live-indicator">
        <span id="indicator-block">Block: —</span>
        <span class="detail" id="indicator-inline">Inline: —</span>
    </div>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        function updateIndicators() {
            // overflow-block detection
            const obNone = document.getElementById('ob-none');
            const obScroll = document.getElementById('ob-scroll');
            const obPaged = document.getElementById('ob-paged');
            const obOptionalPaged = document.getElementById('ob-optional-paged');

            const isObNone = window.matchMedia('(overflow-block: none)').matches;
            const isObScroll = window.matchMedia('(overflow-block: scroll)').matches;
            const isObPaged = window.matchMedia('(overflow-block: paged)').matches;
            const isObOptionalPaged = window.matchMedia('(overflow-block: optional-paged)').matches;

            function setCard(card, isActive, activeText, inactiveText) {
                const value = card.querySelector('.value');
                if (isActive) {
                    value.textContent = activeText;
                    card.style.background = '#d4edda';
                    card.style.borderColor = '#28a745';
                    value.style.color = '#28a745';
                } else {
                    value.textContent = inactiveText;
                    card.style.background = '#e9ecef';
                    card.style.borderColor = '#6c757d';
                    value.style.color = '#6c757d';
                }
            }

            setCard(obNone, isObNone, 'Active ✅', 'Not active');
            setCard(obScroll, isObScroll, 'Active ✅', 'Not active');
            setCard(obPaged, isObPaged, 'Active ✅', 'Not active');
            setCard(obOptionalPaged, isObOptionalPaged, 'Active ✅', 'Not active');

            // overflow-inline detection
            const oiNone = document.getElementById('oi-none');
            const oiScroll = document.getElementById('oi-scroll');

            const isOiNone = window.matchMedia('(overflow-inline: none)').matches;
            const isOiScroll = window.matchMedia('(overflow-inline: scroll)').matches;

            setCard(oiNone, isOiNone, 'Active ✅', 'Not active');
            setCard(oiScroll, isOiScroll, 'Active ✅', 'Not active');

            // Live indicator
            const indicatorBlock = document.getElementById('indicator-block');
            const indicatorInline = document.getElementById('indicator-inline');
            const indicator = document.getElementById('live-indicator');

            let blockValue = 'unknown';
            if (isObScroll) blockValue = 'scroll';
            else if (isObPaged) blockValue = 'paged';
            else if (isObOptionalPaged) blockValue = 'optional-paged';
            else if (isObNone) blockValue = 'none';

            let inlineValue = 'unknown';
            if (isOiScroll) inlineValue = 'scroll';
            else if (isOiNone) inlineValue = 'none';

            indicatorBlock.textContent = '📄 Block: ' + blockValue;
            indicatorInline.textContent = '↔️ Inline: ' + inlineValue;

            // Color the indicator
            if (blockValue === 'paged' || blockValue === 'optional-paged') {
                indicator.style.background = '#28a745';
                indicator.style.color = 'white';
            } else if (blockValue === 'scroll') {
                indicator.style.background = '#007bff';
                indicator.style.color = 'white';
            } else {
                indicator.style.background = '#dc3545';
                indicator.style.color = 'white';
            }
        }

        window.addEventListener('load', updateIndicators);

        // Listen for print changes (when print preview is opened)
        window.addEventListener('beforeprint', function() {
            // Print media queries become active
            setTimeout(updateIndicators, 100);
        });

        window.addEventListener('afterprint', function() {
            setTimeout(updateIndicators, 100);
        });

        updateIndicators();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionAxis
overflow-blockOverflow handling on block axisVertical (default)
overflow-inlineOverflow handling on inline axisHorizontal (default)

overflow-block Values

ValueDescriptionDevice Example
noneContent is clippedProjection, some terminals
scrollContent can be scrolledComputer screens, phones
optional-pagedCan scroll or paginateSome e-readers
pagedContent is broken into pagesPrint, e-readers

overflow-inline Values

ValueDescriptionDevice Example
noneContent is clippedPrint, some terminals
scrollContent can be scrolled horizontallyComputer screens, phones

Block vs Inline Axis

AxisDescriptionDefault Direction
Block axisDirection of block-level layoutVertical (top → bottom)
Inline axisDirection of inline content flowHorizontal (left → right)

Best Practices

Do This:

/* Print-friendly styles */
@media (overflow-block: paged) {
    .article {
        border: none;
        padding: 0;
    }
    .article p {
        orphans: 3;
        widows: 3;
    }
    .no-print {
        display: none;
    }
}

/* Screen-friendly styles */
@media (overflow-block: scroll) {
    .article {
        box-shadow: 0 2px 10px rgba(0,0,0,0.1);
    }
}

/* Handle inline overflow */
@media (overflow-inline: scroll) {
    .container {
        overflow-x: auto;
    }
}

Don’t Do This:

/* Don't rely on overflow-block for critical functionality */
@media (overflow-block: paged) {
    /* This is fine for enhancements, but don't hide essential content */
}

/* Don't forget that axes swap in vertical writing modes */
@media (overflow-block: scroll) {
    /* In vertical-rl, this now refers to horizontal scrolling */
}

/* Don't ignore print styles */
/* Many users still print web pages! */

Pro Tip: overflow-block and overflow-inline are most useful for paged media (print, e-readers). Use overflow-block: paged to provide clean, print-friendly styles — remove shadows, borders, and non-essential elements, and use orphans/widows to control page breaks. Remember that the block and inline axes swap in vertical writing modes (like writing-mode: vertical-rl), so these features adapt automatically to the writing direction!

40. pointer and resolution Media Features

These two media features let you adapt styles based on the accuracy of the pointing device and the pixel density of the display — essential for touch-friendly interfaces and high-DPI screens.


Overview of Features

FeatureDescriptionValues
pointerAccuracy of the primary pointing devicenone, coarse, fine
resolutionPixel density of the output devicedpi, dpcm, dppx

1. pointer

The pointer media feature queries the accuracy of the primary pointing device — such as a mouse, touchpad, or touchscreen.

@media (pointer: fine) {
    .container {
        padding: 20px;
        border: 1px solid #add8e6;
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    }
}

Values

ValueDescriptionDevice Example
noneNo pointing device availableKeyboard-only device, TV remote
coarsePointing device with limited accuracyFinger on touchscreen, stylus
finePointing device with fine accuracyMouse, trackpad, precision stylus

Real-World Examples

Devicepointer Value
Desktop with mousefine
Laptop with trackpadfine
Smartphone (touch)coarse
Tablet (touch)coarse
Smart TV (remote)none or coarse
Gaming console (controller)none or coarse

pointer vs any-pointer

FeatureDescription
pointerPrimary pointing device’s accuracy
any-pointerBest accuracy among all pointing devices

Example:

  • Laptop with touchscreen and mouse:
    • pointer: fine (primary is mouse)
    • any-pointer: fine (at least one fine pointer)
  • Tablet with Bluetooth mouse:
    • pointer: coarse (primary is touch)
    • any-pointer: fine (mouse is fine)

2. resolution

The resolution media feature queries the pixel density of the output device.

@media (resolution: 150dpi) {
    .container {
        padding: 10px;
        border: 1px solid red;
    }
}

Values

UnitDescriptionExample
dpiDots per inch150dpi
dpcmDots per centimeter60dpcm
dppxDots per pixel unit (1dppx = 96dpi)2dppx

Variations

FeatureDescriptionExample
resolutionExact resolution@media (resolution: 150dpi)
min-resolutionMinimum resolution@media (min-resolution: 2dppx)
max-resolutionMaximum resolution@media (max-resolution: 72dpi)

Common Resolutions

DeviceResolutiondppx Equivalent
Older monitors72–96 dpi0.75–1 dppx
Standard laptops96–120 dpi1–1.25 dppx
Retina displays192–220 dpi2–2.3 dppx
High-end smartphones400–500 dpi4–5 dppx
4K monitors150–200 dpi1.5–2 dppx

Unit Conversions

1 dppx = 96 dpi
1 dpi = 1/96 dppx
1 dpcm = 2.54 dpi

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>pointer and resolution Media Features</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
            transition: background 0.3s, color 0.3s;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
            transition: all 0.3s;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== POINTER DEMO ====== */
        .container {
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 8px;
            margin: 15px 0;
            transition: all 0.3s;
            text-align: center;
            font-weight: bold;
            font-size: 1.1rem;
            background: #f8f9fa;
        }

        /* Fine pointer (mouse) */
        @media (pointer: fine) {
            .container {
                padding: 20px;
                border: 2px solid #add8e6;
                box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
                background: #e3f2fd;
            }
            .container::after {
                content: " 🖱️ Fine pointer (mouse)";
                font-weight: normal;
                font-size: 0.85rem;
                color: #007bff;
            }
        }

        /* Coarse pointer (touch) */
        @media (pointer: coarse) {
            .container {
                padding: 10px;
                border: 2px solid #98fb98;
                box-shadow: none;
                background: #e8f5e9;
            }
            .container::after {
                content: " 👆 Coarse pointer (touch)";
                font-weight: normal;
                font-size: 0.85rem;
                color: #28a745;
            }
        }

        /* No pointer */
        @media (pointer: none) {
            .container {
                padding: 15px;
                border: 2px dashed #dc3545;
                background: #f8d7da;
            }
            .container::after {
                content: " ⌨️ No pointing device";
                font-weight: normal;
                font-size: 0.85rem;
                color: #dc3545;
            }
        }

        /* ====== TOUCH-FRIENDLY BUTTONS ====== */
        .btn-group {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin: 15px 0;
        }

        .btn {
            padding: 12px 24px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 1em;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
        }

        /* Larger buttons for touch */
        @media (pointer: coarse) {
            .btn {
                padding: 16px 32px;
                font-size: 1.1em;
                min-height: 48px;
                min-width: 120px;
            }
        }

        /* Smaller buttons for mouse */
        @media (pointer: fine) {
            .btn {
                padding: 10px 20px;
                font-size: 0.95em;
            }
            .btn:hover {
                background: #0056b3;
                transform: translateY(-2px);
            }
        }

        /* ====== RESOLUTION DEMO ====== */
        .resolution-demo {
            padding: 20px;
            border-radius: 8px;
            margin: 15px 0;
            text-align: center;
            font-weight: bold;
            font-size: 1.1rem;
            transition: all 0.3s;
            background: #e9ecef;
            border: 2px solid #ddd;
        }

        /* Low resolution (≤ 72dpi) */
        @media (max-resolution: 72dpi) {
            .resolution-demo {
                background: #ff6b6b;
                color: white;
                border-color: #c92a2a;
            }
            .resolution-demo::after {
                content: " (low resolution ≤ 72dpi)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Medium resolution (72–150dpi) */
        @media (min-resolution: 72dpi) and (max-resolution: 192dpi) {
            .resolution-demo {
                background: #ffc107;
                color: #333;
                border-color: #d39e00;
            }
            .resolution-demo::after {
                content: " (medium resolution 72–192dpi)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* High resolution (≥ 2dppx / 192dpi) */
        @media (min-resolution: 2dppx) {
            .resolution-demo {
                background: #28a745;
                color: white;
                border-color: #1e7e34;
            }
            .resolution-demo::after {
                content: " (high resolution ≥ 2dppx)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* ====== HDPI IMAGE DEMO ====== */
        .hdpi-demo {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            align-items: center;
            margin: 15px 0;
        }

        .hdpi-demo .image-box {
            width: 200px;
            height: 150px;
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 1rem;
            text-align: center;
            padding: 20px;
            /* Standard resolution image */
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            transition: all 0.3s;
        }

        /* Sharper image for high-DPI displays */
        @media (min-resolution: 2dppx) {
            .hdpi-demo .image-box {
                background: linear-gradient(135deg, #007bff, #6c5ce7);
                box-shadow: 0 0 0 2px #28a745, 0 4px 20px rgba(40, 167, 69, 0.3);
            }
            .hdpi-demo .image-box::after {
                content: " (HDPI enhanced)";
                font-weight: normal;
                font-size: 0.8rem;
            }
        }

        /* ====== BORDER WIDTH ADJUSTMENT ====== */
        .border-demo {
            padding: 20px;
            margin: 15px 0;
            border-radius: 8px;
            background: #f8f9fa;
            text-align: center;
            transition: all 0.3s;
            /* Default border */
            border: 1px solid #007bff;
        }

        /* Thinner borders on high-DPI (1px looks thicker) */
        @media (min-resolution: 2dppx) {
            .border-demo {
                border-width: 0.5px;
            }
        }

        /* ====== DETECTION CARDS ====== */
        .detection-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .detection-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            border: 2px solid #ddd;
            background: #f8f9fa;
            transition: all 0.3s;
        }

        .detection-card .label {
            font-size: 0.85rem;
            color: #666;
            display: block;
            margin-bottom: 5px;
        }

        .detection-card .value {
            font-size: 1.1rem;
            font-weight: bold;
            color: #007bff;
        }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #007bff;
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px rgba(0,123,255,0.4);
            z-index: 1000;
            transition: all 0.3s;
            display: flex;
            flex-direction: column;
            gap: 3px;
        }

        .live-indicator .detail {
            font-size: 0.75rem;
            opacity: 0.9;
        }

        /* ====== PRACTICAL: TOUCH-FRIENDLY FORM ====== */
        .form-group {
            margin-bottom: 15px;
        }

        .form-group label {
            display: block;
            font-weight: bold;
            margin-bottom: 5px;
            color: #333;
        }

        .form-group input,
        .form-group select {
            width: 100%;
            padding: 10px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 1em;
            transition: all 0.3s;
        }

        .form-group input:focus,
        .form-group select:focus {
            border-color: #007bff;
            outline: none;
            box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.15);
        }

        /* Larger touch targets for coarse pointers */
        @media (pointer: coarse) {
            .form-group input,
            .form-group select {
                padding: 16px;
                font-size: 1.1em;
                min-height: 48px;
            }
            .form-group label {
                font-size: 1.05em;
            }
        }
    </style>
</head>
<body>

    <h1>pointer and resolution Media Features</h1>

    <!-- ====== 1. POINTER DEMO ====== -->
    <section>
        <h2>1. pointer</h2>
        <p>Queries the <strong>accuracy of the primary pointing device</strong>.</p>

        <div class="container">
            Pointer Detection
        </div>

        <p class="note">On desktop with a mouse: fine. On mobile with touch: coarse. On keyboard-only: none.</p>

        <div class="code-block">
            /* Fine pointer (mouse, trackpad) */
            @media (pointer: fine) {
                .container {
                    padding: 20px;
                    border: 2px solid #add8e6;
                    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
                }
            }

            /* Coarse pointer (touch) */
            @media (pointer: coarse) {
                .container {
                    padding: 10px;
                    border: 2px solid #98fb98;
                    box-shadow: none;
                }
            }

            /* No pointer */
            @media (pointer: none) {
                .container {
                    border: 2px dashed #dc3545;
                }
            }
        </div>
    </section>

    <!-- ====== 2. TOUCH-FRIENDLY BUTTONS ====== -->
    <section>
        <h2>2. Touch-Friendly Buttons</h2>
        <p>Buttons adapt their size based on pointer accuracy.</p>

        <div class="btn-group">
            <button class="btn">Primary</button>
            <button class="btn">Secondary</button>
            <button class="btn">Tertiary</button>
        </div>

        <p class="note">On touch devices, buttons have larger touch targets (48px minimum).</p>

        <div class="code-block">
            /* Smaller buttons for mouse */
            @media (pointer: fine) {
                .btn {
                    padding: 10px 20px;
                }
                .btn:hover {
                    transform: translateY(-2px);
                }
            }

            /* Larger buttons for touch */
            @media (pointer: coarse) {
                .btn {
                    padding: 16px 32px;
                    min-height: 48px;
                    min-width: 120px;
                }
            }
        </div>
    </section>

    <!-- ====== 3. RESOLUTION DEMO ====== -->
    <section>
        <h2>3. resolution</h2>
        <p>Queries the <strong>pixel density</strong> of the output device.</p>

        <div class="resolution-demo">
            Resolution Detection
        </div>

        <div class="code-block">
            /* Low resolution */
            @media (max-resolution: 72dpi) {
                .demo { background: #ff6b6b; }
            }

            /* Medium resolution */
            @media (min-resolution: 72dpi) and (max-resolution: 192dpi) {
                .demo { background: #ffc107; }
            }

            /* High resolution */
            @media (min-resolution: 2dppx) {
                .demo { background: #28a745; }
            }
        </div>
    </section>

    <!-- ====== 4. HDPI IMAGE ENHANCEMENT ====== -->
    <section>
        <h2>4. HDPI Image Enhancement</h2>
        <p>Images can be enhanced on high-resolution displays.</p>

        <div class="hdpi-demo">
            <div class="image-box">🖼️ HDPI Image</div>
            <p>On high-DPI displays (≥ 2dppx), this image gets a sharper border and enhanced shadow.</p>
        </div>

        <div class="code-block">
            /* Sharper image for high-DPI displays */
            @media (min-resolution: 2dppx) {
                .image-box {
                    box-shadow: 0 0 0 2px #28a745, 0 4px 20px rgba(40, 167, 69, 0.3);
                }
            }
        </div>
    </section>

    <!-- ====== 5. BORDER WIDTH ADJUSTMENT ====== -->
    <section>
        <h2>5. Border Width Adjustment</h2>
        <p>Thin borders look thicker on high-DPI displays. This border adjusts accordingly.</p>

        <div class="border-demo">
            This border is 1px on standard displays and 0.5px on high-DPI displays.
        </div>

        <div class="code-block">
            /* Thinner borders on high-DPI */
            @media (min-resolution: 2dppx) {
                .border-demo {
                    border-width: 0.5px;
                }
            }
        </div>
    </section>

    <!-- ====== 6. PRACTICAL: TOUCH-FRIENDLY FORM ====== -->
    <section>
        <h2>6. Practical Example: Touch-Friendly Form</h2>
        <p>Form inputs adapt their size based on pointer accuracy.</p>

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

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

        <div class="form-group">
            <label for="country">Country:</label>
            <select id="country">
                <option value="">Select a country</option>
                <option value="us">United States</option>
                <option value="uk">United Kingdom</option>
                <option value="ca">Canada</option>
            </select>
        </div>

        <div class="code-block">
            /* Larger touch targets for coarse pointers */
            @media (pointer: coarse) {
                .form-group input,
                .form-group select {
                    padding: 16px;
                    font-size: 1.1em;
                    min-height: 48px;
                }
            }
        </div>
    </section>

    <!-- ====== 7. DETECTION SUMMARY ====== -->
    <section>
        <h2>7. Your Device's Capabilities</h2>
        <p>Below is a live detection of your device's capabilities.</p>

        <div class="detection-grid">
            <div class="detection-card" id="pointer-fine">
                <span class="label">pointer: fine</span>
                <span class="value" id="pointer-fine-value">Detecting...</span>
            </div>
            <div class="detection-card" id="pointer-coarse">
                <span class="label">pointer: coarse</span>
                <span class="value" id="pointer-coarse-value">Detecting...</span>
            </div>
            <div class="detection-card" id="pointer-none">
                <span class="label">pointer: none</span>
                <span class="value" id="pointer-none-value">Detecting...</span>
            </div>
            <div class="detection-card" id="any-pointer-fine">
                <span class="label">any-pointer: fine</span>
                <span class="value" id="any-pointer-fine-value">Detecting...</span>
            </div>
            <div class="detection-card" id="res-low">
                <span class="label">max-resolution: 72dpi</span>
                <span class="value" id="res-low-value">Detecting...</span>
            </div>
            <div class="detection-card" id="res-high">
                <span class="label">min-resolution: 2dppx</span>
                <span class="value" id="res-high-value">Detecting...</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect pointer accuracy */
            @media (pointer: fine) { /* Mouse, trackpad */ }
            @media (pointer: coarse) { /* Touch */ }
            @media (pointer: none) { /* No pointer */ }

            /* Detect resolution */
            @media (max-resolution: 72dpi) { /* Low resolution */ }
            @media (min-resolution: 2dppx) { /* High resolution */ }
        </div>
    </section>

    <!-- ====== 8. REFERENCE TABLES ====== -->
    <section>
        <h2>8. Reference Tables</h2>

        <h3>pointer Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Device Example</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>No pointing device</td>
                <td>Keyboard-only, TV remote</td>
            </tr>
            <tr>
                <td><code>coarse</code></td>
                <td>Limited accuracy</td>
                <td>Finger on touchscreen, stylus</td>
            </tr>
            <tr>
                <td><code>fine</code></td>
                <td>Fine accuracy</td>
                <td>Mouse, trackpad, precision stylus</td>
            </tr>
        </table>

        <h3>pointer vs any-pointer</h3>
        <table class="reference-table">
            <tr>
                <th>Feature</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>pointer</code></td>
                <td>Primary pointing device's accuracy</td>
            </tr>
            <tr>
                <td><code>any-pointer</code></td>
                <td>Best accuracy among all pointing devices</td>
            </tr>
        </table>

        <h3>resolution Units</h3>
        <table class="reference-table">
            <tr>
                <th>Unit</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>dpi</code></td>
                <td>Dots per inch</td>
                <td><code>150dpi</code></td>
            </tr>
            <tr>
                <td><code>dpcm</code></td>
                <td>Dots per centimeter</td>
                <td><code>60dpcm</code></td>
            </tr>
            <tr>
                <td><code>dppx</code></td>
                <td>Dots per pixel unit (1dppx = 96dpi)</td>
                <td><code>2dppx</code></td>
            </tr>
        </table>

        <h3>Common Resolutions</h3>
        <table class="reference-table">
            <tr>
                <th>Device</th>
                <th>Resolution</th>
                <th>dppx</th>
            </tr>
            <tr>
                <td>Older monitors</td>
                <td>72–96 dpi</td>
                <td>0.75–1</td>
            </tr>
            <tr>
                <td>Standard laptops</td>
                <td>96–120 dpi</td>
                <td>1–1.25</td>
            </tr>
            <tr>
                <td>Retina displays</td>
                <td>192–220 dpi</td>
                <td>2–2.3</td>
            </tr>
            <tr>
                <td>High-end smartphones</td>
                <td>400–500 dpi</td>
                <td>4–5</td>
            </tr>
            <tr>
                <td>4K monitors</td>
                <td>150–200 dpi</td>
                <td>1.5–2</td>
            </tr>
        </table>
    </section>

    <!-- ====== 9. BEST PRACTICES ====== -->
    <section>
        <h2>9. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>pointer: coarse</code> to create larger touch targets (48px minimum)</li>
                <li>Use <code>pointer: fine</code> for hover effects and smaller UI elements</li>
                <li>Use <code>resolution</code> to serve higher-quality images on high-DPI displays</li>
                <li>Adjust border widths for high-DPI displays (0.5px looks like 1px)</li>
                <li>Test on both touch and mouse devices</li>
                <li>Use <code>min-resolution: 2dppx</code> for Retina/HDPI optimizations</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't rely solely on pointer type — some devices have both</li>
                <li>Don't use tiny touch targets on touch devices</li>
                <li>Don't serve large images to low-resolution displays</li>
                <li>Don't assume all high-DPI displays are mobile</li>
                <li>Don't forget that <code>pointer</code> checks the primary device only</li>
                <li>Don't use <code>resolution</code> for critical functionality</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator" id="live-indicator">
        <span id="indicator-pointer">Pointer: —</span>
        <span class="detail" id="indicator-resolution">Resolution: —</span>
    </div>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        function updateIndicators() {
            // Pointer detection
            const pointerFine = document.getElementById('pointer-fine');
            const pointerCoarse = document.getElementById('pointer-coarse');
            const pointerNone = document.getElementById('pointer-none');
            const anyPointerFine = document.getElementById('any-pointer-fine');

            const isFine = window.matchMedia('(pointer: fine)').matches;
            const isCoarse = window.matchMedia('(pointer: coarse)').matches;
            const isNone = window.matchMedia('(pointer: none)').matches;
            const isAnyFine = window.matchMedia('(any-pointer: fine)').matches;

            function setCard(card, isActive, activeText, inactiveText) {
                const value = card.querySelector('.value');
                if (isActive) {
                    value.textContent = activeText;
                    card.style.background = '#d4edda';
                    card.style.borderColor = '#28a745';
                    value.style.color = '#28a745';
                } else {
                    value.textContent = inactiveText;
                    card.style.background = '#e9ecef';
                    card.style.borderColor = '#6c757d';
                    value.style.color = '#6c757d';
                }
            }

            setCard(pointerFine, isFine, 'Active ✅', 'Not active');
            setCard(pointerCoarse, isCoarse, 'Active ✅', 'Not active');
            setCard(pointerNone, isNone, 'Active ✅', 'Not active');
            setCard(anyPointerFine, isAnyFine, 'Active ✅', 'Not active');

            // Resolution detection
            const resLow = document.getElementById('res-low');
            const resHigh = document.getElementById('res-high');

            const isLowRes = window.matchMedia('(max-resolution: 72dpi)').matches;
            const isHighRes = window.matchMedia('(min-resolution: 2dppx)').matches;

            setCard(resLow, isLowRes, 'Low Res ✅', 'Not low res');
            setCard(resHigh, isHighRes, 'High DPI ✅', 'Not high DPI');

            // Live indicator
            const indicatorPointer = document.getElementById('indicator-pointer');
            const indicatorResolution = document.getElementById('indicator-resolution');
            const indicator = document.getElementById('live-indicator');

            let pointerText = '';
            if (isFine) pointerText = '🖱️ Fine (Mouse)';
            else if (isCoarse) pointerText = '👆 Coarse (Touch)';
            else if (isNone) pointerText = '⌨️ None';
            else pointerText = '❓ Unknown';

            indicatorPointer.textContent = 'Pointer: ' + pointerText;

            // Resolution display
            const dpr = window.devicePixelRatio || 1;
            const dpi = Math.round(dpr * 96);
            let resText = dpr + 'x (' + dpi + 'dpi)';
            if (isHighRes) resText += ' — HDPI';
            indicatorResolution.textContent = 'Resolution: ' + resText;

            // Color the indicator
            if (isFine) {
                indicator.style.background = '#007bff';
                indicator.style.color = 'white';
            } else if (isCoarse) {
                indicator.style.background = '#28a745';
                indicator.style.color = 'white';
            } else {
                indicator.style.background = '#dc3545';
                indicator.style.color = 'white';
            }

            if (isHighRes) {
                indicator.style.boxShadow = '0 4px 15px rgba(40, 167, 69, 0.5)';
            }
        }

        window.addEventListener('load', updateIndicators);
        window.addEventListener('resize', updateIndicators);

        updateIndicators();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionValues
pointerPrimary pointing device accuracynone, coarse, fine
resolutionPixel densitydpi, dpcm, dppx

pointer Values

ValueDescriptionDevice Example
noneNo pointing deviceKeyboard-only, TV remote
coarseLimited accuracyFinger on touchscreen
fineFine accuracyMouse, trackpad

resolution Units

UnitDescriptionExample
dpiDots per inch150dpi
dpcmDots per centimeter60dpcm
dppxDots per pixel unit (1dppx = 96dpi)2dppx

Common Resolutions

DeviceResolutiondppx
Older monitors72–96 dpi0.75–1
Standard laptops96–120 dpi1–1.25
Retina displays192–220 dpi2–2.3
High-end smartphones400–500 dpi4–5
4K monitors150–200 dpi1.5–2

Best Practices

Do This:

/* Larger touch targets for touch devices */
@media (pointer: coarse) {
    .btn {
        padding: 16px 32px;
        min-height: 48px;
        min-width: 120px;
    }
}

/* Hover effects only for mouse */
@media (pointer: fine) {
    .btn:hover {
        transform: translateY(-2px);
    }
}

/* Sharper images for HDPI */
@media (min-resolution: 2dppx) {
    .image {
        background-image: url('image@2x.png');
    }
}

/* Thinner borders on HDPI */
@media (min-resolution: 2dppx) {
    .border {
        border-width: 0.5px;
    }
}

Don’t Do This:

/* Don't use tiny touch targets */
@media (pointer: coarse) {
    .btn {
        padding: 4px 8px; /* Too small for fingers! */
    }
}

/* Don't assume all high-DPI displays are mobile */
@media (min-resolution: 2dppx) {
    /* This could be a 4K desktop monitor */
}

/* Don't rely on pointer type alone */
@media (pointer: fine) {
    /* Some devices have both mouse and touch */
}

Pro Tip: pointer is essential for touch-friendly design. Use pointer: coarse to create larger touch targets (48px minimum) and pointer: fine for hover effects and precision interactions. resolution is key for high-DPI optimization — serve sharper images on Retina displays, and adjust border widths (0.5px looks like 1px on 2x displays). Remember: pointer checks the primary device, while any-pointer checks all devices. A laptop with both mouse and touchscreen has pointer: fine (mouse is primary) but any-pointer: fine too!

41. prefers-color-scheme and prefers-contrast Media Features

These two media features are essential for accessibility and personalization. They let you respect the user’s preferred color scheme (light/dark) and contrast level.


Overview of Features

FeatureDescriptionValues
prefers-color-schemeUser’s preferred color schemelight, dark
prefers-contrastUser’s preferred contrast levelno-preference, more, less, custom

1. prefers-color-scheme

The prefers-color-scheme media feature detects whether the user prefers a light or dark color theme.

@media (prefers-color-scheme: dark) {
    body {
        background-color: #333;
        color: white;
    }
}

Values

ValueDescription
lightUser prefers a light theme (or has no preference)
darkUser prefers a dark theme

How It Works

  • The user sets their preference in their operating system settings
  • Windows: Settings → Personalization → Colors → Choose your mode
  • macOS: System Preferences → General → Appearance
  • iOS: Settings → Display & Brightness → Appearance
  • Android: Settings → Display → Dark theme

Key Points:

  • light is the default if no preference is expressed
  • Always provide a light theme as the base, then enhance for dark
  • Use the same content and structure — only change colors
  • Test both themes for contrast and readability

2. prefers-contrast

The prefers-contrast media feature detects whether the user prefers more or less contrast.

@media (prefers-contrast: more) {
    body {
        background-color: #f0f0f0;
        color: #1a1a1a;
    }
}

Values

ValueDescription
no-preferenceNo specific preference (default)
moreUser prefers higher contrast
lessUser prefers lower contrast
customUser uses a specific set of colors/contrast

How It Works

  • The user sets their preference in their operating system accessibility settings
  • Windows: Settings → Ease of Access → Display → High contrast
  • macOS: System Preferences → Accessibility → Display → Increase contrast
  • iOS: Settings → Accessibility → Display & Text Size → Increase Contrast

Key Points:

  • more — increase contrast for better legibility
  • less — reduce contrast (for users sensitive to bright colors)
  • custom — user has chosen a specific color scheme (often with forced-colors)
  • Always ensure WCAG AAA contrast (7:1) for more

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>prefers-color-scheme and prefers-contrast</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        /* ====== BASE (LIGHT THEME) ====== */
        :root {
            --bg-primary: #ffffff;
            --bg-secondary: #f8f9fa;
            --bg-tertiary: #e9ecef;
            --text-primary: #212529;
            --text-secondary: #6c757d;
            --accent: #007bff;
            --accent-hover: #0056b3;
            --border: #dee2e6;
            --shadow: rgba(0, 0, 0, 0.1);
            --code-bg: #1e1e1e;
            --code-text: #d4d4d4;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: var(--bg-secondary);
            color: var(--text-primary);
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
            transition: background 0.3s, color 0.3s;
        }

        h1 {
            color: var(--accent);
            border-bottom: 3px solid var(--accent);
            padding-bottom: 10px;
        }

        h2 {
            color: var(--accent);
            border-left: 4px solid var(--accent);
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: var(--text-primary);
            margin-top: 20px;
        }

        section {
            background: var(--bg-primary);
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px var(--shadow);
            margin: 20px 0;
            transition: all 0.3s;
        }

        .code-block {
            background: var(--code-bg);
            color: var(--code-text);
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid var(--border);
            text-align: left;
        }

        .reference-table th {
            background: var(--accent);
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: var(--bg-tertiary);
        }

        .note {
            font-size: 0.9rem;
            color: var(--text-secondary);
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DARK THEME ====== */
        @media (prefers-color-scheme: dark) {
            :root {
                --bg-primary: #1a1a1a;
                --bg-secondary: #0d0d0d;
                --bg-tertiary: #2d2d2d;
                --text-primary: #f8f9fa;
                --text-secondary: #adb5bd;
                --accent: #4dabf7;
                --accent-hover: #339af0;
                --border: #444;
                --shadow: rgba(0, 0, 0, 0.5);
                --code-bg: #0d0d0d;
                --code-text: #d4d4d4;
            }
            .highlight {
                background: #4dabf7;
                color: #000;
            }
        }

        /* ====== HIGH CONTRAST ====== */
        @media (prefers-contrast: more) {
            :root {
                --bg-primary: #ffffff;
                --bg-secondary: #ffffff;
                --bg-tertiary: #f0f0f0;
                --text-primary: #000000;
                --text-secondary: #1a1a1a;
                --accent: #0000cc;
                --accent-hover: #000099;
                --border: #000000;
                --shadow: rgba(0, 0, 0, 0.3);
            }
            body {
                border: 2px solid #000;
                padding: 25px;
            }
            section {
                border: 2px solid #000;
                box-shadow: none;
            }
            h1 {
                border-bottom-width: 4px;
            }
            h2 {
                border-left-width: 6px;
            }
            .code-block {
                background: #000;
                color: #fff;
                border: 2px solid #000;
            }
            .reference-table th {
                background: #000;
                color: #fff;
            }
            .reference-table td {
                border-color: #000;
            }
            .note {
                color: #1a1a1a;
            }
            .highlight {
                background: #000;
                color: #fff;
                border: 1px solid #000;
            }
        }

        @media (prefers-contrast: more) and (prefers-color-scheme: dark) {
            :root {
                --bg-primary: #000000;
                --bg-secondary: #000000;
                --bg-tertiary: #1a1a1a;
                --text-primary: #ffffff;
                --text-secondary: #f0f0f0;
                --accent: #66b3ff;
                --accent-hover: #99ccff;
                --border: #ffffff;
            }
            body {
                border-color: #fff;
            }
            section {
                border-color: #fff;
            }
            .code-block {
                background: #000;
                color: #fff;
                border-color: #fff;
            }
            .reference-table th {
                background: #fff;
                color: #000;
            }
            .reference-table td {
                border-color: #fff;
            }
            .highlight {
                background: #fff;
                color: #000;
            }
        }

        /* ====== LOW CONTRAST ====== */
        @media (prefers-contrast: less) {
            :root {
                --bg-primary: #2d2d2d;
                --bg-secondary: #1a1a1a;
                --bg-tertiary: #3d3d3d;
                --text-primary: #d0d0d0;
                --text-secondary: #999;
                --accent: #6c9bd2;
                --accent-hover: #8aadd4;
                --border: #444;
                --shadow: rgba(0, 0, 0, 0.3);
            }
            .highlight {
                background: #6c9bd2;
                color: #1a1a1a;
            }
        }

        /* ====== DETECTION CARDS ====== */
        .detection-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .detection-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            border: 2px solid var(--border);
            background: var(--bg-tertiary);
            transition: all 0.3s;
        }

        .detection-card .label {
            font-size: 0.85rem;
            color: var(--text-secondary);
            display: block;
            margin-bottom: 5px;
        }

        .detection-card .value {
            font-size: 1.1rem;
            font-weight: bold;
            color: var(--accent);
        }

        .detection-card.active {
            border-color: var(--accent);
            background: var(--bg-primary);
        }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: var(--accent);
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px var(--shadow);
            z-index: 1000;
            transition: all 0.3s;
            display: flex;
            flex-direction: column;
            gap: 3px;
        }

        .live-indicator .detail {
            font-size: 0.75rem;
            opacity: 0.9;
        }

        /* ====== PRACTICAL: THEME TOGGLE DEMO ====== */
        .theme-demo {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            margin: 15px 0;
        }

        .theme-card {
            flex: 1;
            min-width: 250px;
            padding: 20px;
            border-radius: 12px;
            border: 2px solid var(--border);
            background: var(--bg-primary);
            transition: all 0.3s;
        }

        .theme-card h4 {
            margin-top: 0;
            color: var(--accent);
        }

        .theme-card .preview {
            padding: 15px;
            border-radius: 8px;
            background: var(--bg-tertiary);
            margin: 10px 0;
            text-align: center;
            font-weight: bold;
            border: 1px solid var(--border);
        }

        /* Light preview */
        .light-preview {
            background: #ffffff;
            color: #212529;
        }

        /* Dark preview */
        .dark-preview {
            background: #1a1a1a;
            color: #f8f9fa;
        }

        /* ====== CONTRAST VISUALIZATION ====== */
        .contrast-demo {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            margin: 15px 0;
        }

        .contrast-box {
            flex: 1;
            min-width: 200px;
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            border: 2px solid var(--border);
        }

        .contrast-normal {
            background: #ffffff;
            color: #6c757d;
        }

        .contrast-more {
            background: #ffffff;
            color: #000000;
            border-color: #000;
        }

        .contrast-less {
            background: #2d2d2d;
            color: #999;
        }

        /* ====== ACCESSIBILITY TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid var(--accent);
            background: var(--bg-tertiary);
        }

        .tip-box.success {
            border-left-color: #28a745;
        }

        .tip-box.warning {
            border-left-color: #ffc107;
        }

        .tip-box.danger {
            border-left-color: #dc3545;
        }
    </style>
</head>
<body>

    <h1>prefers-color-scheme and prefers-contrast</h1>

    <!-- ====== 1. COLOR SCHEME DEMO ====== -->
    <section>
        <h2>1. prefers-color-scheme</h2>
        <p>Detects the user's preferred <strong>color scheme</strong> (light or dark).</p>

        <div class="theme-demo">
            <div class="theme-card">
                <h4>☀️ Light Theme</h4>
                <div class="preview light-preview">
                    This is a light theme preview
                </div>
                <p class="note">Applied when user prefers light mode (or has no preference).</p>
            </div>
            <div class="theme-card">
                <h4>🌙 Dark Theme</h4>
                <div class="preview dark-preview">
                    This is a dark theme preview
                </div>
                <p class="note">Applied when user prefers dark mode.</p>
            </div>
        </div>

        <div class="code-block">
            /* Light theme (default) */
            :root {
                --bg-primary: #ffffff;
                --text-primary: #212529;
                --accent: #007bff;
            }

            /* Dark theme */
            @media (prefers-color-scheme: dark) {
                :root {
                    --bg-primary: #1a1a1a;
                    --text-primary: #f8f9fa;
                    --accent: #4dabf7;
                }
            }
        </div>

        <p class="note"><strong>Try it:</strong> Change your OS theme to dark mode and watch this page adapt!</p>
    </section>

    <!-- ====== 2. CONTRAST DEMO ====== -->
    <section>
        <h2>2. prefers-contrast</h2>
        <p>Detects the user's preferred <strong>contrast level</strong>.</p>

        <div class="contrast-demo">
            <div class="contrast-box contrast-normal">
                Normal Contrast<br>
                <small>#6c757d on #ffffff</small>
            </div>
            <div class="contrast-box contrast-more">
                More Contrast<br>
                <small>#000000 on #ffffff</small>
            </div>
            <div class="contrast-box contrast-less">
                Less Contrast<br>
                <small>#999 on #2d2d2d</small>
            </div>
        </div>

        <div class="code-block">
            /* High contrast preference */
            @media (prefers-contrast: more) {
                :root {
                    --text-primary: #000000;
                    --bg-primary: #ffffff;
                    --accent: #0000cc;
                }
                section {
                    border: 2px solid #000;
                    box-shadow: none;
                }
            }

            /* Low contrast preference */
            @media (prefers-contrast: less) {
                :root {
                    --bg-primary: #2d2d2d;
                    --text-primary: #d0d0d0;
                    --accent: #6c9bd2;
                }
            }
        </div>
    </section>

    <!-- ====== 3. COMBINED THEME + CONTRAST ====== -->
    <section>
        <h2>3. Combined Color Scheme + Contrast</h2>
        <p>Both features can work together for a fully personalized experience.</p>

        <div class="code-block">
            /* Dark + High Contrast */
            @media (prefers-contrast: more) and (prefers-color-scheme: dark) {
                :root {
                    --bg-primary: #000000;
                    --text-primary: #ffffff;
                    --accent: #66b3ff;
                    --border: #ffffff;
                }
            }

            /* Dark + Low Contrast */
            @media (prefers-contrast: less) and (prefers-color-scheme: dark) {
                :root {
                    --bg-primary: #2d2d2d;
                    --text-primary: #d0d0d0;
                }
            }
        </div>
    </section>

    <!-- ====== 4. DETECTION SUMMARY ====== -->
    <section>
        <h2>4. Your Preferences</h2>
        <p>Below is a live detection of your preferences.</p>

        <div class="detection-grid">
            <div class="detection-card" id="scheme-light">
                <span class="label">prefers-color-scheme: light</span>
                <span class="value" id="scheme-light-value">Detecting...</span>
            </div>
            <div class="detection-card" id="scheme-dark">
                <span class="label">prefers-color-scheme: dark</span>
                <span class="value" id="scheme-dark-value">Detecting...</span>
            </div>
            <div class="detection-card" id="contrast-no-pref">
                <span class="label">prefers-contrast: no-preference</span>
                <span class="value" id="contrast-no-pref-value">Detecting...</span>
            </div>
            <div class="detection-card" id="contrast-more">
                <span class="label">prefers-contrast: more</span>
                <span class="value" id="contrast-more-value">Detecting...</span>
            </div>
            <div class="detection-card" id="contrast-less">
                <span class="label">prefers-contrast: less</span>
                <span class="value" id="contrast-less-value">Detecting...</span>
            </div>
            <div class="detection-card" id="contrast-custom">
                <span class="label">prefers-contrast: custom</span>
                <span class="value" id="contrast-custom-value">Detecting...</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect color scheme */
            @media (prefers-color-scheme: light) { /* Light preference */ }
            @media (prefers-color-scheme: dark) { /* Dark preference */ }

            /* Detect contrast preference */
            @media (prefers-contrast: no-preference) { /* Default */ }
            @media (prefers-contrast: more) { /* High contrast */ }
            @media (prefers-contrast: less) { /* Low contrast */ }
            @media (prefers-contrast: custom) { /* Custom */ }
        </div>
    </section>

    <!-- ====== 5. ACCESSIBILITY TIPS ====== -->
    <section>
        <h2>5. Accessibility Tips</h2>

        <div class="tip-box success">
            <strong>✅ Do This:</strong>
            <ul style="margin: 5px 0;">
                <li>Start with light theme as the base</li>
                <li>Use CSS custom properties (variables) for easy theming</li>
                <li>Test both light and dark themes for contrast</li>
                <li>Respect the user's system preferences</li>
                <li>Ensure WCAG AA (4.5:1) or AAA (7:1) contrast</li>
            </ul>
        </div>

        <div class="tip-box warning">
            <strong>⚠️ Be Careful:</strong>
            <ul style="margin: 5px 0;">
                <li>Don't use pure black (#000) on pure white (#fff) — it's harsh</li>
                <li>Don't use pure white (#fff) on pure black (#000) — it causes halation</li>
                <li>Don't forget to test with actual users</li>
                <li>Don't override user preferences without good reason</li>
            </ul>
        </div>

        <div class="tip-box danger">
            <strong>❌ Don't Do This:</strong>
            <ul style="margin: 5px 0;">
                <li>Don't ignore user preferences — it's an accessibility issue</li>
                <li>Don't use low-contrast text (#999 on #fff)</li>
                <li>Don't rely solely on color to convey information</li>
                <li>Don't forget about images — they need dark mode variants too</li>
            </ul>
        </div>
    </section>

    <!-- ====== 6. REFERENCE TABLES ====== -->
    <section>
        <h2>6. Reference Tables</h2>

        <h3>prefers-color-scheme Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>light</code></td>
                <td>User prefers a light theme (or has no preference)</td>
            </tr>
            <tr>
                <td><code>dark</code></td>
                <td>User prefers a dark theme</td>
            </tr>
        </table>

        <h3>prefers-contrast Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>no-preference</code></td>
                <td>No specific preference (default)</td>
            </tr>
            <tr>
                <td><code>more</code></td>
                <td>User prefers higher contrast</td>
            </tr>
            <tr>
                <td><code>less</code></td>
                <td>User prefers lower contrast</td>
            </tr>
            <tr>
                <td><code>custom</code></td>
                <td>User uses a specific set of colors/contrast</td>
            </tr>
        </table>

        <h3>WCAG Contrast Requirements</h3>
        <table class="reference-table">
            <tr>
                <th>Level</th>
                <th>Normal Text</th>
                <th>Large Text</th>
            </tr>
            <tr>
                <td><strong>AA</strong></td>
                <td>4.5:1</td>
                <td>3:1</td>
            </tr>
            <tr>
                <td><strong>AAA</strong></td>
                <td>7:1</td>
                <td>4.5:1</td>
            </tr>
        </table>
    </section>

    <!-- ====== 7. BEST PRACTICES ====== -->
    <section>
        <h2>7. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use CSS custom properties for theming</li>
                <li>Start with light theme, then add dark theme overrides</li>
                <li>Test both themes for readability and contrast</li>
                <li>Respect <code>prefers-contrast: more</code> for accessibility</li>
                <li>Use <code>prefers-contrast: less</code> for users sensitive to bright colors</li>
                <li>Combine both features for a fully personalized experience</li>
                <li>Test with real users who have accessibility needs</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't ignore user preferences — it's an accessibility issue</li>
                <li>Don't use pure black on pure white (or vice versa)</li>
                <li>Don't forget to test with actual users</li>
                <li>Don't use color alone to convey information</li>
                <li>Don't force a theme on users without an option to change</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator" id="live-indicator">
        <span id="indicator-scheme">Scheme: —</span>
        <span class="detail" id="indicator-contrast">Contrast: —</span>
    </div>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        function updateIndicators() {
            // Color scheme detection
            const schemeLight = document.getElementById('scheme-light');
            const schemeDark = document.getElementById('scheme-dark');

            const isLight = window.matchMedia('(prefers-color-scheme: light)').matches;
            const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

            function setCard(card, isActive, activeText, inactiveText) {
                const value = card.querySelector('.value');
                if (isActive) {
                    value.textContent = activeText;
                    card.classList.add('active');
                } else {
                    value.textContent = inactiveText;
                    card.classList.remove('active');
                }
            }

            setCard(schemeLight, isLight, 'Preferred ✅', 'Not preferred');
            setCard(schemeDark, isDark, 'Preferred ✅', 'Not preferred');

            // Contrast detection
            const contrastNoPref = document.getElementById('contrast-no-pref');
            const contrastMore = document.getElementById('contrast-more');
            const contrastLess = document.getElementById('contrast-less');
            const contrastCustom = document.getElementById('contrast-custom');

            const isNoPref = window.matchMedia('(prefers-contrast: no-preference)').matches;
            const isMore = window.matchMedia('(prefers-contrast: more)').matches;
            const isLess = window.matchMedia('(prefers-contrast: less)').matches;
            const isCustom = window.matchMedia('(prefers-contrast: custom)').matches;

            setCard(contrastNoPref, isNoPref, 'Active ✅', 'Not active');
            setCard(contrastMore, isMore, 'Active ✅', 'Not active');
            setCard(contrastLess, isLess, 'Active ✅', 'Not active');
            setCard(contrastCustom, isCustom, 'Active ✅', 'Not active');

            // Live indicator
            const indicatorScheme = document.getElementById('indicator-scheme');
            const indicatorContrast = document.getElementById('indicator-contrast');
            const indicator = document.getElementById('live-indicator');

            let schemeText = isDark ? '🌙 Dark' : '☀️ Light';
            indicatorScheme.textContent = 'Scheme: ' + schemeText;

            let contrastText = 'Default';
            if (isMore) contrastText = 'More';
            else if (isLess) contrastText = 'Less';
            else if (isCustom) contrastText = 'Custom';
            indicatorContrast.textContent = 'Contrast: ' + contrastText;

            // Update indicator color based on contrast
            if (isMore) {
                indicator.style.background = '#000';
                indicator.style.color = '#fff';
                indicator.style.border = '2px solid #fff';
            } else if (isLess) {
                indicator.style.background = '#6c9bd2';
                indicator.style.color = '#1a1a1a';
                indicator.style.border = 'none';
            } else {
                indicator.style.background = isDark ? '#4dabf7' : '#007bff';
                indicator.style.color = 'white';
                indicator.style.border = 'none';
            }
        }

        window.addEventListener('load', updateIndicators);

        // Listen for changes
        window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateIndicators);
        window.matchMedia('(prefers-contrast: more)').addEventListener('change', updateIndicators);
        window.matchMedia('(prefers-contrast: less)').addEventListener('change', updateIndicators);

        updateIndicators();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionValues
prefers-color-schemeUser’s preferred color schemelight, dark
prefers-contrastUser’s preferred contrast levelno-preference, more, less, custom

prefers-color-scheme Values

ValueDescription
lightUser prefers a light theme (or has no preference)
darkUser prefers a dark theme

prefers-contrast Values

ValueDescription
no-preferenceNo specific preference (default)
moreUser prefers higher contrast
lessUser prefers lower contrast
customUser uses a specific set of colors/contrast

WCAG Contrast Requirements

LevelNormal TextLarge Text
AA4.5:13:1
AAA7:14.5:1

Best Practices

Do This:

/* Base light theme */
:root {
    --bg: #ffffff;
    --text: #212529;
    --accent: #007bff;
}

/* Dark theme overrides */
@media (prefers-color-scheme: dark) {
    :root {
        --bg: #1a1a1a;
        --text: #f8f9fa;
        --accent: #4dabf7;
    }
}

/* High contrast */
@media (prefers-contrast: more) {
    :root {
        --bg: #ffffff;
        --text: #000000;
        --accent: #0000cc;
    }
    section {
        border: 2px solid #000;
        box-shadow: none;
    }
}

/* Combined dark + high contrast */
@media (prefers-contrast: more) and (prefers-color-scheme: dark) {
    :root {
        --bg: #000000;
        --text: #ffffff;
        --accent: #66b3ff;
    }
}

Don’t Do This:

/* Don't use pure black on pure white */
body {
    background: #fff;
    color: #000; /* Harsh — use #212529 instead */
}

/* Don't ignore user preferences */
body {
    background: #fff;
    color: #333;
    /* No dark mode support — accessibility issue */
}

/* Don't use low contrast */
.note {
    color: #ccc; /* On white — fails WCAG */
    background: #fff;
}

/* Don't rely solely on color */
.error {
    color: red; /* Add icons or text too */
}

Pro Tip: prefers-color-scheme and prefers-contrast are essential for accessibility. Always start with a light theme as the base, then enhance for dark mode. Use CSS custom properties for easy theming. Respect prefers-contrast: more by increasing contrast and adding borders. Remember: pure black on pure white is harsh — use off-black (#212529) and off-white (#f8f9fa) for better readability. Test with real users who have accessibility needs, and always ensure your text meets WCAG AA (4.5:1) or AAA (7:1) contrast ratios!

42. prefers-reduced-data and prefers-reduced-motion Media Features

These two media features prioritize user comfort and performance. One respects users who want less data usage, the other respects users who are sensitive to motion.


Overview of Features

FeatureDescriptionValues
prefers-reduced-dataUser wants lighter data usageno-preference, reduce
prefers-reduced-motionUser wants less animation/motionno-preference, reduce

1. prefers-reduced-data

The prefers-reduced-data media feature detects if the user has requested a lightweight alternative to save data.

@media (prefers-reduced-data: reduce) {
    .hero {
        background-image: none;
    }
}

Values

ValueDescription
no-preferenceUser has not expressed a preference (default)
reduceUser prefers lighter data usage

When to Use

  • Avoid large background images on reduced data
  • Skip autoplay videos and heavy media
  • Use simpler fonts (system fonts instead of web fonts)
  • Reduce image quality or use placeholders
  • Defer non-essential resources

⚠️ Important Note

prefers-reduced-data is an experimental technology with limited browser support. Always provide a working fallback.

How users enable it:

  • Chrome (Android): Settings → Privacy → Lite mode
  • Safari: Low Data Mode in iOS settings
  • Not yet widely supported in desktop browsers

2. prefers-reduced-motion

The prefers-reduced-motion media feature detects if the user has requested reduced motion — essential for users with vestibular disorders, motion sensitivity, or epilepsy.

@media (prefers-reduced-motion: reduce) {
    .container h1,
    .container p {
        animation: none !important;
        transition: none !important;
    }
}

Values

ValueDescription
no-preferenceUser has not expressed a preference (default)
reduceUser prefers less motion

When to Use

  • Disable animations (fade, slide, bounce)
  • Remove transitions (hover, focus)
  • Stop auto-playing carousels and videos
  • Avoid parallax scrolling
  • Reduce or remove loading spinners

How Users Enable It

  • Windows: Settings → Ease of Access → Display → Show animations
  • macOS: System Preferences → Accessibility → Display → Reduce motion
  • iOS: Settings → Accessibility → Motion → Reduce Motion
  • Android: Settings → Accessibility → Remove animations

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>prefers-reduced-data and prefers-reduced-motion</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        :root {
            --bg-primary: #ffffff;
            --bg-secondary: #f8f9fa;
            --bg-tertiary: #e9ecef;
            --text-primary: #212529;
            --text-secondary: #6c757d;
            --accent: #007bff;
            --border: #dee2e6;
            --shadow: rgba(0, 0, 0, 0.1);
        }

        @media (prefers-color-scheme: dark) {
            :root {
                --bg-primary: #1a1a1a;
                --bg-secondary: #0d0d0d;
                --bg-tertiary: #2d2d2d;
                --text-primary: #f8f9fa;
                --text-secondary: #adb5bd;
                --accent: #4dabf7;
                --border: #444;
                --shadow: rgba(0, 0, 0, 0.5);
            }
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: var(--bg-secondary);
            color: var(--text-primary);
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
            transition: background 0.3s, color 0.3s;
        }

        h1 {
            color: var(--accent);
            border-bottom: 3px solid var(--accent);
            padding-bottom: 10px;
        }

        h2 {
            color: var(--accent);
            border-left: 4px solid var(--accent);
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: var(--text-primary);
            margin-top: 20px;
        }

        section {
            background: var(--bg-primary);
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px var(--shadow);
            margin: 20px 0;
            transition: all 0.3s;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid var(--border);
            text-align: left;
        }

        .reference-table th {
            background: var(--accent);
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: var(--bg-tertiary);
        }

        .note {
            font-size: 0.9rem;
            color: var(--text-secondary);
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== MOTION DEMOS ====== */
        .container h1,
        .container p {
            animation: fadeIn 2s ease-in;
        }

        @keyframes fadeIn {
            from {
                opacity: 0;
                transform: translateY(20px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        @keyframes pulse {
            0%, 100% {
                transform: scale(1);
                box-shadow: 0 0 0 0 rgba(0, 123, 255, 0.4);
            }
            50% {
                transform: scale(1.05);
                box-shadow: 0 0 0 15px rgba(0, 123, 255, 0);
            }
        }

        @keyframes spin {
            from { transform: rotate(0deg); }
            to { transform: rotate(360deg); }
        }

        @keyframes slide {
            0% { transform: translateX(0); }
            50% { transform: translateX(100px); }
            100% { transform: translateX(0); }
        }

        .motion-demo {
            padding: 20px;
            border-radius: 8px;
            background: var(--bg-tertiary);
            border: 2px solid var(--border);
            text-align: center;
            margin: 15px 0;
            min-height: 120px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            gap: 15px;
        }

        .animated-box {
            width: 80px;
            height: 80px;
            background: var(--accent);
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 2rem;
        }

        .animated-box.pulse {
            animation: pulse 2s infinite;
        }

        .animated-box.spin {
            animation: spin 3s linear infinite;
        }

        .animated-box.slide {
            animation: slide 2s ease-in-out infinite;
        }

        /* Transitions */
        .transition-demo {
            padding: 20px;
            border-radius: 8px;
            background: var(--bg-tertiary);
            border: 2px solid var(--border);
            margin: 15px 0;
            cursor: pointer;
            transition: all 0.4s ease;
            text-align: center;
            font-weight: bold;
        }

        .transition-demo:hover {
            background: var(--accent);
            color: white;
            transform: scale(1.02);
            box-shadow: 0 4px 20px var(--shadow);
        }

        /* ====== REDUCED MOTION ====== */
        @media (prefers-reduced-motion: reduce) {
            .container h1,
            .container p {
                animation: none !important;
                transition: none !important;
            }

            .animated-box {
                animation: none !important;
            }

            .animated-box::after {
                content: " (motion reduced)";
                font-size: 0.7rem;
                font-weight: normal;
                display: block;
            }

            .transition-demo {
                transition: none !important;
            }

            .transition-demo:hover {
                transform: none;
            }

            * {
                animation-duration: 0.01ms !important;
                animation-iteration-count: 1 !important;
                transition-duration: 0.01ms !important;
                scroll-behavior: auto !important;
            }
        }

        @media (prefers-reduced-motion: no-preference) {
            .container h1,
            .container p {
                animation: fadeIn 2s ease-in;
            }
        }

        /* ====== REDUCED DATA ====== */
        .hero-section {
            padding: 40px;
            border-radius: 12px;
            text-align: center;
            margin: 15px 0;
            color: white;
            font-weight: bold;
            font-size: 1.5rem;
            /* Heavy background image */
            background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="400" height="200"><defs><linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" style="stop-color:%23007bff"/><stop offset="100%" style="stop-color:%236c5ce7"/></linearGradient></defs><rect width="400" height="200" fill="url(%23g)"/><circle cx="100" cy="100" r="40" fill="rgba(255,255,255,0.1)"/><circle cx="300" cy="50" r="60" fill="rgba(255,255,255,0.1)"/></svg>');
            background-size: cover;
            background-position: center;
            transition: all 0.3s;
        }

        @media (prefers-reduced-data: reduce) {
            .hero-section {
                /* Remove heavy background image */
                background-image: none;
                background: var(--accent);
                font-size: 1.2rem;
                padding: 30px;
            }

            .hero-section::after {
                content: " (data saver mode)";
                font-size: 0.8rem;
                font-weight: normal;
                display: block;
                margin-top: 5px;
            }

            /* Hide non-essential images */
            .decorative-image {
                display: none;
            }

            /* Use system fonts */
            body {
                font-family: system-ui, -apple-system, sans-serif;
            }
        }

        /* ====== DETECTION CARDS ====== */
        .detection-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .detection-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            border: 2px solid var(--border);
            background: var(--bg-tertiary);
            transition: all 0.3s;
        }

        .detection-card .label {
            font-size: 0.85rem;
            color: var(--text-secondary);
            display: block;
            margin-bottom: 5px;
        }

        .detection-card .value {
            font-size: 1.1rem;
            font-weight: bold;
            color: var(--accent);
        }

        .detection-card.active {
            border-color: var(--accent);
            background: var(--bg-primary);
        }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: var(--accent);
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px var(--shadow);
            z-index: 1000;
            transition: all 0.3s;
            display: flex;
            flex-direction: column;
            gap: 3px;
        }

        .live-indicator .detail {
            font-size: 0.75rem;
            opacity: 0.9;
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid var(--accent);
            background: var(--bg-tertiary);
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }

        /* ====== PRACTICAL: ACCESSIBLE ANIMATION ====== */
        .loading-spinner {
            width: 50px;
            height: 50px;
            border: 5px solid var(--bg-tertiary);
            border-top: 5px solid var(--accent);
            border-radius: 50%;
            animation: spin 1s linear infinite;
            margin: 20px auto;
        }

        @media (prefers-reduced-motion: reduce) {
            .loading-spinner {
                animation: none;
                border-top-color: var(--accent);
                /* Show a static alternative */
            }
            .loading-spinner::after {
                content: "Loading...";
                display: block;
                text-align: center;
                font-size: 0.8rem;
                margin-top: 10px;
                color: var(--text-secondary);
            }
        }

        /* ====== PRACTICAL: DATA SAVER IMAGES ====== */
        .image-gallery {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 15px;
            margin: 15px 0;
        }

        .image-gallery .gallery-item {
            height: 150px;
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 1.5rem;
            background: linear-gradient(135deg, var(--accent), #6c5ce7);
            transition: all 0.3s;
        }

        /* High-quality images (default) */
        .image-gallery .gallery-item::after {
            content: "🖼️ HD";
            font-size: 0.8rem;
            position: absolute;
        }

        @media (prefers-reduced-data: reduce) {
            .image-gallery .gallery-item {
                /* Use simple placeholder */
                background: var(--bg-tertiary);
                border: 2px dashed var(--border);
                color: var(--text-secondary);
                font-size: 1rem;
            }
            .image-gallery .gallery-item::after {
                content: "📷 (data saver)";
                font-size: 0.8rem;
            }
        }
    </style>
</head>
<body>

    <h1>prefers-reduced-data and prefers-reduced-motion</h1>

    <!-- ====== 1. REDUCED MOTION DEMO ====== -->
    <section class="container">
        <h2>1. prefers-reduced-motion</h2>
        <p>Detects if the user has requested <strong>reduced motion</strong> for accessibility.</p>

        <h3>Animated Elements</h3>
        <div class="motion-demo">
            <div class="animated-box pulse">💓</div>
            <div class="animated-box spin">🔄</div>
            <div class="animated-box slide">➡️</div>
            <p class="note">These animations are disabled when <code>prefers-reduced-motion: reduce</code> is active.</p>
        </div>

        <h3>Transition Demo</h3>
        <div class="transition-demo">
            Hover over me to see the transition
        </div>
        <p class="note">Transitions are also disabled for users who prefer reduced motion.</p>

        <div class="code-block">
            /* Disable animations and transitions */
            @media (prefers-reduced-motion: reduce) {
                .container h1,
                .container p {
                    animation: none !important;
                    transition: none !important;
                }

                * {
                    animation-duration: 0.01ms !important;
                    animation-iteration-count: 1 !important;
                    transition-duration: 0.01ms !important;
                    scroll-behavior: auto !important;
                }
            }

            /* Enable animations only when no preference */
            @media (prefers-reduced-motion: no-preference) {
                .container h1,
                .container p {
                    animation: fadeIn 2s ease-in;
                }
            }
        </div>
    </section>

    <!-- ====== 2. REDUCED DATA DEMO ====== -->
    <section>
        <h2>2. prefers-reduced-data</h2>
        <p>Detects if the user prefers <strong>lighter data usage</strong>.</p>

        <div class="hero-section">
            🎨 Hero Section with Background Image
        </div>
        <p class="note">On reduced data, the heavy background image is replaced with a solid color.</p>

        <h3>Image Gallery</h3>
        <div class="image-gallery">
            <div class="gallery-item"></div>
            <div class="gallery-item"></div>
            <div class="gallery-item"></div>
            <div class="gallery-item"></div>
        </div>
        <p class="note">On reduced data, high-quality images become simple placeholders.</p>

        <div class="code-block">
            /* Default: heavy background image */
            .hero-section {
                background-image: url('large-image.jpg');
                background-size: cover;
            }

            /* Reduced data: remove heavy images */
            @media (prefers-reduced-data: reduce) {
                .hero-section {
                    background-image: none;
                    background: var(--accent);
                }

                .decorative-image {
                    display: none;
                }

                body {
                    font-family: system-ui, sans-serif;
                }
            }
        </div>

        <div class="tip-box warning">
            <strong>⚠️ Experimental Feature:</strong>
            <code>prefers-reduced-data</code> has limited browser support. Always provide a working fallback.
        </div>
    </section>

    <!-- ====== 3. DETECTION SUMMARY ====== -->
    <section>
        <h2>3. Your Preferences</h2>
        <p>Below is a live detection of your preferences.</p>

        <div class="detection-grid">
            <div class="detection-card" id="motion-no-pref">
                <span class="label">prefers-reduced-motion: no-preference</span>
                <span class="value" id="motion-no-pref-value">Detecting...</span>
            </div>
            <div class="detection-card" id="motion-reduce">
                <span class="label">prefers-reduced-motion: reduce</span>
                <span class="value" id="motion-reduce-value">Detecting...</span>
            </div>
            <div class="detection-card" id="data-no-pref">
                <span class="label">prefers-reduced-data: no-preference</span>
                <span class="value" id="data-no-pref-value">Detecting...</span>
            </div>
            <div class="detection-card" id="data-reduce">
                <span class="label">prefers-reduced-data: reduce</span>
                <span class="value" id="data-reduce-value">Detecting...</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect motion preference */
            @media (prefers-reduced-motion: no-preference) { /* Animations OK */ }
            @media (prefers-reduced-motion: reduce) { /* Reduce motion */ }

            /* Detect data preference */
            @media (prefers-reduced-data: no-preference) { /* Normal data */ }
            @media (prefers-reduced-data: reduce) { /* Lightweight content */ }
        </div>
    </section>

    <!-- ====== 4. PRACTICAL: ACCESSIBLE SPINNER ====== -->
    <section>
        <h2>4. Practical Example: Accessible Loading Spinner</h2>
        <p>A spinner that respects reduced motion preferences.</p>

        <div class="loading-spinner"></div>

        <div class="code-block">
            /* Default: spinning animation */
            .loading-spinner {
                animation: spin 1s linear infinite;
            }

            /* Reduced motion: static alternative */
            @media (prefers-reduced-motion: reduce) {
                .loading-spinner {
                    animation: none;
                }
                .loading-spinner::after {
                    content: "Loading...";
                }
            }
        </div>
    </section>

    <!-- ====== 5. REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>prefers-reduced-motion Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>no-preference</code></td>
                <td>No preference expressed (default)</td>
            </tr>
            <tr>
                <td><code>reduce</code></td>
                <td>User prefers reduced motion</td>
            </tr>
        </table>

        <h3>prefers-reduced-data Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>no-preference</code></td>
                <td>No preference expressed (default)</td>
            </tr>
            <tr>
                <td><code>reduce</code></td>
                <td>User prefers lighter data usage</td>
            </tr>
        </table>

        <h3>When to Reduce Motion</h3>
        <table class="reference-table">
            <tr>
                <th>Element</th>
                <th>Default</th>
                <th>Reduced Motion</th>
            </tr>
            <tr>
                <td>Fade animations</td>
                <td>Enabled</td>
                <td>Disabled</td>
            </tr>
            <tr>
                <td>Slide transitions</td>
                <td>Enabled</td>
                <td>Disabled</td>
            </tr>
            <tr>
                <td>Parallax scrolling</td>
                <td>Enabled</td>
                <td>Disabled</td>
            </tr>
            <tr>
                <td>Auto-playing carousels</td>
                <td>Enabled</td>
                <td>Paused/disabled</td>
            </tr>
            <tr>
                <td>Loading spinners</td>
                <td>Animated</td>
                <td>Static</td>
            </tr>
        </table>

        <h3>When to Reduce Data</h3>
        <table class="reference-table">
            <tr>
                <th>Element</th>
                <th>Default</th>
                <th>Reduced Data</th>
            </tr>
            <tr>
                <td>Background images</td>
                <td>High quality</td>
                <td>None or simplified</td>
            </tr>
            <tr>
                <td>Web fonts</td>
                <td>Custom fonts</td>
                <td>System fonts</td>
            </tr>
            <tr>
                <td>Auto-play videos</td>
                <td>Enabled</td>
                <td>Disabled</td>
            </tr>
            <tr>
                <td>Decorative images</td>
                <td>Visible</td>
                <td>Hidden</td>
            </tr>
            <tr>
                <td>High-res images</td>
                <td>Full quality</td>
                <td>Placeholders</td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Respect <code>prefers-reduced-motion: reduce</code> for all animations</li>
                <li>Provide static alternatives for animated content</li>
                <li>Use <code>prefers-reduced-data: reduce</code> to skip heavy media</li>
                <li>Test with reduced motion enabled in your OS</li>
                <li>Provide working fallbacks (since <code>prefers-reduced-data</code> is experimental)</li>
                <li>Consider the user's comfort over visual flair</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't ignore reduced motion — it's an accessibility requirement</li>
                <li>Don't use animations that can't be disabled</li>
                <li>Don't rely solely on <code>prefers-reduced-data</code> (limited support)</li>
                <li>Don't force heavy media on users with limited data</li>
                <li>Don't forget to test with actual users who have motion sensitivity</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator" id="live-indicator">
        <span id="indicator-motion">Motion: —</span>
        <span class="detail" id="indicator-data">Data: —</span>
    </div>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        function updateIndicators() {
            // Motion detection
            const motionNoPref = document.getElementById('motion-no-pref');
            const motionReduce = document.getElementById('motion-reduce');

            const isMotionNoPref = window.matchMedia('(prefers-reduced-motion: no-preference)').matches;
            const isMotionReduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

            function setCard(card, isActive, activeText, inactiveText) {
                const value = card.querySelector('.value');
                if (isActive) {
                    value.textContent = activeText;
                    card.classList.add('active');
                } else {
                    value.textContent = inactiveText;
                    card.classList.remove('active');
                }
            }

            setCard(motionNoPref, isMotionNoPref, 'Active ✅', 'Not active');
            setCard(motionReduce, isMotionReduce, 'Active ✅', 'Not active');

            // Data detection
            const dataNoPref = document.getElementById('data-no-pref');
            const dataReduce = document.getElementById('data-reduce');

            const isDataNoPref = window.matchMedia('(prefers-reduced-data: no-preference)').matches;
            const isDataReduce = window.matchMedia('(prefers-reduced-data: reduce)').matches;

            setCard(dataNoPref, isDataNoPref, 'Active ✅', 'Not active');
            setCard(dataReduce, isDataReduce, 'Active ✅', 'Not active');

            // Live indicator
            const indicatorMotion = document.getElementById('indicator-motion');
            const indicatorData = document.getElementById('indicator-data');
            const indicator = document.getElementById('live-indicator');

            indicatorMotion.textContent = isMotionReduce ? 'Motion: Reduced 🚫' : 'Motion: Full ✨';
            indicatorData.textContent = isDataReduce ? 'Data: Reduced 📉' : 'Data: Normal 📶';

            // Color the indicator
            if (isMotionReduce || isDataReduce) {
                indicator.style.background = '#28a745';
                indicator.style.color = 'white';
            } else {
                indicator.style.background = '#007bff';
                indicator.style.color = 'white';
            }
        }

        window.addEventListener('load', updateIndicators);

        // Listen for changes
        window.matchMedia('(prefers-reduced-motion: reduce)').addEventListener('change', updateIndicators);
        window.matchMedia('(prefers-reduced-data: reduce)').addEventListener('change', updateIndicators);

        updateIndicators();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionValues
prefers-reduced-motionUser wants less animationno-preference, reduce
prefers-reduced-dataUser wants lighter data usageno-preference, reduce

prefers-reduced-motion Values

ValueDescription
no-preferenceNo preference expressed (default)
reduceUser prefers reduced motion

prefers-reduced-data Values

ValueDescription
no-preferenceNo preference expressed (default)
reduceUser prefers lighter data usage

When to Reduce Motion

ElementDefaultReduced Motion
Fade animationsEnabledDisabled
Slide transitionsEnabledDisabled
Parallax scrollingEnabledDisabled
Auto-playing carouselsEnabledPaused/disabled
Loading spinnersAnimatedStatic

When to Reduce Data

ElementDefaultReduced Data
Background imagesHigh qualityNone or simplified
Web fontsCustom fontsSystem fonts
Auto-play videosEnabledDisabled
Decorative imagesVisibleHidden
High-res imagesFull qualityPlaceholders

Best Practices

Do This:

/* Disable animations for reduced motion */
@media (prefers-reduced-motion: reduce) {
    * {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* Enable animations only when no preference */
@media (prefers-reduced-motion: no-preference) {
    .fade-in {
        animation: fadeIn 2s ease-in;
    }
}

/* Reduce data usage */
@media (prefers-reduced-data: reduce) {
    .hero {
        background-image: none;
        background: #007bff;
    }
    .decorative-image {
        display: none;
    }
}

/* Provide static alternatives */
@media (prefers-reduced-motion: reduce) {
    .spinner {
        animation: none;
    }
    .spinner::after {
        content: "Loading...";
    }
}

Don’t Do This:

/* Don't ignore reduced motion */
.animation {
    animation: bounce 2s infinite;
    /* No reduced motion support — accessibility issue! */
}

/* Don't rely solely on prefers-reduced-data */
@media (prefers-reduced-data: reduce) {
    /* Limited browser support — always provide fallbacks */
}

/* Don't force heavy media on data-saver users */
.hero {
    background-image: url('huge-image.jpg');
    /* No alternative for reduced data */
}

Pro Tip: prefers-reduced-motion is essential for accessibility. Users with vestibular disorders, motion sensitivity, or epilepsy can be physically harmed by excessive animation. Always provide static alternatives — a loading spinner can become “Loading…” text, and a fade-in can simply appear. prefers-reduced-data is still experimental with limited support, so use it as an enhancement, not a requirement. Always provide working fallbacks, and test with actual users who have these preferences enabled!

43. prefers-reduced-transparency and scan Media Features

These two media features address accessibility (transparency preferences) and legacy display technology (interlaced vs progressive scanning).


Overview of Features

FeatureDescriptionValues
prefers-reduced-transparencyUser wants less transparencyno-preference, reduce
scanMonitor’s scanning processinterlaced, progressive

1. prefers-reduced-transparency

The prefers-reduced-transparency media feature detects if the user has requested reduced transparency — important for users who have difficulty reading text over translucent backgrounds.

@media (prefers-reduced-transparency: reduce) {
    body {
        background-color: #ffffff;
    }
}

Values

ValueDescription
no-preferenceUser has not expressed a preference (default)
reduceUser prefers reduced transparency

When to Use

  • Remove backdrop blur effects (backdrop-filter: blur())
  • Replace translucent backgrounds with solid colors
  • Remove opacity from overlays and modals
  • Simplify glassmorphism effects
  • Increase contrast for better readability

How Users Enable It

  • iOS: Settings → Accessibility → Motion → Reduce Transparency
  • macOS: System Preferences → Accessibility → Display → Reduce transparency
  • Windows: Settings → Personalization → Colors → Transparency effects (off)

⚠️ Important Note

prefers-reduced-transparency is a relatively new feature with limited browser support. Always provide a working fallback.


2. scan

The scan media feature detects the scanning process of the display — how the image is drawn on screen.

@media (scan: interlaced) {
    body {
        background-color: #f0f;
        color: #0ff;
    }
}

Values

ValueDescription
interlacedImage drawn in alternating lines (old CRT monitors)
progressiveEach frame is complete (modern displays)

Interlaced vs Progressive

Interlaced:              Progressive:
Frame 1:                 Frame 1:
┌─────────────┐          ┌─────────────┐
│ ███████████ │          │ ███████████ │
│             │          │ ███████████ │
│ ███████████ │          │ ███████████ │
│             │          │ ███████████ │
│ ███████████ │          │ ███████████ │
└─────────────┘          └─────────────┘
Odd lines first,         All lines at once
then even lines

Key Points

AspectInterlacedProgressive
TechnologyOld CRT monitorsModern LCD, OLED
RenderingAlternating linesComplete frames
MotionCan flicker with fast movementSmooth
Thin linesMay flicker (< 1px)No flicker
Current useRare (legacy)Universal

Design Considerations for Interlaced

  • Avoid thin lines (less than 1px) — they can flicker
  • Avoid fast movement — causes visible flicker
  • Use wider strokes for text and graphics
  • Reduce animation speed
  • Most modern developers will never encounter interlaced displays

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>prefers-reduced-transparency and scan</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        :root {
            --bg-primary: #ffffff;
            --bg-secondary: #f8f9fa;
            --bg-tertiary: #e9ecef;
            --text-primary: #212529;
            --text-secondary: #6c757d;
            --accent: #007bff;
            --border: #dee2e6;
            --shadow: rgba(0, 0, 0, 0.1);
        }

        @media (prefers-color-scheme: dark) {
            :root {
                --bg-primary: #1a1a1a;
                --bg-secondary: #0d0d0d;
                --bg-tertiary: #2d2d2d;
                --text-primary: #f8f9fa;
                --text-secondary: #adb5bd;
                --accent: #4dabf7;
                --border: #444;
                --shadow: rgba(0, 0, 0, 0.5);
            }
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: var(--bg-secondary);
            color: var(--text-primary);
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
            transition: background 0.3s, color 0.3s;
        }

        h1 {
            color: var(--accent);
            border-bottom: 3px solid var(--accent);
            padding-bottom: 10px;
        }

        h2 {
            color: var(--accent);
            border-left: 4px solid var(--accent);
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: var(--text-primary);
            margin-top: 20px;
        }

        section {
            background: var(--bg-primary);
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px var(--shadow);
            margin: 20px 0;
            transition: all 0.3s;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid var(--border);
            text-align: left;
        }

        .reference-table th {
            background: var(--accent);
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: var(--bg-tertiary);
        }

        .note {
            font-size: 0.9rem;
            color: var(--text-secondary);
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== TRANSPARENCY DEMO ====== */
        .transparency-demo {
            position: relative;
            padding: 40px 20px;
            border-radius: 12px;
            overflow: hidden;
            margin: 15px 0;
            min-height: 200px;
            display: flex;
            align-items: center;
            justify-content: center;
            /* Background image for transparency effect */
            background-image: linear-gradient(135deg, #007bff, #6c5ce7, #dc3545);
            background-size: cover;
        }

        .glass-card {
            background: rgba(255, 255, 255, 0.15);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.3);
            border-radius: 16px;
            padding: 30px;
            text-align: center;
            color: white;
            font-weight: bold;
            max-width: 400px;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
            transition: all 0.3s;
        }

        .glass-card h3 {
            margin-top: 0;
            color: white;
            text-shadow: 0 2px 10px rgba(0,0,0,0.3);
        }

        .glass-card p {
            margin-bottom: 0;
            font-size: 0.95rem;
            opacity: 0.95;
        }

        /* Reduced transparency: solid background */
        @media (prefers-reduced-transparency: reduce) {
            .glass-card {
                background: var(--bg-primary);
                backdrop-filter: none;
                -webkit-backdrop-filter: none;
                border: 2px solid var(--border);
                color: var(--text-primary);
                box-shadow: 0 4px 15px var(--shadow);
            }
            .glass-card h3 {
                color: var(--text-primary);
                text-shadow: none;
            }
            .glass-card p {
                color: var(--text-secondary);
            }
            .glass-card::after {
                content: " (reduced transparency)";
                display: block;
                font-size: 0.75rem;
                margin-top: 10px;
                color: var(--text-secondary);
                font-weight: normal;
            }
        }

        /* ====== TRANSPARENCY COMPARISON ====== */
        .transparency-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            margin: 15px 0;
        }

        .transparency-box {
            padding: 25px;
            border-radius: 12px;
            text-align: center;
            font-weight: bold;
            color: white;
            min-height: 150px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            /* Colorful background behind */
            background-image: linear-gradient(135deg, #ff6b6b, #ffc107, #28a745, #007bff, #6c5ce7);
            background-size: cover;
        }

        .transparency-box .inner {
            padding: 15px 25px;
            border-radius: 8px;
            width: 100%;
        }

        /* Transparent versions */
        .transparent-high {
            background: rgba(255, 255, 255, 0.2);
            backdrop-filter: blur(8px);
            -webkit-backdrop-filter: blur(8px);
            border: 1px solid rgba(255, 255, 255, 0.3);
        }

        .transparent-medium {
            background: rgba(255, 255, 255, 0.5);
            backdrop-filter: blur(5px);
            -webkit-backdrop-filter: blur(5px);
            border: 1px solid rgba(255, 255, 255, 0.5);
            color: #333;
        }

        .transparent-low {
            background: rgba(255, 255, 255, 0.9);
            color: #333;
            border: 1px solid rgba(0, 0, 0, 0.1);
        }

        /* Reduced transparency: all solid */
        @media (prefers-reduced-transparency: reduce) {
            .transparent-high,
            .transparent-medium,
            .transparent-low {
                background: var(--bg-primary);
                backdrop-filter: none;
                -webkit-backdrop-filter: none;
                border: 2px solid var(--border);
                color: var(--text-primary);
            }
        }

        /* ====== SCAN DEMO ====== */
        .scan-demo {
            padding: 25px;
            border-radius: 8px;
            margin: 15px 0;
            text-align: center;
            font-weight: bold;
            font-size: 1.1rem;
            transition: all 0.3s;
            background: var(--bg-tertiary);
            border: 2px solid var(--border);
        }

        /* Progressive scan (modern displays) */
        @media (scan: progressive) {
            .scan-demo {
                background: #cce5ff;
                color: #004085;
                border-color: #007bff;
            }
            .scan-demo::after {
                content: " (progressive scan — modern display)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Interlaced scan (old CRT monitors) */
        @media (scan: interlaced) {
            .scan-demo {
                background: #f0f;
                color: #0ff;
                border-color: #f0f;
                /* Avoid thin lines and fast movement */
                font-weight: bold;
            }
            .scan-demo::after {
                content: " (interlaced scan — legacy display)";
                font-weight: normal;
                font-size: 0.85rem;
            }
            /* Wider strokes for interlaced */
            .scan-demo {
                border-width: 3px;
            }
        }

        /* ====== INTERLACED DESIGN CONSIDERATIONS ====== */
        .line-demo {
            display: flex;
            flex-direction: column;
            gap: 10px;
            margin: 15px 0;
        }

        .line-demo .thin-line {
            height: 1px;
            background: var(--text-primary);
            width: 100%;
        }

        .line-demo .thick-line {
            height: 4px;
            background: var(--accent);
            width: 100%;
        }

        .line-demo .text-sample {
            font-size: 16px;
            font-weight: 300;
            letter-spacing: 0.5px;
        }

        .line-demo .bold-sample {
            font-size: 16px;
            font-weight: 700;
            letter-spacing: 0.5px;
        }

        /* Interlaced: avoid thin lines and light fonts */
        @media (scan: interlaced) {
            .line-demo .thin-line {
                height: 3px;
            }
            .line-demo .text-sample {
                font-weight: 500;
                font-size: 18px;
            }
            .line-demo .bold-sample {
                font-weight: 900;
            }
        }

        /* ====== DETECTION CARDS ====== */
        .detection-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .detection-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            border: 2px solid var(--border);
            background: var(--bg-tertiary);
            transition: all 0.3s;
        }

        .detection-card .label {
            font-size: 0.85rem;
            color: var(--text-secondary);
            display: block;
            margin-bottom: 5px;
        }

        .detection-card .value {
            font-size: 1.1rem;
            font-weight: bold;
            color: var(--accent);
        }

        .detection-card.active {
            border-color: var(--accent);
            background: var(--bg-primary);
        }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: var(--accent);
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px var(--shadow);
            z-index: 1000;
            transition: all 0.3s;
            display: flex;
            flex-direction: column;
            gap: 3px;
        }

        .live-indicator .detail {
            font-size: 0.75rem;
            opacity: 0.9;
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid var(--accent);
            background: var(--bg-tertiary);
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }

        /* ====== PRACTICAL: ACCESSIBLE MODAL ====== */
        .modal-demo {
            position: relative;
            padding: 40px 20px;
            border-radius: 12px;
            background-image: linear-gradient(135deg, #007bff, #6c5ce7);
            min-height: 250px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin: 15px 0;
        }

        .modal-content {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 12px;
            padding: 30px;
            max-width: 400px;
            text-align: center;
            color: #333;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
            transition: all 0.3s;
        }

        .modal-content h3 {
            margin-top: 0;
            color: #007bff;
        }

        /* Reduced transparency: solid modal */
        @media (prefers-reduced-transparency: reduce) {
            .modal-content {
                background: var(--bg-primary);
                color: var(--text-primary);
                border: 2px solid var(--border);
                box-shadow: 0 4px 15px var(--shadow);
            }
            .modal-content h3 {
                color: var(--accent);
            }
        }
    </style>
</head>
<body>

    <h1>prefers-reduced-transparency and scan</h1>

    <!-- ====== 1. TRANSPARENCY DEMO ====== -->
    <section>
        <h2>1. prefers-reduced-transparency</h2>
        <p>Detects if the user prefers <strong>reduced transparency</strong> — important for users who have difficulty reading text over translucent backgrounds.</p>

        <h3>Glassmorphism Card</h3>
        <div class="transparency-demo">
            <div class="glass-card">
                <h3>✨ Glass Card</h3>
                <p>This card uses transparency and backdrop blur. On reduced transparency, it becomes solid with a border.</p>
            </div>
        </div>

        <h3>Transparency Levels Comparison</h3>
        <div class="transparency-grid">
            <div class="transparency-box">
                <div class="inner transparent-high">High Transparency (0.2)</div>
            </div>
            <div class="transparency-box">
                <div class="inner transparent-medium">Medium Transparency (0.5)</div>
            </div>
            <div class="transparency-box">
                <div class="inner transparent-low">Low Transparency (0.9)</div>
            </div>
        </div>

        <div class="code-block">
            /* Default: glassmorphism with transparency */
            .glass-card {
                background: rgba(255, 255, 255, 0.15);
                backdrop-filter: blur(10px);
                border: 1px solid rgba(255, 255, 255, 0.3);
            }

            /* Reduced transparency: solid background */
            @media (prefers-reduced-transparency: reduce) {
                .glass-card {
                    background: var(--bg-primary);
                    backdrop-filter: none;
                    border: 2px solid var(--border);
                }
            }
        </div>

        <div class="tip-box warning">
            <strong>⚠️ Limited Support:</strong>
            <code>prefers-reduced-transparency</code> is a relatively new feature with limited browser support. Always provide a working fallback.
        </div>
    </section>

    <!-- ====== 2. SCAN DEMO ====== -->
    <section>
        <h2>2. scan</h2>
        <p>Detects the <strong>scanning process</strong> of the display — interlaced (old CRT) or progressive (modern).</p>

        <div class="scan-demo">
            Scan Detection
        </div>

        <h3>Interlaced Design Considerations</h3>
        <div class="line-demo">
            <div class="thin-line"></div>
            <div class="text-sample">Light text sample — thin strokes may flicker on interlaced</div>
            <div class="thick-line"></div>
            <div class="bold-sample">Bold text sample — thicker strokes are more stable</div>
        </div>
        <p class="note">On interlaced displays, thin lines and light fonts can flicker. Use thicker strokes and bolder fonts.</p>

        <div class="code-block">
            /* Progressive scan (modern displays) */
            @media (scan: progressive) {
                .demo {
                    /* Normal styles — thin lines and light fonts are fine */
                }
            }

            /* Interlaced scan (old CRT monitors) */
            @media (scan: interlaced) {
                .demo {
                    /* Use thicker lines and bolder fonts */
                    border-width: 3px;
                }
                .thin-line {
                    height: 3px; /* Avoid flicker */
                }
                .light-text {
                    font-weight: 500; /* Bolder than normal */
                }
            }
        </div>

        <div class="tip-box success">
            <strong>✅ Good News:</strong>
            Interlaced displays are extremely rare today. Most developers will never encounter them. The <code>scan</code> feature is primarily for legacy support.
        </div>
    </section>

    <!-- ====== 3. DETECTION SUMMARY ====== -->
    <section>
        <h2>3. Your Display's Capabilities</h2>
        <p>Below is a live detection of your display's capabilities.</p>

        <div class="detection-grid">
            <div class="detection-card" id="transparency-no-pref">
                <span class="label">prefers-reduced-transparency: no-preference</span>
                <span class="value" id="transparency-no-pref-value">Detecting...</span>
            </div>
            <div class="detection-card" id="transparency-reduce">
                <span class="label">prefers-reduced-transparency: reduce</span>
                <span class="value" id="transparency-reduce-value">Detecting...</span>
            </div>
            <div class="detection-card" id="scan-interlaced">
                <span class="label">scan: interlaced</span>
                <span class="value" id="scan-interlaced-value">Detecting...</span>
            </div>
            <div class="detection-card" id="scan-progressive">
                <span class="label">scan: progressive</span>
                <span class="value" id="scan-progressive-value">Detecting...</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect reduced transparency preference */
            @media (prefers-reduced-transparency: no-preference) { /* Normal */ }
            @media (prefers-reduced-transparency: reduce) { /* Reduced */ }

            /* Detect scan type */
            @media (scan: interlaced) { /* CRT monitor */ }
            @media (scan: progressive) { /* Modern display */ }
        </div>
    </section>

    <!-- ====== 4. PRACTICAL: ACCESSIBLE MODAL ====== -->
    <section>
        <h2>4. Practical Example: Accessible Modal</h2>
        <p>A modal that adapts to transparency preferences.</p>

        <div class="modal-demo">
            <div class="modal-content">
                <h3>📋 Modal Dialog</h3>
                <p>This modal uses a semi-transparent background. On reduced transparency, it becomes fully opaque with a solid border.</p>
            </div>
        </div>

        <div class="code-block">
            /* Default: semi-transparent modal */
            .modal-content {
                background: rgba(255, 255, 255, 0.95);
                box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
            }

            /* Reduced transparency: solid modal */
            @media (prefers-reduced-transparency: reduce) {
                .modal-content {
                    background: var(--bg-primary);
                    border: 2px solid var(--border);
                    box-shadow: 0 4px 15px var(--shadow);
                }
            }
        </div>
    </section>

    <!-- ====== 5. REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>prefers-reduced-transparency Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>no-preference</code></td>
                <td>User has not expressed a preference (default)</td>
            </tr>
            <tr>
                <td><code>reduce</code></td>
                <td>User prefers reduced transparency</td>
            </tr>
        </table>

        <h3>scan Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Display Type</th>
            </tr>
            <tr>
                <td><code>interlaced</code></td>
                <td>Image drawn in alternating lines</td>
                <td>Old CRT monitors</td>
            </tr>
            <tr>
                <td><code>progressive</code></td>
                <td>Each frame is complete</td>
                <td>Modern LCD, OLED</td>
            </tr>
        </table>

        <h3>Interlaced vs Progressive</h3>
        <table class="reference-table">
            <tr>
                <th>Aspect</th>
                <th>Interlaced</th>
                <th>Progressive</th>
            </tr>
            <tr>
                <td><strong>Technology</strong></td>
                <td>Old CRT monitors</td>
                <td>Modern displays</td>
            </tr>
            <tr>
                <td><strong>Rendering</strong></td>
                <td>Alternating lines</td>
                <td>Complete frames</td>
            </tr>
            <tr>
                <td><strong>Thin lines</strong></td>
                <td>May flicker (< 1px)</td>
                <td>No flicker</td>
            </tr>
            <tr>
                <td><strong>Fast motion</strong></td>
                <td>Can cause visible flicker</td>
                <td>Smooth</td>
            </tr>
            <tr>
                <td><strong>Current use</strong></td>
                <td>Rare (legacy)</td>
                <td>Universal</td>
            </tr>
        </table>

        <h3>When to Reduce Transparency</h3>
        <table class="reference-table">
            <tr>
                <th>Element</th>
                <th>Default</th>
                <th>Reduced Transparency</th>
            </tr>
            <tr>
                <td>Glassmorphism cards</td>
                <td>Translucent + blur</td>
                <td>Solid + border</td>
            </tr>
            <tr>
                <td>Modals/overlays</td>
                <td>Semi-transparent</td>
                <td>Fully opaque</td>
            </tr>
            <tr>
                <td>Navigation bars</td>
                <td>Translucent</td>
                <td>Solid</td>
            </tr>
            <tr>
                <td>Dropdown menus</td>
                <td>Transparent</td>
                <td>Solid with border</td>
            </tr>
            <tr>
                <td>Tooltips</td>
                <td>Translucent</td>
                <td>Solid</td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Respect <code>prefers-reduced-transparency: reduce</code> for accessibility</li>
                <li>Replace translucent backgrounds with solid colors</li>
                <li>Remove <code>backdrop-filter: blur()</code> on reduced transparency</li>
                <li>Add borders to maintain visual hierarchy without transparency</li>
                <li>Test with reduced transparency enabled in your OS</li>
                <li>Use <code>scan</code> only for legacy CRT support (rarely needed)</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't rely solely on transparency for visual design</li>
                <li>Don't ignore reduced transparency — it's an accessibility issue</li>
                <li>Don't use <code>backdrop-filter</code> without a fallback</li>
                <li>Don't use thin lines (less than 1px) for critical UI on interlaced displays</li>
                <li>Don't assume all users can comfortably read text over translucent backgrounds</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator" id="live-indicator">
        <span id="indicator-transparency">Transparency: —</span>
        <span class="detail" id="indicator-scan">Scan: —</span>
    </div>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        function updateIndicators() {
            // Transparency detection
            const transparencyNoPref = document.getElementById('transparency-no-pref');
            const transparencyReduce = document.getElementById('transparency-reduce');

            const isNoPref = window.matchMedia('(prefers-reduced-transparency: no-preference)').matches;
            const isReduce = window.matchMedia('(prefers-reduced-transparency: reduce)').matches;

            function setCard(card, isActive, activeText, inactiveText) {
                const value = card.querySelector('.value');
                if (isActive) {
                    value.textContent = activeText;
                    card.classList.add('active');
                } else {
                    value.textContent = inactiveText;
                    card.classList.remove('active');
                }
            }

            setCard(transparencyNoPref, isNoPref, 'Active ✅', 'Not active');
            setCard(transparencyReduce, isReduce, 'Active ✅', 'Not active');

            // Scan detection
            const scanInterlaced = document.getElementById('scan-interlaced');
            const scanProgressive = document.getElementById('scan-progressive');

            const isInterlaced = window.matchMedia('(scan: interlaced)').matches;
            const isProgressive = window.matchMedia('(scan: progressive)').matches;

            setCard(scanInterlaced, isInterlaced, 'Active ✅', 'Not active');
            setCard(scanProgressive, isProgressive, 'Active ✅', 'Not active');

            // Live indicator
            const indicatorTransparency = document.getElementById('indicator-transparency');
            const indicatorScan = document.getElementById('indicator-scan');
            const indicator = document.getElementById('live-indicator');

            indicatorTransparency.textContent = isReduce ? 'Transparency: Reduced 🚫' : 'Transparency: Normal ✨';

            let scanText = 'Unknown';
            if (isProgressive) scanText = 'Progressive ✅';
            else if (isInterlaced) scanText = 'Interlaced ⚠️';
            indicatorScan.textContent = 'Scan: ' + scanText;

            // Color the indicator
            if (isReduce || isInterlaced) {
                indicator.style.background = '#28a745';
                indicator.style.color = 'white';
            } else {
                indicator.style.background = '#007bff';
                indicator.style.color = 'white';
            }
        }

        window.addEventListener('load', updateIndicators);

        // Listen for changes
        window.matchMedia('(prefers-reduced-transparency: reduce)').addEventListener('change', updateIndicators);
        window.matchMedia('(scan: interlaced)').addEventListener('change', updateIndicators);

        updateIndicators();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionValues
prefers-reduced-transparencyUser wants less transparencyno-preference, reduce
scanMonitor’s scanning processinterlaced, progressive

prefers-reduced-transparency Values

ValueDescription
no-preferenceNo preference expressed (default)
reduceUser prefers reduced transparency

scan Values

ValueDescriptionDisplay Type
interlacedAlternating linesOld CRT monitors
progressiveComplete framesModern displays

Interlaced vs Progressive

AspectInterlacedProgressive
TechnologyOld CRTModern LCD/OLED
Thin linesMay flicker (< 1px)No flicker
Fast motionCan flickerSmooth
Current useRareUniversal

Best Practices

Do This:

/* Reduce transparency for accessibility */
@media (prefers-reduced-transparency: reduce) {
    .glass-card {
        background: #ffffff;
        backdrop-filter: none;
        border: 2px solid #ddd;
    }
}

/* Handle interlaced displays (rare) */
@media (scan: interlaced) {
    .thin-line {
        height: 3px; /* Avoid flicker */
    }
    .light-text {
        font-weight: 500;
    }
}

Don’t Do This:

/* Don't rely on transparency for design */
.glass {
    background: rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(10px);
    /* No fallback for reduced transparency */
}

/* Don't use thin lines on interlaced displays */
@media (scan: interlaced) {
    .border {
        border-width: 0.5px; /* Will flicker! */
    }
}

Pro Tip: prefers-reduced-transparency is essential for accessibility. Users with visual impairments may struggle to read text over translucent backgrounds. Always provide a solid fallback — replace backdrop-filter: blur() with a solid background and add a border to maintain visual hierarchy. Note that this feature has limited browser support, so test carefully. scan is a legacy feature — interlaced CRT monitors are extremely rare today, so most developers will never need it. If you do encounter it, use thicker lines (3px+) and bolder fonts to prevent flicker!

44. scripting, update, and video-dynamic-range Media Features

These three media features let you adapt styles based on JavaScript availability, display refresh capability, and HDR video support.


Overview of Features

FeatureDescriptionValues
scriptingDetects JavaScript availabilitynone, initial-only, enabled
updateHow often the display can updatenone, slow, fast
video-dynamic-rangeDynamic range of the video planestandard, high

1. scripting

The scripting media feature detects whether JavaScript is available in the browser.

@media (scripting: enabled) {
    .enabled {
        color: red;
        font-weight: bold;
    }
}

Values

ValueDescription
noneScripting is not available (JavaScript disabled)
initial-onlyScripting available only during initial page load
enabledScripting is fully supported (default)

When to Use

  • Provide fallbacks for users with JavaScript disabled
  • Show/hide JavaScript-dependent UI elements
  • Style progressive enhancement layers
  • Display noscript alternatives with CSS instead of <noscript>

How Users Disable JavaScript

  • Chrome: Settings → Privacy → Site Settings → JavaScript → Blocked
  • Firefox: about:config → javascript.enabled → false
  • Safari: Develop → Disable JavaScript
  • Brave: Shields → Scripts blocked

Key Points:

  • enabled is the default in modern browsers
  • none means no JavaScript at all — plan for progressive enhancement
  • initial-only is rare (some email clients, print preview)
  • Use this to style fallback content instead of relying on <noscript>

2. update

The update media feature checks how frequently the device can update rendered content — essentially, its refresh capability.

@media (update: fast) {
    p {
        animation: slide 1s infinite alternate;
    }
}

Values

ValueDescriptionDevice Example
noneContent cannot be updated after renderingPrint, e-ink (static)
slowUpdates are possible but not fast enough for smooth animationE-ink readers, some low-power devices
fastContent can be updated quickly for smooth animationModern screens (60Hz+)

When to Use

Update ValueRecommendation
noneDisable all animations and transitions
slowUse slow, infrequent animations only
fastEnable smooth animations and transitions

Key Points:

  • fast is the default on modern displays
  • slow devices (e-ink) can’t handle smooth animation
  • none means the content is static after rendering
  • Use this to conditionally enable animations based on device capability

Practical Example

/* No animation on static devices */
@media (update: none) {
    p {
        animation: none;
    }
}

/* Slow animation on e-ink */
@media (update: slow) {
    p {
        animation: slide 5s infinite alternate;
    }
}

/* Fast animation on modern screens */
@media (update: fast) {
    p {
        animation: slide 1s infinite alternate;
    }
}

3. video-dynamic-range

The video-dynamic-range media feature queries the dynamic range of the video plane — specifically for HDR video content.

@media (video-dynamic-range: high) {
    h1 {
        color: blue;
    }
}

Values

ValueDescription
standardStandard Dynamic Range (SDR) — most displays
highHigh Dynamic Range (HDR) — supports HDR video

How It Differs from dynamic-range

FeatureTarget
dynamic-rangeThe whole output device (display)
video-dynamic-rangeThe video plane specifically

Key Points:

  • video-dynamic-range is for video content (HDR video playback)
  • dynamic-range is for the display itself
  • A device may support HDR video but not have a high-dynamic-range display
  • Limited browser support — always provide a standard fallback

HDR Requirements

RequirementMinimum
Color depth> 24-bit
Peak brightnessHigh (1000+ nits)
Contrast ratioHigh

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>scripting, update, and video-dynamic-range</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        :root {
            --bg-primary: #ffffff;
            --bg-secondary: #f8f9fa;
            --bg-tertiary: #e9ecef;
            --text-primary: #212529;
            --text-secondary: #6c757d;
            --accent: #007bff;
            --border: #dee2e6;
            --shadow: rgba(0, 0, 0, 0.1);
        }

        @media (prefers-color-scheme: dark) {
            :root {
                --bg-primary: #1a1a1a;
                --bg-secondary: #0d0d0d;
                --bg-tertiary: #2d2d2d;
                --text-primary: #f8f9fa;
                --text-secondary: #adb5bd;
                --accent: #4dabf7;
                --border: #444;
                --shadow: rgba(0, 0, 0, 0.5);
            }
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: var(--bg-secondary);
            color: var(--text-primary);
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
            transition: background 0.3s, color 0.3s;
        }

        h1 {
            color: var(--accent);
            border-bottom: 3px solid var(--accent);
            padding-bottom: 10px;
        }

        h2 {
            color: var(--accent);
            border-left: 4px solid var(--accent);
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: var(--text-primary);
            margin-top: 20px;
        }

        section {
            background: var(--bg-primary);
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px var(--shadow);
            margin: 20px 0;
            transition: all 0.3s;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid var(--border);
            text-align: left;
        }

        .reference-table th {
            background: var(--accent);
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: var(--bg-tertiary);
        }

        .note {
            font-size: 0.9rem;
            color: var(--text-secondary);
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== SCRIPTING DEMO ====== */
        .scripting-demo {
            padding: 20px;
            border-radius: 8px;
            margin: 15px 0;
            border: 2px solid var(--border);
            background: var(--bg-tertiary);
            text-align: center;
            font-weight: bold;
            font-size: 1.1rem;
            transition: all 0.3s;
        }

        /* No scripting */
        @media (scripting: none) {
            .scripting-demo {
                background: #dc3545;
                color: white;
                border-color: #a71d2a;
            }
            .scripting-demo::after {
                content: " (scripting disabled)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Initial-only scripting */
        @media (scripting: initial-only) {
            .scripting-demo {
                background: #ffc107;
                color: #333;
                border-color: #d39e00;
            }
            .scripting-demo::after {
                content: " (scripting available only on initial load)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Full scripting */
        @media (scripting: enabled) {
            .scripting-demo {
                background: #28a745;
                color: white;
                border-color: #1e7e34;
            }
            .scripting-demo::after {
                content: " (scripting fully enabled)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* ====== UPDATE DEMO ====== */
        .update-demo {
            padding: 20px;
            border-radius: 8px;
            margin: 15px 0;
            border: 2px solid var(--border);
            background: var(--bg-tertiary);
            text-align: center;
            font-weight: bold;
            font-size: 1.1rem;
            transition: all 0.3s;
            overflow: hidden;
            position: relative;
            min-height: 80px;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        @keyframes slide {
            from {
                transform: translateX(-100%);
            }
            to {
                transform: translateX(100%);
            }
        }

        .update-demo .animated-content {
            display: inline-block;
            white-space: nowrap;
        }

        /* No update capability */
        @media (update: none) {
            .update-demo {
                background: #dc3545;
                color: white;
                border-color: #a71d2a;
            }
            .update-demo .animated-content {
                animation: none;
            }
            .update-demo::after {
                content: " (no update capability — animation disabled)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Slow update */
        @media (update: slow) {
            .update-demo {
                background: #ffc107;
                color: #333;
                border-color: #d39e00;
            }
            .update-demo .animated-content {
                animation: slide 5s infinite alternate;
            }
            .update-demo::after {
                content: " (slow update — slow animation)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* Fast update */
        @media (update: fast) {
            .update-demo {
                background: #28a745;
                color: white;
                border-color: #1e7e34;
            }
            .update-demo .animated-content {
                animation: slide 1s infinite alternate;
            }
            .update-demo::after {
                content: " (fast update — smooth animation)";
                font-weight: normal;
                font-size: 0.85rem;
            }
        }

        /* ====== VIDEO-DYNAMIC-RANGE DEMO ====== */
        .hdr-demo {
            border-radius: 12px;
            overflow: hidden;
            margin: 15px 0;
        }

        .hdr-demo .video-container {
            width: 100%;
            height: 250px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.5rem;
            font-weight: bold;
            color: white;
            text-shadow: 0 2px 10px rgba(0,0,0,0.3);
            transition: all 0.3s;
            /* Standard dynamic range */
            background: linear-gradient(135deg, #007bff, #6c5ce7);
        }

        /* High dynamic range video */
        @media (video-dynamic-range: high) {
            .hdr-demo .video-container {
                background: linear-gradient(135deg,
                    oklch(69% 0.27 240),
                    oklch(69% 0.27 300),
                    oklch(69% 0.27 30));
                box-shadow: 0 0 40px rgba(108, 92, 231, 0.5);
            }
            .hdr-demo .video-container::after {
                content: " (HDR video enhanced ✨)";
                font-size: 1rem;
                font-weight: normal;
                display: block;
                margin-top: 5px;
            }
        }

        /* ====== DETECTION CARDS ====== */
        .detection-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .detection-card {
            padding: 15px;
            border-radius: 8px;
            text-align: center;
            border: 2px solid var(--border);
            background: var(--bg-tertiary);
            transition: all 0.3s;
        }

        .detection-card .label {
            font-size: 0.85rem;
            color: var(--text-secondary);
            display: block;
            margin-bottom: 5px;
        }

        .detection-card .value {
            font-size: 1.1rem;
            font-weight: bold;
            color: var(--accent);
        }

        .detection-card.active {
            border-color: var(--accent);
            background: var(--bg-primary);
        }

        /* ====== LIVE INDICATOR ====== */
        .live-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: var(--accent);
            color: white;
            padding: 12px 20px;
            border-radius: 50px;
            font-weight: bold;
            font-size: 0.85rem;
            box-shadow: 0 4px 15px var(--shadow);
            z-index: 1000;
            transition: all 0.3s;
            display: flex;
            flex-direction: column;
            gap: 3px;
        }

        .live-indicator .detail {
            font-size: 0.75rem;
            opacity: 0.9;
        }

        /* ====== NOSCRIPT FALLBACK ====== */
        .noscript-message {
            display: none;
            padding: 15px;
            background: #f8d7da;
            border: 2px solid #dc3545;
            border-radius: 8px;
            color: #721c24;
            margin: 15px 0;
            font-weight: bold;
        }

        @media (scripting: none) {
            .noscript-message {
                display: block;
            }
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid var(--accent);
            background: var(--bg-tertiary);
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>scripting, update, and video-dynamic-range</h1>

    <!-- ====== NOSCRIPT MESSAGE ====== -->
    <div class="noscript-message">
        ⚠️ JavaScript is disabled in your browser. Some features may not work correctly.
    </div>

    <!-- ====== 1. SCRIPTING DEMO ====== -->
    <section>
        <h2>1. scripting</h2>
        <p>Detects whether <strong>JavaScript is available</strong> in the browser.</p>

        <div class="scripting-demo">
            Scripting Detection
        </div>

        <div class="code-block">
            /* No scripting */
            @media (scripting: none) {
                .demo {
                    background: #dc3545;
                }
            }

            /* Initial-only scripting */
            @media (scripting: initial-only) {
                .demo {
                    background: #ffc107;
                }
            }

            /* Full scripting */
            @media (scripting: enabled) {
                .demo {
                    background: #28a745;
                }
            }
        </div>

        <p class="note">Use this to style fallback content for users with JavaScript disabled.</p>
    </section>

    <!-- ====== 2. UPDATE DEMO ====== -->
    <section>
        <h2>2. update</h2>
        <p>Detects how <strong>frequently the display can update</strong> content.</p>

        <div class="update-demo">
            <span class="animated-content">🚀 Animation Speed Demo</span>
        </div>

        <div class="code-block">
            /* No update capability — disable animation */
            @media (update: none) {
                .demo .animated-content {
                    animation: none;
                }
            }

            /* Slow update — slow animation */
            @media (update: slow) {
                .demo .animated-content {
                    animation: slide 5s infinite alternate;
                }
            }

            /* Fast update — smooth animation */
            @media (update: fast) {
                .demo .animated-content {
                    animation: slide 1s infinite alternate;
                }
            }
        </div>

        <p class="note">E-ink displays have <code>update: slow</code> — animations should be infrequent. Print has <code>update: none</code> — no animation at all.</p>
    </section>

    <!-- ====== 3. VIDEO-DYNAMIC-RANGE DEMO ====== -->
    <section>
        <h2>3. video-dynamic-range</h2>
        <p>Detects the <strong>dynamic range of the video plane</strong> — specifically for HDR video.</p>

        <div class="hdr-demo">
            <div class="video-container">
                🎬 HDR Video Demo
            </div>
        </div>

        <div class="code-block">
            /* Standard dynamic range video */
            @media (video-dynamic-range: standard) {
                .video {
                    /* SDR styles */
                }
            }

            /* High dynamic range video */
            @media (video-dynamic-range: high) {
                .video {
                    background: linear-gradient(135deg,
                        oklch(69% 0.27 240),
                        oklch(69% 0.27 300));
                }
            }
        </div>

        <div class="tip-box warning">
            <strong>⚠️ Limited Availability:</strong>
            <code>video-dynamic-range</code> has limited browser support. Always provide a <code>standard</code> fallback.
        </div>
    </section>

    <!-- ====== 4. DETECTION SUMMARY ====== -->
    <section>
        <h2>4. Your Device's Capabilities</h2>
        <p>Below is a live detection of your device's capabilities.</p>

        <div class="detection-grid">
            <div class="detection-card" id="scripting-none">
                <span class="label">scripting: none</span>
                <span class="value" id="scripting-none-value">Detecting...</span>
            </div>
            <div class="detection-card" id="scripting-initial">
                <span class="label">scripting: initial-only</span>
                <span class="value" id="scripting-initial-value">Detecting...</span>
            </div>
            <div class="detection-card" id="scripting-enabled">
                <span class="label">scripting: enabled</span>
                <span class="value" id="scripting-enabled-value">Detecting...</span>
            </div>
            <div class="detection-card" id="update-none">
                <span class="label">update: none</span>
                <span class="value" id="update-none-value">Detecting...</span>
            </div>
            <div class="detection-card" id="update-slow">
                <span class="label">update: slow</span>
                <span class="value" id="update-slow-value">Detecting...</span>
            </div>
            <div class="detection-card" id="update-fast">
                <span class="label">update: fast</span>
                <span class="value" id="update-fast-value">Detecting...</span>
            </div>
            <div class="detection-card" id="vdr-standard">
                <span class="label">video-dynamic-range: standard</span>
                <span class="value" id="vdr-standard-value">Detecting...</span>
            </div>
            <div class="detection-card" id="vdr-high">
                <span class="label">video-dynamic-range: high</span>
                <span class="value" id="vdr-high-value">Detecting...</span>
            </div>
        </div>

        <div class="code-block">
            /* Detect scripting */
            @media (scripting: none) { /* No JavaScript */ }
            @media (scripting: initial-only) { /* Initial load only */ }
            @media (scripting: enabled) { /* Full JavaScript */ }

            /* Detect update capability */
            @media (update: none) { /* No update — static */ }
            @media (update: slow) { /* Slow update — e-ink */ }
            @media (update: fast) { /* Fast update — modern */ }

            /* Detect video dynamic range */
            @media (video-dynamic-range: standard) { /* SDR video */ }
            @media (video-dynamic-range: high) { /* HDR video */ }
        </div>
    </section>

    <!-- ====== 5. REFERENCE TABLES ====== -->
    <section>
        <h2>5. Reference Tables</h2>

        <h3>scripting Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Device Example</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>Scripting not available</td>
                <td>JavaScript disabled, some email clients</td>
            </tr>
            <tr>
                <td><code>initial-only</code></td>
                <td>Scripting only during initial load</td>
                <td>Print preview, some email clients</td>
            </tr>
            <tr>
                <td><code>enabled</code></td>
                <td>Scripting fully supported (default)</td>
                <td>Modern browsers</td>
            </tr>
        </table>

        <h3>update Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Device Example</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>Content cannot be updated after rendering</td>
                <td>Print, static e-ink</td>
            </tr>
            <tr>
                <td><code>slow</code></td>
                <td>Updates possible but not smooth</td>
                <td>E-ink readers, low-power devices</td>
            </tr>
            <tr>
                <td><code>fast</code></td>
                <td>Content updates quickly (default)</td>
                <td>Modern screens (60Hz+)</td>
            </tr>
        </table>

        <h3>video-dynamic-range Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
                <th>Requirements</th>
            </tr>
            <tr>
                <td><code>standard</code></td>
                <td>Standard Dynamic Range (SDR)</td>
                <td>Typical displays</td>
            </tr>
            <tr>
                <td><code>high</code></td>
                <td>High Dynamic Range (HDR)</td>
                <td>Color depth > 24-bit, high brightness, high contrast</td>
            </tr>
        </table>

        <h3>dynamic-range vs video-dynamic-range</h3>
        <table class="reference-table">
            <tr>
                <th>Feature</th>
                <th>Target</th>
            </tr>
            <tr>
                <td><code>dynamic-range</code></td>
                <td>The whole output device (display)</td>
            </tr>
            <tr>
                <td><code>video-dynamic-range</code></td>
                <td>The video plane specifically</td>
            </tr>
        </table>
    </section>

    <!-- ====== 6. BEST PRACTICES ====== -->
    <section>
        <h2>6. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>scripting</code> to style fallbacks for users with JavaScript disabled</li>
                <li>Use <code>update</code> to conditionally enable animations based on device capability</li>
                <li>Use <code>video-dynamic-range</code> to enhance HDR video playback</li>
                <li>Always provide a working fallback for each feature</li>
                <li>Test with JavaScript disabled in your browser</li>
                <li>Test on e-ink devices or simulate slow updates</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't rely solely on <code>scripting</code> for critical functionality</li>
                <li>Don't use fast animations on <code>update: slow</code> devices</li>
                <li>Don't use <code>video-dynamic-range</code> without a <code>standard</code> fallback</li>
                <li>Don't confuse <code>dynamic-range</code> with <code>video-dynamic-range</code></li>
                <li>Don't forget that <code>update: none</code> means no animation at all</li>
            </ul>
        </div>
    </section>

    <!-- ====== LIVE INDICATOR ====== -->
    <div class="live-indicator" id="live-indicator">
        <span id="indicator-scripting">Scripting: —</span>
        <span class="detail" id="indicator-update">Update: —</span>
        <span class="detail" id="indicator-vdr">Video DR: —</span>
    </div>

    <!-- ====== SCRIPT FOR DETECTION ====== -->
    <script>
        function updateIndicators() {
            function setCard(card, isActive, activeText, inactiveText) {
                const value = card.querySelector('.value');
                if (isActive) {
                    value.textContent = activeText;
                    card.classList.add('active');
                } else {
                    value.textContent = inactiveText;
                    card.classList.remove('active');
                }
            }

            // Scripting detection
            const scriptingNone = document.getElementById('scripting-none');
            const scriptingInitial = document.getElementById('scripting-initial');
            const scriptingEnabled = document.getElementById('scripting-enabled');

            const isScriptingNone = window.matchMedia('(scripting: none)').matches;
            const isScriptingInitial = window.matchMedia('(scripting: initial-only)').matches;
            const isScriptingEnabled = window.matchMedia('(scripting: enabled)').matches;

            setCard(scriptingNone, isScriptingNone, 'Active ✅', 'Not active');
            setCard(scriptingInitial, isScriptingInitial, 'Active ✅', 'Not active');
            setCard(scriptingEnabled, isScriptingEnabled, 'Active ✅', 'Not active');

            // Update detection
            const updateNone = document.getElementById('update-none');
            const updateSlow = document.getElementById('update-slow');
            const updateFast = document.getElementById('update-fast');

            const isUpdateNone = window.matchMedia('(update: none)').matches;
            const isUpdateSlow = window.matchMedia('(update: slow)').matches;
            const isUpdateFast = window.matchMedia('(update: fast)').matches;

            setCard(updateNone, isUpdateNone, 'Active ✅', 'Not active');
            setCard(updateSlow, isUpdateSlow, 'Active ✅', 'Not active');
            setCard(updateFast, isUpdateFast, 'Active ✅', 'Not active');

            // Video dynamic range detection
            const vdrStandard = document.getElementById('vdr-standard');
            const vdrHigh = document.getElementById('vdr-high');

            const isVdrStandard = window.matchMedia('(video-dynamic-range: standard)').matches;
            const isVdrHigh = window.matchMedia('(video-dynamic-range: high)').matches;

            setCard(vdrStandard, isVdrStandard, 'Active ✅', 'Not active');
            setCard(vdrHigh, isVdrHigh, 'Active ✅', 'Not active');

            // Live indicator
            const indicatorScripting = document.getElementById('indicator-scripting');
            const indicatorUpdate = document.getElementById('indicator-update');
            const indicatorVdr = document.getElementById('indicator-vdr');
            const indicator = document.getElementById('live-indicator');

            let scriptingText = 'Unknown';
            if (isScriptingEnabled) scriptingText = 'Enabled ✅';
            else if (isScriptingInitial) scriptingText = 'Initial only ⚠️';
            else if (isScriptingNone) scriptingText = 'None ❌';
            indicatorScripting.textContent = 'JS: ' + scriptingText;

            let updateText = 'Unknown';
            if (isUpdateFast) updateText = 'Fast ⚡';
            else if (isUpdateSlow) updateText = 'Slow 🐌';
            else if (isUpdateNone) updateText = 'None 🚫';
            indicatorUpdate.textContent = 'Update: ' + updateText;

            let vdrText = 'Unknown';
            if (isVdrHigh) vdrText = 'HDR ✨';
            else if (isVdrStandard) vdrText = 'SDR';
            indicatorVdr.textContent = 'Video DR: ' + vdrText;

            // Color indicator
            if (isUpdateFast && isScriptingEnabled) {
                indicator.style.background = '#28a745';
                indicator.style.color = 'white';
            } else if (isUpdateSlow || isScriptingNone) {
                indicator.style.background = '#ffc107';
                indicator.style.color = '#333';
            } else {
                indicator.style.background = '#007bff';
                indicator.style.color = 'white';
            }
        }

        window.addEventListener('load', updateIndicators);

        // Listen for changes
        window.matchMedia('(scripting: enabled)').addEventListener('change', updateIndicators);
        window.matchMedia('(update: fast)').addEventListener('change', updateIndicators);
        window.matchMedia('(video-dynamic-range: high)').addEventListener('change', updateIndicators);

        updateIndicators();
    </script>

</body>
</html>

Quick Reference

FeatureDescriptionValues
scriptingJavaScript availabilitynone, initial-only, enabled
updateDisplay update capabilitynone, slow, fast
video-dynamic-rangeDynamic range of video planestandard, high

scripting Values

ValueDescriptionDevice Example
noneNo scriptingJS disabled, some email clients
initial-onlyScripting only on initial loadPrint preview, some email clients
enabledFull scripting (default)Modern browsers

update Values

ValueDescriptionDevice Example
noneContent is static after renderingPrint, static e-ink
slowUpdates possible but not smoothE-ink readers
fastSmooth updates (default)Modern screens (60Hz+)

video-dynamic-range Values

ValueDescriptionRequirements
standardStandard Dynamic Range (SDR)Typical displays
highHigh Dynamic Range (HDR)Color depth > 24-bit, high brightness, high contrast

Best Practices

Do This:

/* Style fallbacks for no JavaScript */
@media (scripting: none) {
    .js-only {
        display: none;
    }
    .noscript-fallback {
        display: block;
    }
}

/* Conditionally enable animations */
@media (update: none) {
    .animated {
        animation: none;
    }
}

@media (update: slow) {
    .animated {
        animation: slide 5s infinite alternate;
    }
}

@media (update: fast) {
    .animated {
        animation: slide 1s infinite alternate;
    }
}

/* Enhance HDR video */
@media (video-dynamic-range: high) {
    .video {
        background: linear-gradient(135deg, oklch(69% 0.27 240), oklch(69% 0.27 300));
    }
}

Don’t Do This:

/* Don't rely on JavaScript for critical functionality */
@media (scripting: enabled) {
    .content {
        display: block;
        /* Content is hidden without JS! */
    }
}

/* Don't use fast animations on slow-update devices */
@media (update: slow) {
    .animated {
        animation: slide 0.1s infinite; /* Will flicker terribly! */
    }
}

/* Don't confuse dynamic-range with video-dynamic-range */
@media (video-dynamic-range: high) {
    /* This is for video, not the whole display */
}

Pro Tip: scripting is essential for progressive enhancement — always provide a working fallback for users with JavaScript disabled. update is great for device-adaptive animations — e-ink readers can’t handle smooth animation, so use slow, infrequent transitions. video-dynamic-range is a specialized feature for HDR video content — it has limited browser support, so always provide a standard fallback. Remember: dynamic-range is for the display, while video-dynamic-range is for the video plane specifically!

45. Transform Property Introduction

The transform property is one of the most powerful tools in CSS. It lets you rotate, scale, skew, and translate elements — all without affecting the layout of other elements.


What is the transform Property?

The transform property applies 2D or 3D transformations to an element. Unlike properties like margin or position, transforms don’t affect the document flow — the element’s original space remains reserved.

Key Benefits

BenefitDescription
No layout impactOther elements stay in place
Hardware acceleratedSmooth performance
CombinableMultiple transforms in one declaration
AnimatableWorks with transition and animation
2D and 3DSupports both flat and spatial transformations

Basic Syntax

.box {
    transform: rotate(45deg);
}

You can combine multiple transform functions:

.box {
    transform: rotate(45deg) scale(1.5) translate(20px, 10px);
}

Important: The order matters! Transforms are applied right to left (last function first).


Transform Functions Overview

CategoryFunctions
Rotationrotate(), rotate3d(), rotateX(), rotateY(), rotateZ()
Scalingscale(), scale3d(), scaleX(), scaleY(), scaleZ()
Skewingskew(), skewX(), skewY()
Translationtranslate(), translate3d(), translateX(), translateY(), translateZ()
Matrixmatrix(), matrix3d()
Perspectiveperspective()

1. rotate()

Rotates an element around its origin (center by default).

.rotate {
    transform: rotate(45deg);
}
  • Positive values rotate clockwise
  • Negative values rotate counter-clockwise
  • Use transform-origin to change the rotation point

2. scale()

Scales an element — makes it larger or smaller.

.scale {
    transform: scale(2, 1); /* 2x width, 1x height */
}
SyntaxEffect
scale(2)2x in both directions
scale(2, 1)2x width, 1x height
scale(0.5)Half size
scaleX(2)2x width only
scaleY(0.5)Half height only

3. skew()

Skews an element — slants it along the X or Y axis.

.skew {
    transform: skew(30deg, -20deg);
}
SyntaxEffect
skew(30deg)Skew 30° along X axis
skew(30deg, -20deg)Skew X 30°, Y -20°
skewX(30deg)Skew X only
skewY(20deg)Skew Y only

4. translate()

Moves an element from its original position.

.translate {
    transform: translate(50px, 25px);
}
SyntaxEffect
translate(50px)Move 50px right
translate(50px, 25px)Move 50px right, 25px down
translateX(50px)Move horizontally
translateY(25px)Move vertically
translate(-50%, -50%)Center an absolutely positioned element

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Transform Property Introduction</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== TRANSFORM DEMOS ====== */
        .demo-area {
            display: flex;
            flex-wrap: wrap;
            gap: 40px;
            justify-content: center;
            align-items: center;
            padding: 40px 20px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 250px;
        }

        .box {
            width: 100px;
            height: 100px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.9rem;
            border-radius: 8px;
            transition: transform 0.5s ease;
            cursor: pointer;
            text-align: center;
            padding: 10px;
        }

        .box:hover {
            box-shadow: 0 8px 25px rgba(0, 123, 255, 0.4);
        }

        /* Individual transforms */
        .rotate {
            transform: rotate(45deg);
        }

        .rotate:hover {
            transform: rotate(225deg);
        }

        .scale {
            transform: scale(1.5, 1);
        }

        .scale:hover {
            transform: scale(2, 2);
        }

        .skew {
            transform: skew(20deg, -10deg);
        }

        .skew:hover {
            transform: skew(0deg, 0deg);
        }

        .translate {
            transform: translate(50px, 25px);
        }

        .translate:hover {
            transform: translate(0, 0);
        }

        /* Combined transforms */
        .combined-1 {
            transform: rotate(45deg) scale(1.2);
        }

        .combined-2 {
            transform: scale(1.5) rotate(-20deg) translate(10px, 10px);
        }

        .combined-3 {
            transform: translate(20px, -20px) skew(10deg, 5deg) scale(0.9);
        }

        /* Origin demo */
        .origin-center {
            transform-origin: center center;
            transform: rotate(45deg);
        }

        .origin-top-left {
            transform-origin: top left;
            transform: rotate(45deg);
        }

        .origin-bottom-right {
            transform-origin: bottom right;
            transform: rotate(45deg);
        }

        /* 3D transform demo */
        .rotate-x {
            transform: rotateX(60deg);
        }

        .rotate-y {
            transform: rotateY(60deg);
        }

        .rotate-z {
            transform: rotateZ(45deg);
        }

        /* 3D card flip */
        .flip-container {
            perspective: 1000px;
            width: 200px;
            height: 200px;
            margin: 20px auto;
        }

        .flip-card {
            width: 100%;
            height: 100%;
            position: relative;
            transform-style: preserve-3d;
            transition: transform 0.8s;
            cursor: pointer;
        }

        .flip-container:hover .flip-card {
            transform: rotateY(180deg);
        }

        .flip-front,
        .flip-back {
            position: absolute;
            width: 100%;
            height: 100%;
            backface-visibility: hidden;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 1.2rem;
            color: white;
        }

        .flip-front {
            background: linear-gradient(135deg, #007bff, #6c5ce7);
        }

        .flip-back {
            background: linear-gradient(135deg, #28a745, #20c997);
            transform: rotateY(180deg);
        }

        /* Practical: button hover */
        .btn-transform {
            padding: 15px 30px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 1em;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
            margin: 5px;
        }

        .btn-transform:hover {
            transform: translateY(-3px) scale(1.02);
            box-shadow: 0 8px 20px rgba(0, 123, 255, 0.3);
        }

        .btn-transform:active {
            transform: translateY(0) scale(0.98);
        }

        /* Practical: card hover */
        .card-transform {
            background: white;
            border: 2px solid #ddd;
            border-radius: 12px;
            padding: 25px;
            max-width: 300px;
            margin: 15px auto;
            transition: all 0.3s;
            cursor: pointer;
            text-align: center;
        }

        .card-transform:hover {
            transform: translateY(-5px) scale(1.02);
            border-color: #007bff;
            box-shadow: 0 10px 30px rgba(0, 123, 255, 0.15);
        }

        /* Image gallery transforms */
        .gallery {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 15px;
            margin: 15px 0;
        }

        .gallery-item {
            height: 150px;
            border-radius: 8px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 2rem;
            transition: all 0.4s;
            cursor: pointer;
            overflow: hidden;
        }

        .gallery-item:hover {
            transform: scale(1.1) rotate(3deg);
            box-shadow: 0 8px 25px rgba(0, 123, 255, 0.3);
            z-index: 10;
        }

        /* Rotate animation */
        @keyframes spin {
            from { transform: rotate(0deg); }
            to { transform: rotate(360deg); }
        }

        .spin {
            animation: spin 3s linear infinite;
        }

        /* ====== DETECTION CARDS ====== */
        .reference-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 15px;
            margin: 20px 0;
        }

        .reference-card {
            padding: 15px;
            border-radius: 8px;
            border: 2px solid #ddd;
            background: #f8f9fa;
            transition: all 0.3s;
        }

        .reference-card h4 {
            margin-top: 0;
            color: #007bff;
        }

        .reference-card code {
            background: #e9ecef;
            padding: 2px 6px;
            border-radius: 4px;
            font-family: 'Courier New', monospace;
            font-size: 0.85rem;
        }
    </style>
</head>
<body>

    <h1>Transform Property Introduction</h1>

    <!-- ====== 1. BASIC TRANSFORMS ====== -->
    <section>
        <h2>1. Basic Transform Functions</h2>
        <p>The <code>transform</code> property applies 2D or 3D transformations without affecting layout.</p>

        <div class="demo-area">
            <div class="box rotate">Rotate<br>45°</div>
            <div class="box scale">Scale<br>2x, 1x</div>
            <div class="box skew">Skew<br>20°, -10°</div>
            <div class="box translate">Translate<br>50px, 25px</div>
        </div>

        <p class="note">Hover over each box to see the transform change!</p>

        <div class="code-block">
            /* Rotate 45 degrees */
            .rotate {
                transform: rotate(45deg);
            }

            /* Scale 2x width, 1x height */
            .scale {
                transform: scale(2, 1);
            }

            /* Skew 20° X, -10° Y */
            .skew {
                transform: skew(20deg, -10deg);
            }

            /* Move 50px right, 25px down */
            .translate {
                transform: translate(50px, 25px);
            }
        </div>
    </section>

    <!-- ====== 2. COMBINED TRANSFORMS ====== -->
    <section>
        <h2>2. Combining Multiple Transforms</h2>
        <p>Multiple transform functions can be combined in a single declaration.</p>

        <div class="demo-area">
            <div class="box combined-1">Rotate + Scale</div>
            <div class="box combined-2">Scale + Rotate + Translate</div>
            <div class="box combined-3">Translate + Skew + Scale</div>
        </div>

        <div class="code-block">
            /* Rotate then scale */
            .combined-1 {
                transform: rotate(45deg) scale(1.2);
            }

            /* Scale, rotate, then translate */
            .combined-2 {
                transform: scale(1.5) rotate(-20deg) translate(10px, 10px);
            }

            /* Translate, skew, then scale */
            .combined-3 {
                transform: translate(20px, -20px) skew(10deg, 5deg) scale(0.9);
            }
        </div>

        <p class="note"><strong>Important:</strong> Transforms are applied <strong>right to left</strong> (last function first).</p>
    </section>

    <!-- ====== 3. TRANSFORM ORIGIN ====== -->
    <section>
        <h2>3. transform-origin</h2>
        <p>Changes the point around which transforms are applied.</p>

        <div class="demo-area">
            <div class="box origin-center">center center<br>(default)</div>
            <div class="box origin-top-left">top left</div>
            <div class="box origin-bottom-right">bottom right</div>
        </div>

        <div class="code-block">
            /* Default origin (center) */
            .origin-center {
                transform-origin: center center;
                transform: rotate(45deg);
            }

            /* Rotate around top-left corner */
            .origin-top-left {
                transform-origin: top left;
                transform: rotate(45deg);
            }

            /* Rotate around bottom-right corner */
            .origin-bottom-right {
                transform-origin: bottom right;
                transform: rotate(45deg);
            }
        </div>
    </section>

    <!-- ====== 4. 3D TRANSFORMS ====== -->
    <section>
        <h2>4. 3D Transforms</h2>
        <p>Transform functions like <code>rotateX()</code>, <code>rotateY()</code>, and <code>rotateZ()</code> work in 3D space.</p>

        <div class="demo-area">
            <div class="box rotate-x">rotateX<br>60°</div>
            <div class="box rotate-y">rotateY<br>60°</div>
            <div class="box rotate-z">rotateZ<br>45°</div>
        </div>

        <div class="code-block">
            /* Rotate around X axis */
            .rotate-x {
                transform: rotateX(60deg);
            }

            /* Rotate around Y axis */
            .rotate-y {
                transform: rotateY(60deg);
            }

            /* Rotate around Z axis */
            .rotate-z {
                transform: rotateZ(45deg);
            }
        </div>
    </section>

    <!-- ====== 5. 3D CARD FLIP ====== -->
    <section>
        <h2>5. Practical Example: 3D Card Flip</h2>
        <p>Hover over the card to see a 3D flip animation.</p>

        <div class="flip-container">
            <div class="flip-card">
                <div class="flip-front">Front</div>
                <div class="flip-back">Back</div>
            </div>
        </div>

        <div class="code-block">
            .flip-container {
                perspective: 1000px;
            }

            .flip-card {
                transform-style: preserve-3d;
                transition: transform 0.8s;
            }

            .flip-container:hover .flip-card {
                transform: rotateY(180deg);
            }

            .flip-back {
                transform: rotateY(180deg);
                backface-visibility: hidden;
            }
        </div>
    </section>

    <!-- ====== 6. PRACTICAL: BUTTON AND CARD HOVER ====== -->
    <section>
        <h2>6. Practical Examples</h2>

        <h3>Button Hover</h3>
        <div style="text-align: center; margin: 15px 0;">
            <button class="btn-transform">Hover Me</button>
            <button class="btn-transform">Click Me</button>
        </div>

        <h3>Card Hover</h3>
        <div class="card-transform">
            <h4 style="margin-top: 0; color: #007bff;">Interactive Card</h4>
            <p>Hover over this card to see the transform effect.</p>
        </div>

        <h3>Image Gallery</h3>
        <div class="gallery">
            <div class="gallery-item">🖼️</div>
            <div class="gallery-item">🎨</div>
            <div class="gallery-item">📷</div>
            <div class="gallery-item">🎭</div>
        </div>

        <div class="code-block">
            /* Button hover */
            .btn:hover {
                transform: translateY(-3px) scale(1.02);
                box-shadow: 0 8px 20px rgba(0, 123, 255, 0.3);
            }

            /* Card hover */
            .card:hover {
                transform: translateY(-5px) scale(1.02);
                box-shadow: 0 10px 30px rgba(0, 123, 255, 0.15);
            }

            /* Gallery item hover */
            .gallery-item:hover {
                transform: scale(1.1) rotate(3deg);
                z-index: 10;
            }
        </div>
    </section>

    <!-- ====== 7. ANIMATED TRANSFORMS ====== -->
    <section>
        <h2>7. Animated Transforms</h2>
        <p>Transforms can be animated with <code>transition</code> or <code>animation</code>.</p>

        <div class="demo-area">
            <div class="box spin">Spinning</div>
        </div>

        <div class="code-block">
            @keyframes spin {
                from { transform: rotate(0deg); }
                to { transform: rotate(360deg); }
            }

            .spin {
                animation: spin 3s linear infinite;
            }
        </div>
    </section>

    <!-- ====== 8. REFERENCE TABLES ====== -->
    <section>
        <h2>8. Reference Tables</h2>

        <h3>Transform Functions</h3>
        <table class="reference-table">
            <tr>
                <th>Category</th>
                <th>Functions</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><strong>Rotation</strong></td>
                <td><code>rotate()</code>, <code>rotate3d()</code>, <code>rotateX()</code>, <code>rotateY()</code>, <code>rotateZ()</code></td>
                <td>Rotate around an axis</td>
            </tr>
            <tr>
                <td><strong>Scaling</strong></td>
                <td><code>scale()</code>, <code>scale3d()</code>, <code>scaleX()</code>, <code>scaleY()</code>, <code>scaleZ()</code></td>
                <td>Resize the element</td>
            </tr>
            <tr>
                <td><strong>Skewing</strong></td>
                <td><code>skew()</code>, <code>skewX()</code>, <code>skewY()</code></td>
                <td>Slant the element</td>
            </tr>
            <tr>
                <td><strong>Translation</strong></td>
                <td><code>translate()</code>, <code>translate3d()</code>, <code>translateX()</code>, <code>translateY()</code>, <code>translateZ()</code></td>
                <td>Move the element</td>
            </tr>
            <tr>
                <td><strong>Matrix</strong></td>
                <td><code>matrix()</code>, <code>matrix3d()</code></td>
                <td>Complex transformations</td>
            </tr>
            <tr>
                <td><strong>Perspective</strong></td>
                <td><code>perspective()</code></td>
                <td>3D perspective effect</td>
            </tr>
        </table>

        <h3>Common Transform Values</h3>
        <table class="reference-table">
            <tr>
                <th>Function</th>
                <th>Example</th>
                <th>Effect</th>
            </tr>
            <tr>
                <td><code>rotate()</code></td>
                <td><code>rotate(45deg)</code></td>
                <td>Rotate 45° clockwise</td>
            </tr>
            <tr>
                <td><code>scale()</code></td>
                <td><code>scale(2, 1)</code></td>
                <td>2x width, 1x height</td>
            </tr>
            <tr>
                <td><code>skew()</code></td>
                <td><code>skew(30deg, -20deg)</code></td>
                <td>Skew 30° X, -20° Y</td>
            </tr>
            <tr>
                <td><code>translate()</code></td>
                <td><code>translate(50px, 25px)</code></td>
                <td>Move 50px right, 25px down</td>
            </tr>
        </table>

        <h3>Related Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>transform-origin</code></td>
                <td>Sets the origin point for transforms</td>
            </tr>
            <tr>
                <td><code>transform-style</code></td>
                <td>Preserves 3D positioning (<code>preserve-3d</code>)</td>
            </tr>
            <tr>
                <td><code>perspective</code></td>
                <td>Sets the 3D perspective for children</td>
            </tr>
            <tr>
                <td><code>backface-visibility</code></td>
                <td>Hides the back face of a 3D element</td>
            </tr>
        </table>
    </section>

    <!-- ====== 9. BEST PRACTICES ====== -->
    <section>
        <h2>9. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>transform</code> for animations instead of <code>top</code>/<code>left</code> (better performance)</li>
                <li>Combine multiple transforms in one declaration</li>
                <li>Use <code>transform-origin</code> to control the pivot point</li>
                <li>Add <code>transition</code> for smooth animations</li>
                <li>Use <code>translate(-50%, -50%)</code> to center elements</li>
                <li>Use <code>will-change: transform</code> for frequently animated elements</li>
                <li>Test transforms on different devices and browsers</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't overuse transforms — they can cause motion sickness</li>
                <li>Don't forget <code>prefers-reduced-motion</code> for accessibility</li>
                <li>Don't animate transforms that cause layout shifts</li>
                <li>Don't use transforms on elements with fixed positioning without testing</li>
                <li>Don't forget that transforms create a new stacking context</li>
            </ul>
        </div>

        <div class="code-block">
            /* Accessibility: respect reduced motion */
            @media (prefers-reduced-motion: reduce) {
                .animated {
                    transition: none;
                    animation: none;
                    transform: none;
                }
            }

            /* Performance: hint the browser */
            .will-animate {
                will-change: transform;
            }
        </div>
    </section>

</body>
</html>

Quick Reference

FunctionExampleEffect
rotate()rotate(45deg)Rotate 45° clockwise
scale()scale(2, 1)2x width, 1x height
skew()skew(30deg, -20deg)Skew 30° X, -20° Y
translate()translate(50px, 25px)Move 50px right, 25px down

Transform Categories

CategoryFunctions
Rotationrotate(), rotate3d(), rotateX(), rotateY(), rotateZ()
Scalingscale(), scale3d(), scaleX(), scaleY(), scaleZ()
Skewingskew(), skewX(), skewY()
Translationtranslate(), translate3d(), translateX(), translateY(), translateZ()
Matrixmatrix(), matrix3d()
Perspectiveperspective()

Related Properties

PropertyDescription
transform-originSets the origin point for transforms
transform-stylePreserves 3D positioning (preserve-3d)
perspectiveSets 3D perspective for children
backface-visibilityHides the back face of a 3D element

Best Practices

Do This:

/* Combine transforms */
.box {
    transform: rotate(45deg) scale(1.5) translate(20px, 10px);
}

/* Use transform for animations (better performance) */
.box:hover {
    transform: translateY(-5px);
    transition: transform 0.3s;
}

/* Center with translate */
.centered {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    .animated {
        transform: none;
        transition: none;
    }
}

Don’t Do This:

/* Don't animate top/left (worse performance) */
.box:hover {
    top: -5px;
    transition: top 0.3s;
}

/* Don't forget transform-origin */
.box {
    transform: rotate(45deg);
    /* Rotates around center by default */
}

/* Don't overuse transforms */
.everything {
    transform: rotate(5deg) scale(1.1) skew(2deg);
}

Pro Tip: The transform property is one of the most powerful tools in CSS. Use it for animations instead of top/left — transforms are hardware-accelerated and don’t cause layout recalculations. Combine multiple transforms in one declaration (e.g., transform: rotate(45deg) scale(1.5)), and remember that the order matters — transforms are applied right to left. Use transform-origin to change the pivot point, and always respect prefers-reduced-motion for accessibility!

46. transform matrix() and matrix3d()

The matrix() and matrix3d() functions are the most powerful — and most complex — transform functions in CSS. They let you apply exact mathematical transformations using matrices.


Overview

FunctionDimensionsMatrix SizeValues
matrix()2D3×3 (6 values)a, b, c, d, e, f
matrix3d()3D4×4 (16 values)a through p

1. matrix() — 2D Transformations

The matrix() function applies a 2D transformation using a 3×3 matrix (represented by 6 values).

.box {
    transform: matrix(a, b, c, d, e, f);
}

Matrix Structure

| a  c  e |
| b  d  f |
| 0  0  1 |
ValueControlsDescription
aScale XHorizontal scaling
bSkew YVertical skew
cSkew XHorizontal skew
dScale YVertical scaling
eTranslate XHorizontal movement
fTranslate YVertical movement

2D Matrix Examples

Translation
.translated {
    transform: matrix(1, 0, 0, 1, 100, 100);
}
  • a=1, d=1 → No scaling
  • b=0, c=0 → No skewing
  • e=100, f=100 → Move 100px right and down

Equivalent to: translate(100px, 100px)


Rotation (45°)
.rotated {
    transform: matrix(0.707, 0.707, -0.707, 0.707, 0, 0);
}
  • 0.707 = cos(45°) ≈ sin(45°)
  • a=cos(θ), b=sin(θ), c=-sin(θ), d=cos(θ)

Equivalent to: rotate(45deg)


Scaling and Skewing
.transformed {
    transform: matrix(1, 0.3, -0.3, 1, 0, 0);
}
  • a=1, d=1 → No scaling
  • b=0.3 → Skew Y by ~16.7°
  • c=-0.3 → Skew X by ~-16.7°

Equivalent to: skew(16.7deg, -16.7deg)


2. matrix3d() — 3D Transformations

The matrix3d() function applies a 3D transformation using a 4×4 matrix (16 values).

.box {
    transform: matrix3d(
        a, b, c, d,
        e, f, g, h,
        i, j, k, l,
        m, n, o, p
    );
}

Matrix Structure

| a  e  i  m |
| b  f  j  n |
| c  g  k  o |
| d  h  l  p |
GroupValuesControls
Linear transformationa, b, c, e, f, g, i, j, kScale, rotate, skew
Translationm, n, oX, Y, Z movement
Perspectived, h, lPerspective effects
HomogeneouspUsually 1

3D Matrix Examples

3D Rotation (45° around Y axis)
.rotated3d {
    transform: matrix3d(
        cos(45deg), 0, sin(45deg), 0,
        0, 1, 0, 0,
        -sin(45deg), 0, cos(45deg), 0,
        0, 0, 0, 1
    );
}
  • Rotates around the Y axis
  • cos(45°) and sin(45°) create the rotation

Equivalent to: rotateY(45deg)


3D Scaling and Translation
.transformed3d {
    transform: matrix3d(
        2, 0, 0, 0,
        0, 2, 0, 0,
        0, 0, 1, 0,
        100, 100, 0, 1
    );
}
  • a=2, f=2 → Scale 2x in X and Y
  • m=100, n=100 → Move 100px right and down

Equivalent to: translate(100px, 100px) scale(2, 2)


3D Skewing
.skewed {
    transform: matrix3d(
        1, 0.3, 0, 0,
        -0.3, 1, 0, 0,
        0, 0, 1, 0,
        0, 0, 0, 1
    );
}
  • b=0.3 → Skew Y
  • e=-0.3 → Skew X

Equivalent to: skew(16.7deg, -16.7deg)


Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>transform matrix() and matrix3d()</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DEMO AREA ====== */
        .demo-area {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            justify-content: center;
            align-items: center;
            padding: 40px 20px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 300px;
            perspective: 800px;
        }

        .box {
            width: 100px;
            height: 100px;
            background: linear-gradient(135deg, #28a745, #20c997);
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.8rem;
            border-radius: 8px;
            transition: transform 0.5s ease-in-out;
            cursor: pointer;
            text-align: center;
            padding: 5px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
        }

        .box:hover {
            box-shadow: 0 8px 25px rgba(40, 167, 69, 0.4);
        }

        /* 2D Matrix transforms */
        .translated {
            transform: matrix(1, 0, 0, 1, 100, 100);
        }

        .translated:hover {
            transform: matrix(1, 0, 0, 1, 150, 50);
        }

        .rotated {
            transform: matrix(0.707, 0.707, -0.707, 0.707, 0, 0);
        }

        .rotated:hover {
            transform: matrix(0.707, 0.707, -0.707, 0.707, 50, 50);
        }

        .transformed {
            transform: matrix(1, 0.3, -0.3, 1, 0, 0);
        }

        .transformed:hover {
            transform: matrix(1.2, 0.5, -0.5, 1.2, 20, 20);
        }

        /* 3D Matrix transforms */
        .rotated3d {
            transform: matrix3d(
                cos(45deg), 0, sin(45deg), 0,
                0, 1, 0, 0,
                -sin(45deg), 0, cos(45deg), 0,
                0, 0, 0, 1
            );
        }

        .rotated3d:hover {
            transform: matrix3d(
                cos(90deg), 0, sin(90deg), 0,
                0, 1, 0, 0,
                -sin(90deg), 0, cos(90deg), 0,
                0, 0, 0, 1
            );
        }

        .transformed3d {
            transform: matrix3d(
                2, 0, 0, 0,
                0, 2, 0, 0,
                0, 0, 1, 0,
                100, 100, 0, 1
            );
        }

        .transformed3d:hover {
            transform: matrix3d(
                2.5, 0, 0, 0,
                0, 2.5, 0, 0,
                0, 0, 1, 0,
                50, 50, 0, 1
            );
        }

        .skewed {
            transform: matrix3d(
                1, 0.3, 0, 0,
                -0.3, 1, 0, 0,
                0, 0, 1, 0,
                0, 0, 0, 1
            );
        }

        .skewed:hover {
            transform: matrix3d(
                1, 0.5, 0, 0,
                -0.5, 1, 0, 0,
                0, 0, 1, 0,
                0, 0, 0, 1
            );
        }

        /* ====== COMPARISON GRID ====== */
        .comparison-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            gap: 20px;
            margin: 15px 0;
        }

        .comparison-card {
            background: white;
            border: 2px solid #ddd;
            border-radius: 8px;
            padding: 20px;
            text-align: center;
            transition: all 0.3s;
        }

        .comparison-card:hover {
            border-color: #007bff;
            box-shadow: 0 4px 15px rgba(0, 123, 255, 0.15);
        }

        .comparison-card h4 {
            margin-top: 0;
            color: #007bff;
        }

        .comparison-card .matrix-display {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 10px;
            border-radius: 6px;
            font-family: 'Courier New', monospace;
            font-size: 0.75rem;
            margin: 10px 0;
            white-space: pre;
            text-align: left;
            overflow-x: auto;
        }

        /* ====== MATRIX VISUALIZATION ====== */
        .matrix-viz {
            display: flex;
            gap: 20px;
            flex-wrap: wrap;
            justify-content: center;
            margin: 20px 0;
        }

        .matrix-box {
            display: grid;
            grid-template-columns: repeat(3, 50px);
            gap: 5px;
            padding: 15px;
            background: #f8f9fa;
            border-radius: 8px;
            border: 2px solid #ddd;
        }

        .matrix-box .cell {
            width: 50px;
            height: 50px;
            display: flex;
            align-items: center;
            justify-content: center;
            background: #007bff;
            color: white;
            border-radius: 4px;
            font-weight: bold;
            font-size: 0.8rem;
        }

        .matrix-box .cell.highlight {
            background: #ffc107;
            color: #333;
        }

        .matrix-box .cell.scale {
            background: #28a745;
        }

        .matrix-box .cell.skew {
            background: #dc3545;
        }

        .matrix-box .cell.translate {
            background: #6c5ce7;
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            background: #f8f9fa;
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>transform matrix() and matrix3d()</h1>

    <!-- ====== 1. MATRIX() DEMO ====== -->
    <section>
        <h2>1. matrix() — 2D Transformations</h2>
        <p>The <code>matrix()</code> function applies a 2D transformation using 6 values.</p>

        <div class="demo-area">
            <div class="box translated">matrix<br>Translate</div>
            <div class="box rotated">matrix<br>Rotate</div>
            <div class="box transformed">matrix<br>Skew + Scale</div>
        </div>

        <p class="note">Hover over each box to see the transform change!</p>

        <div class="code-block">
            /* Translation: move 100px right and down */
            .translated {
                transform: matrix(1, 0, 0, 1, 100, 100);
            }

            /* Rotation: 45 degrees */
            .rotated {
                transform: matrix(0.707, 0.707, -0.707, 0.707, 0, 0);
            }

            /* Skew + Scale */
            .transformed {
                transform: matrix(1, 0.3, -0.3, 1, 0, 0);
            }
        </div>
    </section>

    <!-- ====== 2. MATRIX3D() DEMO ====== -->
    <section>
        <h2>2. matrix3d() — 3D Transformations</h2>
        <p>The <code>matrix3d()</code> function applies a 3D transformation using 16 values.</p>

        <div class="demo-area">
            <div class="box rotated3d">matrix3d<br>Rotate Y</div>
            <div class="box transformed3d">matrix3d<br>Scale + Translate</div>
            <div class="box skewed">matrix3d<br>Skew</div>
        </div>

        <div class="code-block">
            /* 3D Rotation around Y axis */
            .rotated3d {
                transform: matrix3d(
                    cos(45deg), 0, sin(45deg), 0,
                    0, 1, 0, 0,
                    -sin(45deg), 0, cos(45deg), 0,
                    0, 0, 0, 1
                );
            }

            /* 3D Scale + Translate */
            .transformed3d {
                transform: matrix3d(
                    2, 0, 0, 0,
                    0, 2, 0, 0,
                    0, 0, 1, 0,
                    100, 100, 0, 1
                );
            }

            /* 3D Skew */
            .skewed {
                transform: matrix3d(
                    1, 0.3, 0, 0,
                    -0.3, 1, 0, 0,
                    0, 0, 1, 0,
                    0, 0, 0, 1
                );
            }
        </div>
    </section>

    <!-- ====== 3. MATRIX VISUALIZATION ====== -->
    <section>
        <h2>3. Matrix Structure Visualization</h2>

        <h3>2D Matrix (3×3)</h3>
        <div class="matrix-viz">
            <div class="matrix-box">
                <div class="cell scale">a</div>
                <div class="cell skew">c</div>
                <div class="cell translate">e</div>
                <div class="cell skew">b</div>
                <div class="cell scale">d</div>
                <div class="cell translate">f</div>
                <div class="cell">0</div>
                <div class="cell">0</div>
                <div class="cell highlight">1</div>
            </div>
            <div style="max-width: 300px;">
                <p><strong>a, d</strong> — Scale X and Y</p>
                <p><strong>b, c</strong> — Skew Y and X</p>
                <p><strong>e, f</strong> — Translate X and Y</p>
            </div>
        </div>

        <div class="code-block">
            /* 2D matrix structure */
            transform: matrix(a, b, c, d, e, f);

            /* Represented as:
               | a  c  e |
               | b  d  f |
               | 0  0  1 |
            */
        </div>
    </section>

    <!-- ====== 4. COMPARISON ====== -->
    <section>
        <h2>4. matrix() vs matrix3d()</h2>

        <div class="comparison-grid">
            <div class="comparison-card">
                <h4>matrix()</h4>
                <div class="matrix-display">| a  c  e |
| b  d  f |
| 0  0  1 |</div>
                <p><strong>6 values</strong></p>
                <p>2D transformations</p>
                <p>Scale, rotate, skew, translate</p>
            </div>

            <div class="comparison-card">
                <h4>matrix3d()</h4>
                <div class="matrix-display">| a  e  i  m |
| b  f  j  n |
| c  g  k  o |
| d  h  l  p |</div>
                <p><strong>16 values</strong></p>
                <p>3D transformations</p>
                <p>Adds Z-axis and perspective</p>
            </div>
        </div>
    </section>

    <!-- ====== 5. FUNCTION EQUIVALENTS ====== -->
    <section>
        <h2>5. Function Equivalents</h2>
        <p>Many transform functions are shortcuts for matrix values.</p>

        <table class="reference-table">
            <tr>
                <th>Function</th>
                <th>Matrix Equivalent</th>
            </tr>
            <tr>
                <td><code>translate(100px, 50px)</code></td>
                <td><code>matrix(1, 0, 0, 1, 100, 50)</code></td>
            </tr>
            <tr>
                <td><code>scale(2, 2)</code></td>
                <td><code>matrix(2, 0, 0, 2, 0, 0)</code></td>
            </tr>
            <tr>
                <td><code>rotate(45deg)</code></td>
                <td><code>matrix(0.707, 0.707, -0.707, 0.707, 0, 0)</code></td>
            </tr>
            <tr>
                <td><code>skew(30deg, 0)</code></td>
                <td><code>matrix(1, 0, 0.577, 1, 0, 0)</code></td>
            </tr>
            <tr>
                <td><code>rotateY(45deg)</code></td>
                <td><code>matrix3d(cos(45deg), 0, sin(45deg), 0, 0, 1, 0, 0, -sin(45deg), 0, cos(45deg), 0, 0, 0, 0, 1)</code></td>
            </tr>
        </table>

        <div class="code-block">
            /* These are equivalent */
            transform: translate(100px, 50px);
            transform: matrix(1, 0, 0, 1, 100, 50);

            /* These are equivalent */
            transform: scale(2, 2);
            transform: matrix(2, 0, 0, 2, 0, 0);

            /* These are equivalent */
            transform: rotate(45deg);
            transform: matrix(0.707, 0.707, -0.707, 0.707, 0, 0);
        </div>
    </section>

    <!-- ====== 6. REFERENCE TABLES ====== -->
    <section>
        <h2>6. Reference Tables</h2>

        <h3>matrix() Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Controls</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>a</code></td>
                <td>Scale X</td>
                <td>Horizontal scaling</td>
            </tr>
            <tr>
                <td><code>b</code></td>
                <td>Skew Y</td>
                <td>Vertical skew</td>
            </tr>
            <tr>
                <td><code>c</code></td>
                <td>Skew X</td>
                <td>Horizontal skew</td>
            </tr>
            <tr>
                <td><code>d</code></td>
                <td>Scale Y</td>
                <td>Vertical scaling</td>
            </tr>
            <tr>
                <td><code>e</code></td>
                <td>Translate X</td>
                <td>Horizontal movement</td>
            </tr>
            <tr>
                <td><code>f</code></td>
                <td>Translate Y</td>
                <td>Vertical movement</td>
            </tr>
        </table>

        <h3>matrix3d() Value Groups</h3>
        <table class="reference-table">
            <tr>
                <th>Group</th>
                <th>Values</th>
                <th>Controls</th>
            </tr>
            <tr>
                <td><strong>Linear</strong></td>
                <td><code>a, b, c, e, f, g, i, j, k</code></td>
                <td>Scale, rotate, skew</td>
            </tr>
            <tr>
                <td><strong>Translation</strong></td>
                <td><code>m, n, o</code></td>
                <td>X, Y, Z movement</td>
            </tr>
            <tr>
                <td><strong>Perspective</strong></td>
                <td><code>d, h, l</code></td>
                <td>Perspective effects</td>
            </tr>
            <tr>
                <td><strong>Homogeneous</strong></td>
                <td><code>p</code></td>
                <td>Usually <code>1</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 7. BEST PRACTICES ====== -->
    <section>
        <h2>7. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>matrix()</code> for complex 2D transformations</li>
                <li>Use <code>matrix3d()</code> for 3D transformations and perspective</li>
                <li>Use transform functions (<code>rotate()</code>, <code>scale()</code>) for simplicity</li>
                <li>Use matrix when you need precise control over all values</li>
                <li>Remember that `a, d` control scale and `e, f` control translation</li>
                <li>Test matrix transformations in different browsers</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use <code>matrix()</code> when <code>translate()</code> or <code>scale()</code> is clearer</li>
                <li>Don't manually calculate matrices if you can use simpler functions</li>
                <li>Don't forget that <code>matrix3d()</code> requires 16 values</li>
                <li>Don't mix up the order of matrix values</li>
                <li>Don't use matrix transformations without understanding them</li>
            </ul>
        </div>

        <div class="tip-box warning">
            <strong>⚠️ When to Use Matrix:</strong>
            Use <code>matrix()</code> and <code>matrix3d()</code> only when you need to apply a
            transformation that can't be achieved with simpler functions, or when you're
            generating transformations programmatically (e.g., in JavaScript).
        </div>
    </section>

</body>
</html>

Quick Reference

FunctionValuesMatrix Size
matrix()a, b, c, d, e, f3×3 (2D)
matrix3d()16 values (a through p)4×4 (3D)

matrix() Values

ValueControlsDescription
aScale XHorizontal scaling
bSkew YVertical skew
cSkew XHorizontal skew
dScale YVertical scaling
eTranslate XHorizontal movement
fTranslate YVertical movement

matrix3d() Value Groups

GroupValuesControls
Lineara, b, c, e, f, g, i, j, kScale, rotate, skew
Translationm, n, oX, Y, Z movement
Perspectived, h, lPerspective effects
HomogeneouspUsually 1

Function Equivalents

FunctionMatrix Equivalent
translate(100px, 50px)matrix(1, 0, 0, 1, 100, 50)
scale(2, 2)matrix(2, 0, 0, 2, 0, 0)
rotate(45deg)matrix(0.707, 0.707, -0.707, 0.707, 0, 0)

Best Practices

Do This:

/* Use simpler functions when possible */
.box {
    transform: rotate(45deg) scale(1.5) translate(20px, 10px);
}

/* Use matrix() for complex 2D transforms */
.box {
    transform: matrix(1, 0.3, -0.3, 1, 100, 50);
}

/* Use matrix3d() for 3D transforms */
.box {
    transform: matrix3d(
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, 0,
        50, 50, 0, 1
    );
}

Don’t Do This:

/* Don't use matrix when a simple function works */
.box {
    transform: matrix(1, 0, 0, 1, 100, 50);
    /* Use translate(100px, 50px) instead */
}

/* Don't forget the 16 values in matrix3d */
.box {
    transform: matrix3d(1, 0, 0, 0); /* Invalid! */
}

/* Don't mix up matrix value order */
.box {
    transform: matrix(0, 1, 1, 0, 100, 50); /* Wrong order! */
}

Pro Tip: matrix() and matrix3d() are the low-level API of CSS transforms. Most of the time, you should use the simpler functions (rotate(), scale(), translate(), skew()) — they’re easier to read and maintain. Use matrix() when you need precise control over all transformation values, or when you’re generating transforms programmatically with JavaScript. Remember: matrix() uses 6 values (a, b, c, d, e, f), while matrix3d() uses 16 values for full 3D transformations. The order matters — always double-check your matrix values!

47. transform perspective, rotate, and rotate3d

These three properties unlock the third dimension in CSS. With perspective, rotate3d, and transform-style, you can create stunning 3D effects like cubes, cards, and spatial interfaces.


Overview of Features

Property/FunctionDescriptionValues
perspectiveDistance from viewer to z=0 planeLength (e.g., 600px)
rotate()2D rotation around a fixed pointAngle (e.g., 45deg)
rotate3d()3D rotation around a custom axisx, y, z, angle

1. perspective

The perspective property gives the appearance that elements are viewed from a particular distance, creating a 3D effect.

.scene {
    perspective: 600px;
}

How It Works

     Viewer
        👁️
         |
         |  perspective: 600px
         |
    ┌────┴────┐
    │  Scene  │
    └─────────┘
  • Smaller values (e.g., 200px) → Stronger perspective effect
  • Larger values (e.g., 2000px) → Subtler perspective effect
  • Defaultnone (no perspective, flat)

Values

ValueEffect
noneNo perspective (default, flat)
200pxVery strong perspective (close viewer)
600pxModerate perspective (common)
1000pxSubtle perspective (far viewer)
2000px+Very subtle perspective

Key Points:

  • Apply perspective to the parent of the 3D elements
  • Use transform-style: preserve-3d on the 3D container so children are positioned in 3D space
  • Perspective affects all children of the element it’s applied to

2. transform-style

The transform-style property ensures child elements are treated as 3D objects within their parent’s 3D space.

.cube {
    transform-style: preserve-3d;
}

Values

ValueDescription
flatChildren are flattened onto the parent’s plane (default)
preserve-3dChildren maintain their 3D positioning

Key Points:

  • preserve-3d is required for 3D cubes, cards, and scenes
  • Without it, child 3D transforms are flattened
  • Apply to the container that holds the 3D faces

3. rotate()

The rotate() function rotates an element around a fixed point (its center by default) in 2D space.

.rotate:hover {
    transform: rotate(45deg);
}

Values

ValueEffect
rotate(45deg)45° clockwise
rotate(-45deg)45° counter-clockwise
rotate(0.5turn)Half turn (180°)
rotate(1rad)~57.3°

Key Points:

  • Positive values rotate clockwise
  • Negative values rotate counter-clockwise
  • Rotation happens in the 2D plane (no 3D effect)
  • Change the pivot with transform-origin

4. rotate3d()

The rotate3d() function applies a 3D rotation around a custom axis defined by x, y, z coordinates.

.box {
    transform: rotate3d(1, 1, 1, 90deg);
}

Syntax

rotate3d(x, y, z, angle)
ParameterDescription
xX-axis component (0–1)
yY-axis component (0–1)
zZ-axis component (0–1)
angleRotation angle (deg, rad, turn)

Common Axes

AxisFunctionEffect
Xrotate3d(1, 0, 0, angle)Rotate around horizontal axis
Yrotate3d(0, 1, 0, angle)Rotate around vertical axis
Zrotate3d(0, 0, 1, angle)Rotate around depth axis (like rotate())
Diagonalrotate3d(1, 1, 1, angle)Rotate around diagonal axis

Key Points:

  • The axis is a vector (x, y, z) — not necessarily normalized
  • rotate3d(1, 1, 1, 90deg) rotates along a diagonal line from one corner to the opposite
  • Combine with perspective for a true 3D effect
  • Use transform-style: preserve-3d on the parent container

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>perspective, rotate, and rotate3d</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== PERSPECTIVE DEMO ====== */
        .perspective-grid {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            justify-content: center;
            margin: 20px 0;
        }

        .perspective-demo {
            text-align: center;
        }

        .perspective-demo .scene {
            width: 150px;
            height: 150px;
            margin: 0 auto 10px;
            background: #e9ecef;
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .perspective-demo .card {
            width: 100px;
            height: 100px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            border-radius: 8px;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            transition: transform 0.5s;
        }

        .perspective-demo .card.rotate-y {
            transform: rotateY(45deg);
        }

        .perspective-demo .label {
            font-weight: bold;
            color: #333;
            font-size: 0.85rem;
        }

        .perspective-200 { perspective: 200px; }
        .perspective-600 { perspective: 600px; }
        .perspective-1200 { perspective: 1200px; }

        /* ====== ROTATE DEMO ====== */
        .rotate-demo {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            justify-content: center;
            align-items: center;
            padding: 30px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
        }

        .rotate-box {
            width: 100px;
            height: 100px;
            background: linear-gradient(135deg, #28a745, #20c997);
            border-radius: 8px;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.8rem;
            transition: transform 0.5s;
            cursor: pointer;
            text-align: center;
            padding: 5px;
        }

        .rotate-box:hover {
            transform: rotate(45deg);
        }

        .rotate-3d-box {
            width: 100px;
            height: 100px;
            background: linear-gradient(135deg, #dc3545, #fd7e14);
            border-radius: 8px;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.8rem;
            transition: transform 0.5s;
            cursor: pointer;
            text-align: center;
            padding: 5px;
        }

        .rotate-3d-box:hover {
            transform: rotate3d(1, 1, 1, 90deg);
        }

        /* ====== 3D CUBE ====== */
        .cube-scene {
            width: 200px;
            height: 200px;
            perspective: 600px;
            margin: 50px auto;
            background: transparent;
        }

        .cube {
            width: 100%;
            height: 100%;
            position: relative;
            transform-style: preserve-3d;
            animation: rotateCube 10s infinite linear;
        }

        @keyframes rotateCube {
            from { transform: rotateX(0) rotateY(0); }
            to { transform: rotateX(360deg) rotateY(360deg); }
        }

        .cube .face {
            position: absolute;
            width: 200px;
            height: 200px;
            border: 2px solid rgba(0, 0, 0, 0.3);
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            color: white;
            font-size: 1.2rem;
            text-shadow: 0 2px 5px rgba(0,0,0,0.5);
            border-radius: 8px;
        }

        .cube .front {
            background: rgba(255, 0, 0, 0.7);
            transform: translateZ(100px);
        }

        .cube .back {
            background: rgba(0, 255, 0, 0.7);
            transform: rotateY(180deg) translateZ(100px);
        }

        .cube .right {
            background: rgba(0, 0, 255, 0.7);
            transform: rotateY(90deg) translateZ(100px);
        }

        .cube .left {
            background: rgba(255, 255, 0, 0.7);
            transform: rotateY(-90deg) translateZ(100px);
        }

        .cube .top {
            background: rgba(255, 0, 255, 0.7);
            transform: rotateX(90deg) translateZ(100px);
        }

        .cube .bottom {
            background: rgba(0, 255, 255, 0.7);
            transform: rotateX(-90deg) translateZ(100px);
        }

        /* ====== PRACTICAL: 3D CARD ====== */
        .card-scene {
            width: 250px;
            height: 350px;
            perspective: 1000px;
            margin: 20px auto;
        }

        .card-3d {
            width: 100%;
            height: 100%;
            position: relative;
            transform-style: preserve-3d;
            transition: transform 0.8s;
            cursor: pointer;
        }

        .card-scene:hover .card-3d {
            transform: rotateY(180deg);
        }

        .card-face {
            position: absolute;
            width: 100%;
            height: 100%;
            backface-visibility: hidden;
            border-radius: 16px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            padding: 20px;
            text-align: center;
            color: white;
            font-weight: bold;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
        }

        .card-front {
            background: linear-gradient(135deg, #007bff, #6c5ce7);
        }

        .card-front .icon {
            font-size: 3rem;
            margin-bottom: 15px;
        }

        .card-back {
            background: linear-gradient(135deg, #28a745, #20c997);
            transform: rotateY(180deg);
        }

        .card-back h4 {
            margin-top: 0;
        }

        .card-back p {
            font-size: 0.9rem;
            font-weight: normal;
            opacity: 0.95;
        }

        /* ====== PRACTICAL: 3D BUTTON ====== */
        .btn-3d {
            padding: 15px 35px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 1.1em;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
            transform-style: preserve-3d;
            perspective: 500px;
            position: relative;
            margin: 10px;
        }

        .btn-3d:hover {
            transform: rotateX(15deg) rotateY(-15deg) scale(1.05);
            box-shadow: 0 10px 25px rgba(0, 123, 255, 0.4);
        }

        /* ====== AXIS VISUALIZATION ====== */
        .axis-demo {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            justify-content: center;
            margin: 20px 0;
        }

        .axis-box {
            width: 120px;
            height: 120px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            border-radius: 8px;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.75rem;
            text-align: center;
            padding: 5px;
            transition: transform 0.5s;
            cursor: pointer;
        }

        .axis-box:hover {
            transform: rotateX(45deg);
        }

        .axis-box.rotate-y:hover {
            transform: rotateY(45deg);
        }

        .axis-box.rotate-z:hover {
            transform: rotateZ(45deg);
        }

        .axis-box.rotate-3d:hover {
            transform: rotate3d(1, 1, 1, 45deg);
        }

        .axis-demo .scene-wrapper {
            perspective: 600px;
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            background: #f8f9fa;
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>transform perspective, rotate, and rotate3d</h1>

    <!-- ====== 1. PERSPECTIVE DEMO ====== -->
    <section>
        <h2>1. perspective</h2>
        <p>Creates the illusion of depth by defining the distance from the viewer to the z=0 plane.</p>

        <div class="perspective-grid">
            <div class="perspective-demo">
                <div class="scene perspective-200">
                    <div class="card rotate-y">200px</div>
                </div>
                <div class="label">Strong perspective</div>
            </div>
            <div class="perspective-demo">
                <div class="scene perspective-600">
                    <div class="card rotate-y">600px</div>
                </div>
                <div class="label">Moderate perspective</div>
            </div>
            <div class="perspective-demo">
                <div class="scene perspective-1200">
                    <div class="card rotate-y">1200px</div>
                </div>
                <div class="label">Subtle perspective</div>
            </div>
        </div>

        <p class="note">Smaller <code>perspective</code> values create a stronger 3D effect (viewer is closer).</p>

        <div class="code-block">
            /* Apply perspective to the parent */
            .scene {
                perspective: 600px; /* Distance from viewer */
            }

            /* Child elements get 3D positioning */
            .card {
                transform: rotateY(45deg);
            }
        </div>
    </section>

    <!-- ====== 2. ROTATE AND ROTATE3D ====== -->
    <section>
        <h2>2. rotate() and rotate3d()</h2>
        <p>Hover over each box to see the rotation effect.</p>

        <h3>rotate() — 2D Rotation</h3>
        <div class="rotate-demo">
            <div class="rotate-box">rotate(45deg)</div>
        </div>

        <h3>rotate3d() — 3D Rotation</h3>
        <div class="rotate-demo">
            <div class="rotate-3d-box">rotate3d(1,1,1,90deg)</div>
        </div>

        <div class="code-block">
            /* 2D rotation — around a fixed point */
            .box:hover {
                transform: rotate(45deg);
            }

            /* 3D rotation — around a diagonal axis */
            .box:hover {
                transform: rotate3d(1, 1, 1, 90deg);
            }
        </div>
    </section>

    <!-- ====== 3. AXIS VISUALIZATION ====== -->
    <section>
        <h2>3. Rotation Axes</h2>
        <p>Hover over each box to see rotation around different axes.</p>

        <div class="axis-demo">
            <div class="scene-wrapper">
                <div class="axis-box">rotateX(45deg)<br>(horizontal axis)</div>
            </div>
            <div class="scene-wrapper">
                <div class="axis-box rotate-y">rotateY(45deg)<br>(vertical axis)</div>
            </div>
            <div class="scene-wrapper">
                <div class="axis-box rotate-z">rotateZ(45deg)<br>(depth axis)</div>
            </div>
            <div class="scene-wrapper">
                <div class="axis-box rotate-3d">rotate3d(1,1,1,45deg)<br>(diagonal axis)</div>
            </div>
        </div>

        <div class="code-block">
            /* Rotate around X axis (horizontal) */
            .box:hover {
                transform: rotateX(45deg);
            }

            /* Rotate around Y axis (vertical) */
            .box:hover {
                transform: rotateY(45deg);
            }

            /* Rotate around Z axis (depth) — same as rotate() */
            .box:hover {
                transform: rotateZ(45deg);
            }

            /* Rotate around a custom diagonal axis */
            .box:hover {
                transform: rotate3d(1, 1, 1, 45deg);
            }
        </div>
    </section>

    <!-- ====== 4. 3D CUBE ====== -->
    <section>
        <h2>4. 3D Cube</h2>
        <p>A complete 3D cube using <code>perspective</code>, <code>transform-style: preserve-3d</code>, and <code>rotate3d</code>.</p>

        <div class="cube-scene">
            <div class="cube">
                <div class="face front">Front</div>
                <div class="face back">Back</div>
                <div class="face right">Right</div>
                <div class="face left">Left</div>
                <div class="face top">Top</div>
                <div class="face bottom">Bottom</div>
            </div>
        </div>

        <div class="code-block">
            /* Scene with perspective */
            .scene {
                perspective: 600px;
            }

            /* Cube container preserves 3D */
            .cube {
                transform-style: preserve-3d;
                animation: rotateCube 10s infinite linear;
            }

            @keyframes rotateCube {
                from { transform: rotateX(0) rotateY(0); }
                to { transform: rotateX(360deg) rotateY(360deg); }
            }

            /* Each face positioned in 3D space */
            .front {
                transform: translateZ(100px);
            }
            .back {
                transform: rotateY(180deg) translateZ(100px);
            }
            .right {
                transform: rotateY(90deg) translateZ(100px);
            }
            .left {
                transform: rotateY(-90deg) translateZ(100px);
            }
            .top {
                transform: rotateX(90deg) translateZ(100px);
            }
            .bottom {
                transform: rotateX(-90deg) translateZ(100px);
            }
        </div>
    </section>

    <!-- ====== 5. PRACTICAL: 3D CARD FLIP ====== -->
    <section>
        <h2>5. Practical Example: 3D Card Flip</h2>
        <p>Hover over the card to flip it in 3D space.</p>

        <div class="card-scene">
            <div class="card-3d">
                <div class="card-face card-front">
                    <div class="icon">🃏</div>
                    <h3 style="margin: 0;">3D Card</h3>
                    <p style="font-weight: normal; font-size: 0.9rem;">Hover to flip</p>
                </div>
                <div class="card-face card-back">
                    <h4>✨ Back Side</h4>
                    <p>This card uses <code>rotateY(180deg)</code> and <code>backface-visibility: hidden</code> to create a 3D flip effect.</p>
                </div>
            </div>
        </div>

        <div class="code-block">
            .card-scene {
                perspective: 1000px;
            }

            .card-3d {
                transform-style: preserve-3d;
                transition: transform 0.8s;
            }

            .card-scene:hover .card-3d {
                transform: rotateY(180deg);
            }

            .card-face {
                backface-visibility: hidden;
            }

            .card-back {
                transform: rotateY(180deg);
            }
        </div>
    </section>

    <!-- ====== 6. PRACTICAL: 3D BUTTON ====== -->
    <section>
        <h2>6. Practical Example: 3D Button</h2>
        <p>Hover over the button to see a 3D tilt effect.</p>

        <div style="text-align: center;">
            <button class="btn-3d">Hover Me</button>
        </div>

        <div class="code-block">
            .btn-3d {
                transform-style: preserve-3d;
                perspective: 500px;
                transition: all 0.3s;
            }

            .btn-3d:hover {
                transform: rotateX(15deg) rotateY(-15deg) scale(1.05);
                box-shadow: 0 10px 25px rgba(0, 123, 255, 0.4);
            }
        </div>
    </section>

    <!-- ====== 7. REFERENCE TABLES ====== -->
    <section>
        <h2>7. Reference Tables</h2>

        <h3>perspective Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Effect</th>
                <th>Use Case</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>No perspective (flat, default)</td>
                <td>2D layouts</td>
            </tr>
            <tr>
                <td><code>200px</code></td>
                <td>Very strong perspective</td>
                <td>Dramatic 3D effects</td>
            </tr>
            <tr>
                <td><code>600px</code></td>
                <td>Moderate perspective</td>
                <td>Cards, cubes</td>
            </tr>
            <tr>
                <td><code>1000px</code></td>
                <td>Subtle perspective</td>
                <td>Realistic 3D scenes</td>
            </tr>
            <tr>
                <td><code>2000px+</code></td>
                <td>Very subtle perspective</td>
                <td>Large 3D scenes</td>
            </tr>
        </table>

        <h3>rotate() Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Effect</th>
            </tr>
            <tr>
                <td><code>rotate(45deg)</code></td>
                <td>45° clockwise</td>
            </tr>
            <tr>
                <td><code>rotate(-45deg)</code></td>
                <td>45° counter-clockwise</td>
            </tr>
            <tr>
                <td><code>rotate(0.5turn)</code></td>
                <td>Half turn (180°)</td>
            </tr>
        </table>

        <h3>rotate3d() Axes</h3>
        <table class="reference-table">
            <tr>
                <th>Axis</th>
                <th>Function</th>
                <th>Effect</th>
            </tr>
            <tr>
                <td>X</td>
                <td><code>rotate3d(1, 0, 0, angle)</code></td>
                <td>Rotate around horizontal axis</td>
            </tr>
            <tr>
                <td>Y</td>
                <td><code>rotate3d(0, 1, 0, angle)</code></td>
                <td>Rotate around vertical axis</td>
            </tr>
            <tr>
                <td>Z</td>
                <td><code>rotate3d(0, 0, 1, angle)</code></td>
                <td>Rotate around depth axis (like rotate())</td>
            </tr>
            <tr>
                <td>Diagonal</td>
                <td><code>rotate3d(1, 1, 1, angle)</code></td>
                <td>Rotate around diagonal axis</td>
            </tr>
        </table>

        <h3>Related Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>perspective</code></td>
                <td>Distance from viewer (on parent)</td>
            </tr>
            <tr>
                <td><code>perspective-origin</code></td>
                <td>Vanishing point (default: center)</td>
            </tr>
            <tr>
                <td><code>transform-style</code></td>
                <td><code>flat</code> or <code>preserve-3d</code></td>
            </tr>
            <tr>
                <td><code>backface-visibility</code></td>
                <td>Hide back face of 3D element</td>
            </tr>
        </table>
    </section>

    <!-- ====== 8. BEST PRACTICES ====== -->
    <section>
        <h2>8. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Apply <code>perspective</code> to the <strong>parent</strong> of 3D elements</li>
                <li>Use <code>transform-style: preserve-3d</code> for 3D scenes</li>
                <li>Use <code>backface-visibility: hidden</code> for card flips</li>
                <li>Use <code>perspective: 600px–1000px</code> for realistic 3D effects</li>
                <li>Test 3D transforms on different devices</li>
                <li>Respect <code>prefers-reduced-motion</code> for accessibility</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't apply <code>perspective</code> to the element being transformed (apply to parent)</li>
                <li>Don't forget <code>transform-style: preserve-3d</code> for 3D children</li>
                <li>Don't use extreme perspective values (too small or too large)</li>
                <li>Don't overuse 3D effects — they can cause motion sickness</li>
                <li>Don't forget to test with reduced motion preferences</li>
            </ul>
        </div>

        <div class="code-block">
            /* Accessibility: respect reduced motion */
            @media (prefers-reduced-motion: reduce) {
                .cube {
                    animation: none;
                }
                .card-3d {
                    transition: none;
                }
                .card-scene:hover .card-3d {
                    transform: none;
                }
            }
        </div>
    </section>

</body>
</html>

Quick Reference

Property/FunctionDescriptionValues
perspectiveDistance from viewernone, 600px
rotate()2D rotationAngle (45deg)
rotate3d()3D rotation around custom axisx, y, z, angle
transform-style3D positioning of childrenflat, preserve-3d

perspective Values

ValueEffect
noneNo perspective (flat, default)
200pxVery strong perspective
600pxModerate perspective
1000pxSubtle perspective
2000px+Very subtle perspective

rotate3d() Axes

AxisFunctionEffect
Xrotate3d(1, 0, 0, angle)Horizontal axis
Yrotate3d(0, 1, 0, angle)Vertical axis
Zrotate3d(0, 0, 1, angle)Depth axis
Diagonalrotate3d(1, 1, 1, angle)Diagonal axis

Related Properties

PropertyDescription
perspectiveDistance from viewer (on parent)
perspective-originVanishing point (default: center)
transform-styleflat or preserve-3d
backface-visibilityHide back face of 3D element

Best Practices

Do This:

/* Apply perspective to parent */
.scene {
    perspective: 600px;
}

/* Preserve 3D for children */
.cube {
    transform-style: preserve-3d;
}

/* Card flip */
.card-scene:hover .card-3d {
    transform: rotateY(180deg);
}

.card-back {
    transform: rotateY(180deg);
    backface-visibility: hidden;
}

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    .cube {
        animation: none;
    }
}

Don’t Do This:

/* Don't apply perspective to the transformed element */
.box {
    perspective: 600px; /* Wrong — apply to parent */
    transform: rotateY(45deg);
}

/* Don't forget transform-style */
.cube {
    /* Missing transform-style: preserve-3d */
}
.cube .face {
    transform: translateZ(100px); /* Won't work correctly */
}

/* Don't overuse 3D effects */
.everything {
    transform: rotate3d(1, 1, 1, 45deg);
    /* Can cause motion sickness */
}

Pro Tip: The key to 3D transforms is understanding the three key properties: perspective (on the parent), transform-style: preserve-3d (on the container), and the transform functions (rotate3d, translateZ, etc.) on the children. Remember: perspective goes on the parent, not the element being transformed. Use rotate3d(1, 1, 1, 90deg) for a diagonal rotation that looks impressive. And always respect prefers-reduced-motion — 3D effects can be disorienting for users with vestibular disorders!

48. transform rotateX, rotateY, and rotateZ

These three functions are the individual axis rotations in CSS 3D transforms. Each one rotates an element around a specific axis: X (horizontal), Y (vertical), or Z (depth).


Overview of Functions

FunctionAxisEquivalentVisual Effect
rotateX()Horizontalrotate3d(1, 0, 0, angle)Tilts forward/backward
rotateY()Verticalrotate3d(0, 1, 0, angle)Turns left/right
rotateZ()Depthrotate3d(0, 0, 1, angle)Spins in place (2D)

Understanding the Axes

        Y (vertical)
        ↑
        │
        │
        │
        └──────────→ X (horizontal)
       /
      /
     ↙
    Z (depth, toward viewer)
AxisDirectionRotation Effect
XHorizontal (left–right)Tilts top toward/away from viewer
YVertical (up–down)Turns left/right (like a door)
ZDepth (toward viewer)Spins in the 2D plane

1. rotateX()

Rotates an element around the X-axis (horizontal). The top and bottom move toward or away from the viewer.

.rotateX {
    transform: rotateX(45deg);
}
AngleEffect
rotateX(45deg)Top tilts away, bottom tilts toward viewer
rotateX(-45deg)Top tilts toward, bottom tilts away
rotateX(90deg)Element becomes a flat line (edge-on)
rotateX(180deg)Element is flipped upside down

Equivalent: rotate3d(1, 0, 0, 45deg)

Use cases:

  • Flipping cards vertically
  • Creating a “flipboard” effect
  • 3D menus that open upward/downward

2. rotateY()

Rotates an element around the Y-axis (vertical). The left and right sides move toward or away from the viewer.

.rotateY {
    transform: rotateY(45deg);
}
AngleEffect
rotateY(45deg)Right side goes away, left comes forward
rotateY(-45deg)Left side goes away, right comes forward
rotateY(90deg)Element becomes a flat line (edge-on)
rotateY(180deg)Element is flipped (mirror image)

Equivalent: rotate3d(0, 1, 0, 45deg)

Use cases:

  • Card flip animations (horizontal)
  • Carousels
  • Book page turns
  • 3D product previews

3. rotateZ()

Rotates an element around the Z-axis (depth). This is the same as the 2D rotate() function.

.rotateZ {
    transform: rotateZ(45deg);
}
AngleEffect
rotateZ(45deg)45° clockwise (in the 2D plane)
rotateZ(-45deg)45° counter-clockwise
rotateZ(180deg)Upside down (2D)

Equivalent: rotate3d(0, 0, 1, 45deg) = rotate(45deg)

Use cases:

  • Spinning icons
  • Rotating badges
  • 2D rotations in 3D contexts

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>rotateX, rotateY, and rotateZ</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DEMO AREA ====== */
        .demo-area {
            display: flex;
            flex-wrap: wrap;
            gap: 40px;
            justify-content: center;
            align-items: center;
            padding: 50px 20px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 350px;
            perspective: 800px;
        }

        .box {
            width: 150px;
            height: 150px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.9rem;
            border-radius: 12px;
            transition: transform 1s;
            cursor: pointer;
            text-align: center;
            padding: 10px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
            transform-style: preserve-3d;
        }

        .box:hover {
            box-shadow: 0 8px 30px rgba(0, 123, 255, 0.4);
        }

        /* Individual rotations */
        .rotateX {
            transform: rotateX(45deg);
        }

        .rotateX:hover {
            transform: rotateX(90deg);
        }

        .rotateY {
            transform: rotateY(45deg);
        }

        .rotateY:hover {
            transform: rotateY(90deg);
        }

        .rotateZ {
            transform: rotateZ(45deg);
        }

        .rotateZ:hover {
            transform: rotateZ(90deg);
        }

        /* Angle comparisons */
        .rotate-x-30 { transform: rotateX(30deg); }
        .rotate-x-60 { transform: rotateX(60deg); }
        .rotate-x-90 { transform: rotateX(90deg); }
        .rotate-x-neg { transform: rotateX(-45deg); }

        .rotate-y-30 { transform: rotateY(30deg); }
        .rotate-y-60 { transform: rotateY(60deg); }
        .rotate-y-90 { transform: rotateY(90deg); }
        .rotate-y-neg { transform: rotateY(-45deg); }

        .rotate-z-30 { transform: rotateZ(30deg); }
        .rotate-z-90 { transform: rotateZ(90deg); }
        .rotate-z-180 { transform: rotateZ(180deg); }
        .rotate-z-neg { transform: rotateZ(-45deg); }

        /* ====== AXIS VISUALIZATION ====== */
        .axis-viz {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            justify-content: center;
            margin: 20px 0;
        }

        .axis-card {
            text-align: center;
            padding: 20px;
            background: white;
            border: 2px solid #ddd;
            border-radius: 12px;
            width: 200px;
            transition: all 0.3s;
        }

        .axis-card:hover {
            border-color: #007bff;
            box-shadow: 0 4px 15px rgba(0, 123, 255, 0.15);
        }

        .axis-card .axis-icon {
            font-size: 3rem;
            margin-bottom: 10px;
        }

        .axis-card h4 {
            margin: 5px 0;
            color: #007bff;
        }

        .axis-card p {
            font-size: 0.85rem;
            color: #6c757d;
            margin: 5px 0;
        }

        .axis-card code {
            background: #e9ecef;
            padding: 2px 6px;
            border-radius: 4px;
            font-family: 'Courier New', monospace;
            font-size: 0.8rem;
            color: #dc3545;
        }

        /* ====== PRACTICAL: CARD FLIP VERTICAL ====== */
        .flip-container {
            perspective: 1000px;
            width: 250px;
            height: 300px;
            margin: 20px auto;
        }

        .flip-card {
            width: 100%;
            height: 100%;
            position: relative;
            transform-style: preserve-3d;
            transition: transform 0.8s;
            cursor: pointer;
        }

        .flip-container:hover .flip-card {
            transform: rotateX(180deg);
        }

        .flip-front,
        .flip-back {
            position: absolute;
            width: 100%;
            height: 100%;
            backface-visibility: hidden;
            border-radius: 16px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            padding: 20px;
            text-align: center;
            color: white;
            font-weight: bold;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
        }

        .flip-front {
            background: linear-gradient(135deg, #007bff, #6c5ce7);
        }

        .flip-front .icon {
            font-size: 3rem;
            margin-bottom: 15px;
        }

        .flip-back {
            background: linear-gradient(135deg, #28a745, #20c997);
            transform: rotateX(180deg);
        }

        .flip-back h4 {
            margin-top: 0;
        }

        .flip-back p {
            font-size: 0.9rem;
            font-weight: normal;
            opacity: 0.95;
        }

        /* ====== PRACTICAL: 3D CUBE ====== */
        .cube-scene {
            width: 180px;
            height: 180px;
            perspective: 600px;
            margin: 30px auto;
        }

        .cube {
            width: 100%;
            height: 100%;
            position: relative;
            transform-style: preserve-3d;
            animation: spinCube 8s infinite linear;
        }

        @keyframes spinCube {
            from { transform: rotateX(0) rotateY(0); }
            to { transform: rotateX(360deg) rotateY(360deg); }
        }

        .cube .face {
            position: absolute;
            width: 180px;
            height: 180px;
            border: 2px solid rgba(0, 0, 0, 0.3);
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            color: white;
            font-size: 1rem;
            text-shadow: 0 2px 5px rgba(0,0,0,0.5);
            border-radius: 8px;
        }

        .cube .front {
            background: rgba(255, 0, 0, 0.8);
            transform: translateZ(90px);
        }

        .cube .back {
            background: rgba(0, 255, 0, 0.8);
            transform: rotateY(180deg) translateZ(90px);
        }

        .cube .right {
            background: rgba(0, 0, 255, 0.8);
            transform: rotateY(90deg) translateZ(90px);
        }

        .cube .left {
            background: rgba(255, 255, 0, 0.8);
            transform: rotateY(-90deg) translateZ(90px);
        }

        .cube .top {
            background: rgba(255, 0, 255, 0.8);
            transform: rotateX(90deg) translateZ(90px);
        }

        .cube .bottom {
            background: rgba(0, 255, 255, 0.8);
            transform: rotateX(-90deg) translateZ(90px);
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            background: #f8f9fa;
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>rotateX, rotateY, and rotateZ</h1>

    <!-- ====== 1. BASIC ROTATIONS ====== -->
    <section>
        <h2>1. Basic Axis Rotations</h2>
        <p>Hover over each box to see the rotation increase.</p>

        <div class="demo-area">
            <div class="box rotateX">rotateX(45deg)</div>
            <div class="box rotateY">rotateY(45deg)</div>
            <div class="box rotateZ">rotateZ(45deg)</div>
        </div>

        <p class="note"><strong>rotateX</strong> tilts forward/backward. <strong>rotateY</strong> turns left/right. <strong>rotateZ</strong> spins in place.</p>

        <div class="code-block">
            /* Rotate around X-axis (horizontal) */
            .rotateX {
                transform: rotateX(45deg);
            }

            /* Rotate around Y-axis (vertical) */
            .rotateY {
                transform: rotateY(45deg);
            }

            /* Rotate around Z-axis (depth) */
            .rotateZ {
                transform: rotateZ(45deg);
            }
        </div>
    </section>

    <!-- ====== 2. AXIS VISUALIZATION ====== -->
    <section>
        <h2>2. Understanding the Axes</h2>

        <div class="axis-viz">
            <div class="axis-card">
                <div class="axis-icon">↔️</div>
                <h4>X-Axis</h4>
                <p>Horizontal (left–right)</p>
                <code>rotateX(45deg)</code>
                <p class="note">Tilts top toward/away from viewer</p>
            </div>
            <div class="axis-card">
                <div class="axis-icon">↕️</div>
                <h4>Y-Axis</h4>
                <p>Vertical (up–down)</p>
                <code>rotateY(45deg)</code>
                <p class="note">Turns left/right like a door</p>
            </div>
            <div class="axis-card">
                <div class="axis-icon">🔄</div>
                <h4>Z-Axis</h4>
                <p>Depth (toward viewer)</p>
                <code>rotateZ(45deg)</code>
                <p class="note">Spins in the 2D plane (like rotate())</p>
            </div>
        </div>

        <div class="code-block">
            /* These are equivalent */
            rotateX(45deg) = rotate3d(1, 0, 0, 45deg)
            rotateY(45deg) = rotate3d(0, 1, 0, 45deg)
            rotateZ(45deg) = rotate3d(0, 0, 1, 45deg)

            /* rotateZ() is the same as 2D rotate() */
            rotateZ(45deg) = rotate(45deg)
        </div>
    </section>

    <!-- ====== 3. ROTATEX ANGLES ====== -->
    <section>
        <h2>3. rotateX() Angle Comparison</h2>

        <div class="demo-area">
            <div class="box rotate-x-30">30°</div>
            <div class="box rotate-x-60">60°</div>
            <div class="box rotate-x-90">90°</div>
            <div class="box rotate-x-neg">-45°</div>
        </div>

        <div class="code-block">
            .rotate-x-30 { transform: rotateX(30deg); }
            .rotate-x-60 { transform: rotateX(60deg); }
            .rotate-x-90 { transform: rotateX(90deg); }  /* Edge-on */
            .rotate-x-neg { transform: rotateX(-45deg); } /* Opposite direction */
        </div>

        <p class="note">At <code>rotateX(90deg)</code>, the element becomes a flat line (edge-on to the viewer).</p>
    </section>

    <!-- ====== 4. ROTATEY ANGLES ====== -->
    <section>
        <h2>4. rotateY() Angle Comparison</h2>

        <div class="demo-area">
            <div class="box rotate-y-30">30°</div>
            <div class="box rotate-y-60">60°</div>
            <div class="box rotate-y-90">90°</div>
            <div class="box rotate-y-neg">-45°</div>
        </div>

        <div class="code-block">
            .rotate-y-30 { transform: rotateY(30deg); }
            .rotate-y-60 { transform: rotateY(60deg); }
            .rotate-y-90 { transform: rotateY(90deg); }  /* Edge-on */
            .rotate-y-neg { transform: rotateY(-45deg); } /* Opposite direction */
        </div>

        <p class="note">At <code>rotateY(90deg)</code>, the element becomes a flat line (edge-on to the viewer).</p>
    </section>

    <!-- ====== 5. ROTATEZ ANGLES ====== -->
    <section>
        <h2>5. rotateZ() Angle Comparison</h2>

        <div class="demo-area">
            <div class="box rotate-z-30">30°</div>
            <div class="box rotate-z-90">90°</div>
            <div class="box rotate-z-180">180°</div>
            <div class="box rotate-z-neg">-45°</div>
        </div>

        <div class="code-block">
            .rotate-z-30 { transform: rotateZ(30deg); }
            .rotate-z-90 { transform: rotateZ(90deg); }
            .rotate-z-180 { transform: rotateZ(180deg); } /* Upside down */
            .rotate-z-neg { transform: rotateZ(-45deg); }
        </div>

        <p class="note"><code>rotateZ()</code> is a 2D rotation — it doesn't create depth.</p>
    </section>

    <!-- ====== 6. PRACTICAL: VERTICAL CARD FLIP ====== -->
    <section>
        <h2>6. Practical Example: Vertical Card Flip</h2>
        <p>Hover over the card to flip it vertically using <code>rotateX()</code>.</p>

        <div class="flip-container">
            <div class="flip-card">
                <div class="flip-front">
                    <div class="icon">🎴</div>
                    <h3 style="margin: 0;">Vertical Flip</h3>
                    <p style="font-weight: normal; font-size: 0.9rem;">Hover to flip</p>
                </div>
                <div class="flip-back">
                    <h4>✨ Back Side</h4>
                    <p>This card uses <code>rotateX(180deg)</code> to flip vertically.</p>
                </div>
            </div>
        </div>

        <div class="code-block">
            .flip-container {
                perspective: 1000px;
            }

            .flip-card {
                transform-style: preserve-3d;
                transition: transform 0.8s;
            }

            .flip-container:hover .flip-card {
                transform: rotateX(180deg); /* Vertical flip */
            }

            .flip-back {
                transform: rotateX(180deg);
                backface-visibility: hidden;
            }
        </div>
    </section>

    <!-- ====== 7. PRACTICAL: 3D CUBE ====== -->
    <section>
        <h2>7. Practical Example: 3D Cube</h2>
        <p>A rotating cube using <code>rotateX</code> and <code>rotateY</code> together.</p>

        <div class="cube-scene">
            <div class="cube">
                <div class="face front">Front</div>
                <div class="face back">Back</div>
                <div class="face right">Right</div>
                <div class="face left">Left</div>
                <div class="face top">Top</div>
                <div class="face bottom">Bottom</div>
            </div>
        </div>

        <div class="code-block">
            .cube {
                transform-style: preserve-3d;
                animation: spinCube 8s infinite linear;
            }

            @keyframes spinCube {
                from { transform: rotateX(0) rotateY(0); }
                to { transform: rotateX(360deg) rotateY(360deg); }
            }

            /* Each face positioned in 3D space */
            .front { transform: translateZ(90px); }
            .back { transform: rotateY(180deg) translateZ(90px); }
            .right { transform: rotateY(90deg) translateZ(90px); }
            .left { transform: rotateY(-90deg) translateZ(90px); }
            .top { transform: rotateX(90deg) translateZ(90px); }
            .bottom { transform: rotateX(-90deg) translateZ(90px); }
        </div>
    </section>

    <!-- ====== 8. REFERENCE TABLES ====== -->
    <section>
        <h2>8. Reference Tables</h2>

        <h3>Axis Rotation Functions</h3>
        <table class="reference-table">
            <tr>
                <th>Function</th>
                <th>Axis</th>
                <th>Equivalent</th>
                <th>Effect</th>
            </tr>
            <tr>
                <td><code>rotateX()</code></td>
                <td>Horizontal</td>
                <td><code>rotate3d(1, 0, 0, angle)</code></td>
                <td>Tilts forward/backward</td>
            </tr>
            <tr>
                <td><code>rotateY()</code></td>
                <td>Vertical</td>
                <td><code>rotate3d(0, 1, 0, angle)</code></td>
                <td>Turns left/right</td>
            </tr>
            <tr>
                <td><code>rotateZ()</code></td>
                <td>Depth</td>
                <td><code>rotate3d(0, 0, 1, angle)</code></td>
                <td>Spins in 2D plane</td>
            </tr>
        </table>

        <h3>Angle Effects</h3>
        <table class="reference-table">
            <tr>
                <th>Angle</th>
                <th>Effect</th>
            </tr>
            <tr>
                <td><code>0deg</code></td>
                <td>No rotation</td>
            </tr>
            <tr>
                <td><code>45deg</code></td>
                <td>Moderate tilt/turn</td>
            </tr>
            <tr>
                <td><code>90deg</code></td>
                <td>Edge-on (flat line)</td>
            </tr>
            <tr>
                <td><code>180deg</code></td>
                <td>Flipped (upside down / mirror)</td>
            </tr>
            <tr>
                <td><code>360deg</code></td>
                <td>Full rotation (same as 0°)</td>
            </tr>
            <tr>
                <td><code>-45deg</code></td>
                <td>Opposite direction</td>
            </tr>
        </table>

        <h3>Related Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>perspective</code></td>
                <td>Distance from viewer (on parent)</td>
            </tr>
            <tr>
                <td><code>transform-style</code></td>
                <td><code>preserve-3d</code> for 3D children</td>
            </tr>
            <tr>
                <td><code>backface-visibility</code></td>
                <td>Hide back face of 3D element</td>
            </tr>
            <tr>
                <td><code>perspective-origin</code></td>
                <td>Vanishing point (default: center)</td>
            </tr>
        </table>
    </section>

    <!-- ====== 9. BEST PRACTICES ====== -->
    <section>
        <h2>9. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>rotateX()</code> for vertical flips (cards, panels)</li>
                <li>Use <code>rotateY()</code> for horizontal flips (carousels, book pages)</li>
                <li>Use <code>rotateZ()</code> for 2D spinning (icons, badges)</li>
                <li>Apply <code>perspective</code> to the parent for 3D depth</li>
                <li>Use <code>transform-style: preserve-3d</code> on the 3D container</li>
                <li>Use <code>backface-visibility: hidden</code> for card flips</li>
                <li>Test on different devices and browsers</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't apply <code>perspective</code> to the element being rotated (apply to parent)</li>
                <li>Don't forget <code>transform-style: preserve-3d</code> for 3D children</li>
                <li>Don't overuse 3D rotations — they can cause motion sickness</li>
                <li>Don't use <code>rotateX(90deg)</code> or <code>rotateY(90deg)</code> for visible content (it becomes edge-on)</li>
                <li>Don't forget to respect <code>prefers-reduced-motion</code></li>
            </ul>
        </div>

        <div class="code-block">
            /* Accessibility: respect reduced motion */
            @media (prefers-reduced-motion: reduce) {
                .box {
                    transition: none;
                    transform: none;
                }
                .cube {
                    animation: none;
                }
            }
        </div>
    </section>

</body>
</html>

Quick Reference

FunctionAxisEquivalentEffect
rotateX()Horizontalrotate3d(1, 0, 0, angle)Tilts forward/backward
rotateY()Verticalrotate3d(0, 1, 0, angle)Turns left/right
rotateZ()Depthrotate3d(0, 0, 1, angle)Spins in 2D plane

Angle Effects

AngleEffect
0degNo rotation
45degModerate tilt/turn
90degEdge-on (flat line)
180degFlipped (upside down / mirror)
360degFull rotation (same as 0°)
-45degOpposite direction

Use Cases

FunctionBest For
rotateX()Vertical card flips, flipboards, 3D menus
rotateY()Horizontal card flips, carousels, book pages
rotateZ()Spinning icons, rotating badges, 2D rotations

Best Practices

Do This:

/* Vertical card flip */
.card-scene:hover .card {
    transform: rotateX(180deg);
}

/* Horizontal card flip */
.card-scene:hover .card {
    transform: rotateY(180deg);
}

/* 2D spin */
.icon:hover {
    transform: rotateZ(360deg);
}

/* 3D cube with both axes */
.cube {
    animation: spin 8s infinite;
    transform-style: preserve-3d;
}

@keyframes spin {
    from { transform: rotateX(0) rotateY(0); }
    to { transform: rotateX(360deg) rotateY(360deg); }
}

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    .card-scene:hover .card {
        transform: none;
    }
}

Don’t Do This:

/* Don't apply perspective to the rotating element */
.box {
    perspective: 600px; /* Wrong — apply to parent */
    transform: rotateX(45deg);
}

/* Don't forget transform-style for 3D children */
.cube {
    /* Missing transform-style: preserve-3d */
}

/* Don't use 90deg for visible content */
.box {
    transform: rotateX(90deg); /* Becomes a flat line! */
}

Pro Tip: Think of the axes like this: rotateX is like a book cover opening (tilting top away from you), rotateY is like a door swinging (turning left/right), and rotateZ is like a clock hand spinning (2D rotation). Use rotateX(180deg) for vertical card flips, rotateY(180deg) for horizontal flips, and rotateZ() for simple spinning icons. Remember: at 90 degrees, the element becomes edge-on and appears as a flat line — so avoid using 90° for content that needs to remain visible!

49. transform scale() and scale3d()

The scale() and scale3d() functions let you resize elements — making them larger or smaller — without affecting the layout of surrounding elements.


Overview of Functions

FunctionDimensionsValuesDescription
scale()2Ds or s1, s2Uniform or separate X/Y scaling
scale3d()3Ds1, s2, s3X, Y, and Z scaling

1. scale() — 2D Scaling

The scale() function resizes an element in 2D space — horizontally and vertically.

.box {
    transform: scale(1.5);
}

Syntax

scale(s)          /* Uniform scaling */
scale(s1, s2)     /* Separate X and Y scaling */
SyntaxEffect
scale(1.5)1.5x in both directions
scale(1.5, 2)1.5x horizontal, 2x vertical
scale(0.5)Half size (both directions)
scale(2)2x size (both directions)
scale(1)Original size (no change)

Values

ValueEffect
1Original size
> 1Enlarges (e.g., 1.5 = 150%)
< 1Shrinks (e.g., 0.5 = 50%)
0Invisible (zero size)
NegativeFlips/mirrors the element

Key Points:

  • Scaling maintains the element’s aspect ratio when using a single value
  • Scaling doesn’t affect layout — other elements stay in place
  • Scale is applied from the transform-origin (center by default)
  • Use transform-origin to change the scaling pivot

2. scale3d() — 3D Scaling

The scale3d() function resizes an element in 3D space — along the X, Y, and Z axes.

.box {
    transform: scale3d(1.5, 1.5, 2);
}

Syntax

scale3d(s1, s2, s3)
ValueAxisDescription
s1XHorizontal scaling
s2YVertical scaling
s3ZDepth scaling

Key Points:

  • s3 (Z scaling) requires perspective on the parent to be visible
  • scale3d(1, 1, 1) = no scaling
  • scale3d(2, 2, 2) = 2x in all dimensions
  • scale3d(1, 1, 2) = normal X/Y, but 2x depth
  • Use with transform-style: preserve-3d for children to maintain 3D positioning

scale() vs scale3d()

Aspectscale()scale3d()
Dimensions2D (X, Y)3D (X, Y, Z)
Values1 or 23 (required)
Z-axisNot supportedSupported
Perspective neededNoYes (for Z)
Use caseSimple resizing3D effects

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>transform scale() and scale3d()</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DEMO AREA ====== */
        .demo-area {
            display: flex;
            flex-wrap: wrap;
            gap: 40px;
            justify-content: center;
            align-items: center;
            padding: 50px 20px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 250px;
        }

        .demo-area.perspective {
            perspective: 800px;
        }

        .box {
            width: 100px;
            height: 100px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.8rem;
            border-radius: 8px;
            transition: transform 0.5s;
            cursor: pointer;
            text-align: center;
            padding: 5px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
        }

        .box:hover {
            box-shadow: 0 8px 25px rgba(0, 123, 255, 0.4);
        }

        /* Scale demos */
        .scale-1-5 {
            transform: scale(1.5);
        }

        .scale-1-5:hover {
            transform: scale(2);
        }

        .scale-1-5-2 {
            transform: scale(1.5, 2);
        }

        .scale-1-5-2:hover {
            transform: scale(2, 1);
        }

        .scale-half {
            transform: scale(0.5);
        }

        .scale-half:hover {
            transform: scale(0.8);
        }

        /* Scale3d demos */
        .scale3d-2-2-2 {
            transform: scale3d(2, 2, 2);
        }

        .scale3d-2-2-2:hover {
            transform: scale3d(1.5, 1.5, 3);
        }

        .scale3d-1-1-2 {
            transform: scale3d(1, 1, 2);
        }

        .scale3d-1-1-2:hover {
            transform: scale3d(1.5, 1.5, 3);
        }

        /* ====== SCALE COMPARISON ====== */
        .scale-comparison {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 20px;
            margin: 20px 0;
        }

        .scale-item {
            text-align: center;
            padding: 15px;
            background: #f8f9fa;
            border-radius: 8px;
            border: 2px solid #ddd;
            transition: all 0.3s;
        }

        .scale-item:hover {
            border-color: #007bff;
            box-shadow: 0 4px 15px rgba(0, 123, 255, 0.15);
        }

        .scale-item .box-small {
            width: 60px;
            height: 60px;
            margin: 0 auto 10px;
            background: linear-gradient(135deg, #28a745, #20c997);
            border-radius: 8px;
            transition: transform 0.3s;
        }

        .scale-item:hover .box-small {
            transform: scale(1.3);
        }

        .scale-item .label {
            font-weight: bold;
            font-size: 0.85rem;
            color: #007bff;
        }

        /* ====== PRACTICAL: BUTTON SCALE ====== */
        .btn-scale {
            padding: 15px 30px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 1em;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
            margin: 5px;
        }

        .btn-scale:hover {
            transform: scale(1.05);
            background: #0056b3;
            box-shadow: 0 8px 20px rgba(0, 123, 255, 0.3);
        }

        .btn-scale:active {
            transform: scale(0.98);
        }

        /* ====== PRACTICAL: IMAGE GALLERY ====== */
        .gallery {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 15px;
            margin: 15px 0;
        }

        .gallery-item {
            height: 150px;
            border-radius: 8px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 2rem;
            transition: all 0.4s;
            cursor: pointer;
            overflow: hidden;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
        }

        .gallery-item:hover {
            transform: scale(1.1);
            box-shadow: 0 8px 25px rgba(0, 123, 255, 0.3);
            z-index: 10;
        }

        /* ====== PRACTICAL: 3D CUBE SCALE ====== */
        .cube-scene {
            width: 150px;
            height: 150px;
            perspective: 800px;
            margin: 30px auto;
        }

        .cube {
            width: 100%;
            height: 100%;
            position: relative;
            transform-style: preserve-3d;
            animation: pulseCube 3s infinite alternate;
        }

        @keyframes pulseCube {
            from { transform: scale3d(0.8, 0.8, 0.8) rotateX(0) rotateY(0); }
            to { transform: scale3d(1.2, 1.2, 1.2) rotateX(15deg) rotateY(15deg); }
        }

        .cube .face {
            position: absolute;
            width: 150px;
            height: 150px;
            border: 2px solid rgba(0, 0, 0, 0.3);
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            color: white;
            font-size: 0.9rem;
            text-shadow: 0 2px 5px rgba(0,0,0,0.5);
            border-radius: 8px;
        }

        .cube .front {
            background: rgba(255, 0, 0, 0.8);
            transform: translateZ(75px);
        }

        .cube .back {
            background: rgba(0, 255, 0, 0.8);
            transform: rotateY(180deg) translateZ(75px);
        }

        .cube .right {
            background: rgba(0, 0, 255, 0.8);
            transform: rotateY(90deg) translateZ(75px);
        }

        .cube .left {
            background: rgba(255, 255, 0, 0.8);
            transform: rotateY(-90deg) translateZ(75px);
        }

        .cube .top {
            background: rgba(255, 0, 255, 0.8);
            transform: rotateX(90deg) translateZ(75px);
        }

        .cube .bottom {
            background: rgba(0, 255, 255, 0.8);
            transform: rotateX(-90deg) translateZ(75px);
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            background: #f8f9fa;
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>transform scale() and scale3d()</h1>

    <!-- ====== 1. SCALE() DEMO ====== -->
    <section>
        <h2>1. scale() — 2D Scaling</h2>
        <p>Resizes an element horizontally and vertically. Hover over each box to see the scale change!</p>

        <div class="demo-area">
            <div class="box">Original<br>(scale: 1)</div>
            <div class="box scale-1-5">scale(1.5)<br>Uniform</div>
            <div class="box scale-1-5-2">scale(1.5, 2)<br>X=1.5, Y=2</div>
            <div class="box scale-half">scale(0.5)<br>Half size</div>
        </div>

        <div class="code-block">
            /* Uniform scaling — both directions */
            .scale-1-5 {
                transform: scale(1.5);
            }

            /* Separate X and Y scaling */
            .scale-1-5-2 {
                transform: scale(1.5, 2); /* 1.5x width, 2x height */
            }

            /* Shrink to half size */
            .scale-half {
                transform: scale(0.5);
            }
        </div>
    </section>

    <!-- ====== 2. SCALE3D() DEMO ====== -->
    <section>
        <h2>2. scale3d() — 3D Scaling</h2>
        <p>Resizes an element in 3D space (X, Y, and Z axes). Requires <code>perspective</code> on the parent.</p>

        <div class="demo-area perspective">
            <div class="box scale3d-2-2-2">scale3d(2, 2, 2)<br>All axes</div>
            <div class="box scale3d-1-1-2">scale3d(1, 1, 2)<br>Depth only</div>
        </div>

        <div class="code-block">
            /* Scale all three axes */
            .scale3d-2-2-2 {
                transform: scale3d(2, 2, 2); /* 2x in X, Y, Z */
            }

            /* Scale only the Z (depth) axis */
            .scale3d-1-1-2 {
                transform: scale3d(1, 1, 2); /* Normal X/Y, 2x depth */
            }
        </div>

        <p class="note">The Z-axis scale (depth) is only visible when <code>perspective</code> is applied to the parent.</p>
    </section>

    <!-- ====== 3. SCALE COMPARISON ====== -->
    <section>
        <h2>3. Scale Value Comparison</h2>
        <p>Hover over each card to see the scale effect.</p>

        <div class="scale-comparison">
            <div class="scale-item">
                <div class="box-small" style="transform: scale(0.5);"></div>
                <div class="label">scale(0.5)</div>
                <p class="note">Half size</p>
            </div>
            <div class="scale-item">
                <div class="box-small" style="transform: scale(1);"></div>
                <div class="label">scale(1)</div>
                <p class="note">Original</p>
            </div>
            <div class="scale-item">
                <div class="box-small" style="transform: scale(1.5);"></div>
                <div class="label">scale(1.5)</div>
                <p class="note">1.5x size</p>
            </div>
            <div class="scale-item">
                <div class="box-small" style="transform: scale(2);"></div>
                <div class="label">scale(2)</div>
                <p class="note">2x size</p>
            </div>
            <div class="scale-item">
                <div class="box-small" style="transform: scale(2, 0.5);"></div>
                <div class="label">scale(2, 0.5)</div>
                <p class="note">Wide and short</p>
            </div>
        </div>

        <div class="code-block">
            transform: scale(0.5);    /* Half size */
            transform: scale(1);      /* Original size */
            transform: scale(1.5);    /* 1.5x size */
            transform: scale(2);      /* 2x size */
            transform: scale(2, 0.5); /* 2x width, 0.5x height */
        </div>
    </section>

    <!-- ====== 4. PRACTICAL: BUTTON SCALE ====== -->
    <section>
        <h2>4. Practical Example: Button Scale</h2>
        <p>Hover and click the buttons to see the scale effect.</p>

        <div style="text-align: center; margin: 15px 0;">
            <button class="btn-scale">Hover Me</button>
            <button class="btn-scale">Click Me</button>
            <button class="btn-scale">Press Me</button>
        </div>

        <div class="code-block">
            .btn-scale {
                transition: all 0.3s;
            }

            .btn-scale:hover {
                transform: scale(1.05); /* Slightly larger on hover */
            }

            .btn-scale:active {
                transform: scale(0.98); /* Slightly smaller on click */
            }
        </div>
    </section>

    <!-- ====== 5. PRACTICAL: IMAGE GALLERY ====== -->
    <section>
        <h2>5. Practical Example: Image Gallery</h2>
        <p>Hover over each item to see the scale effect.</p>

        <div class="gallery">
            <div class="gallery-item">🖼️</div>
            <div class="gallery-item">🎨</div>
            <div class="gallery-item">📷</div>
            <div class="gallery-item">🎭</div>
        </div>

        <div class="code-block">
            .gallery-item {
                transition: all 0.4s;
            }

            .gallery-item:hover {
                transform: scale(1.1);
                box-shadow: 0 8px 25px rgba(0, 123, 255, 0.3);
                z-index: 10;
            }
        </div>
    </section>

    <!-- ====== 6. PRACTICAL: 3D CUBE SCALE ====== -->
    <section>
        <h2>6. Practical Example: 3D Cube with scale3d()</h2>
        <p>A cube that pulses using <code>scale3d()</code>.</p>

        <div class="cube-scene">
            <div class="cube">
                <div class="face front">Front</div>
                <div class="face back">Back</div>
                <div class="face right">Right</div>
                <div class="face left">Left</div>
                <div class="face top">Top</div>
                <div class="face bottom">Bottom</div>
            </div>
        </div>

        <div class="code-block">
            .cube {
                transform-style: preserve-3d;
                animation: pulseCube 3s infinite alternate;
            }

            @keyframes pulseCube {
                from { transform: scale3d(0.8, 0.8, 0.8) rotateX(0) rotateY(0); }
                to { transform: scale3d(1.2, 1.2, 1.2) rotateX(15deg) rotateY(15deg); }
            }
        </div>
    </section>

    <!-- ====== 7. REFERENCE TABLES ====== -->
    <section>
        <h2>7. Reference Tables</h2>

        <h3>scale() Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Effect</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>scale(1)</code></td>
                <td>Original size</td>
                <td><code>scale(1)</code></td>
            </tr>
            <tr>
                <td><code>scale(1.5)</code></td>
                <td>1.5x size (both axes)</td>
                <td><code>scale(1.5)</code></td>
            </tr>
            <tr>
                <td><code>scale(2)</code></td>
                <td>2x size (both axes)</td>
                <td><code>scale(2)</code></td>
            </tr>
            <tr>
                <td><code>scale(0.5)</code></td>
                <td>Half size</td>
                <td><code>scale(0.5)</code></td>
            </tr>
            <tr>
                <td><code>scale(2, 1)</code></td>
                <td>2x width, 1x height</td>
                <td><code>scale(2, 1)</code></td>
            </tr>
            <tr>
                <td><code>scale(1, 2)</code></td>
                <td>1x width, 2x height</td>
                <td><code>scale(1, 2)</code></td>
            </tr>
        </table>

        <h3>scale3d() Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Effect</th>
            </tr>
            <tr>
                <td><code>scale3d(1, 1, 1)</code></td>
                <td>No scaling</td>
            </tr>
            <tr>
                <td><code>scale3d(2, 2, 2)</code></td>
                <td>2x in all dimensions</td>
            </tr>
            <tr>
                <td><code>scale3d(1, 1, 2)</code></td>
                <td>Normal X/Y, 2x depth</td>
            </tr>
            <tr>
                <td><code>scale3d(2, 1, 1)</code></td>
                <td>2x width only</td>
            </tr>
            <tr>
                <td><code>scale3d(1, 2, 1)</code></td>
                <td>2x height only</td>
            </tr>
        </table>

        <h3>scale() vs scale3d()</h3>
        <table class="reference-table">
            <tr>
                <th>Aspect</th>
                <th>scale()</th>
                <th>scale3d()</th>
            </tr>
            <tr>
                <td><strong>Dimensions</strong></td>
                <td>2D (X, Y)</td>
                <td>3D (X, Y, Z)</td>
            </tr>
            <tr>
                <td><strong>Values</strong></td>
                <td>1 or 2</td>
                <td>3 (required)</td>
            </tr>
            <tr>
                <td><strong>Z-axis</strong></td>
                <td>Not supported</td>
                <td>Supported</td>
            </tr>
            <tr>
                <td><strong>Perspective needed</strong></td>
                <td>No</td>
                <td>Yes (for Z)</td>
            </tr>
            <tr>
                <td><strong>Use case</strong></td>
                <td>Simple resizing</td>
                <td>3D effects</td>
            </tr>
        </table>
    </section>

    <!-- ====== 8. BEST PRACTICES ====== -->
    <section>
        <h2>8. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>scale(1.05)</code> for subtle hover effects on buttons</li>
                <li>Use <code>scale(0.98)</code> for active/pressed states</li>
                <li>Use <code>scale(1.1)</code> for image gallery hover effects</li>
                <li>Use <code>scale3d()</code> for 3D scaling with perspective</li>
                <li>Combine scale with other transforms (rotate, translate)</li>
                <li>Use <code>transform-origin</code> to control the scaling pivot</li>
                <li>Respect <code>prefers-reduced-motion</code> for accessibility</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't scale elements too much (can cause blurriness or overflow)</li>
                <li>Don't use <code>scale3d()</code> without <code>perspective</code> on the parent</li>
                <li>Don't scale text dramatically (can affect readability)</li>
                <li>Don't use negative scale values without understanding the mirror effect</li>
                <li>Don't forget that scaling doesn't affect layout</li>
            </ul>
        </div>

        <div class="code-block">
            /* Accessibility: respect reduced motion */
            @media (prefers-reduced-motion: reduce) {
                .btn-scale:hover,
                .gallery-item:hover {
                    transform: none;
                }
            }

            /* Control scaling pivot */
            .box {
                transform-origin: top left;
                transform: scale(1.5);
            }
        </div>
    </section>

</body>
</html>

Quick Reference

FunctionValuesEffect
scale(s)1 valueUniform scaling
scale(s1, s2)2 valuesX and Y scaling
scale3d(s1, s2, s3)3 valuesX, Y, and Z scaling

scale() Values

ValueEffect
scale(1)Original size
scale(1.5)1.5x size (both axes)
scale(2)2x size (both axes)
scale(0.5)Half size
scale(2, 1)2x width, 1x height
scale(1, 2)1x width, 2x height

scale3d() Values

ValueEffect
scale3d(1, 1, 1)No scaling
scale3d(2, 2, 2)2x in all dimensions
scale3d(1, 1, 2)Normal X/Y, 2x depth
scale3d(2, 1, 1)2x width only
scale3d(1, 2, 1)2x height only

scale() vs scale3d()

Aspectscale()scale3d()
Dimensions2D (X, Y)3D (X, Y, Z)
Values1 or 23 (required)
Z-axisNot supportedSupported
Perspective neededNoYes (for Z)
Use caseSimple resizing3D effects

Best Practices

Do This:

/* Subtle hover effect */
.btn:hover {
    transform: scale(1.05);
}

/* Pressed state */
.btn:active {
    transform: scale(0.98);
}

/* Image gallery hover */
.gallery-item:hover {
    transform: scale(1.1);
}

/* 3D scaling with perspective */
.scene {
    perspective: 800px;
}
.box {
    transform: scale3d(1.5, 1.5, 2);
}

/* Control scaling pivot */
.box {
    transform-origin: top left;
    transform: scale(1.5);
}

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    .btn:hover {
        transform: none;
    }
}

Don’t Do This:

/* Don't scale too much */
.box:hover {
    transform: scale(5); /* Can cause overflow and blurriness */
}

/* Don't use scale3d without perspective */
.box {
    transform: scale3d(2, 2, 2); /* Z scaling won't be visible */
    /* Add perspective on the parent */
}

/* Don't scale text dramatically */
h1:hover {
    transform: scale(3); /* Text becomes blurry and hard to read */
}

Pro Tip: scale() is one of the most versatile transforms. Use subtle scaling (1.02–1.1) for hover effects on buttons, cards, and images — it adds a satisfying “pop” without being distracting. Use scale(0.98) for active/pressed states to simulate a button being pushed down. For 3D effects, use scale3d() with perspective on the parent. Remember: scaling doesn’t affect layout — other elements stay in place, so you don’t need to worry about breaking your page structure. And always respect prefers-reduced-motion for users who are sensitive to motion!

50. transform scaleX, scaleY, and scaleZ

These three functions are the individual axis scaling functions in CSS transforms. Each one scales an element along a specific axis: X (horizontal), Y (vertical), or Z (depth).


Overview of Functions

FunctionAxisEquivalentEffect
scaleX()Horizontalscale3d(s, 1, 1)Stretches width
scaleY()Verticalscale3d(1, s, 1)Stretches height
scaleZ()Depthscale3d(1, 1, s)Stretches depth

Understanding the Axes

        Y (vertical)
        ↑
        │
        │
        │
        └──────────→ X (horizontal)
       /
      /
     ↙
    Z (depth, toward viewer)
AxisDirectionScaling Effect
XHorizontal (left–right)Width increases/decreases
YVertical (up–down)Height increases/decreases
ZDepth (toward viewer)Depth increases/decreases

1. scaleX()

Scales an element horizontally (along the X-axis). Only the width changes.

.scaleX {
    transform: scaleX(2);
}
ValueEffect
scaleX(1)Original width
scaleX(2)2x width
scaleX(0.5)Half width
scaleX(-1)Flipped horizontally (mirror)
scaleX(0)Zero width (invisible)

Equivalent: scale3d(2, 1, 1) or scale(2, 1)

Use cases:

  • Stretching text or images horizontally
  • Creating a “wide” effect
  • Animating width changes (without affecting layout)
  • Flipping elements horizontally

2. scaleY()

Scales an element vertically (along the Y-axis). Only the height changes.

.scaleY {
    transform: scaleY(2);
}
ValueEffect
scaleY(1)Original height
scaleY(2)2x height
scaleY(0.5)Half height
scaleY(-1)Flipped vertically (mirror)
scaleY(0)Zero height (invisible)

Equivalent: scale3d(1, 2, 1) or scale(1, 2)

Use cases:

  • Stretching text or images vertically
  • Creating a “tall” effect
  • Animating height changes (without affecting layout)
  • Flipping elements vertically

3. scaleZ()

Scales an element in depth (along the Z-axis). Requires perspective on the parent to be visible.

.scaleZ {
    transform: scaleZ(2);
}
ValueEffect
scaleZ(1)Original depth
scaleZ(2)2x depth
scaleZ(0.5)Half depth
scaleZ(0)Zero depth

Equivalent: scale3d(1, 1, 2)

Important:

  • scaleZ() only affects 3D-positioned children (those with translateZ)
  • The element itself doesn’t appear to change size
  • Requires perspective on the parent and transform-style: preserve-3d on the container
  • Best used with 3D scenes (cubes, cards, etc.)

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>transform scaleX, scaleY, and scaleZ</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DEMO AREA ====== */
        .demo-area {
            display: flex;
            flex-wrap: wrap;
            gap: 50px;
            justify-content: center;
            align-items: center;
            padding: 50px 20px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 250px;
        }

        .demo-area.perspective {
            perspective: 600px;
        }

        .box {
            width: 100px;
            height: 100px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.9rem;
            border-radius: 8px;
            transition: transform 0.5s;
            cursor: pointer;
            text-align: center;
            padding: 5px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
        }

        .box:hover {
            box-shadow: 0 8px 25px rgba(0, 123, 255, 0.4);
        }

        /* Individual scale functions */
        .scaleX {
            transform: scaleX(2);
        }

        .scaleX:hover {
            transform: scaleX(0.5);
        }

        .scaleY {
            transform: scaleY(2);
        }

        .scaleY:hover {
            transform: scaleY(0.5);
        }

        .scaleZ {
            transform: scaleZ(2);
        }

        .scaleZ:hover {
            transform: scaleZ(0.5);
        }

        /* Comparison grid */
        .scale-comparison {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
            gap: 20px;
            margin: 20px 0;
        }

        .scale-item {
            text-align: center;
            padding: 15px;
            background: #f8f9fa;
            border-radius: 8px;
            border: 2px solid #ddd;
            transition: all 0.3s;
        }

        .scale-item:hover {
            border-color: #007bff;
            box-shadow: 0 4px 15px rgba(0, 123, 255, 0.15);
        }

        .scale-item .demo-box {
            width: 60px;
            height: 60px;
            margin: 0 auto 10px;
            background: linear-gradient(135deg, #28a745, #20c997);
            border-radius: 8px;
            transition: transform 0.3s;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 0.7rem;
            font-weight: bold;
        }

        .scale-item .label {
            font-weight: bold;
            font-size: 0.85rem;
            color: #007bff;
        }

        /* ====== SCALEX DEMO ====== */
        .scaleX-demo {
            display: flex;
            flex-direction: column;
            gap: 15px;
            align-items: center;
            margin: 15px 0;
        }

        .scaleX-row {
            display: flex;
            gap: 15px;
            align-items: center;
            flex-wrap: wrap;
            justify-content: center;
        }

        .scaleX-box {
            width: 80px;
            height: 80px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.8rem;
            transition: transform 0.3s;
        }

        .scaleX-1 { transform: scaleX(1); }
        .scaleX-2 { transform: scaleX(2); }
        .scaleX-0-5 { transform: scaleX(0.5); }
        .scaleX-neg { transform: scaleX(-1); }

        /* ====== SCALEY DEMO ====== */
        .scaleY-demo {
            display: flex;
            gap: 20px;
            align-items: flex-end;
            justify-content: center;
            margin: 15px 0;
            flex-wrap: wrap;
        }

        .scaleY-box {
            width: 80px;
            height: 80px;
            background: linear-gradient(135deg, #28a745, #20c997);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.8rem;
            transition: transform 0.3s;
            transform-origin: bottom;
        }

        .scaleY-1 { transform: scaleY(1); }
        .scaleY-2 { transform: scaleY(2); }
        .scaleY-0-5 { transform: scaleY(0.5); }
        .scaleY-neg { transform: scaleY(-1); }

        /* ====== PRACTICAL: BAR CHART ====== */
        .bar-chart {
            display: flex;
            gap: 20px;
            align-items: flex-end;
            justify-content: center;
            height: 200px;
            margin: 20px 0;
            padding: 20px;
            background: #f8f9fa;
            border-radius: 8px;
            border: 2px solid #ddd;
        }

        .bar {
            width: 60px;
            background: linear-gradient(180deg, #007bff, #6c5ce7);
            border-radius: 8px 8px 0 0;
            transform-origin: bottom;
            transition: transform 0.5s;
            display: flex;
            align-items: flex-start;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.8rem;
            padding-top: 5px;
        }

        .bar:hover {
            transform: scaleY(1.1);
        }

        /* ====== PRACTICAL: HORIZONTAL PROGRESS ====== */
        .progress-container {
            width: 100%;
            max-width: 500px;
            height: 30px;
            background: #e9ecef;
            border-radius: 15px;
            overflow: hidden;
            margin: 15px auto;
        }

        .progress-bar {
            height: 100%;
            background: linear-gradient(90deg, #007bff, #6c5ce7);
            border-radius: 15px;
            transform-origin: left;
            transition: transform 1s;
            display: flex;
            align-items: center;
            justify-content: flex-end;
            padding-right: 10px;
            color: white;
            font-weight: bold;
            font-size: 0.8rem;
        }

        .progress-bar:hover {
            transform: scaleX(1.05);
        }

        /* ====== 3D CUBE WITH SCALEZ ====== */
        .cube-scene {
            width: 150px;
            height: 150px;
            perspective: 800px;
            margin: 30px auto;
        }

        .cube {
            width: 100%;
            height: 100%;
            position: relative;
            transform-style: preserve-3d;
            animation: pulseCubeZ 3s infinite alternate;
        }

        @keyframes pulseCubeZ {
            from { transform: rotateX(-15deg) rotateY(-15deg) scaleZ(1); }
            to { transform: rotateX(-15deg) rotateY(-15deg) scaleZ(2); }
        }

        .cube .face {
            position: absolute;
            width: 150px;
            height: 150px;
            border: 2px solid rgba(0, 0, 0, 0.3);
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            color: white;
            font-size: 0.9rem;
            text-shadow: 0 2px 5px rgba(0,0,0,0.5);
            border-radius: 8px;
        }

        .cube .front {
            background: rgba(255, 0, 0, 0.8);
            transform: translateZ(75px);
        }

        .cube .back {
            background: rgba(0, 255, 0, 0.8);
            transform: rotateY(180deg) translateZ(75px);
        }

        .cube .right {
            background: rgba(0, 0, 255, 0.8);
            transform: rotateY(90deg) translateZ(75px);
        }

        .cube .left {
            background: rgba(255, 255, 0, 0.8);
            transform: rotateY(-90deg) translateZ(75px);
        }

        .cube .top {
            background: rgba(255, 0, 255, 0.8);
            transform: rotateX(90deg) translateZ(75px);
        }

        .cube .bottom {
            background: rgba(0, 255, 255, 0.8);
            transform: rotateX(-90deg) translateZ(75px);
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            background: #f8f9fa;
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>transform scaleX, scaleY, and scaleZ</h1>

    <!-- ====== 1. BASIC SCALE FUNCTIONS ====== -->
    <section>
        <h2>1. Basic Axis Scaling</h2>
        <p>Hover over each box to see the scale change!</p>

        <div class="demo-area">
            <div class="box scaleX">scaleX(2)</div>
            <div class="box scaleY">scaleY(2)</div>
            <div class="box scaleZ">scaleZ(2)</div>
        </div>

        <p class="note"><strong>scaleX</strong> stretches horizontally. <strong>scaleY</strong> stretches vertically. <strong>scaleZ</strong> stretches depth (needs perspective).</p>

        <div class="code-block">
            /* Scale horizontally (X-axis) */
            .scaleX {
                transform: scaleX(2); /* 2x width */
            }

            /* Scale vertically (Y-axis) */
            .scaleY {
                transform: scaleY(2); /* 2x height */
            }

            /* Scale in depth (Z-axis) */
            .scaleZ {
                transform: scaleZ(2); /* 2x depth */
            }
        </div>
    </section>

    <!-- ====== 2. AXIS VISUALIZATION ====== -->
    <section>
        <h2>2. Understanding the Axes</h2>

        <div class="scale-comparison">
            <div class="scale-item">
                <div class="demo-box" style="transform: scaleX(1.5);">X</div>
                <div class="label">scaleX()</div>
                <p class="note">Stretches width</p>
            </div>
            <div class="scale-item">
                <div class="demo-box" style="transform: scaleY(1.5);">Y</div>
                <div class="label">scaleY()</div>
                <p class="note">Stretches height</p>
            </div>
            <div class="scale-item">
                <div class="demo-box" style="transform: scaleZ(1.5);">Z</div>
                <div class="label">scaleZ()</div>
                <p class="note">Stretches depth</p>
            </div>
        </div>

        <div class="code-block">
            /* These are equivalent */
            scaleX(2) = scale3d(2, 1, 1) = scale(2, 1)
            scaleY(2) = scale3d(1, 2, 1) = scale(1, 2)
            scaleZ(2) = scale3d(1, 1, 2)
        </div>
    </section>

    <!-- ====== 3. SCALEX COMPARISON ====== -->
    <section>
        <h2>3. scaleX() Comparison</h2>

        <div class="scaleX-demo">
            <div class="scaleX-row">
                <div class="scaleX-box scaleX-1">scaleX(1)</div>
                <div class="scaleX-box scaleX-2">scaleX(2)</div>
                <div class="scaleX-box scaleX-0-5">scaleX(0.5)</div>
                <div class="scaleX-box scaleX-neg">scaleX(-1)</div>
            </div>
        </div>

        <div class="code-block">
            transform: scaleX(1);   /* Original width */
            transform: scaleX(2);   /* 2x width */
            transform: scaleX(0.5); /* Half width */
            transform: scaleX(-1);  /* Flipped horizontally */
        </div>
    </section>

    <!-- ====== 4. SCALEY COMPARISON ====== -->
    <section>
        <h2>4. scaleY() Comparison</h2>

        <div class="scaleY-demo">
            <div class="scaleY-box scaleY-1">scaleY(1)</div>
            <div class="scaleY-box scaleY-2">scaleY(2)</div>
            <div class="scaleY-box scaleY-0-5">scaleY(0.5)</div>
            <div class="scaleY-box scaleY-neg">scaleY(-1)</div>
        </div>

        <div class="code-block">
            transform: scaleY(1);   /* Original height */
            transform: scaleY(2);   /* 2x height */
            transform: scaleY(0.5); /* Half height */
            transform: scaleY(-1);  /* Flipped vertically */
        </div>
    </section>

    <!-- ====== 5. PRACTICAL: BAR CHART ====== -->
    <section>
        <h2>5. Practical Example: Bar Chart</h2>
        <p>Bars grow using <code>scaleY()</code> — hover over each bar to see the effect.</p>

        <div class="bar-chart">
            <div class="bar" style="height: 40%;">40%</div>
            <div class="bar" style="height: 65%;">65%</div>
            <div class="bar" style="height: 85%;">85%</div>
            <div class="bar" style="height: 55%;">55%</div>
            <div class="bar" style="height: 75%;">75%</div>
        </div>

        <div class="code-block">
            .bar {
                transform-origin: bottom;
                transition: transform 0.5s;
            }

            .bar:hover {
                transform: scaleY(1.1); /* Grows from the bottom */
            }
        </div>

        <p class="note">Use <code>transform-origin: bottom</code> so bars grow upward from their base.</p>
    </section>

    <!-- ====== 6. PRACTICAL: PROGRESS BAR ====== -->
    <section>
        <h2>6. Practical Example: Progress Bar</h2>
        <p>The progress bar uses <code>scaleX()</code> to fill from the left.</p>

        <div class="progress-container">
            <div class="progress-bar" style="width: 75%;">75%</div>
        </div>

        <div class="code-block">
            .progress-bar {
                transform-origin: left;
                transition: transform 1s;
            }

            .progress-bar:hover {
                transform: scaleX(1.05); /* Slight growth on hover */
            }
        </div>

        <p class="note">Use <code>transform-origin: left</code> so the bar grows from the left edge.</p>
    </section>

    <!-- ====== 7. PRACTICAL: 3D CUBE WITH SCALEZ ====== -->
    <section>
        <h2>7. Practical Example: 3D Cube with scaleZ()</h2>
        <p>A cube that pulses in depth using <code>scaleZ()</code>.</p>

        <div class="cube-scene">
            <div class="cube">
                <div class="face front">Front</div>
                <div class="face back">Back</div>
                <div class="face right">Right</div>
                <div class="face left">Left</div>
                <div class="face top">Top</div>
                <div class="face bottom">Bottom</div>
            </div>
        </div>

        <div class="code-block">
            .cube {
                transform-style: preserve-3d;
                animation: pulseCubeZ 3s infinite alternate;
            }

            @keyframes pulseCubeZ {
                from { transform: rotateX(-15deg) rotateY(-15deg) scaleZ(1); }
                to { transform: rotateX(-15deg) rotateY(-15deg) scaleZ(2); }
            }
        </div>

        <p class="note"><code>scaleZ()</code> changes the depth of the cube — the front and back faces move apart.</p>
    </section>

    <!-- ====== 8. REFERENCE TABLES ====== -->
    <section>
        <h2>8. Reference Tables</h2>

        <h3>scaleX() Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Effect</th>
            </tr>
            <tr>
                <td><code>scaleX(1)</code></td>
                <td>Original width</td>
            </tr>
            <tr>
                <td><code>scaleX(2)</code></td>
                <td>2x width</td>
            </tr>
            <tr>
                <td><code>scaleX(0.5)</code></td>
                <td>Half width</td>
            </tr>
            <tr>
                <td><code>scaleX(-1)</code></td>
                <td>Flipped horizontally</td>
            </tr>
        </table>

        <h3>scaleY() Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Effect</th>
            </tr>
            <tr>
                <td><code>scaleY(1)</code></td>
                <td>Original height</td>
            </tr>
            <tr>
                <td><code>scaleY(2)</code></td>
                <td>2x height</td>
            </tr>
            <tr>
                <td><code>scaleY(0.5)</code></td>
                <td>Half height</td>
            </tr>
            <tr>
                <td><code>scaleY(-1)</code></td>
                <td>Flipped vertically</td>
            </tr>
        </table>

        <h3>scaleZ() Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Effect</th>
            </tr>
            <tr>
                <td><code>scaleZ(1)</code></td>
                <td>Original depth</td>
            </tr>
            <tr>
                <td><code>scaleZ(2)</code></td>
                <td>2x depth</td>
            </tr>
            <tr>
                <td><code>scaleZ(0.5)</code></td>
                <td>Half depth</td>
            </tr>
        </table>

        <h3>Function Equivalents</h3>
        <table class="reference-table">
            <tr>
                <th>Function</th>
                <th>Equivalent</th>
            </tr>
            <tr>
                <td><code>scaleX(2)</code></td>
                <td><code>scale3d(2, 1, 1)</code> or <code>scale(2, 1)</code></td>
            </tr>
            <tr>
                <td><code>scaleY(2)</code></td>
                <td><code>scale3d(1, 2, 1)</code> or <code>scale(1, 2)</code></td>
            </tr>
            <tr>
                <td><code>scaleZ(2)</code></td>
                <td><code>scale3d(1, 1, 2)</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 9. BEST PRACTICES ====== -->
    <section>
        <h2>9. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>scaleX()</code> for horizontal stretching (progress bars, dividers)</li>
                <li>Use <code>scaleY()</code> for vertical stretching (bar charts, accordions)</li>
                <li>Use <code>scaleZ()</code> for 3D depth effects (cubes, 3D scenes)</li>
                <li>Use <code>transform-origin</code> to control the scaling pivot</li>
                <li>Combine with other transforms for complex effects</li>
                <li>Respect <code>prefers-reduced-motion</code> for accessibility</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use <code>scaleZ()</code> without <code>perspective</code> on the parent</li>
                <li>Don't scale elements too much (causes blurriness or overflow)</li>
                <li>Don't use <code>scaleX(-1)</code> or <code>scaleY(-1)</code> without understanding the mirror effect</li>
                <li>Don't forget that scaling doesn't affect layout</li>
                <li>Don't scale text dramatically (affects readability)</li>
            </ul>
        </div>

        <div class="code-block">
            /* Accessibility: respect reduced motion */
            @media (prefers-reduced-motion: reduce) {
                .bar:hover,
                .progress-bar:hover {
                    transform: none;
                }
            }

            /* Control scaling pivot */
            .bar {
                transform-origin: bottom; /* Grow from bottom */
            }

            .progress-bar {
                transform-origin: left; /* Fill from left */
            }
        </div>
    </section>

</body>
</html>

Quick Reference

FunctionAxisEquivalentEffect
scaleX()Horizontalscale3d(s, 1, 1)Stretches width
scaleY()Verticalscale3d(1, s, 1)Stretches height
scaleZ()Depthscale3d(1, 1, s)Stretches depth

scaleX() Values

ValueEffect
scaleX(1)Original width
scaleX(2)2x width
scaleX(0.5)Half width
scaleX(-1)Flipped horizontally

scaleY() Values

ValueEffect
scaleY(1)Original height
scaleY(2)2x height
scaleY(0.5)Half height
scaleY(-1)Flipped vertically

scaleZ() Values

ValueEffect
scaleZ(1)Original depth
scaleZ(2)2x depth
scaleZ(0.5)Half depth

Best Practices

Do This:

/* Progress bar fills from left */
.progress-bar {
    transform-origin: left;
    transform: scaleX(0.75);
}

/* Bar chart grows from bottom */
.bar {
    transform-origin: bottom;
    transform: scaleY(0.8);
}

/* 3D cube pulses in depth */
.cube {
    transform-style: preserve-3d;
    transform: scaleZ(2);
}

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    .bar:hover {
        transform: none;
    }
}

Don’t Do This:

/* Don't use scaleZ without perspective */
.box {
    transform: scaleZ(2); /* Won't be visible */
    /* Add perspective on the parent */
}

/* Don't scale too much */
.box:hover {
    transform: scaleX(5); /* Can cause overflow */
}

/* Don't forget transform-origin for bars */
.bar {
    transform: scaleY(2); /* Grows from center by default */
    /* Use transform-origin: bottom for upward growth */
}

Pro Tip: scaleX() and scaleY() are perfect for data visualization — use scaleY() with transform-origin: bottom for bar charts that grow upward, and scaleX() with transform-origin: left for progress bars that fill from the left. scaleZ() is your gateway to 3D depth effects — it changes how far apart the front and back faces of a 3D object are. Remember: scaleZ() requires perspective on the parent and transform-style: preserve-3d on the container to be visible. And always respect prefers-reduced-motion for users who are sensitive to animation!

51. transform skew(), skewX(), and skewY()

These transform functions slant or distort elements along the X or Y axis, creating a parallelogram effect. They’re useful for dynamic banners, stylized cards, and geometric layouts.


Overview of Functions

FunctionAxisEffectEquivalent
skew()X and/or YSlants both axesskewX() + skewY()
skewX()HorizontalSlants left/rightskew(angle, 0)
skewY()VerticalSlants up/downskew(0, angle)

Understanding Skew

Original:               skewX(20deg):          skewY(20deg):
┌─────────────┐         ┌─────────────┐         ┌─────────────┐
│             │         │            /│         │             │
│   Element   │         │  Element  /  │         │   Element   │
│             │         │          /   │         │             │
│             │         │         /    │         │             │
└─────────────┘         └─────────────┘         └─────────────┘
                        Top shifted right       Left shifted down
Skew TypeEffectVisual
skewX()Horizontal slantTop moves right, bottom stays
skewY()Vertical slantLeft moves down, right stays
skew()BothParallelogram shape

1. skew()

The skew() function applies a 2D skew along both axes.

.skewed-element {
    transform: skew(30deg);
}

Syntax

skew(angle)          /* Skew X only */
skew(xAngle, yAngle) /* Skew X and Y */
SyntaxEffect
skew(30deg)Skew X by 30°
skew(30deg, 20deg)Skew X by 30°, Y by 20°
skew(0, 20deg)Skew Y only

Angle Units

UnitExampleDescription
deg30degDegrees
grad100gradGradians (400 = full circle)
rad0.5radRadians (2π = full circle)
turn0.25turnTurns (1 = full circle)

2. skewX()

The skewX() function skews an element horizontally along the X-axis.

.skewX-box {
    transform: skewX(30deg);
}
ValueEffect
skewX(0deg)No skew
skewX(30deg)Top shifts right by 30°
skewX(-30deg)Top shifts left by 30°
skewX(90deg)Extreme distortion

Equivalent: skew(30deg) or skew(30deg, 0)

Use cases:

  • Slanted banners and ribbons
  • Dynamic card layouts
  • Stylized buttons
  • Perspective-like effects

3. skewY()

The skewY() function skews an element vertically along the Y-axis.

.skewY-box {
    transform: skewY(20deg);
}
ValueEffect
skewY(0deg)No skew
skewY(20deg)Left side shifts down by 20°
skewY(-20deg)Left side shifts up by 20°
skewY(90deg)Extreme distortion

Equivalent: skew(0, 20deg)

Use cases:

  • Diagonal section dividers
  • Slanted headers
  • Stylized quotes
  • Vertical rhythm effects

4. Combining skewX() and skewY()

You can combine both skews for a parallelogram effect.

.combined-skew-box {
    transform: skewX(30deg) skewY(20deg);
}

This creates a shape that’s slanted both horizontally and vertically.


Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>transform skew(), skewX(), and skewY()</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DEMO AREA ====== */
        .demo-area {
            display: flex;
            flex-wrap: wrap;
            gap: 40px;
            justify-content: center;
            align-items: center;
            padding: 50px 20px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 250px;
        }

        .box {
            width: 180px;
            height: 100px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.9rem;
            border-radius: 8px;
            transition: transform 0.5s;
            cursor: pointer;
            text-align: center;
            padding: 10px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
        }

        .box:hover {
            box-shadow: 0 8px 25px rgba(0, 123, 255, 0.4);
        }

        /* Individual skews */
        .skewX-box {
            background: linear-gradient(135deg, #4CAF50, #2e7d32);
            transform: skewX(30deg);
        }

        .skewX-box:hover {
            transform: skewX(-30deg);
        }

        .skewY-box {
            background: linear-gradient(135deg, #2196F3, #0d47a1);
            transform: skewY(20deg);
        }

        .skewY-box:hover {
            transform: skewY(-20deg);
        }

        .combined-skew-box {
            background: linear-gradient(135deg, #FF5722, #bf360c);
            transform: skewX(30deg) skewY(20deg);
        }

        .combined-skew-box:hover {
            transform: skewX(-30deg) skewY(-20deg);
        }

        /* Skew demo for text */
        .skewed-text {
            width: 200px;
            height: 100px;
            background: linear-gradient(135deg, #6c5ce7, #4a2a9e);
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            border-radius: 8px;
            transform: skew(15deg);
            transition: transform 0.3s;
        }

        .skewed-text:hover {
            transform: skew(-15deg);
        }

        /* Angle comparison */
        .angle-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 20px;
            margin: 20px 0;
        }

        .angle-item {
            text-align: center;
            padding: 15px;
            background: #f8f9fa;
            border-radius: 8px;
            border: 2px solid #ddd;
            transition: all 0.3s;
        }

        .angle-item:hover {
            border-color: #007bff;
            box-shadow: 0 4px 15px rgba(0, 123, 255, 0.15);
        }

        .angle-item .demo-box {
            width: 80px;
            height: 60px;
            margin: 0 auto 10px;
            background: linear-gradient(135deg, #28a745, #20c997);
            border-radius: 6px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 0.7rem;
            font-weight: bold;
            transition: transform 0.3s;
        }

        .angle-item .label {
            font-weight: bold;
            font-size: 0.85rem;
            color: #007bff;
        }

        /* Angle unit demo */
        .unit-demo {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            justify-content: center;
            margin: 15px 0;
        }

        .unit-box {
            width: 120px;
            height: 80px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.75rem;
            border-radius: 8px;
            background: linear-gradient(135deg, #dc3545, #a71d2a);
            transition: transform 0.3s;
        }

        /* ====== PRACTICAL: SLANTED BANNER ====== */
        .banner-container {
            position: relative;
            padding: 40px 20px;
            background: #e9ecef;
            border-radius: 8px;
            overflow: hidden;
            margin: 15px 0;
        }

        .banner {
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            color: white;
            padding: 30px 50px;
            transform: skewX(-10deg);
            text-align: center;
            font-size: 1.5rem;
            font-weight: bold;
            box-shadow: 0 10px 30px rgba(0, 123, 255, 0.3);
            margin: 0 -20px;
        }

        .banner span {
            display: inline-block;
            transform: skewX(10deg); /* Counter-skew the text */
        }

        /* ====== PRACTICAL: SLANTED CARD ====== */
        .card-container {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            justify-content: center;
            margin: 20px 0;
        }

        .slant-card {
            width: 220px;
            height: 280px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            border-radius: 16px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            color: white;
            text-align: center;
            padding: 20px;
            transform: skewY(-5deg);
            transition: all 0.3s;
            box-shadow: 0 8px 25px rgba(0, 123, 255, 0.2);
            cursor: pointer;
        }

        .slant-card:hover {
            transform: skewY(0deg) scale(1.05);
            box-shadow: 0 15px 40px rgba(0, 123, 255, 0.3);
        }

        .slant-card .icon {
            font-size: 2.5rem;
            margin-bottom: 15px;
        }

        .slant-card h4 {
            margin: 0 0 10px 0;
        }

        .slant-card p {
            font-size: 0.85rem;
            opacity: 0.95;
            margin: 0;
        }

        /* ====== PRACTICAL: 3D PERSPECTIVE SKEW ====== */
        .perspective-scene {
            perspective: 800px;
            margin: 20px auto;
            width: 300px;
        }

        .perspective-skew {
            width: 100%;
            padding: 30px;
            background: linear-gradient(135deg, #28a745, #20c997);
            color: white;
            text-align: center;
            font-weight: bold;
            font-size: 1.2rem;
            border-radius: 12px;
            transform: rotateY(20deg) skewY(5deg);
            transition: transform 0.5s;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            cursor: pointer;
        }

        .perspective-skew:hover {
            transform: rotateY(0deg) skewY(0deg);
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            background: #f8f9fa;
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>transform skew(), skewX(), and skewY()</h1>

    <!-- ====== 1. BASIC SKEW FUNCTIONS ====== -->
    <section>
        <h2>1. Basic Skew Functions</h2>
        <p>Hover over each box to see the skew change!</p>

        <div class="demo-area">
            <div class="box skewX-box">skewX(30deg)</div>
            <div class="box skewY-box">skewY(20deg)</div>
            <div class="box combined-skew-box">skewX(30deg)<br>skewY(20deg)</div>
        </div>

        <p class="note"><strong>skewX</strong> slants horizontally. <strong>skewY</strong> slants vertically. Combining both creates a parallelogram.</p>

        <div class="code-block">
            /* Skew horizontally (X-axis) */
            .skewX-box {
                transform: skewX(30deg);
            }

            /* Skew vertically (Y-axis) */
            .skewY-box {
                transform: skewY(20deg);
            }

            /* Combine both skews */
            .combined-skew-box {
                transform: skewX(30deg) skewY(20deg);
            }
        </div>
    </section>

    <!-- ====== 2. ANGLE COMPARISON ====== -->
    <section>
        <h2>2. Skew Angle Comparison</h2>

        <div class="angle-grid">
            <div class="angle-item">
                <div class="demo-box" style="transform: skewX(0deg);">0°</div>
                <div class="label">skewX(0deg)</div>
                <p class="note">No skew</p>
            </div>
            <div class="angle-item">
                <div class="demo-box" style="transform: skewX(15deg);">15°</div>
                <div class="label">skewX(15deg)</div>
                <p class="note">Subtle slant</p>
            </div>
            <div class="angle-item">
                <div class="demo-box" style="transform: skewX(30deg);">30°</div>
                <div class="label">skewX(30deg)</div>
                <p class="note">Moderate slant</p>
            </div>
            <div class="angle-item">
                <div class="demo-box" style="transform: skewX(45deg);">45°</div>
                <div class="label">skewX(45deg)</div>
                <p class="note">Strong slant</p>
            </div>
            <div class="angle-item">
                <div class="demo-box" style="transform: skewX(-30deg);">-30°</div>
                <div class="label">skewX(-30deg)</div>
                <p class="note">Opposite direction</p>
            </div>
        </div>

        <div class="code-block">
            transform: skewX(0deg);   /* No skew */
            transform: skewX(15deg);  /* Subtle slant */
            transform: skewX(30deg);  /* Moderate slant */
            transform: skewX(45deg);  /* Strong slant */
            transform: skewX(-30deg); /* Opposite direction */
        </div>
    </section>

    <!-- ====== 3. ANGLE UNITS ====== -->
    <section>
        <h2>3. Angle Units</h2>
        <p>Skew angles can be specified in different units.</p>

        <div class="unit-demo">
            <div class="unit-box" style="transform: skew(30deg);">30deg</div>
            <div class="unit-box" style="transform: skew(0.05turn);">0.05turn</div>
            <div class="unit-box" style="transform: skew(10grad);">10grad</div>
            <div class="unit-box" style="transform: skew(0.5rad);">0.5rad</div>
        </div>

        <div class="code-block">
            /* Degrees */
            transform: skew(30deg);

            /* Turns (0.05 turn = 18°) */
            transform: skew(0.05turn);

            /* Gradians (10grad = 9°) */
            transform: skew(10grad);

            /* Radians (0.5rad ≈ 28.6°) */
            transform: skew(0.5rad);
        </div>

        <table class="reference-table">
            <tr>
                <th>Unit</th>
                <th>Full Circle</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>deg</code></td>
                <td>360°</td>
                <td><code>30deg</code></td>
            </tr>
            <tr>
                <td><code>grad</code></td>
                <td>400</td>
                <td><code>100grad</code></td>
            </tr>
            <tr>
                <td><code>rad</code></td>
                <td>2π</td>
                <td><code>0.5rad</code></td>
            </tr>
            <tr>
                <td><code>turn</code></td>
                <td>1</td>
                <td><code>0.25turn</code></td>
            </tr>
        </table>
    </section>

    <!-- ====== 4. PRACTICAL: SLANTED BANNER ====== -->
    <section>
        <h2>4. Practical Example: Slanted Banner</h2>
        <p>A banner with a slanted design — the text is counter-skewed to stay upright.</p>

        <div class="banner-container">
            <div class="banner">
                <span>🎉 Special Offer! 🎉</span>
            </div>
        </div>

        <div class="code-block">
            .banner {
                transform: skewX(-10deg); /* Slant the banner */
            }

            .banner span {
                transform: skewX(10deg); /* Counter-skew the text */
                display: inline-block;
            }
        </div>

        <p class="note">Use a counter-skew on the text to keep it upright while the background is slanted.</p>
    </section>

    <!-- ====== 5. PRACTICAL: SLANTED CARDS ====== -->
    <section>
        <h2>5. Practical Example: Slanted Cards</h2>
        <p>Hover over each card to straighten it.</p>

        <div class="card-container">
            <div class="slant-card">
                <div class="icon">🚀</div>
                <h4>Fast</h4>
                <p>Lightning-fast performance</p>
            </div>
            <div class="slant-card">
                <div class="icon">🎨</div>
                <h4>Beautiful</h4>
                <p>Stunning design system</p>
            </div>
            <div class="slant-card">
                <div class="icon">🔒</div>
                <h4>Secure</h4>
                <p>Enterprise-grade security</p>
            </div>
        </div>

        <div class="code-block">
            .slant-card {
                transform: skewY(-5deg);
                transition: all 0.3s;
            }

            .slant-card:hover {
                transform: skewY(0deg) scale(1.05);
            }
        </div>
    </section>

    <!-- ====== 6. PRACTICAL: 3D PERSPECTIVE SKEW ====== -->
    <section>
        <h2>6. Practical Example: 3D Perspective Skew</h2>
        <p>Combining skew with rotateY for a 3D perspective effect.</p>

        <div class="perspective-scene">
            <div class="perspective-skew">
                🎯 3D Perspective Skew
            </div>
        </div>

        <div class="code-block">
            .perspective-scene {
                perspective: 800px;
            }

            .perspective-skew {
                transform: rotateY(20deg) skewY(5deg);
                transition: transform 0.5s;
            }

            .perspective-skew:hover {
                transform: rotateY(0deg) skewY(0deg);
            }
        </div>
    </section>

    <!-- ====== 7. REFERENCE TABLES ====== -->
    <section>
        <h2>7. Reference Tables</h2>

        <h3>Skew Functions</h3>
        <table class="reference-table">
            <tr>
                <th>Function</th>
                <th>Axis</th>
                <th>Effect</th>
                <th>Equivalent</th>
            </tr>
            <tr>
                <td><code>skew()</code></td>
                <td>X and/or Y</td>
                <td>Slants both axes</td>
                <td>—</td>
            </tr>
            <tr>
                <td><code>skewX()</code></td>
                <td>Horizontal</td>
                <td>Slants left/right</td>
                <td><code>skew(angle, 0)</code></td>
            </tr>
            <tr>
                <td><code>skewY()</code></td>
                <td>Vertical</td>
                <td>Slants up/down</td>
                <td><code>skew(0, angle)</code></td>
            </tr>
        </table>

        <h3>Angle Units</h3>
        <table class="reference-table">
            <tr>
                <th>Unit</th>
                <th>Full Circle</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>deg</code></td>
                <td>360°</td>
                <td><code>30deg</code></td>
            </tr>
            <tr>
                <td><code>grad</code></td>
                <td>400</td>
                <td><code>100grad</code></td>
            </tr>
            <tr>
                <td><code>rad</code></td>
                <td>2π</td>
                <td><code>0.5rad</code></td>
            </tr>
            <tr>
                <td><code>turn</code></td>
                <td>1</td>
                <td><code>0.25turn</code></td>
            </tr>
        </table>

        <h3>Common Skew Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Effect</th>
                <th>Use Case</th>
            </tr>
            <tr>
                <td><code>skewX(10deg)</code></td>
                <td>Subtle slant</td>
                <td>Buttons, tags</td>
            </tr>
            <tr>
                <td><code>skewX(20deg)</code></td>
                <td>Moderate slant</td>
                <td>Banners, ribbons</td>
            </tr>
            <tr>
                <td><code>skewX(30deg)</code></td>
                <td>Strong slant</td>
                <td>Dynamic layouts</td>
            </tr>
            <tr>
                <td><code>skewY(5deg)</code></td>
                <td>Subtle vertical</td>
                <td>Card layouts</td>
            </tr>
            <tr>
                <td><code>skewY(10deg)</code></td>
                <td>Moderate vertical</td>
                <td>Section dividers</td>
            </tr>
        </table>
    </section>

    <!-- ====== 8. BEST PRACTICES ====== -->
    <section>
        <h2>8. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>skewX()</code> for slanted banners and ribbons</li>
                <li>Use <code>skewY()</code> for diagonal section dividers</li>
                <li>Use counter-skew on text to keep it upright</li>
                <li>Combine with other transforms for dynamic effects</li>
                <li>Use subtle angles (5°–20°) for a refined look</li>
                <li>Use <code>transform-origin</code> to control the pivot point</li>
                <li>Respect <code>prefers-reduced-motion</code> for accessibility</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't skew text without counter-skewing it (makes it hard to read)</li>
                <li>Don't use extreme angles (90° makes elements invisible)</li>
                <li>Don't overuse skew — it can look chaotic</li>
                <li>Don't forget that skew affects the element's bounding box</li>
                <li>Don't use skew for critical content that must remain readable</li>
            </ul>
        </div>

        <div class="code-block">
            /* Accessibility: respect reduced motion */
            @media (prefers-reduced-motion: reduce) {
                .slant-card:hover {
                    transform: none;
                }
            }

            /* Counter-skew text for readability */
            .banner {
                transform: skewX(-10deg);
            }
            .banner span {
                display: inline-block;
                transform: skewX(10deg);
            }
        </div>
    </section>

</body>
</html>

Quick Reference

FunctionAxisEffectEquivalent
skew()X and/or YSlants both axes
skewX()HorizontalSlants left/rightskew(angle, 0)
skewY()VerticalSlants up/downskew(0, angle)

Angle Units

UnitFull CircleExample
deg360°30deg
grad400100grad
rad0.5rad
turn10.25turn

Common Skew Values

ValueEffectUse Case
skewX(10deg)Subtle slantButtons, tags
skewX(20deg)Moderate slantBanners, ribbons
skewX(30deg)Strong slantDynamic layouts
skewY(5deg)Subtle verticalCard layouts
skewY(10deg)Moderate verticalSection dividers

Best Practices

Do This:

/* Slanted banner with counter-skewed text */
.banner {
    transform: skewX(-10deg);
}
.banner span {
    display: inline-block;
    transform: skewX(10deg);
}

/* Subtle slanted cards */
.card {
    transform: skewY(-3deg);
    transition: transform 0.3s;
}
.card:hover {
    transform: skewY(0deg);
}

/* Combined skew for parallelogram */
.shape {
    transform: skewX(20deg) skewY(10deg);
}

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    .card:hover {
        transform: none;
    }
}

Don’t Do This:

/* Don't skew text without counter-skewing */
.text {
    transform: skewX(30deg); /* Hard to read! */
}

/* Don't use extreme angles */
.box {
    transform: skewX(90deg); /* Becomes a line! */
}

/* Don't overuse skew */
.everything {
    transform: skewX(20deg) skewY(15deg); /* Chaotic */
}

Pro Tip: skewX() and skewY() are perfect for dynamic, modern designs — slanted banners, ribbons, cards, and section dividers. The key trick is counter-skewing text: if you skew a container by -10deg, skew the text inside by 10deg to keep it upright and readable. Use subtle angles (5°–20°) for a refined look — extreme angles (45°+) can make content unreadable. Remember: skew affects the element’s bounding box, so the element may overflow its container — plan accordingly! And always respect prefers-reduced-motion for users who are sensitive to motion!

52. transform translate() and translate3d()

The translate() and translate3d() functions move elements from their original position — horizontally, vertically, or in 3D space. Unlike position or margin, translation doesn’t affect the layout of other elements.


Overview of Functions

FunctionDimensionsValuesDescription
translate()2Dx or x, yMoves along X and Y
translate3d()3Dx, y, zMoves along X, Y, and Z
translateX()1DxMoves horizontally
translateY()1DyMoves vertically
translateZ()1DzMoves in depth

Understanding Translation

Original:          translate(50px, 30px):
┌─────────┐        
│  Box    │        ┌─────────┐
│         │        │  Box    │
└─────────┘        └─────────┘
                    ← 50px →
                    ↓ 30px
TranslationDirection
Positive XRight
Negative XLeft
Positive YDown
Negative YUp
Positive ZToward viewer
Negative ZAway from viewer

1. translate() — 2D Translation

Moves an element along the X and Y axes.

.translate-single {
    transform: translate(150px);
}

.translate {
    transform: translate(50px, 50px);
}

Syntax

translate(x)        /* X only */
translate(x, y)     /* X and Y */
translate(x, y)     /* Both required if two values */
SyntaxEffect
translate(150px)Move 150px right
translate(50px, 50px)Move 50px right, 50px down
translate(-30px, -20px)Move 30px left, 20px up
translate(50%)Move 50% of element’s width
translate(50%, 50%)Move 50% of width and height

Values

UnitExampleDescription
pxtranslate(50px)Pixels
%translate(50%)Percentage of element size
emtranslate(2em)Relative to font size
remtranslate(2rem)Relative to root font size

Key Points:

  • Percentages are relative to the element’s own size, not the parent
  • translate(50%, 50%) moves the element by 50% of its own width/height
  • Can mix units: translate(50px, 25%)
  • Translation doesn’t affect layout — other elements stay in place

2. translate3d() — 3D Translation

Moves an element along the X, Y, and Z axes.

.translate-3d {
    transform: translate3d(50px, 50px, 100px);
}

Syntax

translate3d(x, y, z)
ValueAxisDescription
xXHorizontal movement
yYVertical movement
zZDepth movement (toward/away from viewer)

Key Points:

  • translateZ() requires perspective on the parent to be visible
  • Positive Z moves toward the viewer; negative Z moves away
  • Use with transform-style: preserve-3d for 3D children

3. translateX(), translateY(), translateZ()

Individual axis translation functions.

.translate-x {
    transform: translateX(50px);
}

.translate-y {
    transform: translateY(30px);
}

.translate-z {
    transform: translateZ(100px);
}
FunctionAxisEquivalent
translateX(50px)Horizontaltranslate(50px, 0)
translateY(30px)Verticaltranslate(0, 30px)
translateZ(100px)Depthtranslate3d(0, 0, 100px)

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>transform translate() and translate3d()</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DEMO AREA ====== */
        .demo-area {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            justify-content: center;
            align-items: center;
            padding: 50px 20px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 250px;
        }

        .demo-area.perspective {
            perspective: 800px;
        }

        .box {
            width: 100px;
            height: 100px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.8rem;
            border-radius: 8px;
            transition: transform 0.5s;
            cursor: pointer;
            text-align: center;
            padding: 5px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
        }

        .box:hover {
            box-shadow: 0 8px 25px rgba(0, 123, 255, 0.4);
        }

        /* Translate demos */
        .translate-single {
            transform: translate(150px);
        }

        .translate-single:hover {
            transform: translate(0);
        }

        .translate {
            transform: translate(50px, 50px);
        }

        .translate:hover {
            transform: translate(0, 0);
        }

        .translate-neg {
            transform: translate(-30px, -20px);
        }

        .translate-neg:hover {
            transform: translate(0, 0);
        }

        .translate-percent {
            transform: translate(50%, 50%);
        }

        .translate-percent:hover {
            transform: translate(0, 0);
        }

        /* Translate3d demos */
        .translate-3d {
            transform: translate3d(50px, 50px, 100px);
        }

        .translate-3d:hover {
            transform: translate3d(0, 0, 0);
        }

        .translate-z {
            transform: translateZ(100px);
        }

        .translate-z:hover {
            transform: translateZ(0);
        }

        /* ====== TRANSLATE COMPARISON ====== */
        .translate-comparison {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 20px;
            margin: 20px 0;
        }

        .translate-item {
            text-align: center;
            padding: 15px;
            background: #f8f9fa;
            border-radius: 8px;
            border: 2px solid #ddd;
            transition: all 0.3s;
        }

        .translate-item:hover {
            border-color: #007bff;
            box-shadow: 0 4px 15px rgba(0, 123, 255, 0.15);
        }

        .translate-item .demo-box {
            width: 60px;
            height: 60px;
            margin: 0 auto 10px;
            background: linear-gradient(135deg, #28a745, #20c997);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 0.7rem;
            font-weight: bold;
            transition: transform 0.3s;
        }

        .translate-item .label {
            font-weight: bold;
            font-size: 0.85rem;
            color: #007bff;
        }

        /* ====== AXIS VISUALIZATION ====== */
        .axis-viz {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            justify-content: center;
            margin: 20px 0;
        }

        .axis-card {
            text-align: center;
            padding: 20px;
            background: white;
            border: 2px solid #ddd;
            border-radius: 12px;
            width: 180px;
            transition: all 0.3s;
        }

        .axis-card:hover {
            border-color: #007bff;
            box-shadow: 0 4px 15px rgba(0, 123, 255, 0.15);
        }

        .axis-card .axis-icon {
            font-size: 2.5rem;
            margin-bottom: 10px;
        }

        .axis-card h4 {
            margin: 5px 0;
            color: #007bff;
        }

        .axis-card p {
            font-size: 0.85rem;
            color: #6c757d;
            margin: 5px 0;
        }

        .axis-card code {
            background: #e9ecef;
            padding: 2px 6px;
            border-radius: 4px;
            font-family: 'Courier New', monospace;
            font-size: 0.8rem;
            color: #dc3545;
        }

        /* ====== PRACTICAL: CENTERING ====== */
        .center-container {
            position: relative;
            height: 250px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
        }

        .centered-box {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 150px;
            height: 100px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            border-radius: 8px;
            box-shadow: 0 4px 15px rgba(0, 123, 255, 0.3);
        }

        /* ====== PRACTICAL: BUTTON LIFT ====== */
        .btn-lift {
            padding: 15px 30px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 1em;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
            margin: 5px;
        }

        .btn-lift:hover {
            transform: translateY(-4px);
            background: #0056b3;
            box-shadow: 0 10px 25px rgba(0, 123, 255, 0.3);
        }

        .btn-lift:active {
            transform: translateY(-1px);
        }

        /* ====== PRACTICAL: TOOLTIP ====== */
        .tooltip-container {
            position: relative;
            display: inline-block;
            margin: 40px 20px;
        }

        .tooltip-trigger {
            padding: 10px 20px;
            background: #6c5ce7;
            color: white;
            border: none;
            border-radius: 8px;
            font-weight: bold;
            cursor: pointer;
        }

        .tooltip-text {
            position: absolute;
            bottom: 100%;
            left: 50%;
            transform: translateX(-50%) translateY(-10px);
            background: #333;
            color: white;
            padding: 8px 15px;
            border-radius: 6px;
            font-size: 0.85rem;
            white-space: nowrap;
            opacity: 0;
            visibility: hidden;
            transition: all 0.3s;
        }

        .tooltip-text::after {
            content: "";
            position: absolute;
            top: 100%;
            left: 50%;
            transform: translateX(-50%);
            border: 6px solid transparent;
            border-top-color: #333;
        }

        .tooltip-container:hover .tooltip-text {
            opacity: 1;
            visibility: visible;
            transform: translateX(-50%) translateY(-5px);
        }

        /* ====== PRACTICAL: 3D CUBE ====== */
        .cube-scene {
            width: 150px;
            height: 150px;
            perspective: 800px;
            margin: 30px auto;
        }

        .cube {
            width: 100%;
            height: 100%;
            position: relative;
            transform-style: preserve-3d;
            animation: rotateCube 8s infinite linear;
        }

        @keyframes rotateCube {
            from { transform: rotateX(0) rotateY(0); }
            to { transform: rotateX(360deg) rotateY(360deg); }
        }

        .cube .face {
            position: absolute;
            width: 150px;
            height: 150px;
            border: 2px solid rgba(0, 0, 0, 0.3);
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            color: white;
            font-size: 0.9rem;
            text-shadow: 0 2px 5px rgba(0,0,0,0.5);
            border-radius: 8px;
        }

        .cube .front {
            background: rgba(255, 0, 0, 0.8);
            transform: translateZ(75px);
        }

        .cube .back {
            background: rgba(0, 255, 0, 0.8);
            transform: rotateY(180deg) translateZ(75px);
        }

        .cube .right {
            background: rgba(0, 0, 255, 0.8);
            transform: rotateY(90deg) translateZ(75px);
        }

        .cube .left {
            background: rgba(255, 255, 0, 0.8);
            transform: rotateY(-90deg) translateZ(75px);
        }

        .cube .top {
            background: rgba(255, 0, 255, 0.8);
            transform: rotateX(90deg) translateZ(75px);
        }

        .cube .bottom {
            background: rgba(0, 255, 255, 0.8);
            transform: rotateX(-90deg) translateZ(75px);
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            background: #f8f9fa;
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>transform translate() and translate3d()</h1>

    <!-- ====== 1. TRANSLATE() DEMO ====== -->
    <section>
        <h2>1. translate() — 2D Translation</h2>
        <p>Hover over each box to see it return to its original position.</p>

        <div class="demo-area">
            <div class="box">Original</div>
            <div class="box translate-single">translate(150px)</div>
            <div class="box translate">translate(50px, 50px)</div>
            <div class="box translate-neg">translate(-30px, -20px)</div>
            <div class="box translate-percent">translate(50%, 50%)</div>
        </div>

        <div class="code-block">
            /* Move 150px right */
            .translate-single {
                transform: translate(150px);
            }

            /* Move 50px right and down */
            .translate {
                transform: translate(50px, 50px);
            }

            /* Move 30px left and 20px up */
            .translate-neg {
                transform: translate(-30px, -20px);
            }

            /* Move 50% of its own width and height */
            .translate-percent {
                transform: translate(50%, 50%);
            }
        </div>
    </section>

    <!-- ====== 2. TRANSLATE3D() DEMO ====== -->
    <section>
        <h2>2. translate3d() — 3D Translation</h2>
        <p>Moves elements in 3D space. Requires <code>perspective</code> on the parent.</p>

        <div class="demo-area perspective">
            <div class="box">Original</div>
            <div class="box translate-3d">translate3d<br>(50, 50, 100)</div>
            <div class="box translate-z">translateZ(100px)</div>
        </div>

        <div class="code-block">
            /* Move in 3D space */
            .translate-3d {
                transform: translate3d(50px, 50px, 100px);
            }

            /* Move only in depth (toward viewer) */
            .translate-z {
                transform: translateZ(100px);
            }
        </div>

        <p class="note">Positive Z moves the element <strong>toward</strong> the viewer; negative Z moves it <strong>away</strong>.</p>
    </section>

    <!-- ====== 3. AXIS VISUALIZATION ====== -->
    <section>
        <h2>3. Understanding the Axes</h2>

        <div class="axis-viz">
            <div class="axis-card">
                <div class="axis-icon">↔️</div>
                <h4>translateX()</h4>
                <p>Horizontal movement</p>
                <code>translateX(50px)</code>
                <p class="note">Positive = right<br>Negative = left</p>
            </div>
            <div class="axis-card">
                <div class="axis-icon">↕️</div>
                <h4>translateY()</h4>
                <p>Vertical movement</p>
                <code>translateY(30px)</code>
                <p class="note">Positive = down<br>Negative = up</p>
            </div>
            <div class="axis-card">
                <div class="axis-icon">🔍</div>
                <h4>translateZ()</h4>
                <p>Depth movement</p>
                <code>translateZ(100px)</code>
                <p class="note">Positive = toward viewer<br>Negative = away</p>
            </div>
        </div>

        <div class="code-block">
            /* These are equivalent */
            translateX(50px) = translate(50px, 0) = translate3d(50px, 0, 0)
            translateY(30px) = translate(0, 30px) = translate3d(0, 30px, 0)
            translateZ(100px) = translate3d(0, 0, 100px)
        </div>
    </section>

    <!-- ====== 4. TRANSLATE COMPARISON ====== -->
    <section>
        <h2>4. Translation Comparison</h2>

        <div class="translate-comparison">
            <div class="translate-item">
                <div class="demo-box" style="transform: translate(0);">0</div>
                <div class="label">translate(0)</div>
                <p class="note">Original position</p>
            </div>
            <div class="translate-item">
                <div class="demo-box" style="transform: translate(20px);">20px</div>
                <div class="label">translate(20px)</div>
                <p class="note">Move right</p>
            </div>
            <div class="translate-item">
                <div class="demo-box" style="transform: translate(0, 20px);">Y</div>
                <div class="label">translateY(20px)</div>
                <p class="note">Move down</p>
            </div>
            <div class="translate-item">
                <div class="demo-box" style="transform: translate(20px, 20px);">XY</div>
                <div class="label">translate(20px, 20px)</div>
                <p class="note">Move diagonally</p>
            </div>
            <div class="translate-item">
                <div class="demo-box" style="transform: translate(-20px, -20px);">-XY</div>
                <div class="label">translate(-20px, -20px)</div>
                <p class="note">Move up-left</p>
            </div>
        </div>

        <div class="code-block">
            transform: translate(0);             /* No movement */
            transform: translate(20px);          /* Move right */
            transform: translate(0, 20px);       /* Move down */
            transform: translate(20px, 20px);    /* Move diagonally */
            transform: translate(-20px, -20px);  /* Move up-left */
        </div>
    </section>

    <!-- ====== 5. PRACTICAL: PERFECT CENTERING ====== -->
    <section>
        <h2>5. Practical Example: Perfect Centering</h2>
        <p>The classic trick: <code>top: 50%; left: 50%; transform: translate(-50%, -50%);</code></p>

        <div class="center-container">
            <div class="centered-box">
                Perfectly Centered
            </div>
        </div>

        <div class="code-block">
            .centered-box {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                /* Move back by half its own width and height */
            }
        </div>

        <p class="note">This works because percentages in <code>translate()</code> are relative to the <strong>element's own size</strong>.</p>
    </section>

    <!-- ====== 6. PRACTICAL: BUTTON LIFT ====== -->
    <section>
        <h2>6. Practical Example: Button Lift</h2>
        <p>Hover and click the buttons to see the translate effect.</p>

        <div style="text-align: center; margin: 15px 0;">
            <button class="btn-lift">Hover Me</button>
            <button class="btn-lift">Click Me</button>
            <button class="btn-lift">Press Me</button>
        </div>

        <div class="code-block">
            .btn-lift {
                transition: all 0.3s;
            }

            .btn-lift:hover {
                transform: translateY(-4px); /* Lift up */
            }

            .btn-lift:active {
                transform: translateY(-1px); /* Press down slightly */
            }
        </div>
    </section>

    <!-- ====== 7. PRACTICAL: TOOLTIP ====== -->
    <section>
        <h2>7. Practical Example: Tooltip</h2>
        <p>Hover over the button to see a tooltip positioned with <code>translate()</code>.</p>

        <div style="text-align: center;">
            <div class="tooltip-container">
                <button class="tooltip-trigger">Hover Me</button>
                <div class="tooltip-text">I'm a tooltip!</div>
            </div>
        </div>

        <div class="code-block">
            .tooltip-text {
                position: absolute;
                bottom: 100%;
                left: 50%;
                transform: translateX(-50%); /* Center horizontally */
            }

            .tooltip-container:hover .tooltip-text {
                transform: translateX(-50%) translateY(-5px); /* Animate up */
            }
        </div>
    </section>

    <!-- ====== 8. PRACTICAL: 3D CUBE ====== -->
    <section>
        <h2>8. Practical Example: 3D Cube with translateZ()</h2>
        <p>A 3D cube built with <code>translateZ()</code> to position each face.</p>

        <div class="cube-scene">
            <div class="cube">
                <div class="face front">Front</div>
                <div class="face back">Back</div>
                <div class="face right">Right</div>
                <div class="face left">Left</div>
                <div class="face top">Top</div>
                <div class="face bottom">Bottom</div>
            </div>
        </div>

        <div class="code-block">
            .cube {
                transform-style: preserve-3d;
            }

            /* Each face positioned with translateZ */
            .front {
                transform: translateZ(75px);
            }
            .back {
                transform: rotateY(180deg) translateZ(75px);
            }
            .right {
                transform: rotateY(90deg) translateZ(75px);
            }
            .left {
                transform: rotateY(-90deg) translateZ(75px);
            }
            .top {
                transform: rotateX(90deg) translateZ(75px);
            }
            .bottom {
                transform: rotateX(-90deg) translateZ(75px);
            }
        </div>
    </section>

    <!-- ====== 9. REFERENCE TABLES ====== -->
    <section>
        <h2>9. Reference Tables</h2>

        <h3>Translate Functions</h3>
        <table class="reference-table">
            <tr>
                <th>Function</th>
                <th>Axes</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>translate()</code></td>
                <td>X, Y</td>
                <td><code>translate(50px, 30px)</code></td>
            </tr>
            <tr>
                <td><code>translate3d()</code></td>
                <td>X, Y, Z</td>
                <td><code>translate3d(50px, 30px, 100px)</code></td>
            </tr>
            <tr>
                <td><code>translateX()</code></td>
                <td>X</td>
                <td><code>translateX(50px)</code></td>
            </tr>
            <tr>
                <td><code>translateY()</code></td>
                <td>Y</td>
                <td><code>translateY(30px)</code></td>
            </tr>
            <tr>
                <td><code>translateZ()</code></td>
                <td>Z</td>
                <td><code>translateZ(100px)</code></td>
            </tr>
        </table>

        <h3>Values</h3>
        <table class="reference-table">
            <tr>
                <th>Unit</th>
                <th>Relative To</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>px</code></td>
                <td>Absolute pixels</td>
                <td><code>translate(50px)</code></td>
            </tr>
            <tr>
                <td><code>%</code></td>
                <td>Element's own size</td>
                <td><code>translate(50%)</code></td>
            </tr>
            <tr>
                <td><code>em</code></td>
                <td>Font size</td>
                <td><code>translate(2em)</code></td>
            </tr>
            <tr>
                <td><code>rem</code></td>
                <td>Root font size</td>
                <td><code>translate(2rem)</code></td>
            </tr>
        </table>

        <h3>Direction Reference</h3>
        <table class="reference-table">
            <tr>
                <th>Direction</th>
                <th>X</th>
                <th>Y</th>
                <th>Z</th>
            </tr>
            <tr>
                <td>Right</td>
                <td>Positive</td>
                <td>—</td>
                <td>—</td>
            </tr>
            <tr>
                <td>Left</td>
                <td>Negative</td>
                <td>—</td>
                <td>—</td>
            </tr>
            <tr>
                <td>Down</td>
                <td>—</td>
                <td>Positive</td>
                <td>—</td>
            </tr>
            <tr>
                <td>Up</td>
                <td>—</td>
                <td>Negative</td>
                <td>—</td>
            </tr>
            <tr>
                <td>Toward viewer</td>
                <td>—</td>
                <td>—</td>
                <td>Positive</td>
            </tr>
            <tr>
                <td>Away from viewer</td>
                <td>—</td>
                <td>—</td>
                <td>Negative</td>
            </tr>
        </table>
    </section>

    <!-- ====== 10. BEST PRACTICES ====== -->
    <section>
        <h2>10. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>translate()</code> for animations instead of <code>top</code>/<code>left</code> (better performance)</li>
                <li>Use <code>translate(-50%, -50%)</code> for perfect centering</li>
                <li>Use <code>translateY()</code> for button lift effects</li>
                <li>Use <code>translateX()</code> for sliding menus and carousels</li>
                <li>Use <code>translateZ()</code> with perspective for 3D effects</li>
                <li>Combine with other transforms for complex animations</li>
                <li>Respect <code>prefers-reduced-motion</code> for accessibility</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't animate <code>top</code>/<code>left</code> when <code>translate()</code> works better</li>
                <li>Don't use <code>translateZ()</code> without <code>perspective</code> on the parent</li>
                <li>Don't forget that percentages in <code>translate()</code> are relative to the element's own size</li>
                <li>Don't use <code>translate()</code> for layout — use it for effects</li>
                <li>Don't translate elements so far they go off-screen</li>
            </ul>
        </div>

        <div class="code-block">
            /* Accessibility: respect reduced motion */
            @media (prefers-reduced-motion: reduce) {
                .btn-lift:hover {
                    transform: none;
                }
            }

            /* Prefer translate over top/left for animations */
            .box {
                transition: transform 0.3s;
            }
            .box:hover {
                transform: translateY(-5px); /* Better performance */
            }
        </div>
    </section>

</body>
</html>

Quick Reference

FunctionAxesExample
translate()X, Ytranslate(50px, 30px)
translate3d()X, Y, Ztranslate3d(50px, 30px, 100px)
translateX()XtranslateX(50px)
translateY()YtranslateY(30px)
translateZ()ZtranslateZ(100px)

Values

UnitRelative ToExample
pxAbsolute pixelstranslate(50px)
%Element’s own sizetranslate(50%)
emFont sizetranslate(2em)
remRoot font sizetranslate(2rem)

Direction Reference

DirectionXYZ
RightPositive
LeftNegative
DownPositive
UpNegative
Toward viewerPositive
Away from viewerNegative

Best Practices

Do This:

/* Perfect centering */
.centered {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

/* Button lift */
.btn:hover {
    transform: translateY(-4px);
}

/* Prefer translate over top/left for animations */
.box {
    transition: transform 0.3s;
}
.box:hover {
    transform: translateX(10px);
}

/* 3D depth */
.scene {
    perspective: 800px;
}
.box {
    transform: translateZ(100px);
}

Don’t Do This:

/* Don't animate top/left (worse performance) */
.box:hover {
    top: -5px;
    transition: top 0.3s;
}

/* Don't use translateZ without perspective */
.box {
    transform: translateZ(100px); /* Won't be visible */
}

/* Don't translate elements off-screen */
.box {
    transform: translate(5000px, 0); /* Lost forever */
}

Pro Tip: translate() is one of the most useful transforms — use it for animations instead of top/left for better performance (it’s hardware-accelerated). The classic translate(-50%, -50%) trick is essential for perfect centering. Use translateY(-4px) for button lift effects and translateX() for sliding menus. Remember: percentages in translate() are relative to the element’s own size, not the parent — that’s what makes the centering trick work! And always respect prefers-reduced-motion for accessibility!

53. Transitions

CSS transitions let you smoothly animate changes to CSS properties over a specified duration. They add polish, interactivity, and visual appeal — turning abrupt state changes into fluid motion.


What is a Transition?

A transition defines how a CSS property changes from one state to another over time. Instead of instantly jumping from red to blue, the color gradually shifts over the specified duration.

Key Benefits

BenefitDescription
Smooth animationsGradual changes instead of instant jumps
InteractivityResponds to hover, focus, and active states
PerformanceHardware-accelerated for transform and opacity
SimplicityPure CSS — no JavaScript required
CustomizableControl duration, timing, and delay

The Four Transition Properties

The transition shorthand combines four individual properties:

PropertyDescriptionDefault
transition-propertyWhich property to animateall
transition-durationHow long the transition takes0s
transition-timing-functionSpeed curve of the transitionease
transition-delayWait before starting0s

1. transition-property

Specifies which CSS property should transition.

.box {
    transition-property: background-color, transform;
}
ValueDescription
noneNo property transitions
allAll animatable properties transition
property-nameSpecific property (e.g., background-color)
MultipleComma-separated list

Best practice: Specify individual properties rather than all for better performance.


2. transition-duration

Specifies how long the transition takes.

.box {
    transition-duration: 0.5s;
}
ValueDescription
0sNo transition (instant)
0.5sHalf a second
1sOne second
500ms500 milliseconds (same as 0.5s)

Note: If duration is 0s, the transition is instant — no animation occurs.


3. transition-timing-function

Specifies the speed curve of the transition.

.box {
    transition-timing-function: ease-in-out;
}
ValueDescription
easeSlow start, fast middle, slow end (default)
linearConstant speed
ease-inSlow start, fast end
ease-outFast start, slow end
ease-in-outSlow start, fast middle, slow end
cubic-bezier(n,n,n,n)Custom curve
steps(n)Stepped animation

4. transition-delay

Specifies how long to wait before starting the transition.

.box {
    transition-delay: 0.2s;
}
ValueDescription
0sStart immediately (default)
0.2sWait 200ms before starting
1sWait 1 second

The transition Shorthand

/* Syntax */
transition: <property> <duration> <timing-function> <delay>;

/* Examples */
transition: background-color 0.5s ease;           /* property, duration, timing */
transition: transform 0.3s ease-in-out 0.1s;      /* all four values */
transition: background-color 0.5s, transform 0.3s; /* multiple properties */
transition: all 0.3s ease;                         /* all properties */

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS Transitions</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DEMO AREA ====== */
        .demo-area {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            justify-content: center;
            align-items: center;
            padding: 40px 20px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 200px;
        }

        .box {
            width: 120px;
            height: 120px;
            background: #007bff;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.85rem;
            border-radius: 12px;
            cursor: pointer;
            text-align: center;
            padding: 10px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
        }

        /* ====== BASIC TRANSITION ====== */
        .transition-box {
            width: 150px;
            height: 150px;
            background-color: #dc3545;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            border-radius: 12px;
            transition: background-color 0.5s ease, transform 0.3s ease;
            cursor: pointer;
            text-align: center;
            padding: 10px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
        }

        .transition-box:hover {
            background-color: #007bff;
            transform: scale(1.2);
        }

        /* ====== TIMING FUNCTIONS ====== */
        .timing-ease {
            transition: transform 1s ease;
        }
        .timing-ease:hover {
            transform: translateX(100px);
        }

        .timing-linear {
            transition: transform 1s linear;
        }
        .timing-linear:hover {
            transform: translateX(100px);
        }

        .timing-ease-in {
            transition: transform 1s ease-in;
        }
        .timing-ease-in:hover {
            transform: translateX(100px);
        }

        .timing-ease-out {
            transition: transform 1s ease-out;
        }
        .timing-ease-out:hover {
            transform: translateX(100px);
        }

        .timing-ease-in-out {
            transition: transform 1s ease-in-out;
        }
        .timing-ease-in-out:hover {
            transform: translateX(100px);
        }

        .timing-custom {
            transition: transform 1s cubic-bezier(0, 1, 1, 0);
        }
        .timing-custom:hover {
            transform: translateX(100px);
        }

        /* ====== DURATION COMPARISON ====== */
        .duration-fast {
            transition: transform 0.2s ease;
        }
        .duration-fast:hover {
            transform: scale(1.3);
        }

        .duration-medium {
            transition: transform 0.5s ease;
        }
        .duration-medium:hover {
            transform: scale(1.3);
        }

        .duration-slow {
            transition: transform 1.5s ease;
        }
        .duration-slow:hover {
            transform: scale(1.3);
        }

        /* ====== DELAY COMPARISON ====== */
        .delay-none {
            transition: transform 0.5s ease 0s;
        }
        .delay-none:hover {
            transform: translateY(-30px);
        }

        .delay-short {
            transition: transform 0.5s ease 0.2s;
        }
        .delay-short:hover {
            transform: translateY(-30px);
        }

        .delay-long {
            transition: transform 0.5s ease 0.5s;
        }
        .delay-long:hover {
            transform: translateY(-30px);
        }

        /* ====== MULTIPLE PROPERTIES ====== */
        .multi-transition {
            transition: 
                background-color 0.5s ease,
                transform 0.3s ease,
                border-radius 0.4s ease,
                box-shadow 0.5s ease;
        }

        .multi-transition:hover {
            background-color: #28a745;
            transform: rotate(10deg) scale(1.1);
            border-radius: 50%;
            box-shadow: 0 10px 30px rgba(40, 167, 69, 0.4);
        }

        /* ====== PRACTICAL: BUTTON ====== */
        .btn-transition {
            padding: 15px 35px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 1em;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            margin: 5px;
        }

        .btn-transition:hover {
            background: #28a745;
            transform: translateY(-3px);
            box-shadow: 0 8px 20px rgba(40, 167, 69, 0.3);
        }

        .btn-transition:active {
            transform: translateY(-1px);
            box-shadow: 0 4px 10px rgba(40, 167, 69, 0.2);
        }

        /* ====== PRACTICAL: CARD ====== */
        .card-transition {
            background: white;
            border: 2px solid #ddd;
            border-radius: 12px;
            padding: 25px;
            max-width: 300px;
            margin: 15px auto;
            transition: all 0.3s ease;
            cursor: pointer;
            text-align: center;
        }

        .card-transition:hover {
            transform: translateY(-8px);
            border-color: #007bff;
            box-shadow: 0 15px 35px rgba(0, 123, 255, 0.15);
        }

        .card-transition h4 {
            margin-top: 0;
            color: #007bff;
            transition: color 0.3s ease;
        }

        .card-transition:hover h4 {
            color: #28a745;
        }

        /* ====== PRACTICAL: TOGGLE SWITCH ====== */
        .toggle-switch {
            position: relative;
            width: 70px;
            height: 36px;
            background: #ccc;
            border-radius: 18px;
            cursor: pointer;
            transition: background 0.3s ease;
            margin: 20px auto;
        }

        .toggle-switch::after {
            content: "";
            position: absolute;
            top: 3px;
            left: 3px;
            width: 30px;
            height: 30px;
            background: white;
            border-radius: 50%;
            transition: transform 0.3s ease, background 0.3s ease;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
        }

        .toggle-switch:hover {
            background: #28a745;
        }

        .toggle-switch:hover::after {
            transform: translateX(34px);
            background: #fff;
        }

        /* ====== PRACTICAL: FADE-IN ====== */
        .fade-container {
            display: flex;
            gap: 20px;
            justify-content: center;
            flex-wrap: wrap;
            margin: 15px 0;
        }

        .fade-box {
            width: 100px;
            height: 100px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.8rem;
            opacity: 0.3;
            transition: opacity 0.5s ease, transform 0.5s ease;
            cursor: pointer;
        }

        .fade-box:hover {
            opacity: 1;
            transform: translateY(-10px);
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            background: #f8f9fa;
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>CSS Transitions</h1>

    <!-- ====== 1. BASIC TRANSITION ====== -->
    <section>
        <h2>1. Basic Transition</h2>
        <p>Hover over the box to see the smooth transition.</p>

        <div class="demo-area">
            <div class="transition-box">Hover Over Me!</div>
        </div>

        <div class="code-block">
            .transition-box {
                transition: background-color 0.5s ease, transform 0.3s ease;
            }

            .transition-box:hover {
                background-color: #007bff;
                transform: scale(1.2);
            }
        </div>
    </section>

    <!-- ====== 2. TIMING FUNCTIONS ====== -->
    <section>
        <h2>2. Timing Functions</h2>
        <p>Each box uses a different timing function. Hover to compare the motion.</p>

        <div class="demo-area" style="flex-direction: column; gap: 15px;">
            <div class="box timing-ease" style="width: 200px; height: 60px;">ease (default)</div>
            <div class="box timing-linear" style="width: 200px; height: 60px; background: #28a745;">linear</div>
            <div class="box timing-ease-in" style="width: 200px; height: 60px; background: #dc3545;">ease-in</div>
            <div class="box timing-ease-out" style="width: 200px; height: 60px; background: #ffc107; color: #333;">ease-out</div>
            <div class="box timing-ease-in-out" style="width: 200px; height: 60px; background: #6c5ce7;">ease-in-out</div>
            <div class="box timing-custom" style="width: 200px; height: 60px; background: #17a2b8;">cubic-bezier(0,1,1,0)</div>
        </div>

        <div class="code-block">
            .timing-ease        { transition: transform 1s ease; }
            .timing-linear      { transition: transform 1s linear; }
            .timing-ease-in     { transition: transform 1s ease-in; }
            .timing-ease-out    { transition: transform 1s ease-out; }
            .timing-ease-in-out { transition: transform 1s ease-in-out; }
            .timing-custom      { transition: transform 1s cubic-bezier(0, 1, 1, 0); }
        </div>
    </section>

    <!-- ====== 3. DURATION COMPARISON ====== -->
    <section>
        <h2>3. Duration Comparison</h2>
        <p>Each box uses a different duration. Hover to compare the speed.</p>

        <div class="demo-area">
            <div class="box duration-fast" style="background: #28a745;">0.2s</div>
            <div class="box duration-medium" style="background: #ffc107; color: #333;">0.5s</div>
            <div class="box duration-slow" style="background: #dc3545;">1.5s</div>
        </div>

        <div class="code-block">
            .duration-fast   { transition: transform 0.2s ease; }
            .duration-medium { transition: transform 0.5s ease; }
            .duration-slow   { transition: transform 1.5s ease; }
        </div>
    </section>

    <!-- ====== 4. DELAY COMPARISON ====== -->
    <section>
        <h2>4. Delay Comparison</h2>
        <p>Each box has a different delay before the transition starts.</p>

        <div class="demo-area">
            <div class="box delay-none" style="background: #007bff;">0s delay</div>
            <div class="box delay-short" style="background: #28a745;">0.2s delay</div>
            <div class="box delay-long" style="background: #dc3545;">0.5s delay</div>
        </div>

        <div class="code-block">
            .delay-none  { transition: transform 0.5s ease 0s; }
            .delay-short { transition: transform 0.5s ease 0.2s; }
            .delay-long  { transition: transform 0.5s ease 0.5s; }
        </div>
    </section>

    <!-- ====== 5. MULTIPLE PROPERTIES ====== -->
    <section>
        <h2>5. Multiple Properties</h2>
        <p>This box transitions multiple properties at once — background, transform, border-radius, and shadow.</p>

        <div class="demo-area">
            <div class="box multi-transition">Hover Me</div>
        </div>

        <div class="code-block">
            .multi-transition {
                transition: 
                    background-color 0.5s ease,
                    transform 0.3s ease,
                    border-radius 0.4s ease,
                    box-shadow 0.5s ease;
            }

            .multi-transition:hover {
                background-color: #28a745;
                transform: rotate(10deg) scale(1.1);
                border-radius: 50%;
                box-shadow: 0 10px 30px rgba(40, 167, 69, 0.4);
            }
        </div>
    </section>

    <!-- ====== 6. PRACTICAL: BUTTON ====== -->
    <section>
        <h2>6. Practical Example: Button</h2>
        <p>Hover and click the buttons to see the transition effects.</p>

        <div style="text-align: center; margin: 15px 0;">
            <button class="btn-transition">Hover Me</button>
            <button class="btn-transition">Click Me</button>
            <button class="btn-transition">Press Me</button>
        </div>

        <div class="code-block">
            .btn-transition {
                transition: all 0.3s ease;
            }

            .btn-transition:hover {
                background: #28a745;
                transform: translateY(-3px);
                box-shadow: 0 8px 20px rgba(40, 167, 69, 0.3);
            }

            .btn-transition:active {
                transform: translateY(-1px);
                box-shadow: 0 4px 10px rgba(40, 167, 69, 0.2);
            }
        </div>
    </section>

    <!-- ====== 7. PRACTICAL: CARD ====== -->
    <section>
        <h2>7. Practical Example: Card</h2>
        <p>Hover over the card to see the lift and shadow transition.</p>

        <div class="card-transition">
            <h4>Interactive Card</h4>
            <p>Hover over this card to see the transition effect. The border color, shadow, and position all transition smoothly.</p>
        </div>

        <div class="code-block">
            .card-transition {
                transition: all 0.3s ease;
            }

            .card-transition:hover {
                transform: translateY(-8px);
                border-color: #007bff;
                box-shadow: 0 15px 35px rgba(0, 123, 255, 0.15);
            }

            .card-transition h4 {
                transition: color 0.3s ease;
            }

            .card-transition:hover h4 {
                color: #28a745;
            }
        </div>
    </section>

    <!-- ====== 8. PRACTICAL: TOGGLE SWITCH ====== -->
    <section>
        <h2>8. Practical Example: Toggle Switch</h2>
        <p>Hover over the switch to see the transition effect.</p>

        <div style="text-align: center;">
            <div class="toggle-switch"></div>
        </div>

        <div class="code-block">
            .toggle-switch {
                transition: background 0.3s ease;
            }

            .toggle-switch::after {
                transition: transform 0.3s ease, background 0.3s ease;
            }

            .toggle-switch:hover {
                background: #28a745;
            }

            .toggle-switch:hover::after {
                transform: translateX(34px);
            }
        </div>
    </section>

    <!-- ====== 9. PRACTICAL: FADE-IN ====== -->
    <section>
        <h2>9. Practical Example: Fade-In</h2>
        <p>Hover over each box to see it fade in and lift up.</p>

        <div class="fade-container">
            <div class="fade-box">Fade 1</div>
            <div class="fade-box">Fade 2</div>
            <div class="fade-box">Fade 3</div>
            <div class="fade-box">Fade 4</div>
        </div>

        <div class="code-block">
            .fade-box {
                opacity: 0.3;
                transition: opacity 0.5s ease, transform 0.5s ease;
            }

            .fade-box:hover {
                opacity: 1;
                transform: translateY(-10px);
            }
        </div>
    </section>

    <!-- ====== 10. REFERENCE TABLES ====== -->
    <section>
        <h2>10. Reference Tables</h2>

        <h3>Transition Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Default</th>
            </tr>
            <tr>
                <td><code>transition-property</code></td>
                <td>Which property to animate</td>
                <td><code>all</code></td>
            </tr>
            <tr>
                <td><code>transition-duration</code></td>
                <td>How long the transition takes</td>
                <td><code>0s</code></td>
            </tr>
            <tr>
                <td><code>transition-timing-function</code></td>
                <td>Speed curve</td>
                <td><code>ease</code></td>
            </tr>
            <tr>
                <td><code>transition-delay</code></td>
                <td>Wait before starting</td>
                <td><code>0s</code></td>
            </tr>
        </table>

        <h3>Timing Functions</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>ease</code></td>
                <td>Slow start, fast middle, slow end (default)</td>
            </tr>
            <tr>
                <td><code>linear</code></td>
                <td>Constant speed</td>
            </tr>
            <tr>
                <td><code>ease-in</code></td>
                <td>Slow start, fast end</td>
            </tr>
            <tr>
                <td><code>ease-out</code></td>
                <td>Fast start, slow end</td>
            </tr>
            <tr>
                <td><code>ease-in-out</code></td>
                <td>Slow start, fast middle, slow end</td>
            </tr>
            <tr>
                <td><code>cubic-bezier(n,n,n,n)</code></td>
                <td>Custom speed curve</td>
            </tr>
            <tr>
                <td><code>steps(n)</code></td>
                <td>Stepped animation</td>
            </tr>
        </table>

        <h3>Common Transition Examples</h3>
        <table class="reference-table">
            <tr>
                <th>Example</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>transition: all 0.3s ease;</code></td>
                <td>All properties, 0.3s, ease</td>
            </tr>
            <tr>
                <td><code>transition: background-color 0.5s;</code></td>
                <td>Background only, 0.5s</td>
            </tr>
            <tr>
                <td><code>transition: transform 0.3s ease-in-out 0.1s;</code></td>
                <td>Transform, 0.3s, custom timing, 0.1s delay</td>
            </tr>
            <tr>
                <td><code>transition: background-color 0.5s, transform 0.3s;</code></td>
                <td>Multiple properties with different durations</td>
            </tr>
        </table>

        <h3>Animatable Properties (Common)</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Notes</th>
            </tr>
            <tr>
                <td><code>opacity</code></td>
                <td>Hardware-accelerated, very smooth</td>
            </tr>
            <tr>
                <td><code>transform</code></td>
                <td>Hardware-accelerated, very smooth</td>
            </tr>
            <tr>
                <td><code>background-color</code></td>
                <td>Commonly used, works well</td>
            </tr>
            <tr>
                <td><code>color</code></td>
                <td>Works well for text</td>
            </tr>
            <tr>
                <td><code>box-shadow</code></td>
                <td>Can be expensive on large elements</td>
            </tr>
            <tr>
                <td><code>border-radius</code></td>
                <td>Works well</td>
            </tr>
            <tr>
                <td><code>width</code>/<code>height</code></td>
                <td>Can cause layout recalculation</td>
            </tr>
        </table>
    </section>

    <!-- ====== 11. BEST PRACTICES ====== -->
    <section>
        <h2>11. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>transform</code> and <code>opacity</code> for the smoothest animations (hardware-accelerated)</li>
                <li>Specify individual properties instead of <code>all</code> for better performance</li>
                <li>Use short durations (0.2s–0.5s) for UI feedback</li>
                <li>Use <code>ease</code> or <code>ease-in-out</code> for natural motion</li>
                <li>Add transitions to hover, focus, and active states</li>
                <li>Use <code>transition-delay</code> for staggered animations</li>
                <li>Respect <code>prefers-reduced-motion</code> for accessibility</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't animate <code>width</code>, <code>height</code>, <code>top</code>, or <code>left</code> (causes layout recalculation)</li>
                <li>Don't use long durations (> 1s) for UI feedback</li>
                <li>Don't forget to add <code>transition</code> to the base state (not just hover)</li>
                <li>Don't animate too many properties at once</li>
                <li>Don't use <code>transition: all</code> for everything</li>
                <li>Don't forget about <code>prefers-reduced-motion</code></li>
            </ul>
        </div>

        <div class="code-block">
            /* Accessibility: respect reduced motion */
            @media (prefers-reduced-motion: reduce) {
                .transition-box,
                .btn-transition,
                .card-transition {
                    transition: none;
                }
            }

            /* Better performance: use transform instead of top/left */
            .box {
                transition: transform 0.3s ease;
            }
            .box:hover {
                transform: translateY(-5px); /* Better than top: -5px */
            }
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionDefault
transition-propertyWhich property to animateall
transition-durationHow long the transition takes0s
transition-timing-functionSpeed curveease
transition-delayWait before starting0s

Timing Functions

ValueDescription
easeSlow start, fast middle, slow end (default)
linearConstant speed
ease-inSlow start, fast end
ease-outFast start, slow end
ease-in-outSlow start, fast middle, slow end
cubic-bezier(n,n,n,n)Custom speed curve

Common Transition Examples

ExampleDescription
transition: all 0.3s ease;All properties, 0.3s, ease
transition: background-color 0.5s;Background only, 0.5s
transition: transform 0.3s ease-in-out 0.1s;Transform, 0.3s, custom timing, 0.1s delay
transition: background-color 0.5s, transform 0.3s;Multiple properties

Best Practices

Do This:

/* Smooth hover effect */
.box {
    transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.box:hover {
    transform: translateY(-5px);
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
}

/* Button feedback */
.btn {
    transition: all 0.2s ease;
}
.btn:hover {
    background: #0056b3;
}
.btn:active {
    transform: scale(0.98);
}

/* Staggered animation */
.item:nth-child(1) { transition-delay: 0s; }
.item:nth-child(2) { transition-delay: 0.1s; }
.item:nth-child(3) { transition-delay: 0.2s; }

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    .box {
        transition: none;
    }
}

Don’t Do This:

/* Don't animate layout properties */
.box {
    transition: width 0.3s, height 0.3s; /* Causes layout recalculation */
}

/* Don't forget the base transition */
.box:hover {
    transition: all 0.3s; /* Too late — transition won't work on mouse-out */
}

/* Don't use excessively long durations */
.box {
    transition: all 3s; /* Too slow for UI */
}

/* Don't use transition: all for everything */
.box {
    transition: all 0.5s; /* Can cause unexpected animations */
}

Pro Tip: Transitions are the key to polished, interactive interfaces. Use transform and opacity for the smoothest animations (they’re hardware-accelerated). Keep durations short — 0.2s–0.5s for UI feedback. Always apply the transition to the base state, not just the hover state, so it works on both mouse-in and mouse-out. Use prefers-reduced-motion to respect users who are sensitive to animation. And remember: less is more — a few well-placed transitions are better than animating everything!

54. transition-behavior, transition-delay, transition-duration, and transition-property

These four longhand properties give you precise control over how transitions behave — which properties animate, how long they take, when they start, and how discrete changes are handled.


Overview of Properties

PropertyDescriptionDefault
transition-propertyWhich properties to animateall
transition-durationHow long the transition takes0s
transition-delayWait before starting0s
transition-behaviorHow discrete properties animatenormal
transition-timing-functionSpeed curveease

1. transition-property

Specifies which CSS properties should transition.

.box {
    transition-property: background-color, transform;
}

Values

ValueDescription
noneNo properties transition
allAll animatable properties transition (default)
property-nameSpecific property (e.g., background-color)
MultipleComma-separated list

Best practice: Specify individual properties rather than all for better performance and predictability.


2. transition-duration

Specifies how long the transition takes.

.box {
    transition-duration: 1s, 2s;
}

Values

ValueDescription
0s / 0msNo transition (instant)
0.5sHalf a second
1sOne second
500ms500 milliseconds
MultipleComma-separated list for multiple properties

Key Point: If you specify multiple durations, they map to the properties in transition-property in order.

transition-property: background-color, transform;
transition-duration: 1s, 2s;
/* background-color: 1s, transform: 2s */

3. transition-delay

Specifies how long to wait before starting the transition.

.box {
    transition-delay: 0.5s;
}

Values

ValueDescription
0sStart immediately (default)
0.2sWait 200ms
0.5sWait half a second
1sWait one second
NegativeStarts partway through the transition
MultipleComma-separated list

Negative delay: A negative value starts the transition already partway through.

transition-delay: -0.5s; /* Starts halfway through a 1s transition */

4. transition-behavior

Specifies how discrete properties (like display, visibility) are animated.

.box {
    transition-behavior: allow-discrete;
}

Values

ValueDescription
normalDiscrete properties don’t animate (default)
allow-discreteDiscrete properties can animate

What Are Discrete Properties?

Discrete properties don’t have intermediate values — they jump from one state to another:

PropertyValues
displaynone, block, flex, etc.
visibilityvisible, hidden
positionstatic, relative, absolute
floatleft, right, none

Without allow-discrete: These properties change instantly — no animation.

With allow-discrete: They can be animated when combined with other properties (like opacity and transform).


5. transition-timing-function

Specifies the speed curve of the transition.

.box {
    transition-timing-function: ease-in;
}

Values

ValueDescription
easeSlow start, fast middle, slow end (default)
ease-inSlow start, fast end
ease-outFast start, slow end
ease-in-outSlow start, fast middle, slow end
linearConstant speed
step-startJump to end immediately
step-endStay at start until the end
cubic-bezier(n,n,n,n)Custom curve

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>transition-behavior, delay, duration, and property</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DEMO AREA ====== */
        .demo-area {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            justify-content: center;
            align-items: center;
            padding: 40px 20px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 200px;
        }

        /* ====== TRANSITION-PROPERTY DEMO ====== */
        .property-demo {
            width: 120px;
            height: 120px;
            background: #3498db;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.8rem;
            border-radius: 12px;
            cursor: pointer;
            text-align: center;
            padding: 10px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
        }

        .property-bg-only {
            transition-property: background-color;
            transition-duration: 0.5s;
            transition-timing-function: ease;
        }
        .property-bg-only:hover {
            background: #e74c3c;
            transform: scale(1.2) rotate(10deg);
        }

        .property-transform-only {
            transition-property: transform;
            transition-duration: 0.5s;
            transition-timing-function: ease;
        }
        .property-transform-only:hover {
            background: #e74c3c;
            transform: scale(1.2) rotate(10deg);
        }

        .property-both {
            transition-property: background-color, transform;
            transition-duration: 0.5s;
            transition-timing-function: ease;
        }
        .property-both:hover {
            background: #e74c3c;
            transform: scale(1.2) rotate(10deg);
        }

        /* ====== DURATION DEMO ====== */
        .duration-box {
            width: 100px;
            height: 100px;
            background: #007bff;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            border-radius: 12px;
            cursor: pointer;
            transition-property: transform;
            transition-timing-function: ease;
        }

        .duration-0-5:hover {
            transition-duration: 0.5s;
            transform: scale(1.3);
        }

        .duration-1:hover {
            transition-duration: 1s;
            transform: scale(1.3);
        }

        .duration-2:hover {
            transition-duration: 2s;
            transform: scale(1.3);
        }

        /* ====== DELAY DEMO ====== */
        .delay-box {
            width: 100px;
            height: 100px;
            background: #28a745;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            border-radius: 12px;
            cursor: pointer;
            transition-property: transform;
            transition-duration: 0.5s;
            transition-timing-function: ease;
        }

        .delay-0:hover {
            transition-delay: 0s;
            transform: translateY(-40px);
        }

        .delay-0-5:hover {
            transition-delay: 0.5s;
            transform: translateY(-40px);
        }

        .delay-1:hover {
            transition-delay: 1s;
            transform: translateY(-40px);
        }

        /* ====== TIMING FUNCTION DEMO ====== */
        .timing-box {
            width: 100px;
            height: 100px;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.75rem;
            border-radius: 12px;
            cursor: pointer;
            transition-property: transform;
            transition-duration: 1s;
        }

        .timing-ease {
            background: #007bff;
            transition-timing-function: ease;
        }
        .timing-ease:hover {
            transform: translateX(80px);
        }

        .timing-linear {
            background: #28a745;
            transition-timing-function: linear;
        }
        .timing-linear:hover {
            transform: translateX(80px);
        }

        .timing-ease-in {
            background: #dc3545;
            transition-timing-function: ease-in;
        }
        .timing-ease-in:hover {
            transform: translateX(80px);
        }

        .timing-ease-out {
            background: #ffc107;
            color: #333;
            transition-timing-function: ease-out;
        }
        .timing-ease-out:hover {
            transform: translateX(80px);
        }

        .timing-ease-in-out {
            background: #6c5ce7;
            transition-timing-function: ease-in-out;
        }
        .timing-ease-in-out:hover {
            transform: translateX(80px);
        }

        /* ====== TRANSITION-BEHAVIOR DEMO ====== */
        .behavior-container {
            display: flex;
            flex-direction: column;
            gap: 20px;
            align-items: center;
        }

        .behavior-card {
            width: 200px;
            padding: 20px;
            background: #007bff;
            color: white;
            border-radius: 12px;
            text-align: center;
            font-weight: bold;
            cursor: pointer;
            position: relative;
            overflow: hidden;
        }

        .behavior-card .hidden-content {
            display: none;
            margin-top: 10px;
            font-size: 0.85rem;
            font-weight: normal;
            opacity: 0;
            transition: opacity 0.5s ease;
        }

        /* Without allow-discrete */
        .behavior-normal {
            transition-property: background-color, display;
            transition-duration: 0.5s;
            transition-behavior: normal;
        }

        .behavior-normal:hover {
            background: #28a745;
        }

        .behavior-normal:hover .hidden-content {
            display: block;
            opacity: 1;
        }

        /* With allow-discrete */
        .behavior-discrete {
            transition-property: background-color, display, opacity;
            transition-duration: 0.5s;
            transition-behavior: allow-discrete;
        }

        .behavior-discrete:hover {
            background: #28a745;
        }

        .behavior-discrete:hover .hidden-content {
            display: block;
            opacity: 1;
        }

        /* ====== PRACTICAL: DROPDOWN ====== */
        .dropdown-container {
            position: relative;
            display: inline-block;
            margin: 20px;
        }

        .dropdown-trigger {
            padding: 12px 24px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 1em;
            font-weight: bold;
            cursor: pointer;
        }

        .dropdown-menu {
            position: absolute;
            top: 100%;
            left: 0;
            min-width: 200px;
            background: white;
            border: 2px solid #ddd;
            border-radius: 8px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
            padding: 10px 0;
            margin-top: 5px;
            opacity: 0;
            visibility: hidden;
            transform: translateY(-10px);
            transition-property: opacity, visibility, transform;
            transition-duration: 0.3s;
            transition-timing-function: ease;
            transition-behavior: allow-discrete;
        }

        .dropdown-container:hover .dropdown-menu {
            opacity: 1;
            visibility: visible;
            transform: translateY(0);
        }

        .dropdown-menu a {
            display: block;
            padding: 10px 20px;
            color: #333;
            text-decoration: none;
            transition: background 0.2s ease;
        }

        .dropdown-menu a:hover {
            background: #e9ecef;
            color: #007bff;
        }

        /* ====== PRACTICAL: MODAL ====== */
        .modal-trigger {
            padding: 12px 24px;
            background: #6c5ce7;
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 1em;
            font-weight: bold;
            cursor: pointer;
            margin: 20px;
        }

        .modal-overlay {
            position: fixed;
            inset: 0;
            background: rgba(0, 0, 0, 0.5);
            display: flex;
            align-items: center;
            justify-content: center;
            opacity: 0;
            visibility: hidden;
            transition-property: opacity, visibility;
            transition-duration: 0.3s;
            transition-behavior: allow-discrete;
            z-index: 1000;
        }

        .modal-content {
            background: white;
            padding: 30px;
            border-radius: 16px;
            max-width: 400px;
            text-align: center;
            transform: scale(0.9);
            transition: transform 0.3s ease;
        }

        .modal-overlay:target {
            opacity: 1;
            visibility: visible;
        }

        .modal-overlay:target .modal-content {
            transform: scale(1);
        }

        .modal-content h3 {
            margin-top: 0;
            color: #6c5ce7;
        }

        .modal-close {
            display: inline-block;
            padding: 10px 20px;
            background: #dc3545;
            color: white;
            text-decoration: none;
            border-radius: 8px;
            font-weight: bold;
            margin-top: 15px;
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            background: #f8f9fa;
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>transition-behavior, delay, duration, and property</h1>

    <!-- ====== 1. TRANSITION-PROPERTY ====== -->
    <section>
        <h2>1. transition-property</h2>
        <p>Hover over each box to see which properties transition.</p>

        <div class="demo-area">
            <div class="property-demo property-bg-only">
                background-color<br>only
            </div>
            <div class="property-demo property-transform-only">
                transform<br>only
            </div>
            <div class="property-demo property-both">
                background + transform
            </div>
        </div>

        <div class="code-block">
            /* Only background-color transitions */
            .property-bg-only {
                transition-property: background-color;
                transition-duration: 0.5s;
            }

            /* Only transform transitions */
            .property-transform-only {
                transition-property: transform;
                transition-duration: 0.5s;
            }

            /* Both properties transition */
            .property-both {
                transition-property: background-color, transform;
                transition-duration: 0.5s;
            }
        </div>

        <p class="note">Use <code>transition-property</code> to control exactly which properties animate.</p>
    </section>

    <!-- ====== 2. TRANSITION-DURATION ====== -->
    <section>
        <h2>2. transition-duration</h2>
        <p>Hover over each box to compare the speed.</p>

        <div class="demo-area">
            <div class="duration-box duration-0-5">0.5s</div>
            <div class="duration-box duration-1" style="background: #28a745;">1s</div>
            <div class="duration-box duration-2" style="background: #dc3545;">2s</div>
        </div>

        <div class="code-block">
            .duration-0-5:hover {
                transition-duration: 0.5s;
                transform: scale(1.3);
            }

            .duration-1:hover {
                transition-duration: 1s;
                transform: scale(1.3);
            }

            .duration-2:hover {
                transition-duration: 2s;
                transform: scale(1.3);
            }
        </div>

        <p class="note">Multiple values can be set for multiple properties: <code>transition-duration: 1s, 2s;</code></p>
    </section>

    <!-- ====== 3. TRANSITION-DELAY ====== -->
    <section>
        <h2>3. transition-delay</h2>
        <p>Hover over each box to see the delayed transition.</p>

        <div class="demo-area">
            <div class="delay-box delay-0">0s</div>
            <div class="delay-box delay-0-5" style="background: #ffc107; color: #333;">0.5s</div>
            <div class="delay-box delay-1" style="background: #dc3545;">1s</div>
        </div>

        <div class="code-block">
            .delay-0:hover {
                transition-delay: 0s;
                transform: translateY(-40px);
            }

            .delay-0-5:hover {
                transition-delay: 0.5s;
                transform: translateY(-40px);
            }

            .delay-1:hover {
                transition-delay: 1s;
                transform: translateY(-40px);
            }
        </div>

        <p class="note">Negative delays start the transition partway through: <code>transition-delay: -0.5s;</code></p>
    </section>

    <!-- ====== 4. TRANSITION-TIMING-FUNCTION ====== -->
    <section>
        <h2>4. transition-timing-function</h2>
        <p>Hover over each box to compare the timing curves.</p>

        <div class="demo-area" style="flex-direction: column; gap: 15px; align-items: flex-start;">
            <div class="timing-box timing-ease">ease</div>
            <div class="timing-box timing-linear">linear</div>
            <div class="timing-box timing-ease-in">ease-in</div>
            <div class="timing-box timing-ease-out">ease-out</div>
            <div class="timing-box timing-ease-in-out">ease-in-out</div>
        </div>

        <div class="code-block">
            .timing-ease        { transition-timing-function: ease; }
            .timing-linear      { transition-timing-function: linear; }
            .timing-ease-in     { transition-timing-function: ease-in; }
            .timing-ease-out    { transition-timing-function: ease-out; }
            .timing-ease-in-out { transition-timing-function: ease-in-out; }
        </div>
    </section>

    <!-- ====== 5. TRANSITION-BEHAVIOR ====== -->
    <section>
        <h2>5. transition-behavior</h2>
        <p>Controls how <strong>discrete properties</strong> (like <code>display</code>) animate.</p>

        <div class="demo-area" style="flex-direction: column;">
            <div class="behavior-container">
                <div class="behavior-card behavior-normal">
                    <div>behavior: normal</div>
                    <div class="hidden-content">This content appears instantly (no transition on display)</div>
                </div>
                <div class="behavior-card behavior-discrete">
                    <div>behavior: allow-discrete</div>
                    <div class="hidden-content">This content can transition with opacity</div>
                </div>
            </div>
        </div>

        <div class="code-block">
            /* Without allow-discrete — display changes instantly */
            .behavior-normal {
                transition-property: background-color, display;
                transition-duration: 0.5s;
                transition-behavior: normal;
            }

            /* With allow-discrete — display can animate */
            .behavior-discrete {
                transition-property: background-color, display, opacity;
                transition-duration: 0.5s;
                transition-behavior: allow-discrete;
            }
        </div>

        <p class="note"><code>allow-discrete</code> is essential for animating <code>display</code>, <code>visibility</code>, and other discrete properties.</p>
    </section>

    <!-- ====== 6. PRACTICAL: DROPDOWN MENU ====== -->
    <section>
        <h2>6. Practical Example: Dropdown Menu</h2>
        <p>Hover over the button to see the dropdown with <code>allow-discrete</code>.</p>

        <div style="text-align: center;">
            <div class="dropdown-container">
                <button class="dropdown-trigger">Hover Me ▼</button>
                <div class="dropdown-menu">
                    <a href="#">🏠 Home</a>
                    <a href="#">📄 About</a>
                    <a href="#">⚙️ Services</a>
                    <a href="#">📞 Contact</a>
                </div>
            </div>
        </div>

        <div class="code-block">
            .dropdown-menu {
                opacity: 0;
                visibility: hidden;
                transform: translateY(-10px);
                transition-property: opacity, visibility, transform;
                transition-duration: 0.3s;
                transition-behavior: allow-discrete;
            }

            .dropdown-container:hover .dropdown-menu {
                opacity: 1;
                visibility: visible;
                transform: translateY(0);
            }
        </div>

        <p class="note">Without <code>allow-discrete</code>, the menu would appear/disappear instantly instead of fading in.</p>
    </section>

    <!-- ====== 7. PRACTICAL: MODAL ====== -->
    <section>
        <h2>7. Practical Example: Modal</h2>
        <p>Click the button to open a modal with a smooth fade-in.</p>

        <div style="text-align: center;">
            <a href="#modal" class="modal-trigger">Open Modal</a>
        </div>

        <div id="modal" class="modal-overlay">
            <div class="modal-content">
                <h3>🎉 Modal Title</h3>
                <p>This modal fades in using <code>transition-behavior: allow-discrete</code> with <code>visibility</code> and <code>opacity</code>.</p>
                <a href="#" class="modal-close">Close</a>
            </div>
        </div>

        <div class="code-block">
            .modal-overlay {
                opacity: 0;
                visibility: hidden;
                transition-property: opacity, visibility;
                transition-duration: 0.3s;
                transition-behavior: allow-discrete;
            }

            .modal-overlay:target {
                opacity: 1;
                visibility: visible;
            }
        </div>
    </section>

    <!-- ====== 8. REFERENCE TABLES ====== -->
    <section>
        <h2>8. Reference Tables</h2>

        <h3>Transition Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Default</th>
            </tr>
            <tr>
                <td><code>transition-property</code></td>
                <td>Which properties to animate</td>
                <td><code>all</code></td>
            </tr>
            <tr>
                <td><code>transition-duration</code></td>
                <td>How long the transition takes</td>
                <td><code>0s</code></td>
            </tr>
            <tr>
                <td><code>transition-delay</code></td>
                <td>Wait before starting</td>
                <td><code>0s</code></td>
            </tr>
            <tr>
                <td><code>transition-behavior</code></td>
                <td>How discrete properties animate</td>
                <td><code>normal</code></td>
            </tr>
            <tr>
                <td><code>transition-timing-function</code></td>
                <td>Speed curve</td>
                <td><code>ease</code></td>
            </tr>
        </table>

        <h3>transition-property Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>No properties transition</td>
            </tr>
            <tr>
                <td><code>all</code></td>
                <td>All animatable properties transition</td>
            </tr>
            <tr>
                <td><code>property-name</code></td>
                <td>Specific property (e.g., <code>background-color</code>)</td>
            </tr>
            <tr>
                <td>Multiple</td>
                <td>Comma-separated list</td>
            </tr>
        </table>

        <h3>transition-behavior Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>normal</code></td>
                <td>Discrete properties don't animate (default)</td>
            </tr>
            <tr>
                <td><code>allow-discrete</code></td>
                <td>Discrete properties can animate</td>
            </tr>
        </table>

        <h3>Discrete Properties (Common)</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Values</th>
            </tr>
            <tr>
                <td><code>display</code></td>
                <td><code>none</code>, <code>block</code>, <code>flex</code></td>
            </tr>
            <tr>
                <td><code>visibility</code></td>
                <td><code>visible</code>, <code>hidden</code></td>
            </tr>
            <tr>
                <td><code>position</code></td>
                <td><code>static</code>, <code>relative</code>, <code>absolute</code></td>
            </tr>
            <tr>
                <td><code>float</code></td>
                <td><code>left</code>, <code>right</code>, <code>none</code></td>
            </tr>
        </table>

        <h3>Timing Functions</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>ease</code></td>
                <td>Slow start, fast middle, slow end</td>
            </tr>
            <tr>
                <td><code>linear</code></td>
                <td>Constant speed</td>
            </tr>
            <tr>
                <td><code>ease-in</code></td>
                <td>Slow start, fast end</td>
            </tr>
            <tr>
                <td><code>ease-out</code></td>
                <td>Fast start, slow end</td>
            </tr>
            <tr>
                <td><code>ease-in-out</code></td>
                <td>Slow start, fast middle, slow end</td>
            </tr>
            <tr>
                <td><code>step-start</code></td>
                <td>Jump to end immediately</td>
            </tr>
            <tr>
                <td><code>step-end</code></td>
                <td>Stay at start until the end</td>
            </tr>
            <tr>
                <td><code>cubic-bezier(n,n,n,n)</code></td>
                <td>Custom curve</td>
            </tr>
        </table>
    </section>

    <!-- ====== 9. BEST PRACTICES ====== -->
    <section>
        <h2>9. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>transition-property</code> to specify exact properties (not <code>all</code>)</li>
                <li>Use <code>transition-behavior: allow-discrete</code> for <code>display</code>/<code>visibility</code></li>
                <li>Use <code>transition-delay</code> for staggered animations</li>
                <li>Keep durations short (0.2s–0.5s) for UI feedback</li>
                <li>Use <code>ease-out</code> for entering elements and <code>ease-in</code> for exiting</li>
                <li>Test with <code>prefers-reduced-motion</code> for accessibility</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't use <code>transition-property: all</code> for everything</li>
                <li>Don't forget <code>allow-discrete</code> when animating <code>display</code></li>
                <li>Don't use long delays for critical UI feedback</li>
                <li>Don't animate layout properties (<code>width</code>, <code>height</code>)</li>
                <li>Don't forget that negative delays start partway through</li>
                <li>Don't use transitions without respecting <code>prefers-reduced-motion</code></li>
            </ul>
        </div>

        <div class="code-block">
            /* Accessibility: respect reduced motion */
            @media (prefers-reduced-motion: reduce) {
                .box,
                .dropdown-menu,
                .modal-overlay {
                    transition: none;
                }
            }

            /* Best practice: specify exact properties */
            .box {
                transition-property: background-color, transform;
                transition-duration: 0.3s, 0.5s;
                transition-timing-function: ease, ease-out;
            }

            /* Enable discrete animations */
            .dropdown {
                transition-property: opacity, visibility;
                transition-duration: 0.3s;
                transition-behavior: allow-discrete;
            }
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionDefault
transition-propertyWhich properties to animateall
transition-durationHow long the transition takes0s
transition-delayWait before starting0s
transition-behaviorHow discrete properties animatenormal
transition-timing-functionSpeed curveease

transition-property Values

ValueDescription
noneNo properties transition
allAll animatable properties transition
property-nameSpecific property
MultipleComma-separated list

transition-behavior Values

ValueDescription
normalDiscrete properties don’t animate (default)
allow-discreteDiscrete properties can animate

Discrete Properties (Common)

PropertyValues
displaynone, block, flex
visibilityvisible, hidden
positionstatic, relative, absolute
floatleft, right, none

Best Practices

Do This:

/* Specify exact properties */
.box {
    transition-property: background-color, transform;
    transition-duration: 0.3s, 0.5s;
    transition-timing-function: ease, ease-out;
}

/* Animate display with allow-discrete */
.dropdown {
    transition-property: opacity, visibility, transform;
    transition-duration: 0.3s;
    transition-behavior: allow-discrete;
}

/* Staggered animation with delay */
.item:nth-child(1) { transition-delay: 0s; }
.item:nth-child(2) { transition-delay: 0.1s; }
.item:nth-child(3) { transition-delay: 0.2s; }

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    .box {
        transition: none;
    }
}

Don’t Do This:

/* Don't use transition-property: all */
.box {
    transition-property: all; /* Unpredictable and less performant */
}

/* Don't forget allow-discrete */
.modal {
    transition-property: visibility, opacity; /* visibility won't animate */
}

/* Don't use long delays for UI */
.btn:hover {
    transition-delay: 2s; /* Users will think it's broken */
}

/* Don't animate layout properties */
.box {
    transition-property: width, height; /* Causes layout recalculation */
}

Pro Tip: The transition-behavior: allow-discrete property is a game-changer for UI animations. Before it, you couldn’t animate display or visibility — modals, dropdowns, and tooltips would just pop in and out. Now you can create smooth fade-in/fade-out animations for these elements. Use it with opacity and visibility for dropdowns and modals. Remember: transition-property should be specific (not all) for better performance and predictability, and always respect prefers-reduced-motion for users who are sensitive to animation!

55. The animation Property

The animation property is one of the most powerful tools in CSS. It lets you create complex, multi-step animations — with full control over timing, repetition, direction, and more.


What is an Animation?

An animation in CSS is defined by two parts:

  1. @keyframes — defines the stages of the animation
  2. animation property — applies the animation to an element

Unlike transitions (which animate between two states), animations can have many stages and run automatically without user interaction.


The animation Shorthand

The animation property is a shorthand for 8 individual animation properties:

PropertyDescriptionDefault
animation-nameName of the @keyframes rulenone
animation-durationHow long one cycle takes0s
animation-timing-functionSpeed curveease
animation-delayWait before starting0s
animation-iteration-countHow many times to repeat1
animation-directionDirection of each cyclenormal
animation-fill-modeStyles before/after animationnone
animation-play-stateRunning or pausedrunning

Syntax

animation: name duration timing-function delay iteration-count direction fill-mode play-state;

Only name and duration are required. All other values are optional.


The @keyframes Rule

The @keyframes rule defines the stages of an animation.

@keyframes exampleAnimation {
    0%   { background-color: red; transform: scale(1); }
    50%  { background-color: blue; transform: scale(1.5); }
    100% { background-color: green; transform: scale(1); }
}

Syntax Options

Using from and to:

@keyframes fadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}

Using percentages:

@keyframes bounce {
    0%   { transform: translateY(0); }
    50%  { transform: translateY(-50px); }
    100% { transform: translateY(0); }
}
KeywordEquivalent
from0%
to100%

Individual Animation Properties

1. animation-name

The name of the @keyframes rule to use.

animation-name: exampleAnimation;

2. animation-duration

How long one cycle of the animation takes.

animation-duration: 4s;

3. animation-timing-function

The speed curve of the animation.

animation-timing-function: ease-in-out;
ValueDescription
easeSlow start, fast middle, slow end (default)
linearConstant speed
ease-inSlow start, fast end
ease-outFast start, slow end
ease-in-outSlow start, fast middle, slow end
cubic-bezier(n,n,n,n)Custom curve
steps(n)Stepped animation

4. animation-delay

How long to wait before starting the animation.

animation-delay: 2s;

5. animation-iteration-count

How many times the animation repeats.

animation-iteration-count: infinite; /* or a number */
ValueDescription
1Plays once (default)
3Plays 3 times
infiniteRepeats forever

6. animation-direction

The direction of each cycle.

animation-direction: alternate;
ValueDescription
normalForward each cycle (default)
reverseBackward each cycle
alternateForward, then backward
alternate-reverseBackward, then forward

7. animation-fill-mode

What styles apply before and after the animation.

animation-fill-mode: forwards;
ValueDescription
noneNo styles applied outside the animation (default)
forwardsKeep the last keyframe’s styles
backwardsApply the first keyframe’s styles during delay
bothApply both forwards and backwards

8. animation-play-state

Whether the animation is running or paused.

animation-play-state: paused;
ValueDescription
runningAnimation is playing (default)
pausedAnimation is paused

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>The animation Property</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DEMO AREA ====== */
        .demo-area {
            display: flex;
            flex-wrap: wrap;
            gap: 40px;
            justify-content: center;
            align-items: center;
            padding: 40px 20px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 200px;
            overflow: hidden;
        }

        /* ====== BASIC ANIMATION ====== */
        .animation-example {
            width: 100px;
            height: 100px;
            background-color: #dc3545;
            border-radius: 12px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
            animation-name: exampleAnimation;
            animation-duration: 4s;
            animation-timing-function: ease-in-out;
            animation-delay: 2s;
            animation-iteration-count: infinite;
        }

        @keyframes exampleAnimation {
            0%   { background-color: #dc3545; transform: scale(1); }
            50%  { background-color: #007bff; transform: scale(1.5); }
            100% { background-color: #28a745; transform: scale(1); }
        }

        /* ====== SHORTHAND ====== */
        .animation-shorthand {
            width: 100px;
            height: 100px;
            background: #6c5ce7;
            border-radius: 12px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
            animation: bounce 2s ease-in-out infinite;
        }

        @keyframes bounce {
            0%, 100% { transform: translateY(0); }
            50%      { transform: translateY(-40px); }
        }

        /* ====== FADE IN ====== */
        .fade-in {
            width: 100px;
            height: 100px;
            background: #28a745;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            animation: fadeIn 2s ease forwards;
            opacity: 0;
        }

        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(20px); }
            to   { opacity: 1; transform: translateY(0); }
        }

        /* ====== SLIDE IN ====== */
        .slide-in {
            width: 100px;
            height: 100px;
            background: #ffc107;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #333;
            font-weight: bold;
            animation: slideIn 1.5s ease-out forwards;
            transform: translateX(-200px);
        }

        @keyframes slideIn {
            from { transform: translateX(-200px); }
            to   { transform: translateX(0); }
        }

        /* ====== PULSE ====== */
        .pulse {
            width: 100px;
            height: 100px;
            background: #dc3545;
            border-radius: 50%;
            animation: pulse 1.5s ease-in-out infinite;
        }

        @keyframes pulse {
            0%   { transform: scale(1); box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7); }
            70%  { transform: scale(1.1); box-shadow: 0 0 0 20px rgba(220, 53, 69, 0); }
            100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(220, 53, 69, 0); }
        }

        /* ====== ROTATE ====== */
        .rotate {
            width: 100px;
            height: 100px;
            background: #17a2b8;
            border-radius: 12px;
            animation: rotate 3s linear infinite;
        }

        @keyframes rotate {
            from { transform: rotate(0deg); }
            to   { transform: rotate(360deg); }
        }

        /* ====== SPINNER ====== */
        .spinner {
            width: 60px;
            height: 60px;
            border: 6px solid #e9ecef;
            border-top: 6px solid #007bff;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            to { transform: rotate(360deg); }
        }

        /* ====== MULTI-STEP ====== */
        .multi-step {
            width: 100px;
            height: 100px;
            background: #007bff;
            border-radius: 12px;
            animation: multiStep 4s ease-in-out infinite;
        }

        @keyframes multiStep {
            0%   { background: #007bff; transform: translate(0, 0) rotate(0deg); }
            25%  { background: #28a745; transform: translate(100px, 0) rotate(90deg); }
            50%  { background: #ffc107; transform: translate(100px, 100px) rotate(180deg); }
            75%  { background: #dc3545; transform: translate(0, 100px) rotate(270deg); }
            100% { background: #007bff; transform: translate(0, 0) rotate(360deg); }
        }

        /* ====== DIRECTION COMPARISON ====== */
        .direction-box {
            width: 80px;
            height: 80px;
            background: #6c5ce7;
            border-radius: 12px;
            animation-duration: 2s;
            animation-timing-function: ease-in-out;
            animation-iteration-count: infinite;
        }

        .direction-normal {
            animation-name: slideAcross;
            animation-direction: normal;
        }

        .direction-reverse {
            animation-name: slideAcross;
            animation-direction: reverse;
        }

        .direction-alternate {
            animation-name: slideAcross;
            animation-direction: alternate;
        }

        .direction-alternate-reverse {
            animation-name: slideAcross;
            animation-direction: alternate-reverse;
        }

        @keyframes slideAcross {
            from { transform: translateX(0); background: #6c5ce7; }
            to   { transform: translateX(150px); background: #28a745; }
        }

        /* ====== FILL MODE COMPARISON ====== */
        .fill-box {
            width: 80px;
            height: 80px;
            background: #007bff;
            border-radius: 12px;
            animation-duration: 2s;
            animation-delay: 1s;
            animation-timing-function: ease;
            animation-fill-mode: none;
            animation-name: fillDemo;
            opacity: 0;
        }

        .fill-none {
            animation-fill-mode: none;
        }

        .fill-forwards {
            animation-fill-mode: forwards;
        }

        .fill-backwards {
            animation-fill-mode: backwards;
        }

        .fill-both {
            animation-fill-mode: both;
        }

        @keyframes fillDemo {
            from { opacity: 0; transform: translateX(-50px); background: #dc3545; }
            to   { opacity: 1; transform: translateX(0); background: #28a745; }
        }

        /* ====== PLAY STATE ====== */
        .play-pause-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 15px;
        }

        .play-pause-box {
            width: 100px;
            height: 100px;
            background: #ffc107;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #333;
            font-weight: bold;
            animation: pulse 1.5s ease-in-out infinite;
        }

        .play-pause-box:hover {
            animation-play-state: paused;
        }

        /* ====== PRACTICAL: LOADING SKELETON ====== */
        .skeleton-container {
            max-width: 400px;
            margin: 15px auto;
            padding: 20px;
            background: white;
            border-radius: 12px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }

        .skeleton-line {
            height: 16px;
            background: linear-gradient(90deg, #e9ecef 25%, #f8f9fa 50%, #e9ecef 75%);
            background-size: 200% 100%;
            border-radius: 8px;
            margin-bottom: 12px;
            animation: shimmer 1.5s infinite;
        }

        .skeleton-line.short {
            width: 60%;
        }

        @keyframes shimmer {
            0%   { background-position: 200% 0; }
            100% { background-position: -200% 0; }
        }

        /* ====== PRACTICAL: BUTTON LOADING ====== */
        .btn-loading {
            padding: 15px 35px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 1em;
            font-weight: bold;
            cursor: pointer;
            display: inline-flex;
            align-items: center;
            gap: 10px;
            margin: 10px;
        }

        .btn-loading .dot {
            width: 8px;
            height: 8px;
            background: white;
            border-radius: 50%;
            animation: dotPulse 1.4s ease-in-out infinite;
        }

        .btn-loading .dot:nth-child(2) {
            animation-delay: 0.2s;
        }

        .btn-loading .dot:nth-child(3) {
            animation-delay: 0.4s;
        }

        @keyframes dotPulse {
            0%, 80%, 100% { transform: scale(0.6); opacity: 0.5; }
            40%           { transform: scale(1); opacity: 1; }
        }

        /* ====== PRACTICAL: FLOATING ELEMENTS ====== */
        .float-container {
            display: flex;
            gap: 30px;
            justify-content: center;
            margin: 20px 0;
        }

        .float-item {
            width: 80px;
            height: 80px;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 2rem;
            animation: float 3s ease-in-out infinite;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
        }

        .float-item:nth-child(1) { background: #007bff; animation-delay: 0s; }
        .float-item:nth-child(2) { background: #28a745; animation-delay: 0.3s; }
        .float-item:nth-child(3) { background: #ffc107; animation-delay: 0.6s; }
        .float-item:nth-child(4) { background: #dc3545; animation-delay: 0.9s; }

        @keyframes float {
            0%, 100% { transform: translateY(0); }
            50%      { transform: translateY(-20px); }
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            background: #f8f9fa;
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>The animation Property</h1>

    <!-- ====== 1. BASIC ANIMATION ====== -->
    <section>
        <h2>1. Basic Animation</h2>
        <p>This box animates through three colors and scales using all individual properties.</p>

        <div class="demo-area">
            <div class="animation-example"></div>
        </div>

        <div class="code-block">
            .animation-example {
                animation-name: exampleAnimation;
                animation-duration: 4s;
                animation-timing-function: ease-in-out;
                animation-delay: 2s;
                animation-iteration-count: infinite;
            }

            @keyframes exampleAnimation {
                0%   { background-color: red; transform: scale(1); }
                50%  { background-color: blue; transform: scale(1.5); }
                100% { background-color: green; transform: scale(1); }
            }
        </div>
    </section>

    <!-- ====== 2. SHORTHAND ====== -->
    <section>
        <h2>2. animation Shorthand</h2>
        <p>The shorthand combines all animation properties into one declaration.</p>

        <div class="demo-area">
            <div class="animation-shorthand"></div>
        </div>

        <div class="code-block">
            /* Shorthand: name duration timing-function delay iteration-count direction fill-mode play-state */
            .animation-shorthand {
                animation: bounce 2s ease-in-out infinite;
            }

            @keyframes bounce {
                0%, 100% { transform: translateY(0); }
                50%      { transform: translateY(-40px); }
            }
        </div>
    </section>

    <!-- ====== 3. COMMON ANIMATIONS ====== -->
    <section>
        <h2>3. Common Animation Patterns</h2>

        <h3>Fade In</h3>
        <div class="demo-area">
            <div class="fade-in">Fade In</div>
        </div>
        <div class="code-block">
            .fade-in {
                animation: fadeIn 2s ease forwards;
                opacity: 0;
            }

            @keyframes fadeIn {
                from { opacity: 0; transform: translateY(20px); }
                to   { opacity: 1; transform: translateY(0); }
            }
        </div>

        <h3>Slide In</h3>
        <div class="demo-area">
            <div class="slide-in">Slide In</div>
        </div>
        <div class="code-block">
            .slide-in {
                animation: slideIn 1.5s ease-out forwards;
                transform: translateX(-200px);
            }

            @keyframes slideIn {
                from { transform: translateX(-200px); }
                to   { transform: translateX(0); }
            }
        </div>

        <h3>Pulse</h3>
        <div class="demo-area">
            <div class="pulse"></div>
        </div>
        <div class="code-block">
            .pulse {
                animation: pulse 1.5s ease-in-out infinite;
            }

            @keyframes pulse {
                0%   { transform: scale(1); box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7); }
                70%  { transform: scale(1.1); box-shadow: 0 0 0 20px rgba(220, 53, 69, 0); }
                100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(220, 53, 69, 0); }
            }
        </div>

        <h3>Rotate</h3>
        <div class="demo-area">
            <div class="rotate"></div>
        </div>
        <div class="code-block">
            .rotate {
                animation: rotate 3s linear infinite;
            }

            @keyframes rotate {
                from { transform: rotate(0deg); }
                to   { transform: rotate(360deg); }
            }
        </div>

        <h3>Spinner</h3>
        <div class="demo-area">
            <div class="spinner"></div>
        </div>
        <div class="code-block">
            .spinner {
                border: 6px solid #e9ecef;
                border-top: 6px solid #007bff;
                border-radius: 50%;
                animation: spin 1s linear infinite;
            }

            @keyframes spin {
                to { transform: rotate(360deg); }
            }
        </div>
    </section>

    <!-- ====== 4. MULTI-STEP ANIMATION ====== -->
    <section>
        <h2>4. Multi-Step Animation</h2>
        <p>This box travels in a square pattern using multiple keyframes.</p>

        <div class="demo-area" style="min-height: 300px;">
            <div class="multi-step"></div>
        </div>

        <div class="code-block">
            .multi-step {
                animation: multiStep 4s ease-in-out infinite;
            }

            @keyframes multiStep {
                0%   { background: #007bff; transform: translate(0, 0) rotate(0deg); }
                25%  { background: #28a745; transform: translate(100px, 0) rotate(90deg); }
                50%  { background: #ffc107; transform: translate(100px, 100px) rotate(180deg); }
                75%  { background: #dc3545; transform: translate(0, 100px) rotate(270deg); }
                100% { background: #007bff; transform: translate(0, 0) rotate(360deg); }
            }
        </div>
    </section>

    <!-- ====== 5. ANIMATION DIRECTION ====== -->
    <section>
        <h2>5. animation-direction</h2>
        <p>Compare the four direction values.</p>

        <div class="demo-area" style="flex-direction: column; gap: 20px; align-items: flex-start;">
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 180px;">normal:</span>
                <div class="direction-box direction-normal"></div>
            </div>
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 180px;">reverse:</span>
                <div class="direction-box direction-reverse"></div>
            </div>
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 180px;">alternate:</span>
                <div class="direction-box direction-alternate"></div>
            </div>
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 180px;">alternate-reverse:</span>
                <div class="direction-box direction-alternate-reverse"></div>
            </div>
        </div>

        <div class="code-block">
            .direction-normal           { animation-direction: normal; }
            .direction-reverse          { animation-direction: reverse; }
            .direction-alternate        { animation-direction: alternate; }
            .direction-alternate-reverse { animation-direction: alternate-reverse; }

            @keyframes slideAcross {
                from { transform: translateX(0); background: #6c5ce7; }
                to   { transform: translateX(150px); background: #28a745; }
            }
        </div>
    </section>

    <!-- ====== 6. ANIMATION FILL MODE ====== -->
    <section>
        <h2>6. animation-fill-mode</h2>
        <p>Compare how styles apply before and after the animation.</p>

        <div class="demo-area" style="flex-direction: column; gap: 20px; align-items: flex-start;">
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 150px;">none:</span>
                <div class="fill-box fill-none"></div>
            </div>
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 150px;">forwards:</span>
                <div class="fill-box fill-forwards"></div>
            </div>
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 150px;">backwards:</span>
                <div class="fill-box fill-backwards"></div>
            </div>
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 150px;">both:</span>
                <div class="fill-box fill-both"></div>
            </div>
        </div>

        <div class="code-block">
            .fill-none      { animation-fill-mode: none; }
            .fill-forwards  { animation-fill-mode: forwards; }
            .fill-backwards { animation-fill-mode: backwards; }
            .fill-both      { animation-fill-mode: both; }

            @keyframes fillDemo {
                from { opacity: 0; transform: translateX(-50px); background: #dc3545; }
                to   { opacity: 1; transform: translateX(0); background: #28a745; }
            }
        </div>

        <p class="note"><strong>forwards</strong> keeps the end state, <strong>backwards</strong> applies the start state during delay, and <strong>both</strong> does both.</p>
    </section>

    <!-- ====== 7. ANIMATION PLAY STATE ====== -->
    <section>
        <h2>7. animation-play-state</h2>
        <p>Hover over the box to pause the animation.</p>

        <div class="demo-area">
            <div class="play-pause-container">
                <div class="play-pause-box">Hover to Pause</div>
            </div>
        </div>

        <div class="code-block">
            .play-pause-box {
                animation: pulse 1.5s ease-in-out infinite;
            }

            .play-pause-box:hover {
                animation-play-state: paused;
            }
        </div>
    </section>

    <!-- ====== 8. PRACTICAL: LOADING SKELETON ====== -->
    <section>
        <h2>8. Practical Example: Loading Skeleton</h2>
        <p>A shimmer effect commonly used in loading placeholders.</p>

        <div class="skeleton-container">
            <div class="skeleton-line"></div>
            <div class="skeleton-line"></div>
            <div class="skeleton-line short"></div>
        </div>

        <div class="code-block">
            .skeleton-line {
                background: linear-gradient(90deg, #e9ecef 25%, #f8f9fa 50%, #e9ecef 75%);
                background-size: 200% 100%;
                animation: shimmer 1.5s infinite;
            }

            @keyframes shimmer {
                0%   { background-position: 200% 0; }
                100% { background-position: -200% 0; }
            }
        </div>
    </section>

    <!-- ====== 9. PRACTICAL: BUTTON LOADING ====== -->
    <section>
        <h2>9. Practical Example: Button Loading Dots</h2>
        <p>Animated dots for a loading button.</p>

        <div style="text-align: center;">
            <button class="btn-loading">
                Loading
                <span class="dot"></span>
                <span class="dot"></span>
                <span class="dot"></span>
            </button>
        </div>

        <div class="code-block">
            .btn-loading .dot {
                width: 8px;
                height: 8px;
                background: white;
                border-radius: 50%;
                animation: dotPulse 1.4s ease-in-out infinite;
            }

            .btn-loading .dot:nth-child(2) { animation-delay: 0.2s; }
            .btn-loading .dot:nth-child(3) { animation-delay: 0.4s; }

            @keyframes dotPulse {
                0%, 80%, 100% { transform: scale(0.6); opacity: 0.5; }
                40%           { transform: scale(1); opacity: 1; }
            }
        </div>
    </section>

    <!-- ====== 10. PRACTICAL: FLOATING ELEMENTS ====== -->
    <section>
        <h2>10. Practical Example: Floating Elements</h2>
        <p>Staggered floating animation with different delays.</p>

        <div class="float-container">
            <div class="float-item">🚀</div>
            <div class="float-item">⭐</div>
            <div class="float-item">🎯</div>
            <div class="float-item">💎</div>
        </div>

        <div class="code-block">
            .float-item {
                animation: float 3s ease-in-out infinite;
            }

            .float-item:nth-child(1) { animation-delay: 0s; }
            .float-item:nth-child(2) { animation-delay: 0.3s; }
            .float-item:nth-child(3) { animation-delay: 0.6s; }
            .float-item:nth-child(4) { animation-delay: 0.9s; }

            @keyframes float {
                0%, 100% { transform: translateY(0); }
                50%      { transform: translateY(-20px); }
            }
        </div>
    </section>

    <!-- ====== 11. REFERENCE TABLES ====== -->
    <section>
        <h2>11. Reference Tables</h2>

        <h3>Animation Properties</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Default</th>
            </tr>
            <tr>
                <td><code>animation-name</code></td>
                <td>Name of the @keyframes rule</td>
                <td><code>none</code></td>
            </tr>
            <tr>
                <td><code>animation-duration</code></td>
                <td>How long one cycle takes</td>
                <td><code>0s</code></td>
            </tr>
            <tr>
                <td><code>animation-timing-function</code></td>
                <td>Speed curve</td>
                <td><code>ease</code></td>
            </tr>
            <tr>
                <td><code>animation-delay</code></td>
                <td>Wait before starting</td>
                <td><code>0s</code></td>
            </tr>
            <tr>
                <td><code>animation-iteration-count</code></td>
                <td>How many times to repeat</td>
                <td><code>1</code></td>
            </tr>
            <tr>
                <td><code>animation-direction</code></td>
                <td>Direction of each cycle</td>
                <td><code>normal</code></td>
            </tr>
            <tr>
                <td><code>animation-fill-mode</code></td>
                <td>Styles before/after animation</td>
                <td><code>none</code></td>
            </tr>
            <tr>
                <td><code>animation-play-state</code></td>
                <td>Running or paused</td>
                <td><code>running</code></td>
            </tr>
        </table>

        <h3>animation-direction Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>normal</code></td>
                <td>Forward each cycle (default)</td>
            </tr>
            <tr>
                <td><code>reverse</code></td>
                <td>Backward each cycle</td>
            </tr>
            <tr>
                <td><code>alternate</code></td>
                <td>Forward, then backward</td>
            </tr>
            <tr>
                <td><code>alternate-reverse</code></td>
                <td>Backward, then forward</td>
            </tr>
        </table>

        <h3>animation-fill-mode Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>No styles applied outside the animation (default)</td>
            </tr>
            <tr>
                <td><code>forwards</code></td>
                <td>Keep the last keyframe's styles</td>
            </tr>
            <tr>
                <td><code>backwards</code></td>
                <td>Apply the first keyframe's styles during delay</td>
            </tr>
            <tr>
                <td><code>both</code></td>
                <td>Apply both forwards and backwards</td>
            </tr>
        </table>

        <h3>@keyframes Syntax</h3>
        <table class="reference-table">
            <tr>
                <th>Syntax</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>from { }</code></td>
                <td>Equivalent to <code>0%</code></td>
            </tr>
            <tr>
                <td><code>to { }</code></td>
                <td>Equivalent to <code>100%</code></td>
            </tr>
            <tr>
                <td><code>50% { }</code></td>
                <td>Halfway through the animation</td>
            </tr>
        </table>
    </section>

    <!-- ====== 12. BEST PRACTICES ====== -->
    <section>
        <h2>12. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>transform</code> and <code>opacity</code> for smooth, hardware-accelerated animations</li>
                <li>Use the shorthand <code>animation</code> for cleaner code</li>
                <li>Use <code>animation-fill-mode: forwards</code> to keep the end state</li>
                <li>Use <code>animation-delay</code> for staggered effects</li>
                <li>Use <code>infinite</code> for continuous animations (loading spinners)</li>
                <li>Respect <code>prefers-reduced-motion</code> for accessibility</li>
                <li>Keep animations short and purposeful</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't animate layout properties (<code>width</code>, <code>height</code>, <code>top</code>, <code>left</code>)</li>
                <li>Don't use <code>infinite</code> animations that distract from content</li>
                <li>Don't forget to specify <code>animation-duration</code> (default is 0s — no animation!)</li>
                <li>Don't use animations for critical functionality that must work without them</li>
                <li>Don't overuse animations — a few well-placed ones are better than many</li>
                <li>Don't forget about <code>prefers-reduced-motion</code></li>
            </ul>
        </div>

        <div class="code-block">
            /* Accessibility: respect reduced motion */
            @media (prefers-reduced-motion: reduce) {
                .animation-example,
                .bounce,
                .pulse,
                .rotate,
                .spinner,
                .float-item {
                    animation: none;
                }
            }

            /* Best practice: use transform and opacity */
            .smooth {
                animation: slideIn 1s ease forwards;
            }

            @keyframes slideIn {
                from { opacity: 0; transform: translateY(20px); }
                to   { opacity: 1; transform: translateY(0); }
            }
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionDefault
animation-nameName of the @keyframes rulenone
animation-durationHow long one cycle takes0s
animation-timing-functionSpeed curveease
animation-delayWait before starting0s
animation-iteration-countHow many times to repeat1
animation-directionDirection of each cyclenormal
animation-fill-modeStyles before/after animationnone
animation-play-stateRunning or pausedrunning

animation-direction Values

ValueDescription
normalForward each cycle (default)
reverseBackward each cycle
alternateForward, then backward
alternate-reverseBackward, then forward

animation-fill-mode Values

ValueDescription
noneNo styles applied outside the animation (default)
forwardsKeep the last keyframe’s styles
backwardsApply the first keyframe’s styles during delay
bothApply both forwards and backwards

@keyframes Syntax

SyntaxDescription
from { }Equivalent to 0%
to { }Equivalent to 100%
50% { }Halfway through the animation

Best Practices

Do This:

/* Simple bounce animation */
.bounce {
    animation: bounce 1s ease infinite;
}

@keyframes bounce {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-20px); }
}

/* Fade in and stay visible */
.fade-in {
    animation: fadeIn 1s ease forwards;
    opacity: 0;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* Staggered animation */
.item:nth-child(1) { animation-delay: 0s; }
.item:nth-child(2) { animation-delay: 0.1s; }
.item:nth-child(3) { animation-delay: 0.2s; }

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    .bounce, .fade-in {
        animation: none;
    }
}

Don’t Do This:

/* Don't forget animation-duration */
.box {
    animation-name: bounce; /* Duration is 0s by default — no animation! */
}

/* Don't animate layout properties */
.box {
    animation: moveBox 1s infinite;
}
@keyframes moveBox {
    from { left: 0; }
    to   { left: 100px; } /* Causes layout recalculation */
}

/* Don't overuse infinite animations */
.everything {
    animation: spin 1s infinite; /* Distracting */
}

Pro Tip: CSS animations are perfect for attention-grabbing effects (loading spinners, notifications), entrance animations (fade in, slide in), and continuous ambient effects (floating, pulsing). Use transform and opacity for the smoothest animations — they’re hardware-accelerated. Remember: animation-duration is required (default 0s means no animation). Use animation-fill-mode: forwards to keep the end state. And always respect prefers-reduced-motion — some users are sensitive to motion and may experience discomfort from animations!

56. Animation Properties — Part 1

This lesson covers six essential animation properties: animation-name, animation-duration, animation-timing-function, animation-delay, animation-iteration-count, and animation-direction.


Overview of Properties

PropertyDescriptionDefault
animation-nameName of the @keyframes rulenone
animation-durationHow long one cycle takes0s
animation-timing-functionSpeed curveease
animation-delayWait before starting0s
animation-iteration-countHow many times to repeat1
animation-directionDirection of each cyclenormal

1. animation-name

Specifies the name of the @keyframes rule that defines the animation.

.box {
    animation-name: slideIn;
}
ValueDescription
noneNo animation (default)
custom-nameName of a @keyframes rule
MultipleComma-separated list

Multiple animations:

.box {
    animation-name: slideIn, fadeIn;
    animation-duration: 2s, 1s;
}

2. animation-duration

Specifies the length of time for one animation cycle.

.box {
    animation-duration: 2s;
}
ValueDescription
0sNo animation (default)
2s2 seconds
500ms500 milliseconds
autoFills the entire timeline (for time-based animations)

Important: If duration is 0s, the animation doesn’t play — even if animation-name is set.


3. animation-timing-function

Controls how the animation progresses through its duration — the speed curve.

.box {
    animation-timing-function: ease-in-out;
}
ValueDescription
easeSlow start, fast middle, slow end (default)
linearConstant speed
ease-inSlow start, fast end
ease-outFast start, slow end
ease-in-outSlow start, fast middle, slow end
cubic-bezier(n,n,n,n)Custom curve
steps(n)Stepped animation

4. animation-delay

Specifies the wait time before the animation starts.

.box {
    animation-delay: 1s;
}
ValueDescription
0sStart immediately (default)
1sWait 1 second
500msWait 500 milliseconds
NegativeStarts partway through the animation

Negative Delay

A negative delay starts the animation already in progress:

animation-delay: -2s; /* Starts 2 seconds into the animation */

Visual comparison:

animation-delay: 0s;   → [start]──────[end]
animation-delay: 1s;   → ────[start]──────[end]
animation-delay: -2s;  → ──[starts 2s in]──[end]

5. animation-iteration-count

Specifies how many times the animation repeats.

.box {
    animation-iteration-count: 3;
}
ValueDescription
1Plays once (default)
3Plays 3 times
infiniteRepeats forever
0.5Plays half the animation
2.5Plays 2.5 cycles

Non-integer values: 0.5 plays half the animation, 2.5 plays two and a half cycles.


6. animation-direction

Specifies whether the animation plays forward, backward, or alternates.

.box {
    animation-direction: alternate-reverse;
}
ValueDescriptionCycle 1Cycle 2Cycle 3
normalForward each cycle
reverseBackward each cycle
alternateForward, then backward
alternate-reverseBackward, then forward

Visual comparison:

normal:             [1→2→3] [1→2→3] [1→2→3]
reverse:            [3→2→1] [3→2→1] [3→2→1]
alternate:          [1→2→3] [3→2→1] [1→2→3]
alternate-reverse:  [3→2→1] [1→2→3] [3→2→1]

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Animation Properties — Part 1</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DEMO AREA ====== */
        .demo-area {
            display: flex;
            flex-wrap: wrap;
            gap: 40px;
            justify-content: center;
            align-items: center;
            padding: 40px 20px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 200px;
            overflow: hidden;
        }

        /* ====== MAIN DEMO BOX ====== */
        .box {
            width: 100px;
            height: 100px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            border-radius: 12px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
            animation-name: slideIn;
            animation-duration: 2s;
            animation-delay: 1s;
            animation-iteration-count: 3;
            animation-timing-function: ease-in-out;
            animation-direction: alternate-reverse;
        }

        @keyframes slideIn {
            from { transform: translateX(-100%); }
            to   { transform: translateX(0); }
        }

        /* ====== TIMING FUNCTIONS ====== */
        .timing-box {
            width: 80px;
            height: 80px;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.7rem;
            animation-name: moveRight;
            animation-duration: 2s;
            animation-iteration-count: infinite;
        }

        .timing-ease {
            background: #007bff;
            animation-timing-function: ease;
        }
        .timing-linear {
            background: #28a745;
            animation-timing-function: linear;
        }
        .timing-ease-in {
            background: #dc3545;
            animation-timing-function: ease-in;
        }
        .timing-ease-out {
            background: #ffc107;
            color: #333;
            animation-timing-function: ease-out;
        }
        .timing-ease-in-out {
            background: #6c5ce7;
            animation-timing-function: ease-in-out;
        }

        @keyframes moveRight {
            from { transform: translateX(0); }
            to   { transform: translateX(150px); }
        }

        /* ====== DELAY COMPARISON ====== */
        .delay-box {
            width: 80px;
            height: 80px;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.7rem;
            animation-name: fadeSlide;
            animation-duration: 1s;
            animation-fill-mode: forwards;
            animation-iteration-count: 1;
            opacity: 0;
        }

        .delay-0 {
            background: #007bff;
            animation-delay: 0s;
        }
        .delay-1 {
            background: #28a745;
            animation-delay: 1s;
        }
        .delay-neg {
            background: #dc3545;
            animation-delay: -0.5s;
        }

        @keyframes fadeSlide {
            from { opacity: 0; transform: translateX(-50px); }
            to   { opacity: 1; transform: translateX(0); }
        }

        /* ====== ITERATION COUNT ====== */
        .iteration-box {
            width: 80px;
            height: 80px;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.7rem;
            animation-name: pulseScale;
            animation-duration: 1s;
            animation-timing-function: ease-in-out;
        }

        .iter-1 {
            background: #007bff;
            animation-iteration-count: 1;
        }
        .iter-3 {
            background: #28a745;
            animation-iteration-count: 3;
        }
        .iter-half {
            background: #ffc107;
            color: #333;
            animation-iteration-count: 0.5;
        }
        .iter-infinite {
            background: #dc3545;
            animation-iteration-count: infinite;
        }

        @keyframes pulseScale {
            0%, 100% { transform: scale(1); }
            50%      { transform: scale(1.3); }
        }

        /* ====== DIRECTION COMPARISON ====== */
        .direction-box {
            width: 80px;
            height: 80px;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.7rem;
            animation-name: slideAcross;
            animation-duration: 2s;
            animation-iteration-count: infinite;
            animation-timing-function: ease-in-out;
        }

        .dir-normal {
            background: #007bff;
            animation-direction: normal;
        }
        .dir-reverse {
            background: #28a745;
            animation-direction: reverse;
        }
        .dir-alternate {
            background: #dc3545;
            animation-direction: alternate;
        }
        .dir-alternate-reverse {
            background: #6c5ce7;
            animation-direction: alternate-reverse;
        }

        @keyframes slideAcross {
            from { transform: translateX(0); }
            to   { transform: translateX(150px); }
        }

        /* ====== PRACTICAL: SLIDE IN BANNER ====== */
        .banner-container {
            padding: 20px;
            background: #e9ecef;
            border-radius: 8px;
            overflow: hidden;
            margin: 15px 0;
        }

        .banner {
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            color: white;
            padding: 20px 30px;
            border-radius: 8px;
            font-weight: bold;
            font-size: 1.2rem;
            text-align: center;
            animation-name: bannerSlide;
            animation-duration: 1s;
            animation-delay: 0.5s;
            animation-fill-mode: backwards;
            animation-timing-function: ease-out;
        }

        @keyframes bannerSlide {
            from {
                opacity: 0;
                transform: translateY(-50px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        /* ====== PRACTICAL: STAGGERED LIST ====== */
        .staggered-list {
            list-style: none;
            padding: 0;
            margin: 15px 0;
        }

        .staggered-list li {
            padding: 12px 20px;
            background: white;
            border-radius: 8px;
            margin-bottom: 8px;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
            animation-name: listItemIn;
            animation-duration: 0.5s;
            animation-fill-mode: both;
            animation-timing-function: ease-out;
            opacity: 0;
            transform: translateX(-30px);
        }

        .staggered-list li:nth-child(1) { animation-delay: 0.1s; }
        .staggered-list li:nth-child(2) { animation-delay: 0.2s; }
        .staggered-list li:nth-child(3) { animation-delay: 0.3s; }
        .staggered-list li:nth-child(4) { animation-delay: 0.4s; }
        .staggered-list li:nth-child(5) { animation-delay: 0.5s; }

        @keyframes listItemIn {
            from {
                opacity: 0;
                transform: translateX(-30px);
            }
            to {
                opacity: 1;
                transform: translateX(0);
            }
        }

        /* ====== PRACTICAL: PULSING NOTIFICATION ====== */
        .notification-container {
            position: relative;
            display: inline-block;
            margin: 20px;
        }

        .notification-badge {
            position: absolute;
            top: -8px;
            right: -8px;
            background: #dc3545;
            color: white;
            border-radius: 50%;
            width: 24px;
            height: 24px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 0.75rem;
            font-weight: bold;
            animation-name: pulseRing;
            animation-duration: 1.5s;
            animation-iteration-count: infinite;
            animation-timing-function: ease-out;
        }

        @keyframes pulseRing {
            0% {
                box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7);
            }
            70% {
                box-shadow: 0 0 0 12px rgba(220, 53, 69, 0);
            }
            100% {
                box-shadow: 0 0 0 0 rgba(220, 53, 69, 0);
            }
        }

        .notification-icon {
            font-size: 2.5rem;
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            background: #f8f9fa;
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>Animation Properties — Part 1</h1>

    <!-- ====== 1. MAIN DEMO ====== -->
    <section>
        <h2>1. Complete Animation with All Properties</h2>
        <p>This box uses <code>animation-name</code>, <code>animation-duration</code>, <code>animation-delay</code>, <code>animation-iteration-count</code>, <code>animation-timing-function</code>, and <code>animation-direction</code>.</p>

        <div class="demo-area">
            <div class="box"></div>
        </div>

        <div class="code-block">
            @keyframes slideIn {
                from { transform: translateX(-100%); }
                to   { transform: translateX(0); }
            }

            .box {
                animation-name: slideIn;
                animation-duration: 2s;
                animation-delay: 1s;
                animation-iteration-count: 3;
                animation-timing-function: ease-in-out;
                animation-direction: alternate-reverse;
            }
        </div>

        <p class="note">The box waits 1 second, then slides in and out 3 times, alternating direction.</p>
    </section>

    <!-- ====== 2. ANIMATION-NAME ====== -->
    <section>
        <h2>2. animation-name</h2>
        <p>Specifies which <code>@keyframes</code> rule to use. You can specify multiple animations separated by commas.</p>

        <div class="code-block">
            /* Single animation */
            .box {
                animation-name: slideIn;
            }

            /* Multiple animations */
            .box {
                animation-name: slideIn, fadeIn;
                animation-duration: 2s, 1s;
            }
        </div>
    </section>

    <!-- ====== 3. ANIMATION-DURATION ====== -->
    <section>
        <h2>3. animation-duration</h2>
        <p>Specifies how long one cycle takes. <code>0s</code> means no animation.</p>

        <div class="code-block">
            .box { animation-duration: 2s; }   /* 2 seconds */
            .box { animation-duration: 500ms; } /* 500 milliseconds */
            .box { animation-duration: 0s; }   /* No animation */
        </div>

        <p class="note"><strong>Important:</strong> If <code>animation-duration</code> is <code>0s</code> (the default), the animation won't play — even if <code>animation-name</code> is set.</p>
    </section>

    <!-- ====== 4. ANIMATION-TIMING-FUNCTION ====== -->
    <section>
        <h2>4. animation-timing-function</h2>
        <p>Each box moves across the screen with a different timing function.</p>

        <div class="demo-area" style="flex-direction: column; gap: 15px; align-items: flex-start;">
            <div style="display: flex; align-items: center; gap: 15px;">
                <span style="font-weight: bold; min-width: 110px;">ease:</span>
                <div class="timing-box timing-ease">ease</div>
            </div>
            <div style="display: flex; align-items: center; gap: 15px;">
                <span style="font-weight: bold; min-width: 110px;">linear:</span>
                <div class="timing-box timing-linear">linear</div>
            </div>
            <div style="display: flex; align-items: center; gap: 15px;">
                <span style="font-weight: bold; min-width: 110px;">ease-in:</span>
                <div class="timing-box timing-ease-in">ease-in</div>
            </div>
            <div style="display: flex; align-items: center; gap: 15px;">
                <span style="font-weight: bold; min-width: 110px;">ease-out:</span>
                <div class="timing-box timing-ease-out">ease-out</div>
            </div>
            <div style="display: flex; align-items: center; gap: 15px;">
                <span style="font-weight: bold; min-width: 110px;">ease-in-out:</span>
                <div class="timing-box timing-ease-in-out">ease-in-out</div>
            </div>
        </div>

        <div class="code-block">
            @keyframes moveRight {
                from { transform: translateX(0); }
                to   { transform: translateX(150px); }
            }

            .timing-ease        { animation-timing-function: ease; }
            .timing-linear      { animation-timing-function: linear; }
            .timing-ease-in     { animation-timing-function: ease-in; }
            .timing-ease-out    { animation-timing-function: ease-out; }
            .timing-ease-in-out { animation-timing-function: ease-in-out; }
        </div>
    </section>

    <!-- ====== 5. ANIMATION-DELAY ====== -->
    <section>
        <h2>5. animation-delay</h2>
        <p>Compare positive and negative delays. Refresh the page to see the difference.</p>

        <div class="demo-area">
            <div style="text-align: center;">
                <div class="delay-box delay-0">0s</div>
                <p class="note">delay: 0s</p>
            </div>
            <div style="text-align: center;">
                <div class="delay-box delay-1">1s</div>
                <p class="note">delay: 1s</p>
            </div>
            <div style="text-align: center;">
                <div class="delay-box delay-neg">-0.5s</div>
                <p class="note">delay: -0.5s</p>
            </div>
        </div>

        <div class="code-block">
            .delay-0   { animation-delay: 0s; }
            .delay-1   { animation-delay: 1s; }
            .delay-neg { animation-delay: -0.5s; }

            @keyframes fadeSlide {
                from { opacity: 0; transform: translateX(-50px); }
                to   { opacity: 1; transform: translateX(0); }
            }
        </div>

        <p class="note">A <strong>negative delay</strong> starts the animation already partway through. With <code>-0.5s</code> on a <code>1s</code> animation, it starts halfway (at 50% opacity and position).</p>
    </section>

    <!-- ====== 6. ANIMATION-ITERATION-COUNT ====== -->
    <section>
        <h2>6. animation-iteration-count</h2>
        <p>Compare different iteration counts. Watch closely — they all use the same animation.</p>

        <div class="demo-area">
            <div style="text-align: center;">
                <div class="iteration-box iter-1">1×</div>
                <p class="note">count: 1</p>
            </div>
            <div style="text-align: center;">
                <div class="iteration-box iter-3">3×</div>
                <p class="note">count: 3</p>
            </div>
            <div style="text-align: center;">
                <div class="iteration-box iter-half">0.5×</div>
                <p class="note">count: 0.5</p>
            </div>
            <div style="text-align: center;">
                <div class="iteration-box iter-infinite">∞</div>
                <p class="note">count: infinite</p>
            </div>
        </div>

        <div class="code-block">
            .iter-1        { animation-iteration-count: 1; }
            .iter-3        { animation-iteration-count: 3; }
            .iter-half     { animation-iteration-count: 0.5; }
            .iter-infinite { animation-iteration-count: infinite; }

            @keyframes pulseScale {
                0%, 100% { transform: scale(1); }
                50%      { transform: scale(1.3); }
            }
        </div>
    </section>

    <!-- ====== 7. ANIMATION-DIRECTION ====== -->
    <section>
        <h2>7. animation-direction</h2>
        <p>Compare the four direction values. Watch how each box moves.</p>

        <div class="demo-area" style="flex-direction: column; gap: 15px; align-items: flex-start;">
            <div style="display: flex; align-items: center; gap: 15px;">
                <span style="font-weight: bold; min-width: 160px;">normal:</span>
                <div class="direction-box dir-normal">normal</div>
            </div>
            <div style="display: flex; align-items: center; gap: 15px;">
                <span style="font-weight: bold; min-width: 160px;">reverse:</span>
                <div class="direction-box dir-reverse">reverse</div>
            </div>
            <div style="display: flex; align-items: center; gap: 15px;">
                <span style="font-weight: bold; min-width: 160px;">alternate:</span>
                <div class="direction-box dir-alternate">alternate</div>
            </div>
            <div style="display: flex; align-items: center; gap: 15px;">
                <span style="font-weight: bold; min-width: 160px;">alternate-reverse:</span>
                <div class="direction-box dir-alternate-reverse">alt-rev</div>
            </div>
        </div>

        <div class="code-block">
            @keyframes slideAcross {
                from { transform: translateX(0); }
                to   { transform: translateX(150px); }
            }

            .dir-normal           { animation-direction: normal; }
            .dir-reverse          { animation-direction: reverse; }
            .dir-alternate        { animation-direction: alternate; }
            .dir-alternate-reverse { animation-direction: alternate-reverse; }
        </div>

        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Cycle 1</th>
                <th>Cycle 2</th>
                <th>Cycle 3</th>
            </tr>
            <tr>
                <td><code>normal</code></td>
                <td>→</td>
                <td>→</td>
                <td>→</td>
            </tr>
            <tr>
                <td><code>reverse</code></td>
                <td>←</td>
                <td>←</td>
                <td>←</td>
            </tr>
            <tr>
                <td><code>alternate</code></td>
                <td>→</td>
                <td>←</td>
                <td>→</td>
            </tr>
            <tr>
                <td><code>alternate-reverse</code></td>
                <td>←</td>
                <td>→</td>
                <td>←</td>
            </tr>
        </table>
    </section>

    <!-- ====== 8. PRACTICAL: SLIDE-IN BANNER ====== -->
    <section>
        <h2>8. Practical Example: Slide-In Banner</h2>
        <p>Refresh the page to see the banner slide in from the top.</p>

        <div class="banner-container">
            <div class="banner">
                🎉 Welcome! This banner slides in from the top.
            </div>
        </div>

        <div class="code-block">
            .banner {
                animation-name: bannerSlide;
                animation-duration: 1s;
                animation-delay: 0.5s;
                animation-fill-mode: backwards;
                animation-timing-function: ease-out;
            }

            @keyframes bannerSlide {
                from { opacity: 0; transform: translateY(-50px); }
                to   { opacity: 1; transform: translateY(0); }
            }
        </div>

        <p class="note">The <code>animation-fill-mode: backwards</code> applies the <code>from</code> styles during the delay, so the banner is invisible before it starts.</p>
    </section>

    <!-- ====== 9. PRACTICAL: STAGGERED LIST ====== -->
    <section>
        <h2>9. Practical Example: Staggered List</h2>
        <p>Refresh the page to see the list items appear one by one.</p>

        <ul class="staggered-list">
            <li>✨ First item slides in</li>
            <li>🚀 Second item follows</li>
            <li>🎯 Third item appears</li>
            <li>💎 Fourth item arrives</li>
            <li>🔥 Fifth item completes the list</li>
        </ul>

        <div class="code-block">
            .staggered-list li {
                animation-name: listItemIn;
                animation-duration: 0.5s;
                animation-fill-mode: both;
                animation-timing-function: ease-out;
            }

            .staggered-list li:nth-child(1) { animation-delay: 0.1s; }
            .staggered-list li:nth-child(2) { animation-delay: 0.2s; }
            .staggered-list li:nth-child(3) { animation-delay: 0.3s; }
            .staggered-list li:nth-child(4) { animation-delay: 0.4s; }
            .staggered-list li:nth-child(5) { animation-delay: 0.5s; }

            @keyframes listItemIn {
                from { opacity: 0; transform: translateX(-30px); }
                to   { opacity: 1; transform: translateX(0); }
            }
        </div>
    </section>

    <!-- ====== 10. PRACTICAL: PULSING NOTIFICATION ====== -->
    <section>
        <h2>10. Practical Example: Pulsing Notification</h2>
        <p>A notification badge that pulses to draw attention.</p>

        <div style="text-align: center;">
            <div class="notification-container">
                <span class="notification-icon">🔔</span>
                <span class="notification-badge">3</span>
            </div>
        </div>

        <div class="code-block">
            .notification-badge {
                animation-name: pulseRing;
                animation-duration: 1.5s;
                animation-iteration-count: infinite;
                animation-timing-function: ease-out;
            }

            @keyframes pulseRing {
                0%   { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7); }
                70%  { box-shadow: 0 0 0 12px rgba(220, 53, 69, 0); }
                100% { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0); }
            }
        </div>
    </section>

    <!-- ====== 11. REFERENCE TABLES ====== -->
    <section>
        <h2>11. Reference Tables</h2>

        <h3>Animation Properties — Part 1</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Default</th>
            </tr>
            <tr>
                <td><code>animation-name</code></td>
                <td>Name of the @keyframes rule</td>
                <td><code>none</code></td>
            </tr>
            <tr>
                <td><code>animation-duration</code></td>
                <td>How long one cycle takes</td>
                <td><code>0s</code></td>
            </tr>
            <tr>
                <td><code>animation-timing-function</code></td>
                <td>Speed curve</td>
                <td><code>ease</code></td>
            </tr>
            <tr>
                <td><code>animation-delay</code></td>
                <td>Wait before starting</td>
                <td><code>0s</code></td>
            </tr>
            <tr>
                <td><code>animation-iteration-count</code></td>
                <td>How many times to repeat</td>
                <td><code>1</code></td>
            </tr>
            <tr>
                <td><code>animation-direction</code></td>
                <td>Direction of each cycle</td>
                <td><code>normal</code></td>
            </tr>
        </table>

        <h3>animation-timing-function Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>ease</code></td>
                <td>Slow start, fast middle, slow end (default)</td>
            </tr>
            <tr>
                <td><code>linear</code></td>
                <td>Constant speed</td>
            </tr>
            <tr>
                <td><code>ease-in</code></td>
                <td>Slow start, fast end</td>
            </tr>
            <tr>
                <td><code>ease-out</code></td>
                <td>Fast start, slow end</td>
            </tr>
            <tr>
                <td><code>ease-in-out</code></td>
                <td>Slow start, fast middle, slow end</td>
            </tr>
            <tr>
                <td><code>cubic-bezier(n,n,n,n)</code></td>
                <td>Custom curve</td>
            </tr>
            <tr>
                <td><code>steps(n)</code></td>
                <td>Stepped animation</td>
            </tr>
        </table>

        <h3>animation-iteration-count Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>1</code></td>
                <td>Plays once (default)</td>
            </tr>
            <tr>
                <td><code>3</code></td>
                <td>Plays 3 times</td>
            </tr>
            <tr>
                <td><code>infinite</code></td>
                <td>Repeats forever</td>
            </tr>
            <tr>
                <td><code>0.5</code></td>
                <td>Plays half the animation</td>
            </tr>
            <tr>
                <td><code>2.5</code></td>
                <td>Plays 2.5 cycles</td>
            </tr>
        </table>

        <h3>animation-direction Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>normal</code></td>
                <td>Forward each cycle (default)</td>
            </tr>
            <tr>
                <td><code>reverse</code></td>
                <td>Backward each cycle</td>
            </tr>
            <tr>
                <td><code>alternate</code></td>
                <td>Forward, then backward</td>
            </tr>
            <tr>
                <td><code>alternate-reverse</code></td>
                <td>Backward, then forward</td>
            </tr>
        </table>
    </section>

    <!-- ====== 12. BEST PRACTICES ====== -->
    <section>
        <h2>12. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Always specify <code>animation-duration</code> — the default is <code>0s</code></li>
                <li>Use <code>animation-delay</code> for staggered effects</li>
                <li>Use <code>animation-iteration-count: infinite</code> for continuous animations</li>
                <li>Use <code>animation-direction: alternate</code> for back-and-forth motion</li>
                <li>Use negative delays to start animations partway through</li>
                <li>Use <code>transform</code> and <code>opacity</code> for smooth performance</li>
                <li>Respect <code>prefers-reduced-motion</code> for accessibility</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't forget <code>animation-duration</code> — nothing will happen</li>
                <li>Don't use <code>infinite</code> for animations that should stop</li>
                <li>Don't confuse <code>animation-delay</code> with <code>animation-duration</code></li>
                <li>Don't use negative delays without understanding the effect</li>
                <li>Don't animate layout properties like <code>width</code> or <code>height</code></li>
                <li>Don't forget about <code>prefers-reduced-motion</code></li>
            </ul>
        </div>

        <div class="code-block">
            /* Accessibility: respect reduced motion */
            @media (prefers-reduced-motion: reduce) {
                .box,
                .banner,
                .staggered-list li,
                .notification-badge {
                    animation: none;
                }
            }

            /* Staggered animation */
            .item:nth-child(1) { animation-delay: 0.1s; }
            .item:nth-child(2) { animation-delay: 0.2s; }
            .item:nth-child(3) { animation-delay: 0.3s; }
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionDefault
animation-nameName of the @keyframes rulenone
animation-durationHow long one cycle takes0s
animation-timing-functionSpeed curveease
animation-delayWait before starting0s
animation-iteration-countHow many times to repeat1
animation-directionDirection of each cyclenormal

animation-timing-function Values

ValueDescription
easeSlow start, fast middle, slow end (default)
linearConstant speed
ease-inSlow start, fast end
ease-outFast start, slow end
ease-in-outSlow start, fast middle, slow end
cubic-bezier(n,n,n,n)Custom curve
steps(n)Stepped animation

animation-iteration-count Values

ValueDescription
1Plays once (default)
3Plays 3 times
infiniteRepeats forever
0.5Plays half the animation
2.5Plays 2.5 cycles

animation-direction Values

ValueDescription
normalForward each cycle (default)
reverseBackward each cycle
alternateForward, then backward
alternate-reverseBackward, then forward

Best Practices

Do This:

/* Complete animation setup */
.box {
    animation-name: slideIn;
    animation-duration: 2s;
    animation-timing-function: ease-in-out;
    animation-delay: 0.5s;
    animation-iteration-count: 3;
    animation-direction: alternate;
}

/* Staggered animation with delay */
.item:nth-child(1) { animation-delay: 0.1s; }
.item:nth-child(2) { animation-delay: 0.2s; }
.item:nth-child(3) { animation-delay: 0.3s; }

/* Continuous animation */
.spinner {
    animation: spin 1s linear infinite;
}

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    .box {
        animation: none;
    }
}

Don’t Do This:

/* Don't forget animation-duration */
.box {
    animation-name: slideIn; /* Duration is 0s — nothing happens! */
}

/* Don't confuse delay with duration */
.box {
    animation-delay: 2s;    /* Waits 2s before starting */
    animation-duration: 1s; /* Then takes 1s to complete */
}

/* Don't use infinite for one-time animations */
.alert {
    animation: pulse 1s infinite; /* Will pulse forever! */
}

/* Don't forget reduced motion */
@media (prefers-reduced-motion: reduce) {
    /* Missing — animations still play */
}

Pro Tip: The six properties in this lesson are the core of CSS animations. Remember: animation-duration is required (default 0s means no animation). Use animation-delay for staggered effects — applying incremental delays to list items creates a beautiful cascade. animation-iteration-count: infinite is perfect for continuous animations like spinners and pulses. animation-direction: alternate creates natural back-and-forth motion. And always respect prefers-reduced-motion — some users experience discomfort from animations!

57. Animation Properties — Part 2

This lesson covers the remaining animation properties: animation-fill-mode, animation-play-state, animation-timeline, and animation-composition.


Overview of Properties

PropertyDescriptionDefault
animation-fill-modeStyles before/after animationnone
animation-play-stateRunning or pausedrunning
animation-timelineTimeline that controls the animationauto
animation-compositionHow multiple animations combinereplace

1. animation-fill-mode

Defines the styles applied to an element before and after the animation plays.

.box {
    animation-fill-mode: forwards;
}

Values

ValueDescription
noneNo styles applied outside the animation (default)
forwardsKeep the last keyframe’s styles after the animation ends
backwardsApply the first keyframe’s styles during the delay
bothApply both forwards and backwards

Visual Explanation

Without fill-mode:
[before] [animation] [after → reverts to original]

With forwards:
[before] [animation] [after → keeps end state]

With backwards:
[before → shows start state] [animation] [after]

With both:
[before → shows start state] [animation] [after → keeps end state]

Key Points:

  • forwards — the element stays at the animation’s end state
  • backwards — the element shows the start state during the delay
  • both — combines both effects
  • Without fill-mode, the element snaps back to its original state after the animation

2. animation-play-state

Controls whether an animation is running or paused.

.box {
    animation-play-state: paused;
}

Values

ValueDescription
runningAnimation is playing (default)
pausedAnimation is paused

Key Points:

  • Useful for pausing animations on hover
  • The animation resumes from where it was paused
  • Commonly used with :hover for interactive control

Example:

.animation:hover {
    animation-play-state: paused;
}

3. animation-timeline

Allows you to specify a timeline that controls the animation instead of the default document timeline.

.box {
    animation-timeline: scroll();
}

Values

ValueDescription
autoDefault document timeline (default)
noneNo timeline — animation doesn’t play
scroll()Binds animation to scroll position
view()Binds animation to element visibility in viewport

scroll() Timeline

.box {
    animation-timeline: scroll();
}

The animation progresses in sync with scrolling — as the user scrolls, the animation advances. This creates scroll-driven animations that feel connected to the user’s interaction.

Variations:

animation-timeline: scroll();           /* Root scroller */
animation-timeline: scroll(root);       /* Root scroller */
animation-timeline: scroll(nearest);    /* Nearest scrollable ancestor */
animation-timeline: scroll(self);       /* The element itself */

view() Timeline

.box {
    animation-timeline: view();
}

The animation progresses based on the element’s visibility within the viewport — as the element enters, crosses, and exits the viewport, the animation plays.

Key Points:

  • animation-timeline is a modern feature with growing browser support
  • Scroll-driven animations are performant — they run on the compositor thread
  • Always provide a fallback for browsers that don’t support it

4. animation-composition

Controls how multiple animations that target the same properties combine their effects.

.box {
    animation-composition: add;
}

Values

ValueDescription
replaceNew animations overwrite previous ones (default)
addNew animations add to existing effects
accumulateSimilar to add, but with additional rules for keyframes and timing

How It Works

replace (default): The last animation wins.

.box {
    animation-name: moveRight, fadeOut;
    animation-composition: replace;
    /* fadeOut's opacity replaces any opacity from moveRight */
}

add: Effects are combined.

.box {
    animation-name: moveRight, moveUp;
    animation-composition: add;
    /* The box moves both right AND up */
}

accumulate: Similar to add, but keyframe values accumulate.

.box {
    animation-name: scale1, scale2;
    animation-composition: accumulate;
    /* scale1 and scale2 combine their scale values */
}

Key Points:

  • replace is the default — later animations override earlier ones
  • add combines transform effects (e.g., translate + rotate)
  • accumulate is useful for stacking animations with the same property

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Animation Properties — Part 2</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            line-height: 1.6;
        }

        h1 {
            color: #007bff;
            border-bottom: 3px solid #007bff;
            padding-bottom: 10px;
        }

        h2 {
            color: #28a745;
            border-left: 4px solid #28a745;
            padding-left: 15px;
            margin-top: 30px;
        }

        h3 {
            color: #333;
            margin-top: 20px;
        }

        section {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 20px 0;
        }

        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
            margin: 10px 0;
        }

        .reference-table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        .reference-table th,
        .reference-table td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }

        .reference-table th {
            background: #007bff;
            color: white;
        }

        .reference-table tr:nth-child(even) {
            background: #f8f9fa;
        }

        .note {
            font-size: 0.9rem;
            color: #6c757d;
            margin-top: 5px;
        }

        .highlight {
            background: #ffc107;
            color: #333;
            padding: 2px 6px;
            border-radius: 4px;
            font-weight: bold;
        }

        /* ====== DEMO AREA ====== */
        .demo-area {
            display: flex;
            flex-wrap: wrap;
            gap: 40px;
            justify-content: center;
            align-items: center;
            padding: 40px 20px;
            background: #e9ecef;
            border-radius: 8px;
            margin: 15px 0;
            min-height: 200px;
            overflow: hidden;
        }

        /* ====== BASIC ANIMATION ====== */
        .box {
            width: 100px;
            height: 100px;
            background: #007bff;
            border-radius: 12px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
            animation-name: exampleAnimation;
            animation-duration: 2s;
            animation-fill-mode: forwards;
        }

        @keyframes exampleAnimation {
            from {
                transform: translateX(0);
                background-color: #007bff;
            }
            to {
                transform: translateX(200px);
                background-color: #dc3545;
            }
        }

        /* ====== FILL MODE COMPARISON ====== */
        .fill-box {
            width: 80px;
            height: 80px;
            background: #007bff;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.7rem;
            animation-name: fillDemo;
            animation-duration: 1s;
            animation-delay: 0.5s;
            animation-timing-function: ease;
        }

        .fill-none {
            animation-fill-mode: none;
        }

        .fill-forwards {
            animation-fill-mode: forwards;
        }

        .fill-backwards {
            animation-fill-mode: backwards;
        }

        .fill-both {
            animation-fill-mode: both;
        }

        @keyframes fillDemo {
            from {
                opacity: 0;
                transform: translateX(-50px);
                background: #dc3545;
            }
            to {
                opacity: 1;
                transform: translateX(0);
                background: #28a745;
            }
        }

        /* ====== PLAY STATE ====== */
        .play-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 15px;
        }

        .play-box {
            width: 100px;
            height: 100px;
            background: #6c5ce7;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            animation: pulseAnim 1.5s ease-in-out infinite;
        }

        .play-box:hover {
            animation-play-state: paused;
        }

        @keyframes pulseAnim {
            0%, 100% {
                transform: scale(1);
                box-shadow: 0 0 0 0 rgba(108, 92, 231, 0.7);
            }
            50% {
                transform: scale(1.15);
                box-shadow: 0 0 0 15px rgba(108, 92, 231, 0);
            }
        }

        /* ====== COMPOSITION ====== */
        .composition-box {
            width: 80px;
            height: 80px;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 0.6rem;
            animation-duration: 3s;
            animation-iteration-count: infinite;
            animation-timing-function: ease-in-out;
        }

        .comp-replace {
            background: #007bff;
            animation-name: moveRight, rotateBox;
            animation-composition: replace;
        }

        .comp-add {
            background: #28a745;
            animation-name: moveRight, moveUp;
            animation-composition: add;
        }

        .comp-accumulate {
            background: #ffc107;
            color: #333;
            animation-name: scaleUp, scaleDown;
            animation-composition: accumulate;
        }

        @keyframes moveRight {
            from { transform: translateX(0); }
            to   { transform: translateX(100px); }
        }

        @keyframes moveUp {
            from { transform: translateY(0); }
            to   { transform: translateY(-50px); }
        }

        @keyframes rotateBox {
            from { transform: rotate(0deg); }
            to   { transform: rotate(180deg); }
        }

        @keyframes scaleUp {
            from { transform: scale(1); }
            to   { transform: scale(1.5); }
        }

        @keyframes scaleDown {
            from { transform: scale(1); }
            to   { transform: scale(0.7); }
        }

        /* ====== SCROLL TIMELINE ====== */
        .scroll-container {
            height: 300px;
            overflow-y: scroll;
            background: #f8f9fa;
            border: 2px solid #ddd;
            border-radius: 8px;
            margin: 15px 0;
            position: relative;
        }

        .scroll-content {
            height: 1200px;
            padding: 20px;
        }

        .scroll-animated-box {
            width: 80px;
            height: 80px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            border-radius: 12px;
            position: sticky;
            top: 20px;
            animation-name: scrollAnimation;
            animation-duration: 1s;
            animation-timeline: scroll(nearest);
            animation-fill-mode: both;
        }

        @keyframes scrollAnimation {
            from {
                transform: scale(0.5) rotate(0deg);
                background: #007bff;
                opacity: 0.5;
            }
            to {
                transform: scale(1) rotate(360deg);
                background: #28a745;
                opacity: 1;
            }
        }

        .scroll-instruction {
            position: sticky;
            top: 0;
            background: rgba(255, 255, 255, 0.9);
            padding: 10px;
            border-radius: 8px;
            text-align: center;
            font-weight: bold;
            color: #007bff;
            z-index: 10;
        }

        /* ====== PRACTICAL: HOVER-PAUSE CARD ====== */
        .hover-pause-container {
            display: flex;
            gap: 30px;
            justify-content: center;
            flex-wrap: wrap;
            margin: 20px 0;
        }

        .hover-pause-card {
            width: 180px;
            height: 180px;
            background: linear-gradient(135deg, #007bff, #6c5ce7);
            border-radius: 16px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            color: white;
            text-align: center;
            padding: 20px;
            cursor: pointer;
            animation: floatCard 3s ease-in-out infinite;
            box-shadow: 0 8px 25px rgba(0, 123, 255, 0.2);
        }

        .hover-pause-card:hover {
            animation-play-state: paused;
        }

        .hover-pause-card .icon {
            font-size: 2.5rem;
            margin-bottom: 10px;
        }

        .hover-pause-card h4 {
            margin: 0;
            font-size: 1rem;
        }

        .hover-pause-card p {
            margin: 5px 0 0 0;
            font-size: 0.8rem;
            opacity: 0.9;
        }

        @keyframes floatCard {
            0%, 100% { transform: translateY(0); }
            50%      { transform: translateY(-15px); }
        }

        /* ====== PRACTICAL: SCROLL PROGRESS ====== */
        .progress-scroll-container {
            height: 250px;
            overflow-y: scroll;
            background: #f8f9fa;
            border: 2px solid #ddd;
            border-radius: 8px;
            margin: 15px 0;
            position: relative;
        }

        .progress-scroll-content {
            height: 1000px;
            padding: 20px;
        }

        .progress-indicator {
            position: sticky;
            top: 0;
            height: 8px;
            background: #e9ecef;
            border-radius: 4px;
            z-index: 10;
        }

        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, #007bff, #6c5ce7);
            border-radius: 4px;
            animation-name: progressGrow;
            animation-duration: 1s;
            animation-timeline: scroll(nearest);
            animation-fill-mode: both;
            transform-origin: left;
        }

        @keyframes progressGrow {
            from { transform: scaleX(0); }
            to   { transform: scaleX(1); }
        }

        /* ====== TIPS ====== */
        .tip-box {
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            background: #f8f9fa;
        }

        .tip-box.success { border-left-color: #28a745; }
        .tip-box.warning { border-left-color: #ffc107; }
        .tip-box.danger { border-left-color: #dc3545; }
    </style>
</head>
<body>

    <h1>Animation Properties — Part 2</h1>

    <!-- ====== 1. BASIC ANIMATION WITH FILL-MODE ====== -->
    <section>
        <h2>1. animation-fill-mode: forwards</h2>
        <p>The box stays at its final position and color after the animation ends.</p>

        <div class="demo-area">
            <div class="box"></div>
        </div>

        <div class="code-block">
            .box {
                animation-name: exampleAnimation;
                animation-duration: 2s;
                animation-fill-mode: forwards;
            }

            @keyframes exampleAnimation {
                from { transform: translateX(0); background-color: blue; }
                to   { transform: translateX(200px); background-color: red; }
            }
        </div>

        <p class="note">Without <code>fill-mode: forwards</code>, the box would snap back to its original position and color.</p>
    </section>

    <!-- ====== 2. FILL MODE COMPARISON ====== -->
    <section>
        <h2>2. animation-fill-mode Comparison</h2>
        <p>Refresh the page to see the four fill-mode values in action.</p>

        <div class="demo-area" style="flex-direction: column; gap: 20px; align-items: flex-start;">
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 150px;">none:</span>
                <div class="fill-box fill-none">none</div>
            </div>
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 150px;">forwards:</span>
                <div class="fill-box fill-forwards">forwards</div>
            </div>
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 150px;">backwards:</span>
                <div class="fill-box fill-backwards">backwards</div>
            </div>
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 150px;">both:</span>
                <div class="fill-box fill-both">both</div>
            </div>
        </div>

        <div class="code-block">
            .fill-none      { animation-fill-mode: none; }
            .fill-forwards  { animation-fill-mode: forwards; }
            .fill-backwards { animation-fill-mode: backwards; }
            .fill-both      { animation-fill-mode: both; }

            @keyframes fillDemo {
                from { opacity: 0; transform: translateX(-50px); background: #dc3545; }
                to   { opacity: 1; transform: translateX(0); background: #28a745; }
            }
        </div>

        <p class="note"><strong>none</strong> reverts after the animation. <strong>forwards</strong> keeps the end state. <strong>backwards</strong> applies the start state during the delay. <strong>both</strong> does both.</p>
    </section>

    <!-- ====== 3. ANIMATION-PLAY-STATE ====== -->
    <section>
        <h2>3. animation-play-state</h2>
        <p>Hover over the box to pause the animation.</p>

        <div class="demo-area">
            <div class="play-container">
                <div class="play-box">Hover to Pause</div>
            </div>
        </div>

        <div class="code-block">
            .play-box {
                animation: pulseAnim 1.5s ease-in-out infinite;
            }

            .play-box:hover {
                animation-play-state: paused;
            }
        </div>
    </section>

    <!-- ====== 4. ANIMATION-COMPOSITION ====== -->
    <section>
        <h2>4. animation-composition</h2>
        <p>Compare how multiple animations combine with different composition values.</p>

        <div class="demo-area" style="flex-direction: column; gap: 25px; align-items: flex-start;">
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 180px;">replace (default):</span>
                <div class="composition-box comp-replace">replace</div>
            </div>
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 180px;">add:</span>
                <div class="composition-box comp-add">add</div>
            </div>
            <div style="display: flex; align-items: center; gap: 20px;">
                <span style="font-weight: bold; min-width: 180px;">accumulate:</span>
                <div class="composition-box comp-accumulate">accumulate</div>
            </div>
        </div>

        <div class="code-block">
            /* replace: later animation overwrites earlier */
            .comp-replace {
                animation-name: moveRight, rotateBox;
                animation-composition: replace;
            }

            /* add: effects combine (move right AND up) */
            .comp-add {
                animation-name: moveRight, moveUp;
                animation-composition: add;
            }

            /* accumulate: scale values add together */
            .comp-accumulate {
                animation-name: scaleUp, scaleDown;
                animation-composition: accumulate;
            }
        </div>

        <p class="note">With <code>add</code>, the box moves both right and up. With <code>replace</code>, only the second animation's transform applies.</p>
    </section>

    <!-- ====== 5. ANIMATION-TIMELINE (SCROLL) ====== -->
    <section>
        <h2>5. animation-timeline: scroll()</h2>
        <p>Scroll inside the box to see the animation progress with the scroll position.</p>

        <div class="scroll-container">
            <div class="scroll-content">
                <div class="scroll-instruction">⬇️ Scroll down to animate ⬇️</div>
                <div class="scroll-animated-box"></div>
                <p style="margin-top: 20px; color: #6c757d;">
                    The box grows, rotates, and changes color as you scroll.
                    Keep scrolling to see the full animation.
                </p>
                <p style="margin-top: 200px; color: #6c757d;">
                    The animation is driven by the scroll position — not by time.
                </p>
                <p style="margin-top: 200px; color: #6c757d;">
                    Near the bottom — the animation is almost complete.
                </p>
                <p style="margin-top: 200px; color: #6c757d;">
                    🎉 You've reached the end!
                </p>
            </div>
        </div>

        <div class="code-block">
            .scroll-animated-box {
                animation-name: scrollAnimation;
                animation-duration: 1s;
                animation-timeline: scroll(nearest);
                animation-fill-mode: both;
            }

            @keyframes scrollAnimation {
                from {
                    transform: scale(0.5) rotate(0deg);
                    background: #007bff;
                    opacity: 0.5;
                }
                to {
                    transform: scale(1) rotate(360deg);
                    background: #28a745;
                    opacity: 1;
                }
            }
        </div>

        <div class="tip-box warning">
            <strong>⚠️ Browser Support:</strong>
            <code>animation-timeline</code> is a modern feature. Check <a href="https://caniuse.com/css-scroll-timeline" target="_blank">caniuse.com</a> for current browser support.
        </div>
    </section>

    <!-- ====== 6. PRACTICAL: HOVER-PAUSE CARDS ====== -->
    <section>
        <h2>6. Practical Example: Hover-Pause Cards</h2>
        <p>Hover over a card to pause its floating animation.</p>

        <div class="hover-pause-container">
            <div class="hover-pause-card">
                <div class="icon">🚀</div>
                <h4>Fast</h4>
                <p>Hover to pause</p>
            </div>
            <div class="hover-pause-card">
                <div class="icon">🎨</div>
                <h4>Beautiful</h4>
                <p>Hover to pause</p>
            </div>
            <div class="hover-pause-card">
                <div class="icon">🔒</div>
                <h4>Secure</h4>
                <p>Hover to pause</p>
            </div>
        </div>

        <div class="code-block">
            .hover-pause-card {
                animation: floatCard 3s ease-in-out infinite;
            }

            .hover-pause-card:hover {
                animation-play-state: paused;
            }

            @keyframes floatCard {
                0%, 100% { transform: translateY(0); }
                50%      { transform: translateY(-15px); }
            }
        </div>
    </section>

    <!-- ====== 7. PRACTICAL: SCROLL PROGRESS ====== -->
    <section>
        <h2>7. Practical Example: Scroll Progress Bar</h2>
        <p>Scroll inside the box to see the progress bar fill based on scroll position.</p>

        <div class="progress-scroll-container">
            <div class="progress-scroll-content">
                <div class="progress-indicator">
                    <div class="progress-fill"></div>
                </div>
                <p style="margin-top: 20px; color: #6c757d;">
                    The progress bar at the top fills as you scroll.
                </p>
                <p style="margin-top: 300px; color: #6c757d;">
                    Keep scrolling to see the progress grow.
                </p>
                <p style="margin-top: 300px; color: #6c757d;">
                    Almost there...
                </p>
                <p style="margin-top: 300px; color: #6c757d;">
                    🎉 Complete!
                </p>
            </div>
        </div>

        <div class="code-block">
            .progress-fill {
                animation-name: progressGrow;
                animation-duration: 1s;
                animation-timeline: scroll(nearest);
                animation-fill-mode: both;
                transform-origin: left;
            }

            @keyframes progressGrow {
                from { transform: scaleX(0); }
                to   { transform: scaleX(1); }
            }
        </div>
    </section>

    <!-- ====== 8. REFERENCE TABLES ====== -->
    <section>
        <h2>8. Reference Tables</h2>

        <h3>Animation Properties — Part 2</h3>
        <table class="reference-table">
            <tr>
                <th>Property</th>
                <th>Description</th>
                <th>Default</th>
            </tr>
            <tr>
                <td><code>animation-fill-mode</code></td>
                <td>Styles before/after animation</td>
                <td><code>none</code></td>
            </tr>
            <tr>
                <td><code>animation-play-state</code></td>
                <td>Running or paused</td>
                <td><code>running</code></td>
            </tr>
            <tr>
                <td><code>animation-timeline</code></td>
                <td>Timeline that controls the animation</td>
                <td><code>auto</code></td>
            </tr>
            <tr>
                <td><code>animation-composition</code></td>
                <td>How multiple animations combine</td>
                <td><code>replace</code></td>
            </tr>
        </table>

        <h3>animation-fill-mode Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>No styles applied outside the animation (default)</td>
            </tr>
            <tr>
                <td><code>forwards</code></td>
                <td>Keep the last keyframe's styles</td>
            </tr>
            <tr>
                <td><code>backwards</code></td>
                <td>Apply the first keyframe's styles during delay</td>
            </tr>
            <tr>
                <td><code>both</code></td>
                <td>Apply both forwards and backwards</td>
            </tr>
        </table>

        <h3>animation-play-state Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>running</code></td>
                <td>Animation is playing (default)</td>
            </tr>
            <tr>
                <td><code>paused</code></td>
                <td>Animation is paused</td>
            </tr>
        </table>

        <h3>animation-timeline Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>auto</code></td>
                <td>Default document timeline (default)</td>
            </tr>
            <tr>
                <td><code>none</code></td>
                <td>No timeline — animation doesn't play</td>
            </tr>
            <tr>
                <td><code>scroll()</code></td>
                <td>Binds animation to scroll position</td>
            </tr>
            <tr>
                <td><code>view()</code></td>
                <td>Binds animation to element visibility in viewport</td>
            </tr>
        </table>

        <h3>animation-composition Values</h3>
        <table class="reference-table">
            <tr>
                <th>Value</th>
                <th>Description</th>
            </tr>
            <tr>
                <td><code>replace</code></td>
                <td>New animations overwrite previous ones (default)</td>
            </tr>
            <tr>
                <td><code>add</code></td>
                <td>New animations add to existing effects</td>
            </tr>
            <tr>
                <td><code>accumulate</code></td>
                <td>Similar to add, with additional rules for keyframes</td>
            </tr>
        </table>
    </section>

    <!-- ====== 9. BEST PRACTICES ====== -->
    <section>
        <h2>9. Best Practices</h2>

        <div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
            <h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
            <ul>
                <li>Use <code>animation-fill-mode: forwards</code> to keep the end state</li>
                <li>Use <code>animation-fill-mode: backwards</code> to apply start styles during delay</li>
                <li>Use <code>animation-play-state: paused</code> on hover for interactive control</li>
                <li>Use <code>animation-timeline: scroll()</code> for scroll-driven animations</li>
                <li>Use <code>animation-composition: add</code> to combine transform effects</li>
                <li>Always provide fallbacks for modern features</li>
                <li>Respect <code>prefers-reduced-motion</code> for accessibility</li>
            </ul>
        </div>

        <div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
            <h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
            <ul>
                <li>Don't forget <code>animation-fill-mode</code> — elements snap back without it</li>
                <li>Don't use <code>animation-timeline</code> without a fallback for unsupported browsers</li>
                <li>Don't confuse <code>animation-composition: add</code> with <code>replace</code></li>
                <li>Don't pause animations that are essential for feedback</li>
                <li>Don't forget that scroll-driven animations need a scrollable container</li>
                <li>Don't forget about <code>prefers-reduced-motion</code></li>
            </ul>
        </div>

        <div class="code-block">
            /* Accessibility: respect reduced motion */
            @media (prefers-reduced-motion: reduce) {
                .box,
                .fill-box,
                .play-box,
                .composition-box,
                .scroll-animated-box,
                .hover-pause-card {
                    animation: none;
                }
            }

            /* Scroll-driven animation with fallback */
            .scroll-animated-box {
                animation-name: scrollAnimation;
                animation-duration: 1s;
                animation-fill-mode: both;
            }

            @supports (animation-timeline: scroll()) {
                .scroll-animated-box {
                    animation-timeline: scroll(nearest);
                }
            }
        </div>
    </section>

</body>
</html>

Quick Reference

PropertyDescriptionDefault
animation-fill-modeStyles before/after animationnone
animation-play-stateRunning or pausedrunning
animation-timelineTimeline that controls the animationauto
animation-compositionHow multiple animations combinereplace

animation-fill-mode Values

ValueDescription
noneNo styles applied outside the animation (default)
forwardsKeep the last keyframe’s styles
backwardsApply the first keyframe’s styles during delay
bothApply both forwards and backwards

animation-play-state Values

ValueDescription
runningAnimation is playing (default)
pausedAnimation is paused

animation-timeline Values

ValueDescription
autoDefault document timeline (default)
noneNo timeline — animation doesn’t play
scroll()Binds animation to scroll position
view()Binds animation to element visibility

animation-composition Values

ValueDescription
replaceNew animations overwrite previous ones (default)
addNew animations add to existing effects
accumulateSimilar to add, with additional rules for keyframes

Best Practices

Do This:

/* Keep the end state */
.box {
    animation-fill-mode: forwards;
}

/* Pause on hover */
.box:hover {
    animation-play-state: paused;
}

/* Scroll-driven animation with fallback */
@supports (animation-timeline: scroll()) {
    .box {
        animation-timeline: scroll();
    }
}

/* Combine transforms */
.box {
    animation-name: moveRight, rotate;
    animation-composition: add;
}

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    .box {
        animation: none;
    }
}

Don’t Do This:

/* Don't forget fill-mode */
.box {
    animation: slideIn 1s;
    /* Snaps back after animation */
}

/* Don't use animation-timeline without fallback */
.box {
    animation-timeline: scroll();
    /* Won't work in unsupported browsers */
}

/* Don't use replace when you want combined effects */
.box {
    animation-name: moveRight, moveUp;
    animation-composition: replace;
    /* Only moveUp applies — moveRight is overwritten */
}

Pro Tip: animation-fill-mode: forwards is essential for entrance animations — without it, elements snap back to their original state. animation-play-state: paused on hover gives users control over animations, which is great for accessibility. animation-timeline: scroll() enables scroll-driven animations — a modern, performant way to create engaging scroll experiences (always provide a fallback). animation-composition: add lets you combine multiple transforms (e.g., move right AND rotate). And always respect prefers-reduced-motion — some users experience discomfort from animations!

58. CSS Cheatsheet — Complete Reference

1. Selectors

Basic Selectors

SelectorSyntaxDescription
Elementp { }Targets all elements by tag name
Class.highlight { }Targets elements with a specific class
ID#main-title { }Targets one unique element
Universal* { }Targets all elements
Attribute[ type="text" ] { }Targets elements with a specific attribute
p { color: blue; }
.highlight { background-color: yellow; }
#main-title { font-size: 36px; }
* { margin: 0; padding: 0; }
[type="text"] { border: 1px solid black; }

Attribute Selectors

SyntaxDescriptionExample
[ attr ]Has attribute[ disabled ] { }
[ attr="value" ]Exact match[ type="text" ] { }
[ attr^="value" ]Starts with[ class^="btn-" ] { }
[ attr$="value" ]Ends with[ href$=".pdf" ] { }
[ attr*="value" ]Contains[ class*="icon" ] { }
[ attr~="value" ]Word match[ class~="active" ] { }

Combinators

CombinatorSyntaxDescription
Descendantdiv p { }All <p> inside <div>
Childul > li { }Direct children only
Adjacent Siblingh1 + p { }<p> immediately after <h1>
General Siblingh2 ~ p { }All <p> after <h2>
div p { color: red; }
ul > li { font-weight: bold; }
h1 + p { margin-top: 20px; }
h2 ~ p { font-style: italic; }

Pseudo-Classes

Pseudo-ClassDescription
:hoverMouse over element
:focusElement has focus
:activeElement being clicked
:visitedVisited link
:first-childFirst child of parent
:last-childLast child of parent
:nth-child(n)Nth child
:not(selector)Negation
a:hover { color: red; }
input:focus { border-color: blue; }
li:first-child { font-weight: bold; }
li:nth-child(odd) { background: #f0f0f0; }

Pseudo-Elements

Pseudo-ElementDescription
::beforeInsert before content
::afterInsert after content
::first-lineFirst line of text
::first-letterFirst letter
::placeholderInput placeholder
.quote::before { content: "“"; }
.quote::after { content: "”"; }
p::first-letter { font-size: 2em; }
input::placeholder { color: gray; }

2. Box Model

The Four Layers

┌─────────────────────────────────────┐
│              MARGIN                  │
│  ┌───────────────────────────────┐  │
│  │           BORDER               │  │
│  │  ┌─────────────────────────┐  │  │
│  │  │        PADDING          │  │  │
│  │  │  ┌───────────────────┐  │  │  │
│  │  │  │     CONTENT       │  │  │  │
│  │  │  └───────────────────┘  │  │  │
│  │  └─────────────────────────┘  │  │
│  └───────────────────────────────┘  │
└─────────────────────────────────────┘

Properties

/* Margin — space OUTSIDE the border */
margin: 10px;                    /* All sides */
margin: 10px 20px;               /* Vertical | Horizontal */
margin: 10px 20px 30px;          /* Top | Horizontal | Bottom */
margin: 10px 20px 30px 40px;     /* Top | Right | Bottom | Left */
margin: 0 auto;                  /* Center block element */

/* Padding — space INSIDE the border */
padding: 10px;
padding: 10px 20px;
padding: 10px 20px 30px;
padding: 10px 20px 30px 40px;

/* Border */
border: 1px solid black;
border-width: 2px;
border-style: dashed;  /* solid, dashed, dotted, double, groove, ridge, inset, outset */
border-color: red;
border-radius: 8px;    /* Rounded corners */

/* Width & Height */
width: 300px;
height: 200px;
max-width: 100%;
min-height: 100vh;

/* Box Sizing (best practice) */
*, *::before, *::after {
    box-sizing: border-box;
}

3. Typography

/* Font Family */
font-family: 'Segoe UI', Arial, sans-serif;

/* Font Size */
font-size: 16px;
font-size: 1rem;      /* Relative to root */
font-size: 1.2em;     /* Relative to parent */
font-size: clamp(1rem, 2vw, 2rem); /* Responsive */

/* Font Weight */
font-weight: normal;   /* 400 */
font-weight: bold;     /* 700 */
font-weight: 300;      /* Light */

/* Font Style */
font-style: italic;
font-style: normal;

/* Text Alignment */
text-align: left;      /* Default */
text-align: center;
text-align: right;
text-align: justify;

/* Text Decoration */
text-decoration: none;
text-decoration: underline;
text-decoration: line-through;

/* Text Transform */
text-transform: uppercase;
text-transform: lowercase;
text-transform: capitalize;

/* Line Height */
line-height: 1.6;      /* Unitless — recommended */
line-height: 24px;

/* Letter Spacing */
letter-spacing: 2px;

/* Word Spacing */
word-spacing: 4px;

/* Text Shadow */
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);

/* Truncate Text */
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;

4. Colors

FormatExampleDescription
NamedredPredefined color names
Hex#FF00006-digit hex
Hex (short)#F003-digit hex
RGBrgb(255, 0, 0)Red, Green, Blue (0–255)
RGBArgba(255, 0, 0, 0.5)RGB + opacity
HSLhsl(0, 100%, 50%)Hue, Saturation, Lightness
HSLAhsla(0, 100%, 50%, 0.5)HSL + opacity
Modernoklch(69% 0.27 240)Perceptually uniform
/* Color Properties */
color: #333;
background-color: rgba(255, 0, 0, 0.5);
border-color: hsl(0, 100%, 75%);
caret-color: red;

/* Opacity */
opacity: 0.7;

/* Gradients */
background: linear-gradient(to right, red, blue);
background: radial-gradient(circle, red, blue);
background: conic-gradient(red, blue, green, red);
background: repeating-linear-gradient(45deg, red 10%, blue 20%);

5. Background

/* Background Color */
background-color: #f0f0f0;

/* Background Image */
background-image: url('image.jpg');
background-image: linear-gradient(to right, red, blue);

/* Background Repeat */
background-repeat: no-repeat;  /* repeat, repeat-x, repeat-y, space, round */

/* Background Position */
background-position: center;   /* top, bottom, left, right, center, % */
background-position: center top;

/* Background Size */
background-size: cover;        /* cover, contain, auto, 100% */
background-size: contain;

/* Background Attachment */
background-attachment: fixed;  /* scroll, fixed, local */

/* Background Clip */
background-clip: padding-box;  /* border-box, padding-box, content-box, text */

/* Background Origin */
background-origin: border-box;

/* Shorthand */
background: url('image.jpg') center / cover no-repeat fixed #f8f9fa;

6. Display

ValueDescription
blockFull width, new line
inlineSits next to other elements
inline-blockInline but respects width/height
flexFlex container
gridGrid container
noneHidden (removed from flow)
display: block;
display: inline;
display: inline-block;
display: flex;
display: grid;
display: none;

7. Positioning

ValueDescription
staticNormal flow (default)
relativeRelative to normal position
absoluteRelative to nearest positioned ancestor
fixedRelative to viewport
stickyRelative until threshold, then fixed
/* Relative */
position: relative;
top: 20px;
left: 30px;

/* Absolute */
position: absolute;
top: 50px;
right: 100px;

/* Fixed */
position: fixed;
bottom: 20px;
left: 30px;

/* Sticky */
position: sticky;
top: 0;

/* Z-index */
z-index: 10;

/* Center with absolute + translate */
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

8. Flexbox

Container Properties

.container {
    display: flex;

    /* Direction */
    flex-direction: row;         /* Default */
    flex-direction: column;
    flex-direction: row-reverse;
    flex-direction: column-reverse;

    /* Wrapping */
    flex-wrap: nowrap;           /* Default */
    flex-wrap: wrap;
    flex-wrap: wrap-reverse;

    /* Shorthand */
    flex-flow: row wrap;

    /* Main Axis Alignment */
    justify-content: flex-start;    /* Default */
    justify-content: flex-end;
    justify-content: center;
    justify-content: space-between;
    justify-content: space-around;
    justify-content: space-evenly;

    /* Cross Axis Alignment */
    align-items: stretch;           /* Default */
    align-items: flex-start;
    align-items: flex-end;
    align-items: center;
    align-items: baseline;

    /* Multi-line Alignment */
    align-content: flex-start;
    align-content: center;
    align-content: space-between;

    /* Gap */
    gap: 20px;
    gap: 20px 10px;  /* row-gap column-gap */
}

Item Properties

.item {
    /* Growth */
    flex-grow: 0;        /* Default */
    flex-grow: 1;

    /* Shrinking */
    flex-shrink: 1;      /* Default */
    flex-shrink: 0;

    /* Base Size */
    flex-basis: auto;    /* Default */
    flex-basis: 200px;
    flex-basis: 50%;

    /* Shorthand */
    flex: 1;             /* grow: 1, shrink: 1, basis: 0% */
    flex: auto;          /* grow: 1, shrink: 1, basis: auto */
    flex: none;          /* grow: 0, shrink: 0, basis: auto */
    flex: 2 1 200px;     /* grow: 2, shrink: 1, basis: 200px */

    /* Individual Alignment */
    align-self: center;

    /* Order */
    order: 2;            /* Default is 0 */
}

9. Grid

Container Properties

.container {
    display: grid;

    /* Columns */
    grid-template-columns: 1fr 2fr 1fr;
    grid-template-columns: repeat(3, 1fr);
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    grid-template-columns: minmax(100px, 200px) auto;

    /* Rows */
    grid-template-rows: 100px auto 200px;
    grid-template-rows: repeat(3, 1fr);

    /* Named Areas */
    grid-template-areas:
        "header header header"
        "sidebar main main"
        "footer footer footer";

    /* Shorthand */
    grid-template:
        "header header" auto
        "sidebar main" 200px / 1fr 3fr;

    /* Gaps */
    gap: 20px;
    row-gap: 20px;
    column-gap: 10px;

    /* Alignment */
    justify-items: start;   /* start, center, end, stretch */
    align-items: start;     /* start, center, end, stretch */
    justify-content: center; /* whole grid */
    align-content: center;

    /* Auto Placement */
    grid-auto-flow: row;          /* row, column, row dense */
    grid-auto-columns: 200px;
    grid-auto-rows: 100px;
}

Item Properties

.item {
    /* Named Area */
    grid-area: header;

    /* Numeric Placement */
    grid-area: 1 / 1 / 3 / 3;   /* row-start / col-start / row-end / col-end */

    /* Individual */
    grid-row: 1 / 3;
    grid-column: 2 / 4;
    grid-row-start: 1;
    grid-row-end: 3;
    grid-column-start: 2;
    grid-column-end: 4;

    /* Span */
    grid-column: 1 / span 2;

    /* Self Alignment */
    justify-self: center;
    align-self: center;
}

10. Transitions

/* Individual Properties */
transition-property: background-color, transform;
transition-duration: 0.5s;
transition-timing-function: ease-in-out;
transition-delay: 0.2s;
transition-behavior: allow-discrete;  /* For display/visibility */

/* Shorthand */
transition: background-color 0.5s ease;
transition: transform 0.3s ease-in-out 0.1s;
transition: all 0.3s ease;

/* Multiple Properties */
transition: 
    background-color 0.5s ease,
    transform 0.3s ease,
    box-shadow 0.5s ease;

Timing Functions

ValueDescription
easeSlow start, fast middle, slow end (default)
linearConstant speed
ease-inSlow start, fast end
ease-outFast start, slow end
ease-in-outSlow start, fast middle, slow end
cubic-bezier(n,n,n,n)Custom curve
steps(n)Stepped animation

11. Animations

Applying Animations

.box {
    /* Individual Properties */
    animation-name: slideIn;
    animation-duration: 2s;
    animation-timing-function: ease-in-out;
    animation-delay: 0.5s;
    animation-iteration-count: infinite;
    animation-direction: alternate;
    animation-fill-mode: forwards;
    animation-play-state: running;
    animation-timeline: scroll();
    animation-composition: replace;

    /* Shorthand */
    animation: slideIn 2s ease-in-out 0.5s infinite alternate forwards;
}

@keyframes

/* Using from/to */
@keyframes fadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* Using percentages */
@keyframes bounce {
    0%   { transform: translateY(0); }
    50%  { transform: translateY(-50px); }
    100% { transform: translateY(0); }
}

/* Multi-step */
@keyframes multiStep {
    0%   { background: red; transform: translate(0, 0); }
    25%  { background: blue; transform: translate(100px, 0); }
    50%  { background: green; transform: translate(100px, 100px); }
    75%  { background: yellow; transform: translate(0, 100px); }
    100% { background: red; transform: translate(0, 0); }
}

Animation Properties Reference

PropertyValuesDefault
animation-name@keyframes namenone
animation-durations, ms0s
animation-timing-functionease, linear, etc.ease
animation-delays, ms0s
animation-iteration-countnumber, infinite1
animation-directionnormal, reverse, alternate, alternate-reversenormal
animation-fill-modenone, forwards, backwards, bothnone
animation-play-staterunning, pausedrunning
animation-timelineauto, none, scroll(), view()auto
animation-compositionreplace, add, accumulatereplace

12. Transforms

/* 2D Transforms */
transform: translate(50px, 25px);
transform: translateX(50px);
transform: translateY(25px);
transform: scale(1.5);
transform: scale(1.5, 2);
transform: scaleX(2);
transform: scaleY(0.5);
transform: rotate(45deg);
transform: skew(30deg, -20deg);
transform: skewX(30deg);
transform: skewY(20deg);

/* 3D Transforms */
transform: translate3d(50px, 25px, 100px);
transform: translateZ(100px);
transform: scale3d(1.5, 1.5, 2);
transform: scaleZ(2);
transform: rotate3d(1, 1, 1, 90deg);
transform: rotateX(45deg);
transform: rotateY(45deg);
transform: rotateZ(45deg);

/* Matrix */
transform: matrix(1, 0, 0, 1, 100, 100);
transform: matrix3d(...);  /* 16 values */

/* Combined */
transform: rotate(45deg) scale(1.5) translate(20px, 10px);

/* Related Properties */
transform-origin: center center;  /* top left, bottom right, % */
transform-style: preserve-3d;
perspective: 800px;
backface-visibility: hidden;

13. Media Queries

Common Breakpoints

BreakpointDevice
320pxSmall phones
480pxLarger phones
768pxTablets
1024pxSmall laptops
1200pxDesktops
1440pxLarge desktops

Syntax

/* Width-based */
@media (min-width: 768px) { }
@media (max-width: 1024px) { }
@media (min-width: 768px) and (max-width: 1024px) { }

/* Orientation */
@media (orientation: portrait) { }
@media (orientation: landscape) { }

/* Dark mode */
@media (prefers-color-scheme: dark) { }
@media (prefers-color-scheme: light) { }

/* Reduced motion */
@media (prefers-reduced-motion: reduce) { }
@media (prefers-reduced-motion: no-preference) { }

/* Contrast */
@media (prefers-contrast: more) { }
@media (prefers-contrast: less) { }

/* Hover capability */
@media (hover: hover) { }
@media (hover: none) { }

/* Pointer accuracy */
@media (pointer: fine) { }
@media (pointer: coarse) { }
@media (pointer: none) { }

/* Reduced data */
@media (prefers-reduced-data: reduce) { }

/* Reduced transparency */
@media (prefers-reduced-transparency: reduce) { }

/* Forced colors (high contrast mode) */
@media (forced-colors: active) { }

/* Print */
@media print { }

/* Range syntax (modern) */
@media (width >= 768px) { }
@media (768px <= width <= 1024px) { }

Common Media Features

FeatureDescription
width / min-width / max-widthViewport width
height / min-height / max-heightViewport height
orientationportrait / landscape
aspect-ratioViewport ratio
resolutionPixel density (dpi, dppx)
hover / any-hoverHover capability
pointer / any-pointerPointer accuracy
prefers-color-schemeDark/light mode
prefers-reduced-motionReduced motion
prefers-contrastContrast preference
prefers-reduced-dataData saver
prefers-reduced-transparencyTransparency preference
forced-colorsHigh contrast mode
color-gamutColor space (srgb, p3, rec2020)
dynamic-rangeHDR support
scriptingJavaScript availability
updateRefresh rate (none, slow, fast)
overflow-blockBlock axis overflow
overflow-inlineInline axis overflow
gridGrid-based screen

14. Units

Absolute Units

UnitDescription
pxPixels (1/96 inch)
cmCentimeters
mmMillimeters
inInches
ptPoints (1/72 inch)
pcPicas (12 points)

Relative Units

UnitRelative To
%Parent element
emCurrent font size
remRoot font size
vwViewport width (1% = 1vw)
vhViewport height
vminSmaller of vw/vh
vmaxLarger of vw/vh
chWidth of ‘0’ character
exx-height of font
frFraction of available space
lhLine height

Angle Units

UnitDescription
degDegrees (360 = full circle)
radRadians (2π = full circle)
gradGradians (400 = full circle)
turnTurns (1 = full circle)

15. Other Useful Properties

/* Visibility */
visibility: hidden;
display: none;
opacity: 0.5;

/* Overflow */
overflow: hidden;
overflow: auto;
overflow: scroll;
overflow-x: auto;
overflow-y: scroll;

/* Cursor */
cursor: pointer;
cursor: default;
cursor: not-allowed;

/* Box Shadow */
box-shadow: 2px 4px 6px rgba(0, 0, 0, 0.5);
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
box-shadow: 0 4px 6px rgba(0,0,0,0.1), 0 10px 20px rgba(0,0,0,0.05);

/* Filters */
filter: blur(5px);
filter: brightness(150%);
filter: contrast(200%);
filter: grayscale(100%);
filter: hue-rotate(180deg);
filter: invert(100%);
filter: saturate(200%);
filter: sepia(70%);
filter: drop-shadow(0 4px 6px rgba(0,0,0,0.3));

/* Object Fit */
object-fit: cover;      /* contain, fill, none, scale-down */
object-position: center;

/* Aspect Ratio */
aspect-ratio: 16 / 9;

/* Writing Mode */
writing-mode: vertical-rl;
writing-mode: horizontal-tb;

/* Scroll Behavior */
scroll-behavior: smooth;

/* User Select */
user-select: none;

/* Pointer Events */
pointer-events: none;
pointer-events: auto;

16. Best Practices

✅ Do This

/* Use box-sizing globally */
*, *::before, *::after {
    box-sizing: border-box;
}

/* Use CSS custom properties for theming */
:root {
    --primary: #007bff;
    --text: #333;
}
.button {
    background: var(--primary);
    color: var(--text);
}

/* Use transform instead of top/left for animations */
.box {
    transition: transform 0.3s ease;
}
.box:hover {
    transform: translateY(-5px);
}

/* Use rem for font sizes */
html { font-size: 16px; }
h1 { font-size: 2rem; }

/* Use modern layout systems */
.container {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 20px;
}

/* Respect user preferences */
@media (prefers-reduced-motion: reduce) {
    * { animation: none; transition: none; }
}
@media (prefers-color-scheme: dark) {
    :root { --bg: #1a1a1a; --text: #f8f9fa; }
}

/* Use logical properties */
margin-inline: auto;   /* Instead of margin-left/right */
padding-block: 20px;   /* Instead of padding-top/bottom */

❌ Don’t Do This

/* Don't use !important */
.button { color: red !important; }

/* Don't use px for font sizes (accessibility issue) */
p { font-size: 16px; }  /* Use rem instead */

/* Don't animate layout properties */
.box { transition: width 0.3s, height 0.3s; }

/* Don't use IDs for styling */
#button { }  /* Use classes instead */

/* Don't use transition: all */
.box { transition: all 0.3s; }  /* Specify properties */

/* Don't ignore reduced motion */
/* Always provide @media (prefers-reduced-motion: reduce) */

/* Don't use fixed pixel widths for responsive layouts */
.container { width: 1200px; }  /* Use max-width + % */

17. CSS Custom Properties (Variables)

/* Define */
:root {
    --primary-color: #007bff;
    --secondary-color: #6c5ce7;
    --text-color: #333;
    --spacing: 20px;
    --border-radius: 8px;
    --shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

/* Use */
.button {
    background: var(--primary-color);
    color: var(--text-color);
    padding: var(--spacing);
    border-radius: var(--border-radius);
    box-shadow: var(--shadow);
}

/* Fallback */
.color {
    color: var(--text-color, #333);
}

/* Override for dark mode */
@media (prefers-color-scheme: dark) {
    :root {
        --text-color: #f8f9fa;
        --primary-color: #4dabf7;
    }
}

18. Functions

/* calc() — Calculations */
width: calc(100% - 40px);
height: calc(100vh - 80px);
font-size: calc(1rem + 2vw);

/* clamp() — Responsive sizing */
font-size: clamp(1rem, 2vw, 2rem);
width: clamp(300px, 50%, 800px);

/* min() / max() */
width: min(100%, 800px);
width: max(300px, 50%);

/* var() — Custom properties */
color: var(--text-color);

/* url() — Resources */
background-image: url('image.jpg');

/* Counter */
counter-reset: section;
counter-increment: section;
content: counter(section);

Quick Reference Card

SELECTORS          BOX MODEL         FLEXBOX          GRID
─────────          ─────────         ───────          ────
p { }              margin            display: flex    display: grid
.class { }         padding           flex-direction   grid-template-columns
#id { }            border            justify-content  grid-template-rows
* { }              width/height      align-items      gap
[attr] { }         box-sizing        gap              grid-area
div p { }                            flex             grid-row / grid-column
ul > li { }        POSITION          flex-wrap
h1 + p { }         ────────          align-self       ANIMATION
h2 ~ p { }         static            order            ─────────
                   relative                           animation
:hover { }         absolute          TRANSITIONS      @keyframes
::before { }       fixed             ───────────      animation-name
                   sticky            transition       animation-duration
UNITS                                transition-property
─────              TYPOGRAPHY        transition-duration
px  em  rem        ──────────        transition-timing-function
%   vw  vh         font-family       transition-delay
fr  ch  deg        font-size
                   font-weight       TRANSFORMS
                   text-align        ──────────
                   line-height       translate
                   letter-spacing    scale
                   text-transform    rotate
                   text-shadow       skew
                                     perspective

THE END


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!