25 CSS Background Animations13 / 25
Animated Fog / Mist Drift Background
Three sheets of fractal-noise fog crossing the frame at different heights, speeds and directions, so the density in front of you is always changing. The noise is generated by an inline SVG filter — one data URI, no cloud PNGs — and each sheet is masked into a horizontal band, which is why it reads as ground mist instead of a texture laid over the whole screen.
Published
The code
<section class="bga-13" aria-label="Animated fog and mist drift background demo">
<div class="bga-13__night" aria-hidden="true"></div>
<div class="bga-13__moon" aria-hidden="true"></div>
<div class="bga-13__trees" aria-hidden="true"></div>
<div class="bga-13__band bga-13__band--high" aria-hidden="true"><div class="bga-13__sheet" style="--bga-13-t:74s"></div></div>
<div class="bga-13__band bga-13__band--mid" aria-hidden="true"><div class="bga-13__sheet bga-13__sheet--rev" style="--bga-13-t:52s"></div></div>
<div class="bga-13__band bga-13__band--low" aria-hidden="true"><div class="bga-13__sheet" style="--bga-13-t:38s"></div></div>
<div class="bga-13__stage">
<div class="bga-13__panel">
<p class="bga-13__eyebrow">Atmosphere · 13</p>
<h1 class="bga-13__title">Fog is noise, banded and parallaxed.</h1>
<p class="bga-13__sub">One tiling turbulence texture, three masked bands, three speeds. The mask is what turns a texture into weather.</p>
<div class="bga-13__layers" aria-hidden="true">
<div><b>High</b><span>74s · opacity .22</span></div>
<div><b>Mid</b><span>52s · reversed</span></div>
<div><b>Low</b><span>38s · opacity .5</span></div>
</div>
</div>
</div>
</section><section class="bga-13" aria-label="Animated fog and mist drift background demo">
<div class="bga-13__night" aria-hidden="true"></div>
<div class="bga-13__moon" aria-hidden="true"></div>
<div class="bga-13__trees" aria-hidden="true"></div>
<div class="bga-13__band bga-13__band--high" aria-hidden="true"><div class="bga-13__sheet" style="--bga-13-t:74s"></div></div>
<div class="bga-13__band bga-13__band--mid" aria-hidden="true"><div class="bga-13__sheet bga-13__sheet--rev" style="--bga-13-t:52s"></div></div>
<div class="bga-13__band bga-13__band--low" aria-hidden="true"><div class="bga-13__sheet" style="--bga-13-t:38s"></div></div>
<div class="bga-13__stage">
<div class="bga-13__panel">
<p class="bga-13__eyebrow">Atmosphere · 13</p>
<h1 class="bga-13__title">Fog is noise, banded and parallaxed.</h1>
<p class="bga-13__sub">One tiling turbulence texture, three masked bands, three speeds. The mask is what turns a texture into weather.</p>
<div class="bga-13__layers" aria-hidden="true">
<div><b>High</b><span>74s · opacity .22</span></div>
<div><b>Mid</b><span>52s · reversed</span></div>
<div><b>Low</b><span>38s · opacity .5</span></div>
</div>
</div>
</div>
</section>.bga-13,
.bga-13 *,
.bga-13 *::before,
.bga-13 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bga-13 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
overflow: hidden;
isolation: isolate;
--bga-13-bg: oklch(0.19 0.028 250);
--bga-13-mist: oklch(0.9 0.02 240);
--bga-13-acc: oklch(0.84 0.09 210);
background: var(--bga-13-bg);
color: oklch(0.96 0.008 240);
font-family: ui-sans-serif,system-ui,-apple-system,'Segoe UI',sans-serif;
-webkit-font-smoothing: antialiased;
}
.bga-13__night {
position: absolute;
inset: 0;
background: linear-gradient(180deg,oklch(0.14 0.03 262) 0%,oklch(0.22 0.035 248) 46%,oklch(0.34 0.03 232) 100%);
}
.bga-13__moon {
position: absolute;
top: 14%;
left: 66%;
width: min(20vmax,190px);
aspect-ratio: 1;
border-radius: 50%;
background: radial-gradient(circle,oklch(0.98 0.02 220) 0 30%,color-mix(in oklab,var(--bga-13-acc) 42%,transparent) 46%,transparent 72%);
filter: blur(1px);
animation: bga-13-glow 12s ease-in-out infinite alternate;
}
@keyframes bga-13-glow {
to {
opacity: .7;
scale: 1.06;
}
}
.bga-13__trees {
position: absolute;
inset-inline: 0;
inset-block-end: 0;
height: 34%;
opacity: .55;
background: conic-gradient(from 180deg at 12% 100%,transparent 0 44%,oklch(0.12 0.02 255) 44% 56%,transparent 56%), conic-gradient(from 180deg at 30% 100%,transparent 0 46%,oklch(0.1 0.02 255) 46% 54%,transparent 54%), conic-gradient(from 180deg at 52% 100%,transparent 0 45%,oklch(0.13 0.02 255) 45% 55%,transparent 55%), conic-gradient(from 180deg at 74% 100%,transparent 0 46%,oklch(0.1 0.02 255) 46% 54%,transparent 54%), conic-gradient(from 180deg at 92% 100%,transparent 0 44%,oklch(0.12 0.02 255) 44% 56%,transparent 56%);
}
.bga-13__band {
position: absolute;
inset-inline: 0;
overflow: hidden;
pointer-events: none;
-webkit-mask-image: linear-gradient(transparent,oklch(0 0 0) 26%,oklch(0 0 0) 74%,transparent);
mask-image: linear-gradient(transparent,oklch(0 0 0) 26%,oklch(0 0 0) 74%,transparent);
}
.bga-13__band--high {
top: 6%;
height: 34%;
opacity: .24;
}
.bga-13__band--mid {
top: 34%;
height: 36%;
opacity: .34;
}
.bga-13__band--low {
inset-block-end: 0;
height: 46%;
opacity: .52;
}
.bga-13__sheet {
position: absolute;
inset-block: -20%;
inset-inline-start: 0;
width: 300%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='600'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.008 0.015' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='900' height='600' filter='url(%23f)' opacity='0.85'/%3E%3C/svg%3E");
background-size: 900px 600px;
background-repeat: repeat;
mix-blend-mode: screen;
filter: blur(10px) contrast(1.25) brightness(1.25);
animation: bga-13-cross var(--bga-13-t,50s) linear infinite,bga-13-breathe 26s ease-in-out infinite alternate;
}
.bga-13__sheet--rev {
animation-direction: reverse,normal;
}
@keyframes bga-13-cross {
to {
translate: -33.3333% 0;
}
}
@keyframes bga-13-breathe {
to {
scale: 1.08 1.16;
}
}
.bga-13__stage {
position: relative;
z-index: 5;
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
align-content: center;
padding: clamp(22px,5vw,68px);
}
.bga-13__panel {
width: min(100%,660px);
display: grid;
gap: 15px;
justify-items: center;
text-align: center;
padding: clamp(26px,3.8vw,48px);
border-radius: 20px;
background: oklch(0.15 0.025 250/.5);
border: 1px solid oklch(1 0 0/.13);
backdrop-filter: blur(14px) saturate(1.2);
-webkit-backdrop-filter: blur(14px) saturate(1.2);
box-shadow: 0 44px 100px -54px oklch(0 0 0/.95);
}
.bga-13__eyebrow {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
letter-spacing: .24em;
text-transform: uppercase;
color: var(--bga-13-acc);
}
.bga-13__title {
font-size: clamp(26px,5vw,50px);
font-weight: 600;
line-height: 1.06;
letter-spacing: -.045em;
text-wrap: balance;
}
.bga-13__sub {
max-width: 48ch;
font-size: clamp(13.5px,1.3vw,16px);
line-height: 1.6;
color: oklch(0.93 0.01 240/.76);
text-wrap: pretty;
}
.bga-13__layers {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
margin-top: 6px;
}
.bga-13__layers div {
display: grid;
gap: 2px;
min-width: 126px;
padding: 10px 14px;
border-radius: 12px;
text-align: left;
background: oklch(1 0 0/.06);
border: 1px solid oklch(1 0 0/.1);
}
.bga-13__layers b {
font-size: 12.5px;
font-weight: 640;
letter-spacing: -.01em;
}
.bga-13__layers span {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 10.5px;
color: oklch(0.88 0.01 240/.6);
}
@media (prefers-reduced-motion: reduce) {
.bga-13__sheet,
.bga-13__moon {
animation: none;
}
}.bga-13,
.bga-13 *,
.bga-13 *::before,
.bga-13 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bga-13 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
overflow: hidden;
isolation: isolate;
--bga-13-bg: oklch(0.19 0.028 250);
--bga-13-mist: oklch(0.9 0.02 240);
--bga-13-acc: oklch(0.84 0.09 210);
background: var(--bga-13-bg);
color: oklch(0.96 0.008 240);
font-family: ui-sans-serif,system-ui,-apple-system,'Segoe UI',sans-serif;
-webkit-font-smoothing: antialiased;
}
.bga-13__night {
position: absolute;
inset: 0;
background: linear-gradient(180deg,oklch(0.14 0.03 262) 0%,oklch(0.22 0.035 248) 46%,oklch(0.34 0.03 232) 100%);
}
.bga-13__moon {
position: absolute;
top: 14%;
left: 66%;
width: min(20vmax,190px);
aspect-ratio: 1;
border-radius: 50%;
background: radial-gradient(circle,oklch(0.98 0.02 220) 0 30%,color-mix(in oklab,var(--bga-13-acc) 42%,transparent) 46%,transparent 72%);
filter: blur(1px);
animation: bga-13-glow 12s ease-in-out infinite alternate;
}
@keyframes bga-13-glow {
to {
opacity: .7;
scale: 1.06;
}
}
.bga-13__trees {
position: absolute;
inset-inline: 0;
inset-block-end: 0;
height: 34%;
opacity: .55;
background: conic-gradient(from 180deg at 12% 100%,transparent 0 44%,oklch(0.12 0.02 255) 44% 56%,transparent 56%), conic-gradient(from 180deg at 30% 100%,transparent 0 46%,oklch(0.1 0.02 255) 46% 54%,transparent 54%), conic-gradient(from 180deg at 52% 100%,transparent 0 45%,oklch(0.13 0.02 255) 45% 55%,transparent 55%), conic-gradient(from 180deg at 74% 100%,transparent 0 46%,oklch(0.1 0.02 255) 46% 54%,transparent 54%), conic-gradient(from 180deg at 92% 100%,transparent 0 44%,oklch(0.12 0.02 255) 44% 56%,transparent 56%);
}
.bga-13__band {
position: absolute;
inset-inline: 0;
overflow: hidden;
pointer-events: none;
-webkit-mask-image: linear-gradient(transparent,oklch(0 0 0) 26%,oklch(0 0 0) 74%,transparent);
mask-image: linear-gradient(transparent,oklch(0 0 0) 26%,oklch(0 0 0) 74%,transparent);
}
.bga-13__band--high {
top: 6%;
height: 34%;
opacity: .24;
}
.bga-13__band--mid {
top: 34%;
height: 36%;
opacity: .34;
}
.bga-13__band--low {
inset-block-end: 0;
height: 46%;
opacity: .52;
}
.bga-13__sheet {
position: absolute;
inset-block: -20%;
inset-inline-start: 0;
width: 300%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='600'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.008 0.015' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='900' height='600' filter='url(%23f)' opacity='0.85'/%3E%3C/svg%3E");
background-size: 900px 600px;
background-repeat: repeat;
mix-blend-mode: screen;
filter: blur(10px) contrast(1.25) brightness(1.25);
animation: bga-13-cross var(--bga-13-t,50s) linear infinite,bga-13-breathe 26s ease-in-out infinite alternate;
}
.bga-13__sheet--rev {
animation-direction: reverse,normal;
}
@keyframes bga-13-cross {
to {
translate: -33.3333% 0;
}
}
@keyframes bga-13-breathe {
to {
scale: 1.08 1.16;
}
}
.bga-13__stage {
position: relative;
z-index: 5;
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
align-content: center;
padding: clamp(22px,5vw,68px);
}
.bga-13__panel {
width: min(100%,660px);
display: grid;
gap: 15px;
justify-items: center;
text-align: center;
padding: clamp(26px,3.8vw,48px);
border-radius: 20px;
background: oklch(0.15 0.025 250/.5);
border: 1px solid oklch(1 0 0/.13);
backdrop-filter: blur(14px) saturate(1.2);
-webkit-backdrop-filter: blur(14px) saturate(1.2);
box-shadow: 0 44px 100px -54px oklch(0 0 0/.95);
}
.bga-13__eyebrow {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
letter-spacing: .24em;
text-transform: uppercase;
color: var(--bga-13-acc);
}
.bga-13__title {
font-size: clamp(26px,5vw,50px);
font-weight: 600;
line-height: 1.06;
letter-spacing: -.045em;
text-wrap: balance;
}
.bga-13__sub {
max-width: 48ch;
font-size: clamp(13.5px,1.3vw,16px);
line-height: 1.6;
color: oklch(0.93 0.01 240/.76);
text-wrap: pretty;
}
.bga-13__layers {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
margin-top: 6px;
}
.bga-13__layers div {
display: grid;
gap: 2px;
min-width: 126px;
padding: 10px 14px;
border-radius: 12px;
text-align: left;
background: oklch(1 0 0/.06);
border: 1px solid oklch(1 0 0/.1);
}
.bga-13__layers b {
font-size: 12.5px;
font-weight: 640;
letter-spacing: -.01em;
}
.bga-13__layers span {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 10.5px;
color: oklch(0.88 0.01 240/.6);
}
@media (prefers-reduced-motion: reduce) {
.bga-13__sheet,
.bga-13__moon {
animation: none;
}
}Here's a working CSS Background Animation from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Animated Fog / Mist Drift Background
Source: https://codefronts.com/motion/css-background-animations/infinite-scrolling-diagonal-text-marquee-background/
Three sheets of fractal-noise fog crossing the frame at different heights, speeds and directions, so the density in front of you is always changing. The noise is generated by an inline SVG filter — one data URI, no cloud PNGs — and each sheet is masked into a horizontal band, which is why it reads as ground mist instead of a texture laid over the whole screen.
## HTML
```html
<section class="bga-13" aria-label="Animated fog and mist drift background demo">
<div class="bga-13__night" aria-hidden="true"></div>
<div class="bga-13__moon" aria-hidden="true"></div>
<div class="bga-13__trees" aria-hidden="true"></div>
<div class="bga-13__band bga-13__band--high" aria-hidden="true"><div class="bga-13__sheet" style="--bga-13-t:74s"></div></div>
<div class="bga-13__band bga-13__band--mid" aria-hidden="true"><div class="bga-13__sheet bga-13__sheet--rev" style="--bga-13-t:52s"></div></div>
<div class="bga-13__band bga-13__band--low" aria-hidden="true"><div class="bga-13__sheet" style="--bga-13-t:38s"></div></div>
<div class="bga-13__stage">
<div class="bga-13__panel">
<p class="bga-13__eyebrow">Atmosphere · 13</p>
<h1 class="bga-13__title">Fog is noise, banded and parallaxed.</h1>
<p class="bga-13__sub">One tiling turbulence texture, three masked bands, three speeds. The mask is what turns a texture into weather.</p>
<div class="bga-13__layers" aria-hidden="true">
<div><b>High</b><span>74s · opacity .22</span></div>
<div><b>Mid</b><span>52s · reversed</span></div>
<div><b>Low</b><span>38s · opacity .5</span></div>
</div>
</div>
</div>
</section>
```
## CSS
```css
.bga-13,
.bga-13 *,
.bga-13 *::before,
.bga-13 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bga-13 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
overflow: hidden;
isolation: isolate;
--bga-13-bg: oklch(0.19 0.028 250);
--bga-13-mist: oklch(0.9 0.02 240);
--bga-13-acc: oklch(0.84 0.09 210);
background: var(--bga-13-bg);
color: oklch(0.96 0.008 240);
font-family: ui-sans-serif,system-ui,-apple-system,'Segoe UI',sans-serif;
-webkit-font-smoothing: antialiased;
}
.bga-13__night {
position: absolute;
inset: 0;
background: linear-gradient(180deg,oklch(0.14 0.03 262) 0%,oklch(0.22 0.035 248) 46%,oklch(0.34 0.03 232) 100%);
}
.bga-13__moon {
position: absolute;
top: 14%;
left: 66%;
width: min(20vmax,190px);
aspect-ratio: 1;
border-radius: 50%;
background: radial-gradient(circle,oklch(0.98 0.02 220) 0 30%,color-mix(in oklab,var(--bga-13-acc) 42%,transparent) 46%,transparent 72%);
filter: blur(1px);
animation: bga-13-glow 12s ease-in-out infinite alternate;
}
@keyframes bga-13-glow {
to {
opacity: .7;
scale: 1.06;
}
}
.bga-13__trees {
position: absolute;
inset-inline: 0;
inset-block-end: 0;
height: 34%;
opacity: .55;
background: conic-gradient(from 180deg at 12% 100%,transparent 0 44%,oklch(0.12 0.02 255) 44% 56%,transparent 56%), conic-gradient(from 180deg at 30% 100%,transparent 0 46%,oklch(0.1 0.02 255) 46% 54%,transparent 54%), conic-gradient(from 180deg at 52% 100%,transparent 0 45%,oklch(0.13 0.02 255) 45% 55%,transparent 55%), conic-gradient(from 180deg at 74% 100%,transparent 0 46%,oklch(0.1 0.02 255) 46% 54%,transparent 54%), conic-gradient(from 180deg at 92% 100%,transparent 0 44%,oklch(0.12 0.02 255) 44% 56%,transparent 56%);
}
.bga-13__band {
position: absolute;
inset-inline: 0;
overflow: hidden;
pointer-events: none;
-webkit-mask-image: linear-gradient(transparent,oklch(0 0 0) 26%,oklch(0 0 0) 74%,transparent);
mask-image: linear-gradient(transparent,oklch(0 0 0) 26%,oklch(0 0 0) 74%,transparent);
}
.bga-13__band--high {
top: 6%;
height: 34%;
opacity: .24;
}
.bga-13__band--mid {
top: 34%;
height: 36%;
opacity: .34;
}
.bga-13__band--low {
inset-block-end: 0;
height: 46%;
opacity: .52;
}
.bga-13__sheet {
position: absolute;
inset-block: -20%;
inset-inline-start: 0;
width: 300%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='600'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.008 0.015' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='900' height='600' filter='url(%23f)' opacity='0.85'/%3E%3C/svg%3E");
background-size: 900px 600px;
background-repeat: repeat;
mix-blend-mode: screen;
filter: blur(10px) contrast(1.25) brightness(1.25);
animation: bga-13-cross var(--bga-13-t,50s) linear infinite,bga-13-breathe 26s ease-in-out infinite alternate;
}
.bga-13__sheet--rev {
animation-direction: reverse,normal;
}
@keyframes bga-13-cross {
to {
translate: -33.3333% 0;
}
}
@keyframes bga-13-breathe {
to {
scale: 1.08 1.16;
}
}
.bga-13__stage {
position: relative;
z-index: 5;
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
align-content: center;
padding: clamp(22px,5vw,68px);
}
.bga-13__panel {
width: min(100%,660px);
display: grid;
gap: 15px;
justify-items: center;
text-align: center;
padding: clamp(26px,3.8vw,48px);
border-radius: 20px;
background: oklch(0.15 0.025 250/.5);
border: 1px solid oklch(1 0 0/.13);
backdrop-filter: blur(14px) saturate(1.2);
-webkit-backdrop-filter: blur(14px) saturate(1.2);
box-shadow: 0 44px 100px -54px oklch(0 0 0/.95);
}
.bga-13__eyebrow {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
letter-spacing: .24em;
text-transform: uppercase;
color: var(--bga-13-acc);
}
.bga-13__title {
font-size: clamp(26px,5vw,50px);
font-weight: 600;
line-height: 1.06;
letter-spacing: -.045em;
text-wrap: balance;
}
.bga-13__sub {
max-width: 48ch;
font-size: clamp(13.5px,1.3vw,16px);
line-height: 1.6;
color: oklch(0.93 0.01 240/.76);
text-wrap: pretty;
}
.bga-13__layers {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
margin-top: 6px;
}
.bga-13__layers div {
display: grid;
gap: 2px;
min-width: 126px;
padding: 10px 14px;
border-radius: 12px;
text-align: left;
background: oklch(1 0 0/.06);
border: 1px solid oklch(1 0 0/.1);
}
.bga-13__layers b {
font-size: 12.5px;
font-weight: 640;
letter-spacing: -.01em;
}
.bga-13__layers span {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 10.5px;
color: oklch(0.88 0.01 240/.6);
}
@media (prefers-reduced-motion: reduce) {
.bga-13__sheet,
.bga-13__moon {
animation: none;
}
}
```Here's a working CSS Background Animation from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Animated Fog / Mist Drift Background
Source: https://codefronts.com/motion/css-background-animations/infinite-scrolling-diagonal-text-marquee-background/
Three sheets of fractal-noise fog crossing the frame at different heights, speeds and directions, so the density in front of you is always changing. The noise is generated by an inline SVG filter — one data URI, no cloud PNGs — and each sheet is masked into a horizontal band, which is why it reads as ground mist instead of a texture laid over the whole screen.
## HTML
```html
<section class="bga-13" aria-label="Animated fog and mist drift background demo">
<div class="bga-13__night" aria-hidden="true"></div>
<div class="bga-13__moon" aria-hidden="true"></div>
<div class="bga-13__trees" aria-hidden="true"></div>
<div class="bga-13__band bga-13__band--high" aria-hidden="true"><div class="bga-13__sheet" style="--bga-13-t:74s"></div></div>
<div class="bga-13__band bga-13__band--mid" aria-hidden="true"><div class="bga-13__sheet bga-13__sheet--rev" style="--bga-13-t:52s"></div></div>
<div class="bga-13__band bga-13__band--low" aria-hidden="true"><div class="bga-13__sheet" style="--bga-13-t:38s"></div></div>
<div class="bga-13__stage">
<div class="bga-13__panel">
<p class="bga-13__eyebrow">Atmosphere · 13</p>
<h1 class="bga-13__title">Fog is noise, banded and parallaxed.</h1>
<p class="bga-13__sub">One tiling turbulence texture, three masked bands, three speeds. The mask is what turns a texture into weather.</p>
<div class="bga-13__layers" aria-hidden="true">
<div><b>High</b><span>74s · opacity .22</span></div>
<div><b>Mid</b><span>52s · reversed</span></div>
<div><b>Low</b><span>38s · opacity .5</span></div>
</div>
</div>
</div>
</section>
```
## CSS
```css
.bga-13,
.bga-13 *,
.bga-13 *::before,
.bga-13 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.bga-13 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
overflow: hidden;
isolation: isolate;
--bga-13-bg: oklch(0.19 0.028 250);
--bga-13-mist: oklch(0.9 0.02 240);
--bga-13-acc: oklch(0.84 0.09 210);
background: var(--bga-13-bg);
color: oklch(0.96 0.008 240);
font-family: ui-sans-serif,system-ui,-apple-system,'Segoe UI',sans-serif;
-webkit-font-smoothing: antialiased;
}
.bga-13__night {
position: absolute;
inset: 0;
background: linear-gradient(180deg,oklch(0.14 0.03 262) 0%,oklch(0.22 0.035 248) 46%,oklch(0.34 0.03 232) 100%);
}
.bga-13__moon {
position: absolute;
top: 14%;
left: 66%;
width: min(20vmax,190px);
aspect-ratio: 1;
border-radius: 50%;
background: radial-gradient(circle,oklch(0.98 0.02 220) 0 30%,color-mix(in oklab,var(--bga-13-acc) 42%,transparent) 46%,transparent 72%);
filter: blur(1px);
animation: bga-13-glow 12s ease-in-out infinite alternate;
}
@keyframes bga-13-glow {
to {
opacity: .7;
scale: 1.06;
}
}
.bga-13__trees {
position: absolute;
inset-inline: 0;
inset-block-end: 0;
height: 34%;
opacity: .55;
background: conic-gradient(from 180deg at 12% 100%,transparent 0 44%,oklch(0.12 0.02 255) 44% 56%,transparent 56%), conic-gradient(from 180deg at 30% 100%,transparent 0 46%,oklch(0.1 0.02 255) 46% 54%,transparent 54%), conic-gradient(from 180deg at 52% 100%,transparent 0 45%,oklch(0.13 0.02 255) 45% 55%,transparent 55%), conic-gradient(from 180deg at 74% 100%,transparent 0 46%,oklch(0.1 0.02 255) 46% 54%,transparent 54%), conic-gradient(from 180deg at 92% 100%,transparent 0 44%,oklch(0.12 0.02 255) 44% 56%,transparent 56%);
}
.bga-13__band {
position: absolute;
inset-inline: 0;
overflow: hidden;
pointer-events: none;
-webkit-mask-image: linear-gradient(transparent,oklch(0 0 0) 26%,oklch(0 0 0) 74%,transparent);
mask-image: linear-gradient(transparent,oklch(0 0 0) 26%,oklch(0 0 0) 74%,transparent);
}
.bga-13__band--high {
top: 6%;
height: 34%;
opacity: .24;
}
.bga-13__band--mid {
top: 34%;
height: 36%;
opacity: .34;
}
.bga-13__band--low {
inset-block-end: 0;
height: 46%;
opacity: .52;
}
.bga-13__sheet {
position: absolute;
inset-block: -20%;
inset-inline-start: 0;
width: 300%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='600'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.008 0.015' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='900' height='600' filter='url(%23f)' opacity='0.85'/%3E%3C/svg%3E");
background-size: 900px 600px;
background-repeat: repeat;
mix-blend-mode: screen;
filter: blur(10px) contrast(1.25) brightness(1.25);
animation: bga-13-cross var(--bga-13-t,50s) linear infinite,bga-13-breathe 26s ease-in-out infinite alternate;
}
.bga-13__sheet--rev {
animation-direction: reverse,normal;
}
@keyframes bga-13-cross {
to {
translate: -33.3333% 0;
}
}
@keyframes bga-13-breathe {
to {
scale: 1.08 1.16;
}
}
.bga-13__stage {
position: relative;
z-index: 5;
min-height: 100vh;
min-height: 100svh;
display: grid;
place-items: center;
align-content: center;
padding: clamp(22px,5vw,68px);
}
.bga-13__panel {
width: min(100%,660px);
display: grid;
gap: 15px;
justify-items: center;
text-align: center;
padding: clamp(26px,3.8vw,48px);
border-radius: 20px;
background: oklch(0.15 0.025 250/.5);
border: 1px solid oklch(1 0 0/.13);
backdrop-filter: blur(14px) saturate(1.2);
-webkit-backdrop-filter: blur(14px) saturate(1.2);
box-shadow: 0 44px 100px -54px oklch(0 0 0/.95);
}
.bga-13__eyebrow {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
letter-spacing: .24em;
text-transform: uppercase;
color: var(--bga-13-acc);
}
.bga-13__title {
font-size: clamp(26px,5vw,50px);
font-weight: 600;
line-height: 1.06;
letter-spacing: -.045em;
text-wrap: balance;
}
.bga-13__sub {
max-width: 48ch;
font-size: clamp(13.5px,1.3vw,16px);
line-height: 1.6;
color: oklch(0.93 0.01 240/.76);
text-wrap: pretty;
}
.bga-13__layers {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
margin-top: 6px;
}
.bga-13__layers div {
display: grid;
gap: 2px;
min-width: 126px;
padding: 10px 14px;
border-radius: 12px;
text-align: left;
background: oklch(1 0 0/.06);
border: 1px solid oklch(1 0 0/.1);
}
.bga-13__layers b {
font-size: 12.5px;
font-weight: 640;
letter-spacing: -.01em;
}
.bga-13__layers span {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 10.5px;
color: oklch(0.88 0.01 240/.6);
}
@media (prefers-reduced-motion: reduce) {
.bga-13__sheet,
.bga-13__moon {
animation: none;
}
}
```How this works
Fog is noise plus banding plus parallax. The noise is a single tiling feTurbulence data URI reused by all three sheets, so the browser decodes one texture:
<feTurbulence type='fractalNoise' baseFrequency='.008 .014'
numOctaves='4' stitchTiles='stitch'/>The very low baseFrequency is what makes it fog rather than grain — long wavelengths, big soft masses. The anisotropic pair (x lower than y) stretches the clouds horizontally, which is how wind-shaped mist actually looks.
Each sheet is 300% wide and translated by exactly one third, so the tiled noise loops seamlessly:
.sheet { width: 300%; animation: cross var(--t) linear infinite; }
@keyframes cross { to { translate: -33.3333% 0; } }The band is a mask, and it is what sells the atmosphere:
mask-image: linear-gradient(transparent, #000 30%, #000 70%, transparent);Confining each sheet to its own vertical band — low and dense, mid and thin, high and faint — creates depth layering that a single full-height fog layer can never produce. Add a slow scale breathing animation on one sheet and the mass appears to swell and thin as it passes.
Everything animated is translate and opacity. The expensive part (rasterising the noise) happens once.
Make it yours
- Raise
numOctavesto 5 for wispier, more detailed edges; drop to 2 for smooth, heavy marine fog. - Tint each sheet differently with
background-color+mask-image: url(noise)instead of using the noise as the background — coloured fog for horror, sci-fi or festival scenes. - Reverse one sheet's direction (
animation-direction: reverse) so layers cross each other; opposing motion reads far more like real weather. - For a light theme, invert the noise with
filter: invert(1)and lower the opacity — the same layer becomes soft morning haze on a pale background.
Gotchas — read before shipping
- Fog kills contrast unpredictably. Put copy on a panel or keep the densest sheet below the content band, as here.
- Translating a 300%-wide filtered element can exceed the maximum texture size on mobile GPUs; keep sheets to 300% and no more than three.
- The loop distance must be exactly 100%/N of the oversized width or the fog visibly jumps — 33.3333% for 300%.
- Do not animate
filter: blur()on the sheets; set it once. Animated blur on a full-screen layer is one of the most expensive things you can do in CSS. - Layered
mix-blend-mode: screenfog over a dark background can clip to pure white where sheets overlap — keep per-sheet opacity under about 0.5.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 120+ | 15.4+ | 53+ | 120+ |
Unprefixed mask-image is Chrome 120; -webkit-mask-image covers earlier Chromium and Safari and is included. SVG filter data URIs and keyframes are universal.