CSS3 & Responsive Design

Box Shadows & Text Shadows

20 min Lesson 16 of 60

Introduction to CSS Shadows

Shadows are one of the most powerful visual tools in CSS. They add depth, dimension, and realism to flat screen designs, transforming simple elements into components that feel like they exist in physical space. CSS provides two distinct shadow properties: box-shadow for adding shadows to elements and text-shadow for adding shadows to text. While both share similar syntax foundations, they serve different purposes and produce very different visual effects.

Before CSS3, creating shadow effects required image editors, pre-rendered PNG files, or complex multi-element workarounds. Today, shadows are achieved with a single line of CSS, are fully dynamic, respond to layout changes automatically, and can even be animated. Shadows are used extensively in modern web design to indicate elevation (how "high" an element is above the page surface), create visual hierarchy, provide interactive feedback on hover and click states, and produce creative artistic effects.

In this lesson, we will master both box-shadow and text-shadow from their basic syntax to advanced multi-layer techniques, explore Material Design elevation patterns, learn creative text effects like neon glow and embossed text, understand the performance implications of shadows, and build practical CSS-only designs including the popular neumorphism style.

The box-shadow Property: Syntax Deep Dive

The box-shadow property adds one or more shadow layers to an element's frame. Unlike text-shadow, box-shadow follows the shape of the element's border-box (including border-radius). This means if you have a rounded element, the shadow will also be rounded. The full syntax of box-shadow includes up to six values.

box-shadow Syntax Breakdown

/* Full syntax */
box-shadow: [inset] offset-x offset-y [blur-radius] [spread-radius] [color];

/* Minimum required: offset-x and offset-y */
.shadow-basic {
    box-shadow: 5px 5px;
    /* offset-x: 5px (shadow moves right)
       offset-y: 5px (shadow moves down)
       blur: 0 (sharp edge)
       spread: 0 (same size as element)
       color: defaults to currentColor (text color) */
}

/* With blur radius */
.shadow-blur {
    box-shadow: 5px 5px 10px;
    /* blur-radius: 10px -- the shadow becomes softer and larger */
}

/* With blur and spread */
.shadow-spread {
    box-shadow: 5px 5px 10px 2px;
    /* spread-radius: 2px -- the shadow expands 2px in all directions */
}

/* With explicit color */
.shadow-color {
    box-shadow: 5px 5px 10px 0px rgba(0, 0, 0, 0.3);
}

/* Inset shadow (inside the element) */
.shadow-inset {
    box-shadow: inset 5px 5px 10px rgba(0, 0, 0, 0.2);
}

Understanding Each Value

Let us examine each value in the box-shadow syntax in detail, because understanding exactly what each parameter controls is essential for creating precise shadow effects.

offset-x -- The horizontal offset of the shadow. A positive value moves the shadow to the right. A negative value moves the shadow to the left. A value of 0 means the shadow is centered horizontally behind the element. This is a required value.

offset-y -- The vertical offset of the shadow. A positive value moves the shadow downward. A negative value moves the shadow upward. A value of 0 means the shadow is centered vertically behind the element. This is a required value.

blur-radius -- Controls the blurriness of the shadow. A value of 0 produces a sharp, hard-edged shadow with no blur. The higher the value, the softer and more spread out the shadow becomes. The blur is implemented as a Gaussian blur, meaning the shadow fades gradually from the center of the shadow edge. This value cannot be negative. It defaults to 0 if omitted.

spread-radius -- Controls the size of the shadow relative to the element. A positive value expands the shadow beyond the element's dimensions. A negative value shrinks the shadow smaller than the element. A value of 0 means the shadow is the same size as the element (before blur). This value can be negative. It defaults to 0 if omitted.

