Black Background with Smoke Effects: CSS Animations & Techniques

Create mesmerizing smoke effects on black backgrounds using pure CSS. Learn how to build animated smoke, fog, mist, and vapor effects for dramatic and atmospheric web designs.

Last reviewed on 2026-04-30

Live Smoke Effect Demo

SMOKE

Pure CSS Animation

Basic Smoke Effects on Black Backgrounds

Start with simple CSS techniques to create smoke-like appearances:

1. Static Smoke with Gradients

/* Static smoke effect */
.smoke-static {
    background: 
        radial-gradient(ellipse at bottom, rgba(255,255,255,0.1) 0%, transparent 40%),
        #000;
    height: 400px;
}

/* Multiple smoke layers */
.smoke-layers {
    background: 
        radial-gradient(circle at 20% 80%, rgba(255,255,255,0.08) 0%, transparent 50%),
        radial-gradient(circle at 80% 80%, rgba(255,255,255,0.08) 0%, transparent 50%),
        radial-gradient(circle at 50% 80%, rgba(255,255,255,0.1) 0%, transparent 50%),
        #000;
}

2. Blurred Smoke Elements

/* Smoke with blur filter */
.smoke-blur {
    position: relative;
    background: #000;
    overflow: hidden;
}

.smoke-blur::before {
    content: '';
    position: absolute;
    bottom: 0;
    left: 50%;
    width: 300px;
    height: 300px;
    background: radial-gradient(circle, rgba(255,255,255,0.2) 0%, transparent 70%);
    filter: blur(40px);
    transform: translateX(-50%);
}

Animated Smoke Patterns

Rising Smoke Animation

/* Rising smoke animation */
@keyframes smoke-rise {
    0% {
        transform: translateY(0) translateX(0) scale(1);
        opacity: 0;
    }
    10% {
        opacity: 0.4;
    }
    25% {
        transform: translateY(-30px) translateX(10px) scale(1.1);
    }
    50% {
        transform: translateY(-80px) translateX(-10px) scale(1.3);
        opacity: 0.2;
    }
    75% {
        transform: translateY(-130px) translateX(10px) scale(1.5);
    }
    100% {
        transform: translateY(-200px) translateX(0) scale(2);
        opacity: 0;
    }
}

.rising-smoke {
    position: relative;
    background: #000;
    height: 500px;
    overflow: hidden;
}

.smoke-particle {
    position: absolute;
    bottom: 0;
    width: 100px;
    height: 100px;
    background: radial-gradient(circle, rgba(255,255,255,0.3) 0%, transparent 70%);
    border-radius: 50%;
    filter: blur(20px);
    animation: smoke-rise 6s infinite;
}

/* Multiple particles with delays */
.smoke-particle:nth-child(1) { left: 10%; animation-delay: 0s; }
.smoke-particle:nth-child(2) { left: 30%; animation-delay: 1s; }
.smoke-particle:nth-child(3) { left: 50%; animation-delay: 2s; }
.smoke-particle:nth-child(4) { left: 70%; animation-delay: 3s; }
.smoke-particle:nth-child(5) { left: 90%; animation-delay: 4s; }

Swirling Smoke Effect

/* Swirling smoke animation */
@keyframes smoke-swirl {
    0% {
        transform: rotate(0deg) translateY(0) scale(1);
        opacity: 0;
    }
    20% {
        opacity: 0.3;
    }
    50% {
        transform: rotate(180deg) translateY(-100px) scale(1.5);
        opacity: 0.2;
    }
    100% {
        transform: rotate(360deg) translateY(-200px) scale(2);
        opacity: 0;
    }
}

.swirling-smoke {
    background: #000;
    position: relative;
    overflow: hidden;
}

.swirl-particle {
    position: absolute;
    width: 150px;
    height: 150px;
    background: conic-gradient(from 0deg, transparent, rgba(255,255,255,0.1), transparent);
    filter: blur(25px);
    animation: smoke-swirl 8s infinite ease-out;
}

Fog & Mist Effects

Create atmospheric fog effects that complement black backgrounds:

Horizontal Fog Drift

/* Drifting fog effect */
@keyframes fog-drift {
    0% {
        transform: translateX(-100%);
    }
    100% {
        transform: translateX(100%);
    }
}

.fog-container {
    position: relative;
    background: #000;
    height: 400px;
    overflow: hidden;
}

