Lab

404 / Error Pages Lab

Seven creative error-state designs — a good 404 page turns a dead end into a brand moment.

1. Minimal — giant 404, one line of text, primary action
404

Page not found

We couldn't find what you were looking for — but you can start over from the home page.

← Back home
<section>
  <div class="code">404</div>
  <h2>Page not found</h2>
  <p>We couldn't find the page.</p>
  <a class="btn">← Back home</a>
</section>
.code {
  font-size: 6rem;
  font-weight: 900;
  letter-spacing: -0.04em;
  line-height: 1;
}
2. Illustrated — floating character with a gentle bounce animation
404

Whoops — wrong turn.

This page may have been moved, deleted, or never existed in the first place.

Take me home
<div class="art">404</div>
.art {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  background: linear-gradient(135deg, #ec4899, #f59e0b);
  animation: float 3s ease-in-out infinite;
}

/* CSS-drawn eyes using ::before and ::after */
.art::before, .art::after {
  content: "";
  position: absolute;
  width: 30px;
  height: 20px;
  background: #fff;
  border-radius: 50%;
}

@keyframes float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-12px); }
}
3. Space — twinkling CSS stars + gradient 404 text
404

You've drifted off course

The page you're looking for is somewhere in another galaxy.

Return to Earth
<section class="space">
  <div class="code">404</div>
  <h2>You've drifted off course</h2>
</section>
/* Stars drawn with box-shadow (no images!) */
.space::before {
  content: "";
  position: absolute;
  width: 3px; height: 3px;
  background: #fff;
  border-radius: 50%;
  box-shadow:
    20px 30px 0 #fff,
    100px 80px 0 #ec4899,
    250px 40px 0 #fff,
    /* ...dozens more stars */;
  animation: twinkle 4s infinite;
}

@keyframes twinkle {
  0%, 100% { opacity: .4; }
  50%      { opacity: 1; }
}
4. Typographic — giant serif numerals fading into the page
404

Lost in translation

We searched high and low, but this page seems to have wandered off.

Find your way
<div class="code">404</div>
/* Gradient text that fades bottom-to-transparent */
.code {
  font-family: Georgia, serif;
  font-size: clamp(8rem, 24vw, 16rem);
  background: linear-gradient(180deg, #111 40%, rgba(17,17,17,.1));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
5. Glitch — chromatic aberration effect using duplicated pseudo-elements
404

System anomaly detected

> ERROR_CODE: PAGE_NOT_FOUND
> attempting reroute...

Return to safe mode
<div class="glitch">404</div>
.glitch {
  position: relative;
  color: #fff;
}

/* Two duplicate layers, each clipped differently */
.glitch::before, .glitch::after {
  content: "404";
  position: absolute;
  inset: 0;
}

.glitch::before {
  color: #ec4899;
  animation: glitch1 2s infinite;
}
.glitch::after {
  color: #06b6d4;
  animation: glitch2 2.2s infinite;
}

/* clip-path jumps between random bands */
@keyframes glitch1 {
  0%,100% { clip-path: inset(0 0 70% 0); }
  20%    { clip-path: inset(30% 0 40% 0); }
  60%    { clip-path: inset(10% 0 60% 0); }
}
6. Search 404 — actionable: search bar + popular-page suggestions
404

Can't find what you're looking for?

Try searching — or jump straight to one of our most-visited pages below.

Popular: Pricing· Docs· Blog· Contact
<div class="search">
  <input type="search" placeholder="Search...">
  <button>Search</button>
</div>
/* Pill-shaped search bar with inline button */
.search {
  display: flex;
  background: #fff;
  border-radius: 999px;
  padding: 6px;
  box-shadow: 0 8px 20px rgba(0,0,0,.06);
}

.search input {
  flex: 1;
  padding: 10px 18px;
  border: none;
  outline: none;
  background: transparent;
}

.search button {
  background: #111;
  color: #fff;
  border-radius: 999px;
  padding: 10px 20px;
}
7. Maintenance Mode — playful wiggle icon + ETA countdown

We're tuning things up

A quick maintenance window — we'll be back in a flash. Thanks for your patience.

ETA: 15 minutes

Get status updates
<div class="icon"><i class="ph-duotone ph-wrench"></i></div>
<h2>We're tuning things up</h2>
<div class="eta">ETA: 15 minutes</div>
.icon {
  width: 90px;
  height: 90px;
  border-radius: 50%;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: wiggle 2s ease-in-out infinite;
}

@keyframes wiggle {
  0%, 100% { transform: rotate(-6deg); }
  50%      { transform: rotate(6deg); }
}