color -- The color of the shadow. Any valid CSS color value works -- hex, RGB, RGBA, HSL, HSLA, or named colors. If omitted, it defaults to currentColor (the element's text color). In practice, you almost always want to use an RGBA color with low opacity (like 0.1 to 0.4) for realistic shadows.

inset -- When present, the shadow is drawn inside the element rather than outside. This creates the visual effect of the element being pressed into the surface or having a recessed area. If omitted, the shadow is drawn outside (an outer shadow).

Visualizing Each Parameter

/* No shadow (starting point) */
.no-shadow {
    box-shadow: none;
}

/* Only horizontal offset -- shadow shifts right */
.shadow-right {
    box-shadow: 10px 0px 0px 0px rgba(0, 0, 0, 0.3);
}

/* Only vertical offset -- shadow shifts down */
.shadow-down {
    box-shadow: 0px 10px 0px 0px rgba(0, 0, 0, 0.3);
}

/* Negative offsets -- shadow shifts left and up */
.shadow-top-left {
    box-shadow: -10px -10px 0px 0px rgba(0, 0, 0, 0.3);
}

/* Centered shadow with only blur (soft glow effect) */
.shadow-glow {
    box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.3);
}

/* Centered shadow with only spread (solid border-like effect) */
.shadow-border {
    box-shadow: 0px 0px 0px 3px #3498db;
}

/* Negative spread -- shadow is smaller than the element */
.shadow-shrink {
    box-shadow: 0px 10px 15px -5px rgba(0, 0, 0, 0.3);
}
Tip: Using box-shadow: 0 0 0 3px #color with zero blur and a positive spread creates a "border" effect that does not affect layout. Unlike a real border, a box-shadow border does not add to the element's total dimensions or push surrounding elements. This is extremely useful when you want to add a visual outline without changing the layout, for example on focus states where adding a border would cause content to shift.

Inset Shadows

The inset keyword changes the shadow from being drawn outside the element to being drawn inside it. Inset shadows are commonly used to create the appearance of pressed buttons, recessed input fields, inner glows, and depth effects that suggest the element is cut into the surface rather than raised above it.

Inset Shadow Examples

/* Basic inset shadow -- element appears pressed into the page */
.pressed {
    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);
}

/* Strong inset shadow -- creates a deep well effect */
.well {
    box-shadow: inset 0 4px 8px rgba(0, 0, 0, 0.3);
    background: #f5f5f5;
    padding: 20px;
    border-radius: 8px;
}

/* Inset shadow from all sides -- inner glow */
.inner-glow {
    box-shadow: inset 0 0 20px rgba(52, 152, 219, 0.5);
}

/* Inset shadow on an input field -- common for form styling */
.input-field {
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 10px 14px;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
}

.input-field:focus {
    border-color: #3498db;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1),
                0 0 0 3px rgba(52, 152, 219, 0.2);
}

/* Pressed button using inset on active state */
.btn {
    padding: 12px 24px;
    background: #3498db;
    color: white;
    border: none;
    border-radius: 6px;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
    cursor: pointer;
    transition: all 0.15s ease;
}

.btn:active {
    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3);
    transform: translateY(1px);
}
Note: Inset and outer shadows are independent. You can combine both on the same element by listing them in a comma-separated list. The inset keyword must be the first value in each shadow declaration where it is used. You cannot place it at the end of the shadow values.

Multiple Box Shadows (Layered Shadows)

One of the most powerful features of box-shadow is the ability to apply multiple shadows to a single element. You simply separate each shadow with a comma. Shadows are rendered in the order they are listed, with the first shadow on top (closest to the viewer) and subsequent shadows behind it. This layering capability opens up enormous creative possibilities.

Multiple Shadow Layers

/* Two-layer shadow for more realistic depth */
.card-realistic {
    box-shadow:
        0 1px 3px rgba(0, 0, 0, 0.12),
        0 1px 2px rgba(0, 0, 0, 0.24);
}

/* Three-layer shadow -- even more natural depth */
.card-deep {
    box-shadow:
        0 1px 1px rgba(0, 0, 0, 0.08),
        0 2px 4px rgba(0, 0, 0, 0.08),
        0 4px 8px rgba(0, 0, 0, 0.08);
}

/* Combining outer and inset shadows */
.combined {
    box-shadow:
        0 4px 12px rgba(0, 0, 0, 0.15),      /* outer shadow for elevation */
        inset 0 -2px 4px rgba(0, 0, 0, 0.05); /* subtle inner bottom shadow */
}

/* Colorful multi-shadow effect */
.rainbow-glow {
    box-shadow:
        0 0 10px rgba(255, 0, 0, 0.3),
        0 0 20px rgba(255, 165, 0, 0.2),
        0 0 30px rgba(255, 255, 0, 0.1),
        0 0 40px rgba(0, 128, 0, 0.05);
}