.fog-layer {
    position: absolute;
    width: 200%;
    height: 100%;
    background: linear-gradient(90deg, 
        transparent 0%, 
        rgba(255,255,255,0.05) 20%, 
        rgba(255,255,255,0.1) 50%, 
        rgba(255,255,255,0.05) 80%, 
        transparent 100%
    );
    filter: blur(40px);
    animation: fog-drift 20s infinite linear;
}

.fog-layer:nth-child(2) {
    animation-duration: 30s;
    animation-direction: reverse;
    opacity: 0.5;
}

.fog-layer:nth-child(3) {
    animation-duration: 25s;
    animation-delay: 5s;
    opacity: 0.7;
}

Ground Fog Effect

/* Ground fog on black background */
.ground-fog {
    position: relative;
    background: #000;
    height: 500px;
}

.ground-fog::before,
.ground-fog::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 200px;
}

.ground-fog::before {
    background: linear-gradient(to top, 
        rgba(255,255,255,0.1) 0%, 
        transparent 100%
    );
    filter: blur(20px);
}

.ground-fog::after {
    background: radial-gradient(ellipse at bottom, 
        rgba(255,255,255,0.08) 0%, 
        transparent 60%
    );
    filter: blur(30px);
    animation: fog-pulse 4s infinite ease-in-out;
}

@keyframes fog-pulse {
    0%, 100% { opacity: 0.6; }
    50% { opacity: 1; }
}

Particle-Based Smoke Effects

CSS-Only Particle System

/* Particle smoke system */
.particle-smoke {
    position: relative;
    background: #000;
    height: 600px;
    overflow: hidden;
}

/* Base particle */
.particle {
    position: absolute;
    width: 4px;
    height: 4px;
    background: rgba(255,255,255,0.6);
    border-radius: 50%;
    filter: blur(2px);
}

/* Particle animations */
@keyframes particle-1 {
    0% {
        transform: translate(0, 0) scale(0);
        opacity: 1;
    }
    10% {
        transform: translate(10px, -20px) scale(2);
    }
    40% {
        transform: translate(-20px, -80px) scale(4);
        opacity: 0.5;
    }
    70% {
        transform: translate(30px, -150px) scale(6);
        opacity: 0.2;
    }
    100% {
        transform: translate(-10px, -250px) scale(8);
        opacity: 0;
    }
}

/* Create multiple particles */
.particle:nth-child(1) { left: 50%; bottom: 0; animation: particle-1 4s infinite; }
.particle:nth-child(2) { left: 51%; bottom: 0; animation: particle-1 4s infinite 0.1s; }
.particle:nth-child(3) { left: 49%; bottom: 0; animation: particle-1 4s infinite 0.2s; }
/* ... repeat for more particles */

/* Dense smoke using box-shadow */
.dense-smoke {
    position: absolute;
    bottom: 100px;
    left: 50%;
    width: 2px;
    height: 2px;
    background: rgba(255,255,255,0.2);
    box-shadow: 
        0 0 10px 10px rgba(255,255,255,0.05),
        10px 10px 20px 20px rgba(255,255,255,0.03),
        -10px -10px 20px 20px rgba(255,255,255,0.03),
        20px 0 30px 30px rgba(255,255,255,0.02),
        -20px 0 30px 30px rgba(255,255,255,0.02);
    filter: blur(3px);
    animation: smoke-expansion 5s infinite;
}

@keyframes smoke-expansion {
    0% {
        transform: scale(1) translateY(0);
        opacity: 0;
    }
    20% {
        opacity: 1;
    }
    100% {
        transform: scale(5) translateY(-200px);
        opacity: 0;
    }
}

Advanced Gradient Smoke Techniques

Multi-Layer Gradient Smoke

/* Complex gradient smoke */
.gradient-smoke {
    position: relative;
    background: #000;
    height: 500px;
    overflow: hidden;
}

.gradient-smoke::before,
.gradient-smoke::after {
    content: '';
    position: absolute;
    bottom: -50px;
    left: 50%;
    width: 600px;
    height: 600px;
    transform: translateX(-50%);
}

.gradient-smoke::before {
    background: 
        radial-gradient(circle at center, rgba(255,255,255,0.1) 0%, transparent 30%),
        radial-gradient(circle at 30% 40%, rgba(255,255,255,0.08) 0%, transparent 40%),
        radial-gradient(circle at 70% 40%, rgba(255,255,255,0.08) 0%, transparent 40%);
    filter: blur(40px);
    animation: smoke-morph 10s infinite ease-in-out;
}

