Official website: grrr.atonalstudio.com
GRRR experiment is not a library, it’s a concept.
GRRR is a CSS Grid system designed around runtime configuration via CSS custom properties. Rather than baking values into compiled CSS, every sizing decision — columns, gutters, margins, off areas — lives in variables that cascade and inherit like normal CSS. This means a single class can power layouts across breakpoints, themes, and nested contexts without re-compiling.
It pairs naturally with subgrid for nested components and named grid lines for semantic placement. When used consistently it can significantly reduce the CSS footprint of block-based or component-driven UIs since it’s a simple css file around 1kb gzipped.
CDN
<link rel="stylesheet" href="https://atonalstudio.github.io/GRRR/dist/latest/grrr.min.css">
Download
Visit the GRRR Repository and grab the files from the dist directory.
GRRR uses named lines in grid-template-columns to expose semantic placement areas.
| Area | Description | Example placement |
|---|---|---|
col |
Individual column tracks | col-start 2 / col-end 5 |
gutter |
Space between columns | gutter-start 2 / gutter-end 5 |
board |
All columns + gutters combined | board |
off |
Space between board and margin |
off-start 1 / off-end 2 |
margin |
Space between off and the window edge |
margin-start 1 / margin-end 1 (left side) |
full |
The entire grid, edge to edge | full |
gap or column-gap. Gutters are real column tracks.row-gap is safe to use.grrr-span() Sass function to calculate this automatically — see Sass Functions.<div class="grrr">
<div class="comp-1"></div>
<div class="comp-2"></div>
</div>
:root {
--grrr-cols: 12;
--grrr-gutter: 18px;
--grrr-margin: 20px;
--grrr-col-width: 84px;
/* Define named areas once, use everywhere */
--content-area: col-start 4 / col-end 9;
--wide-area: col-start 2 / col-end 11;
}
@media (max-width: 1024px) {
:root {
--grrr-cols: 8;
--grrr-gutter: 12px;
--content-area: col-start 2 / col-end 7;
--wide-area: board;
}
}
@media (max-width: 768px) {
:root {
--grrr-cols: 4;
--content-area: board;
/* Switch to fluid at mobile */
--grrr-off: 0;
--grrr-fluid-col: var(--grrr-use-fluid-col);
--content-area: board;
}
}
.comp-1 { grid-column: var(--content-area); }
.comp-2 { grid-column: var(--wide-area); }
grrrThe base bounded grid. Columns have a maximum width (--grrr-col-width). The board is centred; off areas absorb remaining space on both sides.
Setup variables
| Variable | Description | Default |
|---|---|---|
--grrr-cols |
Number of columns | 12 |
--grrr-gutter |
Space between columns | 18px |
--grrr-margin |
Margin on both sides | 20px |
--grrr-margin-left |
Left margin (overrides --grrr-margin) |
— |
--grrr-margin-right |
Right margin (overrides --grrr-margin) |
— |
--grrr-col-width |
Max column width | 84px |
--grrr-off |
Off area on both sides | minmax(0, 1fr) |
--grrr-off-left |
Left off area (overrides --grrr-off) |
— |
--grrr-off-right |
Right off area (overrides --grrr-off) |
— |
<div class="grrr">
<div class="comp-1"></div>
<div class="comp-2"></div>
</div>
grrr--fluidColumns stretch to fill all available width. Off area collapses to zero. No max column width.
<div class="grrr grrr--fluid">
<div class="comp-1"></div>
<div class="comp-2"></div>
</div>
grrr--stillA range of columns (still-start → still-end) keeps its bounded width. Columns outside that range shrink to zero as the viewport narrows — making the still area “sticky” within the layout.
Setup variables
| Variable | Description | Default |
|---|---|---|
--grrr-cols |
Number of columns | 12 |
--grrr-gutter |
Space between columns | 18px |
--grrr-margin |
Margin on both sides | 20px |
--grrr-col-width |
Max column width | 84px |
--grrr-still-start |
First column of the still area | 3 |
--grrr-still-end |
Last column of the still area | 10 |
--grrr-still |
Column sizing for still tracks. Set to var(--grrr-unstill) to disable |
initial |
<div class="grrr grrr--still">
<div class="comp-1"></div>
<div class="comp-2"></div>
</div>
Modifier classes
| Class | Description |
|---|---|
.grrr--still--from-first |
Still area starts at column 1 — no fluid columns before it. |
.grrr--still--to-last |
Still area ends at the last column — no fluid columns after it. |
.grrr--still--off |
Disables still — all columns behave as fluid (--grrr-unstill). |
You cannot combine
--from-firstand--to-last. For a fully bounded layout use a plain.grrr.
grrr--fluid + grrr--stillCombine both modifiers to get fluid columns outside the still range and bounded columns inside it.
<div class="grrr grrr--fluid grrr--still">
<div class="comp-1"></div>
<div class="comp-2"></div>
</div>
grrr--inheritInherits the complete grid definition from a parent GRRR. Useful for wrapper elements that must pass grid tracks through without re-declaring them.
<div class="grrr">
<div class="comp-1"></div>
<div class="grrr--inherit">
<div class="comp-2"></div>
<div class="comp-3"></div>
</div>
</div>
grrr--unsetDeactivates the grid entirely on an element.
<div class="grrr grrr--unset"></div>
GRRR exposes read-only CSS custom properties that reflect computed grid values. These are available on any element that uses a GRRR mixin and are useful for sizing components that live outside the grid tracks (flex children, absolutely positioned elements, canvas layers, etc.).
| Variable | Description |
|---|---|
--grrr-use-col-width |
Resolved column width: min(responsive-width, --grrr-col-width) |
--grrr-use-col-responsive-width |
Column width computed from available space: board-width / cols |
--grrr-use-board-width |
Actual rendered board width, accounting for bounded vs collapsed states |
--grrr-use-board-fluid-width |
Actual rendered board width in fluid state, width between both margins |
--grrr-use-off-total-width |
Total remaining space outside the board: canvas - margins - board (both sides) |
--grrr-use-off-width |
One side’s off area: --grrr-use-off-total-width / 2. Assumes symmetric. |
--grrr-use-still-area |
Shorthand for the still area placement: col-start N / col-end M |
--grrr-unstill |
The fluid column value. Assign to --grrr-still to turn off the still effect. |
--grrr-use-fluid-col |
The fluid column value (minmax(0, 1fr)). Assign to --grrr-fluid-col to go fluid. |
Limitation: Utility variables rely on
calc()and are only accurate when columns, gutters, and margins are defined as fixed<length>values (e.g.px). If you use1fr,minmax(), or other intrinsic sizing functions in the GRRR setup, CSS cannot resolve them to concrete lengths at calculation time, resulting in incorrect values. In these cases, rely onsubgridor alternative strategies.
Sizing a flex child to match a column span:
.my-component {
display: flex;
/* width of 3 columns + 2 gutters between them */
width: calc(var(--grrr-use-col-width) * 3 + var(--grrr-gutter) * 2);
}
Switching to fluid at a breakpoint without a modifier class:
@media (max-width: 768px) {
.my-grrr {
--grrr-fluid-col: var(--grrr-use-fluid-col);
--grrr-off: 0;
}
}
Sass is optional. Useful for shorthand calculations in elements within a GRRR parent using different display models (e.g. flex,
position: absolute, canvas) that need to use grid references.
grrr-spanReturns the grid-column end line for a span of N columns, including the gutters between them.
| Parameter | Required | Description |
|---|---|---|
$span |
yes | Number of columns to span |
.my-class {
grid-column: col-start 2 / grrr-span(4);
}
grrr-span-widthReturns the computed width of N columns including the gutters between them, for a bounded grid.
| Parameter | Required | Default | Description |
|---|---|---|---|
$n-cols |
yes | — | Number of columns |
$n-extra-gutters |
no | 0 |
Additional gutters to add |
.my-class {
width: grrr-span-width(3);
}
grrr-span-width-fluidSame as grrr-span-width but uses the responsive column width rather than the fixed maximum.
| Parameter | Required | Default | Description |
|---|---|---|---|
$n-cols |
yes | — | Number of columns |
$n-extra-gutters |
no | 0 |
Additional gutters to add |
.my-class {
width: grrr-span-width-fluid(4, 1);
}
grrr-span-width-stillReturns the pixel-fixed width of N columns as measured — using --grrr-col-width as the column size rather than the responsive width. Use this when sizing elements that must match still columns exactly and should not shrink or stretch with the grid.
| Parameter | Required | Default | Description |
|---|---|---|---|
$n-cols |
yes | — | Number of columns |
$n-extra-gutters |
no | 0 |
Additional gutters |
$col-width |
no | var(--_grrr-col-width) |
Override column width |
$gutter-width |
no | grid gutter | Override gutter width |
.my-class {
width: grrr-span-width-still(2, 1);
}
GRRR works seamlessly with CSS Subgrid. A child of a .grrr can inherit the parent’s column tracks, letting deeply nested components align to the same grid without re-declaring it.
A component placed on the board spans the full grid width and passes column tracks down to its own children.
<div class="grrr">
<section class="my-section">
<div class="my-section__text"></div>
<div class="my-section__media"></div>
</section>
</div>
.my-section {
display: grid;
grid-column: full; /* span the entire grid width */
grid-template-columns: subgrid; /* inherit all parent tracks */
}
.my-section__text { grid-column: col-start 1 / col-end 6; }
.my-section__media { grid-column: col-start 7 / col-end 12; }
Pair subgrid with named area variables to keep placement decoupled from the grid structure. Changing the variable at a breakpoint reflows every component using it.
:root {
--content-area: col-start 4 / col-end 9;
--wide-area: col-start 2 / col-end 11;
}
.my-section {
display: grid;
grid-column: full;
grid-template-columns: subgrid;
}
.my-section__intro { grid-column: var(--wide-area); }
.my-section__body { grid-column: var(--content-area); }
@media (max-width: 768px) {
:root {
--content-area: board;
--wide-area: board;
}
}
When a component lives inside a .grrr--still, subgrid inherits the still column tracks. Use --grrr-use-still-area to snap the wrapper exactly over the still range.
<div class="grrr grrr--still">
<div class="panel">
<div class="panel__label"></div>
<div class="panel__content"></div>
</div>
</div>
.panel {
display: grid;
grid-column: var(--grrr-use-still-area); /* snaps to the still area */
grid-template-columns: subgrid;
}
.panel__label { grid-column: col-start 1 / col-end 2; }
.panel__content { grid-column: col-start 3 / col-end 8; }
Safe to use in browsers released after mid-2024.
Documentation version: 1.0 | Last updated: June 2024
GRRR relies on a specific set of modern CSS features. The table below shows the minimum browser version required for each one and the overall floor for full support.
| Feature | Chrome | Firefox | Safari | Edge | Notes |
|---|---|---|---|---|---|
CSS Grid — named lines, repeat(), minmax() |
57 | 52 | 10.1 | 16 | Core layout engine — caniuse |
CSS Custom Properties (var()) |
49 | 31 | 9.1 | 16 | Used for every config value — caniuse |
calc() inside repeat() count |
66 | 61 | 12.1 | 66 | Part of grid/calc support — caniuse |
min() in property values |
79 | 75 | 11.1 | 79 | Used in column width resolution — caniuse |
Container queries (container-type) |
105 | 110 | 16.0 | 105 | caniuse |
cqw length units |
105 | 110 | 16.0 | 105 | Container query units — caniuse |
CSS Subgrid (grid-template-columns: subgrid) |
117 | 71 | 16.0 | 117 | caniuse |
@property (registered custom properties) |
85 | 128 | 16.4 | 85 | caniuse |
| Browser | Minimum version | Limiting feature |
|---|---|---|
| Chrome / Edge | 117 | Subgrid |
| Firefox | 128 | @property |
| Safari | 16.4 | @property |
Even prior to baseline browser support, GRRR remains largely functional. However, issues may arise with certain calculations (when used) and with subgrid (which is not a core feature of GRRR).
MIT License — free for commercial and non-commercial use. Credit to atonal.studio appreciated.