/* Neon border effect with multiple spread shadows */
.neon-border {
    box-shadow:
        0 0 5px #fff,
        0 0 10px #fff,
        0 0 20px #0ff,
        0 0 40px #0ff,
        0 0 60px #0ff;
}

/* Using spread to create multiple "borders" */
.multi-border {
    box-shadow:
        0 0 0 4px #3498db,
        0 0 0 8px #2ecc71,
        0 0 0 12px #e74c3c;
}
Tip: Layering multiple soft shadows with increasing offsets and blur values produces much more realistic shadows than a single shadow. In the real world, light comes from multiple angles and creates complex shadow patterns. By stacking 2-3 subtle shadow layers, you can simulate this natural effect. This is the technique used by Google's Material Design and many professional design systems.

Material Design Elevation with box-shadow

Google's Material Design system defines five levels of elevation (shadow depth), each representing how "high" an element is floating above the page surface. Higher elevation means the element is more prominent and casts a larger, more diffuse shadow. Understanding this system is valuable even if you are not building a Material Design app, because the elevation concept translates directly to visual hierarchy in any design.

Material Design Elevation Levels

/* Elevation 1 -- Resting state: cards, buttons */
.elevation-1 {
    box-shadow:
        0 1px 3px rgba(0, 0, 0, 0.12),
        0 1px 2px rgba(0, 0, 0, 0.24);
}

/* Elevation 2 -- Raised state: cards on hover, floating buttons */
.elevation-2 {
    box-shadow:
        0 3px 6px rgba(0, 0, 0, 0.16),
        0 3px 6px rgba(0, 0, 0, 0.23);
}

/* Elevation 3 -- Sub-menu, dropdown, snackbar */
.elevation-3 {
    box-shadow:
        0 10px 20px rgba(0, 0, 0, 0.19),
        0 6px 6px rgba(0, 0, 0, 0.23);
}

/* Elevation 4 -- Navigation bar, dialog */
.elevation-4 {
    box-shadow:
        0 14px 28px rgba(0, 0, 0, 0.25),
        0 10px 10px rgba(0, 0, 0, 0.22);
}

/* Elevation 5 -- Modal, highest priority overlays */
.elevation-5 {
    box-shadow:
        0 19px 38px rgba(0, 0, 0, 0.30),
        0 15px 12px rgba(0, 0, 0, 0.22);
}

/* Interactive elevation -- card lifts on hover */
.card-interactive {
    box-shadow:
        0 1px 3px rgba(0, 0, 0, 0.12),
        0 1px 2px rgba(0, 0, 0, 0.24);
    transition: box-shadow 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}

.card-interactive:hover {
    box-shadow:
        0 14px 28px rgba(0, 0, 0, 0.25),
        0 10px 10px rgba(0, 0, 0, 0.22);
}

/* CSS Custom Properties for consistent elevation */
:root {
    --shadow-sm: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
    --shadow-md: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
    --shadow-lg: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
    --shadow-xl: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
}

.card { box-shadow: var(--shadow-sm); }
.card:hover { box-shadow: var(--shadow-lg); }
Note: Material Design uses two shadow layers for each elevation level -- one for the ambient shadow (a large, soft shadow from overhead light) and one for the key shadow (a smaller, sharper shadow from a directional light source). This dual-shadow approach is what makes Material elevation look so natural compared to a single box-shadow.

The text-shadow Property

The text-shadow property adds shadow effects specifically to text content. Its syntax is simpler than box-shadow because it does not support the spread or inset values. Text shadows are applied to the text glyphs themselves -- the shadow follows the shape of each letter, including curves and serif details.

text-shadow Syntax

/* Syntax */
text-shadow: offset-x offset-y blur-radius color;

/* Basic text shadow */
.shadow-text {
    text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}

/* Sharp text shadow (no blur) */
.sharp-shadow {
    text-shadow: 1px 1px 0px #333;
}

/* Subtle text shadow for readability on light backgrounds */
.subtle-shadow {
    text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
}

/* Light text on dark background with glow */
.text-glow {
    color: white;
    text-shadow: 0 0 10px rgba(255, 255, 255, 0.8);
}

