Paper Cutout Design: 9 Layered Landing Sections
Paper cutout design is a layout style where every surface looks like it was cut with scissors and glued down: each panel gets its thickness from a zero-blur
Most "paper cutout" boards on Pinterest are Photoshop exports, and they get heavy the moment you move them to the web. Nothing that follows uses a single image file. Scroll the one-pager first and see if you can spot what actually makes it read as paper.
Below the page, the nine parts it's built from are broken out into their own grid. The order isn't by popularity — it follows what happens to a single sheet of paper on screen: it gets cut and placed, moved, stacked, stamped, dog-eared, taped, torn, sent drifting, and finally pressed.
Auto-plays · click a tile to jump to its section · all nine in one zip
- 01 Cut-paper hero
- 02 Lifted paper tab nav
- 03 Paper-band card grid
- 04 Sticker checkmark list
- 05 Dog-ear pricing
- 06 Taped testimonial note
- 07 Torn-edge CTA band
- 08 Confetti strip footer
- 09 Paper buttons & inputs
01Cut-paper hero
A white sheet rises while the three colored scraps behind it sink. The two layers have to move in opposite directions, or the stack reads as one flat plane. The shadow drops by exactly as much as the sheet lifts, blurring and lightening on the way.
.heropaper__sheet {
box-shadow: 0 10px 18px rgba(42, 35, 32, .14);
animation: sheetLift 2s ease-out infinite;
}
.heropaper__scrap { animation: scrapDrift 2s ease-out infinite; }
.heropaper__scrap--butter { animation-delay: -.66s; }
.heropaper__scrap--leaf { animation-delay: -1.33s; }
@keyframes sheetLift {
0%, 100% { transform: translateY(0); box-shadow: 0 10px 18px rgba(42, 35, 32, .14); }
50% { transform: translateY(-12px); box-shadow: 0 22px 28px rgba(42, 35, 32, .1); }
}
@keyframes scrapDrift {
0%, 100% { transform: translateY(0) rotate(-2deg); }
50% { transform: translateY(8px) rotate(3deg); }
}
02Lifted paper tab nav
A yellow paper chip hops between tabs instead of an underline sliding underneath. Because it rises 5px before every move, it reads as being picked up and set back down rather than sliding across.
.navpaper__tabs { --step: 76px; } /* 72px tab + 4px gap */
.navpaper__tab { flex: 0 0 72px; } /* fixed width, so the hop distance matches the render */
.navpaper__chip { animation: chipHop 2s cubic-bezier(.2, .8, .2, 1) infinite; }
@keyframes chipHop {
0% { transform: translateX(0) translateY(0); }
12% { transform: translateX(0) translateY(-5px); }
25% { transform: translateX(var(--step)) translateY(0); }
50% { transform: translateX(calc(var(--step) * 2)) translateY(0); }
75% { transform: translateX(var(--step)) translateY(0); }
100% { transform: translateX(0) translateY(0); }
}
03Paper-band card grid
Each of three white cards wears a different paper band across its top edge. The card bodies stay white; color only ever appears in the band and the icon. They peel up in turn, 0.22s apart.
.cardpaper { display: flex; gap: 12px; align-items: stretch; }
.cardpaper__card {
box-shadow: 0 6px 0 rgba(42, 35, 32, .16); /* zero blur = paper thickness */
animation: cardPeel 2s cubic-bezier(.2, .8, .2, 1) infinite;
}
.cardpaper__card::before { /* the band laid across the top */
content: ""; position: absolute; left: 12px; right: 12px; top: -8px;
height: 16px; border-radius: 4px;
}
.cardpaper__card--sky { animation-delay: -.22s; }
.cardpaper__card--leaf { animation-delay: -.44s; }
@keyframes cardPeel {
0%, 100% { transform: translateY(0); box-shadow: 0 6px 0 rgba(42, 35, 32, .16); }
45% { transform: translateY(-14px) rotate(-2deg); box-shadow: 0 18px 8px rgba(42, 35, 32, .12); }
}
04Sticker checkmark list
Four round stickers get stamped down in sequence. The weight of the press comes from squashing to 0.45, overshooting to 1.18, and then settling. With four stickers and four colors, each one gets a color of its own.
.stickerlist__dot {
box-shadow: 0 3px 0 rgba(42, 35, 32, .2);
animation: stickerStamp 2s cubic-bezier(.2, 1.4, .4, 1) infinite;
}
.stickerlist__row:nth-child(2) .stickerlist__dot { animation-delay: -1.75s; }
.stickerlist__row:nth-child(3) .stickerlist__dot { animation-delay: -1.5s; }
.stickerlist__row:nth-child(4) .stickerlist__dot { animation-delay: -1.25s; }
@keyframes stickerStamp {
0%, 60%, 100% { transform: scale(1) rotate(0deg); }
10% { transform: scale(.45) rotate(-12deg); }
22% { transform: scale(1.18) rotate(6deg); }
34% { transform: scale(1) rotate(0deg); }
}
05Dog-ear pricing
The recommended plan's top-right corner folds over, showing the sheet's back-side color, and then opens back up. The triangle is cut once with clip-path, and the fold itself is a single scale pinned to the corner point.
.dogear__plan { position: relative; overflow: hidden; }
.dogear__fold {
position: absolute; top: 0; right: 0; width: 40px; height: 40px;
background: #f6c453; /* the back side of the sheet */
clip-path: polygon(100% 0, 0 0, 100% 100%);
transform-origin: 100% 0; /* fold around the corner point */
animation: cornerFold 2s ease-out infinite;
}
@keyframes cornerFold {
0%, 100% { transform: scale(1); }
50% { transform: scale(.28); }
}
06Taped testimonial note
Two strips of masking tape hold down the note's top corners. Putting the pivot 12px above the paper means the same rotation swings the bottom edge much farther, which is what sells the weight of the hanging note.
.tapenote {
transform-origin: 50% -12px; /* pivot outside the sheet */
animation: noteSway 2s cubic-bezier(.2, .8, .2, 1) infinite;
}
.tapenote__tape { position: absolute; top: -10px; width: 56px; height: 20px; opacity: .92; }
.tapenote__tape--l { left: 16px; transform: rotate(-6deg); }
.tapenote__tape--r { right: 16px; transform: rotate(5deg); }
@keyframes noteSway {
0%, 100% { transform: rotate(-1.6deg); }
50% { transform: rotate(1.6deg); }
}
07Torn-edge CTA band
The band is torn into a zigzag along both long edges. The teeth come from three mask layers rather than an image: two conic-gradient layers that bite into the top and bottom edges, plus one linear-gradient that keeps the body of the band intact. The only thing moving is the button, and its shadow thins as it drops.
.tornband {
mask:
conic-gradient(from -45deg at bottom, #0000, #000 1deg 89deg, #0000 90deg) bottom / 14px 7px repeat-x,
conic-gradient(from 135deg at top, #0000, #000 1deg 89deg, #0000 90deg) top / 14px 7px repeat-x,
linear-gradient(#000 0 0) center / 100% calc(100% - 14px) no-repeat;
}
.tornband__btn { animation: paperPress 2s cubic-bezier(.2, .8, .2, 1) infinite; }
@keyframes paperPress {
0%, 100% { transform: translateY(-8px); box-shadow: 0 14px 0 rgba(42, 35, 32, .3); }
50% { transform: translateY(0); box-shadow: 0 2px 0 rgba(42, 35, 32, .3); }
}
08Confetti strip footer
The closing strip holds two identical sets of four chips and slides by exactly one set. When the cycle wraps, the last frame is pixel-for-pixel identical to the first, so there's no seam. Spacing the chips with gap breaks that arithmetic.
.pfoot__track {
display: flex;
width: max-content;
animation: stripFlow 2s linear infinite;
}
.pfoot__bit {
width: 36px; height: 20px;
margin-right: 12px; /* 2N chips have only 2N-1 gaps, so -50% would drift */
border-radius: 4px;
}
@keyframes stripFlow {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
09Paper buttons & inputs
Two buttons press down 6px, half a cycle apart. Since that 6px shadow is the paper's thickness, each press sinks the button by exactly one sheet. The input flips the idea around with an inset shadow.
.paperui__field {
box-shadow: inset 0 3px 0 #e7dccb; /* a carved groove — never add an outer shadow too */
}
.paperui__btn--solid { box-shadow: 0 6px 0 rgba(42, 35, 32, .28); }
.paperui__btn--ghost {
box-shadow: 0 6px 0 #e7dccb, inset 0 0 0 2px #e7dccb;
animation-delay: -1s; /* half a cycle behind, so they alternate */
}
@keyframes btnPress {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(6px); }
}
The custom tailwind.config
What has to live in one place here isn't the palette but the shadows. Mixing the thickness of a sheet lying flat (shadow-paper) with the blurred shadow of a lifted one (shadow-lift) is what breaks the paper illusion, so the two get separate names from the start.
theme: {
extend: {
colors: {
paper: "#fbf6ec", sheet: "#ffffff", ink: "#2a2320", stone: "#5c5048",
coral: "#cc3d26", sky: "#2f6fb8", leaf: "#2b7d5a",
butter: "#f6c453", blush: "#f6b3ab", edge: "#e7dccb",
},
borderRadius: { card: "16px", control: "12px", chip: "4px", pill: "999px" },
boxShadow: {
paper: "0 6px 0 rgba(42,35,32,.16)", // flat on the surface = thickness
"paper-edge": "0 6px 0 #e7dccb",
lift: "0 18px 8px rgba(42,35,32,.12)", // only while raised
"lift-high": "0 22px 28px rgba(42,35,32,.1)",
groove: "inset 0 3px 0 #e7dccb", // carved groove
},
},
},
| Role | Token | When |
|---|---|---|
| Paper thickness | shadow-paper |
A card or button resting on the surface |
| Raised | shadow-lift |
Hover and active states only |
| Carved groove | shadow-groove |
Inside an input |
The vibe-coding prompt
With the config in place, the instruction you hand Cursor or Claude Code fits in one block. What matters is that the shadow rules come before the color list. The full version ships as prompt.md inside the zip.
Give paper lying flat a zero-blur shadow: 0 6px 0 rgba(42,35,32,.16). Those 6px are the
paper's thickness and stay identical across the whole page. Swap to 0 18px 8px only while
something is raised. Background is one tone, paper(#fbf6ec); surfaces are one tone,
sheet(#ffffff). There are five paper colors and at most three per screen. White text goes
on coral, sky, or leaf only. Build torn edges from conic-gradient masks, never an image.
Here's a full-page capture of page/index.html at a 1280px viewport, built from exactly that instruction.

Where it breaks (the trap)
The bug that hid longest was type size. Across all nine stylesheets, size and weight were packed onto one line as font: 800 24px/1.1; with font-family: inherit; right underneath — and in the render, the price figure looked smaller than the heading above it. Dumping the computed values with Playwright showed that figure resolving to 16px/400 instead of 24px, and the hero heading landing on the browser default of 32px/700 rather than the intended 22px. The font shorthand requires a font-family in its final slot; leave it out and the browser discards the entire declaration. Only after unpacking all 21 occurrences into separate font-weight, font-size, and line-height properties did the measured values match the written ones.
The second one lived in the one-pager. With the Tailwind Play CDN in use, body { background: theme('colors.paper') } sat in an ordinary <style> block — and the page rendered plain white while the dog-ear on the pricing card never showed up at all. Both computed backgrounds came back as rgba(0, 0, 0, 0): the Play CDN compiles only a <style> tag marked type="text/tailwindcss" and throws away theme() anywhere else. The build with both problems fixed is in the zip, which opens with the password rysqfgwr.
Accessibility
Bright paper tones make contrast easy to reason about, right up until white text lands on a colored scrap. Working the relative-luminance formula from the WCAG 2.1 minimum contrast criterion by hand puts ink (#2a2320) at 14.34:1 against the paper ground (#fbf6ec) and the secondary stone (#5c5048) at 7.23:1, both comfortably past the 4.5:1 body-text bar. The accents were the problem. The coral originally picked, #d6452f, came out at 4.42:1 against white — under the bar — and had to be darkened to #cc3d26 before it reached 4.93:1. The same pass gave sky (#2f6fb8) 5.14:1 and leaf (#2b7d5a) 5.02:1, while butter (#f6c453) and blush (#f6b3ab) couldn't carry white text at any usable value, so the code restricts them to ink text at 9.52:1 and 8.79:1.
For motion, the media query from the MDN prefers-reduced-motion page is wired into all nine parts, so visitors who reduce motion see the sheets and the strip held still. The thickness shadows, which follow the MDN box-shadow page, survive that, so the layering still reads. The torn edge, built with the technique on the MDN mask page, is pure decoration: a browser without support just shows a rectangular band, and no content is lost.
For other landing page styles, browse the design trends category; what this blog gives away is explained on the about page.
FAQ
Wouldn't a paper texture image sell it better?
A texture photo makes the page heavier and forces a re-export every time the background color changes. What sells paper here is the zero-blur shadow and a thickness that always points the same way. Once the layers read without a photo, texture becomes optional rather than load-bearing.
Can each element get its own shadow thickness?
Keeping one value per screen is safer. When thicknesses vary, people read it as misalignment rather than as sheets of different weights. If you want a different feel, move the whole page from 6px to 3px or 10px at once instead of scattering values element by element.
Does this style survive on a dark background?
The thickness shadow has to be darker than the ground to register, and a dark ground leaves it nowhere to go. If you have to, drop the shadow and give each sheet a bright top edge instead (inset 0 1px 0) so it catches the light. That trade gives up the airy, weightless feel this style is built on.