Get AI summaries of any video or article — Sign up free
Build a Curvaceous Homepage // Wavy Background Tutorial with SVG & CSS thumbnail

Build a Curvaceous Homepage // Wavy Background Tutorial with SVG & CSS

Fireship·
5 min read

Based on Fireship's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.

TL;DR

Use VS Code Emmet snippets to generate repeated section markup quickly, then style each `section` as a centered flex container.

Briefing

A curvy, wave-filled homepage can be built without starting from scratch—by combining CSS-only shapes, SVG “spacer” backgrounds, and a JavaScript-driven morphing blob. The payoff is a design that turns flat section breaks into smooth, attention-grabbing transitions, while staying beginner-friendly through practical tooling and copy-pasteable snippets.

The build starts with a simple HTML page: a hero section at the top, multiple content sections in the middle, and a footer at the bottom. To speed up markup, the workflow uses VS Code Emmet snippets (like `section*8`) to generate repeated section blocks containing headings and paragraphs. For local preview, the tutorial recommends running `npx serve` to view the page at `localhost:5000`.

Styling establishes the baseline look: margin reset, a Google Fonts typeface, light text on a dark background, and a flexbox layout that centers content within each section. Each `section` is set to `position: relative` so decorative elements can be absolutely positioned inside it. With consistent spacing—minimum height, top/bottom padding, and responsive left/right padding using viewport width units—the page becomes a clean canvas for curves.

The first curve technique uses pure CSS. An empty `div` acts as a container for a “curve” layer positioned at the bottom of its parent section. The curve is created by stacking `::before` and `::after` pseudo-elements shaped as ellipses via `border-radius` with two values (vertical and horizontal radii). Careful placement with `transform: translate(...)` aligns the overlapping ellipses to sell the illusion of a continuous wave. Because this approach can cause horizontal overflow, the parent can set `overflow-x: hidden` to prevent unwanted scrollbars.

For simpler, more scalable separators, the tutorial shifts to SVG. It uses free web tools to generate wave SVGs automatically: one tool (Shape Divider) outputs an SVG snippet and matching CSS, while another (High) can generate layered wave backgrounds with adjustable colors and an important aspect ratio—treated like a long, skinny divider. The downloaded SVG is then applied as a background image through a reusable CSS class that leverages the `aspect-ratio` property, ensuring the spacer scales correctly. Empty `div` elements with these classes become the transition graphics between sections.

The final flourish brings motion. Using SVG morphing, the tutorial generates two blob shapes (downloaded as raw SVG) and extracts the relevant `path`/group elements. Each blob path gets an ID (`blob one` and `blob two`), and a small JavaScript setup uses a library called CuteJS (loaded via CDN) to animate between the two shapes. The second blob starts hidden, then the morph runs with a specified duration (3,000ms) and a “yo-yo” back-and-forth effect. The result is a homepage where section transitions feel alive—static curves, SVG wave dividers, and a continuously morphing centerpiece blob—without requiring advanced graphics tooling beyond the provided generators.

Cornell Notes

The homepage becomes “curvaceous” by layering three techniques: CSS ellipses, SVG wave dividers, and an animated SVG blob morph. CSS curves are built by stacking `::before` and `::after` pseudo-elements with elliptical `border-radius`, then aligning them using `transform: translate(...)` inside a `position: relative` section. SVG separators are generated with tools (Shape Divider and High), downloaded as SVG, and applied via CSS background images using the `aspect-ratio` property for consistent scaling. For motion, two blob paths extracted from raw SVG are morphed with CuteJS, using IDs like `blob one` and `blob two`, a 3,000ms duration, and a yo-yo animation that reverses back and forth.

How does the CSS-only curve technique create a wave-like shape without an SVG?

It relies on overlapping ellipses made from pseudo-elements. A bottom-positioned container `div` holds `::before` and `::after`, each with an elliptical `border-radius` using two values (vertical radius, horizontal radius). Both pseudo-elements have explicit width/height and are absolutely positioned. The illusion comes from aligning the two ellipses with `transform: translate(X, Y)` so their overlap reads as a continuous curve. If the overlap pushes content beyond the viewport, setting `overflow-x: hidden` on the parent prevents horizontal scrolling.

Why set `position: relative` on each `section`?

`position: relative` creates a positioning context for absolutely positioned decorative elements. The curve container and pseudo-elements are positioned relative to their parent `section`, not the page. Without this, the wave layers would anchor to the document or another ancestor, breaking the intended layout where each transition sits exactly at the bottom (or between) its corresponding content block.

What makes SVG wave dividers easier to scale than hand-tuned CSS curves?

SVG generators produce the exact path geometry and matching CSS snippet automatically. Instead of manually aligning ellipses, the workflow downloads a prebuilt wave SVG and applies it as a background image. The tutorial further improves scaling by using the CSS `aspect-ratio` property: a `.spacer` class sets the element’s ratio to match the SVG’s intended proportions, so the separator stays “long and skinny” across screen sizes.

How does the tutorial animate a morphing blob between two SVG shapes?

Two blob shapes are prepared as SVG paths/groups extracted from raw SVG downloads. Each blob path is given an ID (e.g., `blob one` and `blob two`). CuteJS is loaded via a CDN script tag, then a call to `cute.to(...).from(blob one).to(blob two)` sets the start and end shapes. Options include `duration: 3000` milliseconds and `yo-yo: true` to reverse back and forth. The second blob is set to `visibility: hidden` initially so only the starting shape appears.

What role do the “spacer layers” play in the final layout?

They act as visual transition bands between sections. The page inserts empty `div` elements with classes that apply the downloaded SVG as a background. A `flip` utility rotates one spacer by 180° so the wave direction matches the surrounding content. By stacking spacers above and below a central blob section, the layout gains layered, curvy separation without complex layout math.

Review Questions

  1. When building a CSS curve from pseudo-elements, which properties control the ellipse shape and which property is used to align the overlap?
  2. Why is the `aspect-ratio` property useful when applying an SVG as a background separator?
  3. What IDs and options are needed to morph between two SVG blob shapes using CuteJS?

Key Points

  1. 1

    Use VS Code Emmet snippets to generate repeated section markup quickly, then style each `section` as a centered flex container.

  2. 2

    Set `position: relative` on each `section` so decorative curves and spacers can be absolutely positioned in the correct local area.

  3. 3

    Create CSS waves by overlapping `::before` and `::after` ellipses using elliptical `border-radius`, then fine-tune alignment with `transform: translate(...)`.

  4. 4

    Prevent layout issues from CSS overlaps by applying `overflow-x: hidden` to the relevant parent container.

  5. 5

    Generate SVG wave dividers with tools, download the SVG, and apply it as a background using CSS `aspect-ratio` for consistent scaling.

  6. 6

    For motion, extract two blob paths from raw SVG, assign IDs, and morph them with CuteJS using a 3,000ms duration and yo-yo reversal.

Highlights

The first wave is built from nothing but CSS: two overlapping pseudo-elements shaped with elliptical `border-radius` and aligned via `transform: translate(...)`.
SVG separators become plug-and-play by applying downloaded wave files as background images and matching their proportions with the CSS `aspect-ratio` property.
A morphing blob animation can be achieved by extracting two SVG blob paths and using CuteJS to interpolate between them with a simple `from(...).to(...)` call and yo-yo behavior.

Topics

  • Curved Homepage
  • CSS Ellipse Waves
  • SVG Wave Dividers
  • SVG Morphing Blobs
  • CuteJS Animation