/* Colored text shadow */
.colored-shadow {
    color: #333;
    text-shadow: 3px 3px 6px rgba(52, 152, 219, 0.5);
}

/* No text shadow (reset) */
.no-shadow-text {
    text-shadow: none;
}

Multiple Text Shadows

Just like box-shadow, text-shadow supports multiple comma-separated shadow layers. This is where text shadows become truly powerful, enabling creative typography effects that would otherwise require image editing software.

Multiple Text Shadow Layers

/* Layered text shadow for greater depth */
.deep-text-shadow {
    text-shadow:
        1px 1px 2px rgba(0, 0, 0, 0.2),
        2px 2px 4px rgba(0, 0, 0, 0.1),
        3px 3px 6px rgba(0, 0, 0, 0.05);
}

/* 3D / Retro text effect */
.retro-3d {
    color: #e74c3c;
    text-shadow:
        1px 1px 0 #c0392b,
        2px 2px 0 #a93226,
        3px 3px 0 #922b21,
        4px 4px 0 #7b241c,
        5px 5px 0 #641e16;
}

/* Outline / Stroke text effect */
.text-outline {
    color: white;
    text-shadow:
        -1px -1px 0 #333,
         1px -1px 0 #333,
        -1px  1px 0 #333,
         1px  1px 0 #333;
}

/* Double shadow for vintage look */
.vintage-text {
    color: #2c3e50;
    text-shadow:
        2px 2px 0 #ecf0f1,
        4px 4px 0 rgba(0, 0, 0, 0.1);
}

Creative Text Shadow Effects

Text shadows can be combined in creative ways to produce stunning visual effects. The following techniques are commonly used in web design for hero sections, headings, logos, and artistic typography. Let us explore the most popular creative text effects and how to build them.

Embossed and Debossed Text

Embossed text appears to be raised from the surface, while debossed text appears to be pressed into it. These effects rely on placing a light shadow on one side and a dark shadow on the opposite side, simulating light hitting a raised or recessed surface.

Embossed and Debossed Effects

/* Embossed text -- appears raised (light above, dark below) */
.embossed {
    color: #ccc;
    background: #ccc;
    text-shadow:
        -1px -1px 1px rgba(255, 255, 255, 0.8),
         1px  1px 1px rgba(0, 0, 0, 0.3);
}

/* Debossed / Engraved text -- appears pressed in (dark above, light below) */
.debossed {
    color: #666;
    background: #888;
    text-shadow:
         1px  1px 1px rgba(255, 255, 255, 0.4),
        -1px -1px 1px rgba(0, 0, 0, 0.4);
}

/* Letterpress effect on a dark background */
.letterpress-dark {
    color: #222;
    background: #333;
    text-shadow: 0 1px 1px rgba(255, 255, 255, 0.1);
}

/* Letterpress effect on a light background */
.letterpress-light {
    color: #ddd;
    background: #eee;
    text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.2);
}

Neon Glow Text

Neon glow effects are one of the most visually striking things you can achieve with text shadows. By layering multiple shadows with increasing blur values and bright colors, you can simulate the look of neon signage. This effect works best on dark backgrounds with bright text colors.

Neon Glow Effects

/* Classic neon glow */
.neon-blue {
    color: #fff;
    text-shadow:
        0 0 7px #fff,
        0 0 10px #fff,
        0 0 21px #fff,
        0 0 42px #0fa,
        0 0 82px #0fa,
        0 0 92px #0fa,
        0 0 102px #0fa,
        0 0 151px #0fa;
    background: #111;
    font-family: cursive;
}

/* Pink neon */
.neon-pink {
    color: #fff;
    text-shadow:
        0 0 5px #fff,
        0 0 10px #fff,
        0 0 20px #ff00de,
        0 0 40px #ff00de,
        0 0 80px #ff00de;
    background: #1a1a2e;
}

/* Subtle neon for UI text */
.neon-subtle {
    color: #00d4ff;
    text-shadow:
        0 0 4px rgba(0, 212, 255, 0.6),
        0 0 8px rgba(0, 212, 255, 0.3);
}

/* Flickering neon animation */
@keyframes neon-flicker {
    0%, 19%, 21%, 23%, 25%, 54%, 56%, 100% {
        text-shadow:
            0 0 4px #fff,
            0 0 11px #fff,
            0 0 19px #fff,
            0 0 40px #0fa,
            0 0 80px #0fa;
    }
    20%, 24%, 55% {
        text-shadow: none;
    }
}