.gradient-smoke::after {
    background: conic-gradient(
        from 0deg at 50% 50%,
        transparent 0deg,
        rgba(255,255,255,0.05) 60deg,
        transparent 120deg,
        rgba(255,255,255,0.05) 180deg,
        transparent 240deg,
        rgba(255,255,255,0.05) 300deg,
        transparent 360deg
    );
    filter: blur(60px);
    animation: smoke-rotate 20s infinite linear;
}

@keyframes smoke-morph {
    0%, 100% {
        transform: translateX(-50%) scale(1);
    }
    50% {
        transform: translateX(-50%) scale(1.2);
    }
}

@keyframes smoke-rotate {
    from {
        transform: translateX(-50%) rotate(0deg);
    }
    to {
        transform: translateX(-50%) rotate(360deg);
    }
}

Colored Smoke on Black

/* Colored smoke effects */
.colored-smoke {
    background: #000;
    position: relative;
    overflow: hidden;
}

/* Blue smoke */
.blue-smoke {
    background: 
        radial-gradient(circle at 30% 80%, rgba(100, 149, 237, 0.1) 0%, transparent 50%),
        radial-gradient(circle at 70% 80%, rgba(30, 144, 255, 0.1) 0%, transparent 50%),
        #000;
    filter: blur(20px);
}

/* Purple smoke */
.purple-smoke {
    background: 
        radial-gradient(circle at center bottom, rgba(147, 51, 234, 0.1) 0%, transparent 50%),
        radial-gradient(circle at 20% 80%, rgba(139, 92, 246, 0.08) 0%, transparent 40%),
        radial-gradient(circle at 80% 80%, rgba(167, 139, 250, 0.08) 0%, transparent 40%),
        #000;
}

/* Fire smoke (red-orange) */
.fire-smoke {
    background: 
        radial-gradient(circle at 50% 100%, rgba(255, 69, 0, 0.1) 0%, transparent 40%),
        radial-gradient(circle at 30% 90%, rgba(255, 140, 0, 0.08) 0%, transparent 50%),
        radial-gradient(circle at 70% 90%, rgba(255, 99, 71, 0.08) 0%, transparent 50%),
        #000;
}

Performance Optimization for Smoke Effects

Best Practices

  • Use CSS transforms instead of position properties for animations
  • Leverage GPU acceleration with transform3d or will-change
  • Limit the number of animated elements to maintain 60fps
  • Use CSS containment to isolate animation effects
  • Implement visibility checks to pause off-screen animations

Optimized Smoke Implementation

/* Performance-optimized smoke */
.optimized-smoke {
    position: relative;
    background: #000;
    overflow: hidden;
    contain: layout style paint;
}

.smoke-element-optimized {
    position: absolute;
    will-change: transform, opacity;
    transform: translateZ(0); /* GPU acceleration */
    backface-visibility: hidden;
    animation: smoke-rise-optimized 8s infinite;
}

@keyframes smoke-rise-optimized {
    0% {
        transform: translate3d(0, 0, 0) scale(1);
        opacity: 0;
    }
    10% {
        opacity: 0.3;
    }
    100% {
        transform: translate3d(0, -200px, 0) scale(2);
        opacity: 0;
    }
}

/* Pause animation when not visible */
.smoke-element-optimized {
    animation-play-state: paused;
}

.smoke-container:hover .smoke-element-optimized {
    animation-play-state: running;
}

Real-World Smoke Effect Examples

1. Hero Section with Smoke

