Skip to content

A Tailwind CSS v4 plugin by Numbered

Fluid
Layout System

Design each breakpoint once. Your page renders 1:1 at every mockup width, then columns, gutters, margins and type scale fluidly in between.

$ bun add @numbered/tailwind-fluid-layout-system
Scroll to resize the screen

01 / 10 · desktop · your screen

Your screen

This is your screen, on the desktop grid of this page. Scroll to shrink it and watch the layout follow.

desktop: { columns: 12, gutter: 10, margin: 24, mockupWidth: 1440, screen: 'lg' }

Reference

Everything the plugin exposes.

Fluid layout anchors both grid and type to one reference: the mockup width of each breakpoint.

At that width, 1px in the design is 1px on screen. Between breakpoints, columns, gutters, margins and the root font size scale with the viewport, so the page keeps the design's proportions.

Describe each breakpoint once (mockup width, columns, gutter, margin). The plugin generates the CSS variables and Tailwind utilities to size, space and position anything on the grid, at any depth.

Simulator

viewport width1440px · desktop

Aa text-4xl · 36.0px

viewport at 65% of 2200px

grid
12 cols · desktop
mockupWidth
1440px
fontScalingMaxWidth
1540px
--grid-width
1392.0px
--column
106.8px
--gutter
10.0px
--margin
24.0px
1rem
16.0px
// tailwind.config.js
theme: {
  grid: {
    mobile:  { columns: 6,  gutter: 10, margin: 10, mockupWidth: 375 },
    desktop: { columns: 12, gutter: 10, margin: 24, mockupWidth: 1440, screen: 'lg' }
  }
}

From design to code

Measure the mockup, write the class. At the mockup width every utility renders the exact pixel value from the design, and between breakpoints it scales in proportion, so the layout never drifts from the design. Here with the grids of this page, drawn at 375px on mobile and 1440px on desktop:

class375px1024px1440px1920px
span-w-3174.5242.1340.5454.0
span-w-2-wide120.3166.2233.7311.6
gutter-w-15.97.110.013.3
margin-w-110.017.124.032.0
text-4xl36.025.636.038.5
p-2424.017.124.025.7

Rem based Tailwind values scale the same way until fontScalingMaxWidth (1540px here) stops them. To go from a measured width to a class, use the px-to-cols CLI at the end of this page.

How it works

Each breakpoint writes four variables on html: --column, --gutter, --margin and --grid-width. They are expressed in vw, so a 1440px mockup renders pixel perfect at 1440px and keeps its proportions at every other width. The faint lines on this page are the grid guidelines.

Live values · resize the window

Fluid type

The root font size follows the same rule: 1rem equals 16px at the mockup width and scales with it. Every rem based Tailwind value (font sizes, spacing, radii) scales in step with the grid, so type set in the mockup keeps its size relative to the layout. Set fontScalingMaxWidth to stop the growth on large screens; the simulator above marks where it kicks in.

Columns

span-* sizes an element to a number of columns, gutters between them included.

span-w-1
span-w-2
span-w-3

Add -wide for one extra gutter, -wider for two. Handy for offsets that land on the next column.

span-w-2
span-w-2-wide
span-w-2-wider

Gutters and margins

gutter-* and margin-* give multiples of the gutter and of the outer page margin.

span-w-2
span-w-2
span-w-2
span-w-2
gutter-ml-1
span-ml-1-wider

Any property

The three prefixes combine with width, height, padding, margin, inset, gap, scroll spacing, border width and text indent. Counts can be fractional and negative: span-w-1.5, span-w-1.5-wide, -span-ml-1. Beyond the widest grid, use an arbitrary value: span-w-[16].

Playground

count3.0columns

span-w-3

width: calc(3 * var(--column) + 2 * var(--gutter))

= 0.0px at this viewport

Nesting

CSS subgrid can pass the page grid down, but only if every wrapper in between is itself a subgrid. One flex row or positioned box breaks the chain. These utilities resolve to viewport units instead, not percentages of the parent, so span-w-2 has the same width in the body, in a flex row, in a grid cell or in an absolutely positioned box four wrappers deep. Offset each level by whole columns and its content stays on the page grid, whatever the parent is.

From mockup to class, agents included

The bundled CLI converts a measured pixel width into the closest class, for you or for your coding agent.

bunx @numbered/tailwind-fluid-layout-system 330 --columns 24 --mockup 1440 --gutter 24 --margin 24
# → span-w-6 (330px, exact)

In agentic development, the agent can't eyeball a grid either. Feed it the Figma frame and let it pipe every measurement through --batch, JSON in, JSON out, instead of guessing span-w-7 and hoping. The fluid-layout skill teaches it the routine, so what it ships matches the mockup.

echo '[{"pixels":250,"columns":12,"mockupWidth":1440,"gutter":20,"margin":60}]' \
  | bunx @numbered/tailwind-fluid-layout-system --batch

Install the skill in your project:

bunx skills add https://fls.numbered.com