.neon-flicker {
    animation: neon-flicker 1.5s infinite alternate;
}

Fire Text Effect

By layering warm-colored shadows (yellow, orange, red) with increasing offsets and blur values, you can create the illusion of text engulfed in flames. The key is stacking the colors from bright yellow near the text to dark red further away.

Fire Text Effect

/* Fire text */
.fire-text {
    color: #fff;
    background: #000;
    text-shadow:
        0 -1px 4px #FFF,
        0 -2px 10px #ff0,
        0 -4px 20px #ff8000,
        0 -6px 30px #ff0000,
        0 -8px 40px #ff0000;
    font-size: 48px;
    font-weight: bold;
}

/* Subtle warm glow (more practical for UI) */
.warm-glow {
    color: #ff6b35;
    text-shadow:
        0 0 4px rgba(255, 107, 53, 0.4),
        0 0 8px rgba(255, 68, 0, 0.2);
}

Shadow Performance Considerations

While shadows are visually appealing, they come with performance costs that you should understand. Shadows require the browser to perform additional rendering work, and in some situations, they can cause noticeable performance degradation, especially on lower-powered devices or when many shadowed elements are on screen simultaneously.

How shadows affect rendering: When the browser renders a shadow, it must calculate the shadow shape, apply the Gaussian blur (which is computationally expensive), composite the shadow layer with the element and the rest of the page, and repaint the affected area whenever the element changes. The blur radius is the most expensive parameter -- larger blur values require more computation because the blur algorithm must sample more pixels.

Performance-Optimized Shadows

/* SLOW: Large blur on many elements */
.card-slow {
    box-shadow: 0 10px 80px rgba(0, 0, 0, 0.3);
    /* 80px blur is expensive to compute */
}

/* FAST: Small blur with multiple layers */
.card-fast {
    box-shadow:
        0 1px 3px rgba(0, 0, 0, 0.12),
        0 1px 2px rgba(0, 0, 0, 0.24);
    /* Small blur values are much cheaper */
}

/* BETTER: Use pseudo-element for animated shadows */
.card-optimized {
    position: relative;
}

.card-optimized::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border-radius: inherit;
    box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25);
    opacity: 0;
    transition: opacity 0.3s ease;
    z-index: -1;
}

.card-optimized:hover::after {
    opacity: 1;
    /* Animating opacity is GPU-accelerated and much faster
       than animating box-shadow directly */
}

/* AVOID: Animating box-shadow directly */
.card-bad-animation {
    transition: box-shadow 0.3s ease; /* Triggers repaint every frame */
}

/* PREFER: Animating opacity on a pseudo-element */
.card-good-animation {
    /* Shadow is fixed on the pseudo-element,
       only opacity changes -- GPU accelerated */
}
Warning: Animating box-shadow directly with CSS transitions causes the browser to repaint the shadow on every animation frame. For smooth 60fps animations, use the pseudo-element technique shown above: apply the final shadow to a ::after pseudo-element positioned behind the card, set its opacity to 0, and transition only the opacity on hover. Opacity changes are handled by the GPU compositor and do not trigger expensive repaints.

CSS-Only Designs with Shadows

Box shadows are not just for decoration -- they can be used creatively to build entire visual designs without additional HTML elements or images. Because you can layer unlimited shadows and control their position, size, and color independently, a single element with many box-shadows can create pixel art, icons, patterns, and more.

Creative Shadow Designs

/* One-element loading dots */
.loading-dots {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: #3498db;
    box-shadow:
        20px 0 0 #3498db,
        40px 0 0 #3498db;
    animation: loading 1.2s ease-in-out infinite;
}