/* Hero with rising smoke */
.hero-smoke {
    position: relative;
    min-height: 100vh;
    background: #000;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

.hero-smoke::before {
    content: '';
    position: absolute;
    bottom: -100px;
    left: 0;
    right: 0;
    height: 400px;
    background: linear-gradient(to top, rgba(255,255,255,0.1) 0%, transparent 100%);
    filter: blur(40px);
    animation: hero-smoke-rise 15s infinite ease-out;
}

@keyframes hero-smoke-rise {
    0%, 100% {
        transform: translateY(0) scaleY(1);
    }
    50% {
        transform: translateY(-50px) scaleY(1.2);
    }
}

.hero-content {
    position: relative;
    z-index: 1;
    text-align: center;
    color: white;
}

2. Loading Screen with Smoke

/* Smoke loading animation */
.loading-smoke {
    position: fixed;
    inset: 0;
    background: #000;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 9999;
}

.loading-smoke::after {
    content: 'LOADING';
    color: white;
    font-size: 2rem;
    font-weight: bold;
    letter-spacing: 0.5rem;
    animation: smoke-text 3s infinite;
}

@keyframes smoke-text {
    0%, 100% {
        filter: blur(0);
        opacity: 1;
    }
    50% {
        filter: blur(4px);
        opacity: 0.5;
    }
}

.smoke-loader {
    position: absolute;
    width: 100%;
    height: 100%;
    background: 
        radial-gradient(circle at 50% 50%, transparent 30%, rgba(255,255,255,0.03) 70%, transparent 100%);
    animation: smoke-pulse 2s infinite ease-in-out;
}

@keyframes smoke-pulse {
    0%, 100% {
        transform: scale(0.8);
        opacity: 0;
    }
    50% {
        transform: scale(1.5);
        opacity: 1;
    }
}

3. Interactive Smoke on Hover

/* Interactive smoke effect */
.smoke-card {
    position: relative;
    background: #000;
    padding: 3rem;
    border-radius: 12px;
    overflow: hidden;
    cursor: pointer;
    transition: transform 0.3s ease;
}

.smoke-card::before,
.smoke-card::after {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
    filter: blur(40px);
    opacity: 0;
    transition: opacity 0.5s ease;
}

.smoke-card::before {
    top: -50%;
    left: -50%;
}

.smoke-card::after {
    bottom: -50%;
    right: -50%;
}

.smoke-card:hover::before,
.smoke-card:hover::after {
    opacity: 1;
}

.smoke-card:hover {
    transform: translateY(-5px);
}

Customizable Smoke Effects with CSS Variables

/* Smoke effect variables */
:root {
    --smoke-color: rgba(255, 255, 255, 0.1);
    --smoke-blur: 30px;
    --smoke-duration: 8s;
    --smoke-height: 300px;
    --smoke-particles: 5;
}

.custom-smoke {
    position: relative;
    background: #000;
    overflow: hidden;
    height: 500px;
}

.custom-smoke-particle {
    position: absolute;
    bottom: 0;
    width: var(--smoke-height);
    height: var(--smoke-height);
    background: radial-gradient(circle, var(--smoke-color) 0%, transparent 70%);
    filter: blur(var(--smoke-blur));
    animation: custom-smoke-rise var(--smoke-duration) infinite ease-out;
}

/* Dynamic smoke colors */
.custom-smoke.blue {
    --smoke-color: rgba(100, 149, 237, 0.2);
}

.custom-smoke.red {
    --smoke-color: rgba(255, 69, 0, 0.2);
}

.custom-smoke.green {
    --smoke-color: rgba(50, 205, 50, 0.2);
}

When a Smoke Effect Helps and When It Hurts

A smoke effect is a strong stylistic statement. It works when the page exists to set a mood — a film promo, a game landing page, a music release, a luxury fragrance — and the visitor is there to be impressed before they read anything specific. It works against you when the page exists to deliver information, because moving translucent shapes constantly pull the eye away from the text.

A simple test: if you can hide the smoke layer with display: none and the page becomes harder to use rather than just less atmospheric, the smoke is doing real work. If hiding it makes the page faster to scan, the smoke is decoration that's competing with content.

Performance Reality Check

Pure-CSS smoke leans heavily on three expensive operations: filter: blur(), multiple stacked semi-transparent layers, and constant transform or opacity animation on those layers. Even on a modern desktop GPU each one is cheap individually; together they can drop a mobile device into 20–30 fps territory and noticeably warm the case.

Practical limits worth following:

  • Cap simultaneous smoke particles at five to seven. More layers don't read as more smoke; they just multiply paint cost.
  • Keep filter: blur() under 40 pixels. Beyond that the visual difference vanishes but the cost keeps rising.
  • Animate transform and opacity only — these stay on the compositor. Animating top, left, or filter values forces layout or paint on every frame.
  • Wrap the entire effect in @media (prefers-reduced-motion: no-preference). Provide a static fallback — a dark gradient, no movement — for everyone else.

Common Mistakes

  • Smoke that obscures the call to action. A particle drifting across a button at the moment a user goes to click it is a usability defect, not an effect. Keep the bottom 30% of the hero area calm.
  • Pure white smoke on pure black. Reads as graphic, not atmospheric. Tint the smoke very slightly toward the surrounding palette — a hint of warm grey for a film noir feel, a hint of cool grey for sci-fi.
  • Smoke that loops too obviously. If the cycle is shorter than about eight seconds, the eye locks onto the loop. Stagger animation delays so each particle has its own phase.
  • No fallback for older Safari. Older WebKit ignores backdrop-filter in some configurations. The base design must look acceptable without any blur — design the static state first, add the effect second.