@keyframes loading {
    0%, 80%, 100% { box-shadow: 20px 0 0 #3498db, 40px 0 0 #3498db; }
    40% { box-shadow: 20px -15px 0 #3498db, 40px 0 0 #3498db; }
}

/* Shadow-only underline that does not affect layout */
.fancy-underline {
    box-shadow: inset 0 -4px 0 0 #3498db;
    display: inline;
    padding-bottom: 2px;
}

/* Double border using shadows (no extra HTML) */
.double-frame {
    border: 2px solid #333;
    box-shadow:
        0 0 0 4px #fff,       /* white gap */
        0 0 0 6px #333;       /* outer border */
}

/* Photo frame effect */
.photo-frame {
    box-shadow:
        0 0 0 5px #fff,                           /* white mat */
        0 0 0 6px #ccc,                           /* mat border */
        0 0 0 15px #f5f0eb,                        /* wide mat */
        0 0 0 16px #ccc,                           /* frame inner edge */
        4px 4px 15px 16px rgba(0, 0, 0, 0.3);     /* frame shadow */
}

/* Ribbon / Page fold effect */
.page-curl {
    position: relative;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}

.page-curl::after {
    content: "";
    position: absolute;
    bottom: 12px;
    right: 10px;
    width: 50%;
    height: 30px;
    box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.4);
    transform: rotate(3deg);
    z-index: -1;
}

Neumorphism (Soft UI) with Shadows

Neumorphism (a combination of "new" and "skeuomorphism") is a design trend that uses dual shadows -- one light and one dark -- on a background that matches the element's background color, creating the illusion of soft, extruded shapes that appear to be part of the surface itself. This style relies heavily on box-shadow and requires careful color management.

Neumorphism Patterns

/* Base setup -- background color must match */
.neumorphic-container {
    background: #e0e5ec;
}

/* Raised neumorphic element */
.neu-raised {
    background: #e0e5ec;
    border-radius: 16px;
    box-shadow:
         8px  8px 16px #b8bec7,
        -8px -8px 16px #ffffff;
}

/* Pressed / inset neumorphic element */
.neu-pressed {
    background: #e0e5ec;
    border-radius: 16px;
    box-shadow:
        inset  8px  8px 16px #b8bec7,
        inset -8px -8px 16px #ffffff;
}

/* Neumorphic button */
.neu-button {
    background: #e0e5ec;
    border: none;
    border-radius: 12px;
    padding: 14px 28px;
    font-size: 16px;
    color: #6b7280;
    cursor: pointer;
    box-shadow:
         6px  6px 12px #b8bec7,
        -6px -6px 12px #ffffff;
    transition: all 0.2s ease;
}

.neu-button:hover {
    box-shadow:
         4px  4px  8px #b8bec7,
        -4px -4px  8px #ffffff;
}

.neu-button:active {
    box-shadow:
        inset 4px  4px  8px #b8bec7,
        inset -4px -4px  8px #ffffff;
}

/* Neumorphic input field */
.neu-input {
    background: #e0e5ec;
    border: none;
    border-radius: 10px;
    padding: 12px 18px;
    font-size: 14px;
    color: #333;
    box-shadow:
        inset 3px  3px  6px #b8bec7,
        inset -3px -3px  6px #ffffff;
}

.neu-input:focus {
    outline: none;
    box-shadow:
        inset 3px  3px  6px #b8bec7,
        inset -3px -3px  6px #ffffff,
        0 0 0 2px rgba(52, 152, 219, 0.4);
}

/* Neumorphic card */
.neu-card {
    background: #e0e5ec;
    border-radius: 20px;
    padding: 30px;
    box-shadow:
         10px  10px 20px #b8bec7,
        -10px -10px 20px #ffffff;
}

/* Neumorphic circle avatar */
.neu-avatar {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    background: #e0e5ec;
    box-shadow:
         6px  6px 12px #b8bec7,
        -6px -6px 12px #ffffff;
    display: flex;
    align-items: center;
    justify-content: center;
}
Warning: Neumorphism can create accessibility problems. The low contrast between the element and its background makes it difficult for users with visual impairments to distinguish interactive elements from the background. If you use neumorphism, always ensure sufficient contrast for text, add clear focus indicators, and consider providing a high-contrast alternative. The style also does not translate well to dark mode without recalculating the shadow colors for the new background.

Practical Examples: Putting It All Together

Let us combine the concepts we have covered into complete, production-ready components that demonstrate real-world shadow usage.

Complete Card Component with Elevation

<!-- HTML -->
<div class="shadow-card">
    <div class="shadow-card__image">
        <img src="photo.jpg" alt="Card image">
    </div>
    <div class="shadow-card__body">
        <h3>Card Title</h3>
        <p>Card description text goes here.</p>
        <button class="shadow-card__btn">Learn More</button>
    </div>
</div>

/* CSS */
.shadow-card {
    background: white;
    border-radius: 12px;
    overflow: hidden;
    box-shadow:
        0 1px 3px rgba(0, 0, 0, 0.1),
        0 1px 2px rgba(0, 0, 0, 0.06);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.shadow-card:hover {
    transform: translateY(-4px);
    box-shadow:
        0 12px 24px rgba(0, 0, 0, 0.12),
        0 6px 12px rgba(0, 0, 0, 0.08);
}

.shadow-card__image img {
    width: 100%;
    display: block;
}

.shadow-card__body {
    padding: 20px;
}

.shadow-card__btn {
    padding: 10px 20px;
    background: #3498db;
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    box-shadow: 0 2px 4px rgba(52, 152, 219, 0.4);
    transition: box-shadow 0.2s ease;
}

.shadow-card__btn:hover {
    box-shadow: 0 4px 8px rgba(52, 152, 219, 0.5);
}

.shadow-card__btn:active {
    box-shadow: 0 1px 2px rgba(52, 152, 219, 0.4);
    transform: translateY(1px);
}

Modal / Dialog with Backdrop Shadow

/* Modal overlay */
.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
}

/* Modal box with deep shadow */
.modal-box {
    background: white;
    border-radius: 16px;
    padding: 32px;
    max-width: 500px;
    width: 90%;
    box-shadow:
        0 25px 50px rgba(0, 0, 0, 0.25),
        0 12px 24px rgba(0, 0, 0, 0.15);
}

/* Floating Action Button (FAB) */
.fab {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: #e74c3c;
    color: white;
    border: none;
    font-size: 24px;
    cursor: pointer;
    position: fixed;
    bottom: 24px;
    right: 24px;
    box-shadow:
        0 4px 8px rgba(231, 76, 60, 0.4),
        0 2px 4px rgba(0, 0, 0, 0.2);
    transition: box-shadow 0.3s ease, transform 0.3s ease;
}

.fab:hover {
    transform: scale(1.05);
    box-shadow:
        0 8px 16px rgba(231, 76, 60, 0.5),
        0 4px 8px rgba(0, 0, 0, 0.2);
}

Text Shadow for Hero Headings

/* Hero heading with image background */
.hero-heading {
    font-size: 64px;
    font-weight: 900;
    color: white;
    text-shadow:
        0 2px 4px rgba(0, 0, 0, 0.5),
        0 4px 8px rgba(0, 0, 0, 0.3);
}

/* Subtle heading shadow for regular pages */
.page-heading {
    font-size: 36px;
    font-weight: 700;
    color: #2c3e50;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

/* Long shadow text effect */
.long-shadow-text {
    color: #e74c3c;
    font-size: 72px;
    font-weight: bold;
    text-shadow:
        1px 1px 0 rgba(0,0,0,0.1),
        2px 2px 0 rgba(0,0,0,0.1),
        3px 3px 0 rgba(0,0,0,0.1),
        4px 4px 0 rgba(0,0,0,0.1),
        5px 5px 0 rgba(0,0,0,0.1),
        6px 6px 0 rgba(0,0,0,0.1),
        7px 7px 0 rgba(0,0,0,0.1),
        8px 8px 0 rgba(0,0,0,0.1);
}
Exercise 1: Create a card component that uses the Material Design elevation system. The card should have Elevation 1 by default, Elevation 3 on hover (with a smooth transition), and Elevation 5 when focused. Use CSS custom properties to store the shadow values. Add a colored left border accent and a subtle inset shadow at the top of the card body.
Exercise 2: Build a complete neumorphic form with the following elements: a raised container card, two input fields (with inset neumorphic shadows), a raised button that becomes pressed on click, and a toggle switch using neumorphic styling. The entire design should use only one background color (#e0e5ec) with light and dark shadows to create depth.
Exercise 3: Create a heading that uses a neon glow text-shadow effect. The text should be white on a dark background, with multiple layers of colored glow shadows. Then add a CSS animation that makes the glow subtly pulse (expanding and contracting the blur values). Include a flickering variation that simulates a malfunctioning neon sign with random on/off states.