Tachyons Neo

11 min read Original article ↗
Tachyons Neo v2.0.1 GitHub

§ 00 Index — A Functional CSS Toolkit

A small, composable CSS toolkit. Sharper defaults for modern viewports, css variable design tokens, a small CSS Grid layer, and a handful of utilities for prototyping. No build step, no dependencies, one core stylesheet; add app.css for semantic application tokens.

§ 01 Install

Drop the core stylesheet in and go. Page-level responsive utilities work by default. Load it from jsDelivr, vendor it with curl, or copy the file into your project. Add app.css after it when product UI needs semantic light/dark tokens.

CDN — jsDelivr

<!-- Pinned to a tag (recommended) -->
<link rel="stylesheet"
      href="https://cdn.jsdelivr.net/gh/gobijan/tachyons-neo@v2.0.1/tachyons.css">
<link rel="stylesheet"
      href="https://cdn.jsdelivr.net/gh/gobijan/tachyons-neo@v2.0.1/app.css">

<!-- Major-floating -->
<link rel="stylesheet"
      href="https://cdn.jsdelivr.net/gh/gobijan/tachyons-neo@2/tachyons.css">
<link rel="stylesheet"
      href="https://cdn.jsdelivr.net/gh/gobijan/tachyons-neo@2/app.css">

<!-- Latest main (no cache guarantee) -->
<link rel="stylesheet"
      href="https://cdn.jsdelivr.net/gh/gobijan/tachyons-neo/tachyons.css">
<link rel="stylesheet"
      href="https://cdn.jsdelivr.net/gh/gobijan/tachyons-neo/app.css">

Application UI

<link rel="stylesheet" href="tachyons.css">
<link rel="stylesheet" href="app.css">

Vendor

curl -O \
  https://raw.githubusercontent.com/gobijan/tachyons-neo/main/tachyons.css

curl -O \
  https://raw.githubusercontent.com/gobijan/tachyons-neo/main/app.css

<link rel="stylesheet" href="tachyons.css">
<link rel="stylesheet" href="app.css">

§ 02 Patches

01

-m query step

The -m modifier now queries the nearest container and has no upper bound — styles applied at the medium step continue applying at large unless explicitly overridden. Since html is the default page container, this behaves like the old page breakpoint.

<div class="pa3 pa5-m">
  Padding-5 applies from
  480px and up.
</div>

02

Gap scale

Eight gap utilities for flex and grid layouts, mapped to the Tachyons spacing scale. Responsive variants query the nearest container.

.g0 { gap: 0      }
.g1 { gap: .25rem }
.g2 { gap: .5rem  }
.g3 { gap: 1rem   }
.g4 { gap: 2rem   }
.g5 { gap: 4rem   }
.g6 { gap: 8rem   }
.g7 { gap: 16rem  }

03

Dynamic viewport heights

Heights using the dvh unit — accounts for collapsible mobile browser chrome so 100 % really means 100 %. Responsive variants query the nearest container.

.dvh-25      { height:     25dvh }
.dvh-50      { height:     50dvh }
.dvh-75      { height:     75dvh }
.dvh-100     { height:    100dvh }
.min-dvh-100 { min-height: 100dvh }

04

Hairline opacities

Extra-low opacity steps for whisper-thin overlays, dividers, and tints. Available as colour, background, and hover variants for both black and white.

.black-025   rgba(0,0,0,.025)
.black-0125  rgba(0,0,0,.0125)
.white-05    hsla(0,0%,100%,.05)
.white-025   hsla(0,0%,100%,.025)
.white-0125  hsla(0,0%,100%,.0125)

// also: .hover-* and .hover-bg-*

05

Outlined type

Renders text as an outline using -webkit-text-stroke. Combine with an inline stroke-width for thicker strokes. See the headline above. Responsive variants query the nearest container.

.stroke {
  -webkit-text-stroke: 1px currentColor;
  -webkit-text-fill-color: transparent;
}

06

Grid system

A small, opinionated CSS Grid layer — grid and grid-lanes display utilities, equal-fraction shrink-safe columns, and column spans. Pairs with the gap scale. Responsive variants query the nearest container.

.grid       display: grid
.grid-lanes display: grid-lanes

.gtc1       grid-template-columns: repeat(1, minmax(0, 1fr))
.gtc2       grid-template-columns: repeat(2, minmax(0, 1fr))
.gtc3       grid-template-columns: repeat(3, minmax(0, 1fr))
.gtc4       grid-template-columns: repeat(4, minmax(0, 1fr))

.csp1       grid-column: span 1
.csp2       grid-column: span 2
.csp3       grid-column: span 3
.csp-full   grid-column: 1 / -1

07

Filters & effects

A handful of one-shot effects: a tactile press dimmer, a colour inverter, and a backdrop blur for glass surfaces.

.active-dim:active {
  opacity: .8;
  transition: opacity .15s ease-out;
}
.invert { filter: invert(1) }
.blur   {
  backdrop-filter:         blur(30px);
  -webkit-backdrop-filter: blur(30px);
}

08

Form & list helpers

Two small affordances. Disable the textarea resize handle, and place list markers inside the content box where they belong.

.resize-none { resize: none }
.list-inside { list-style-position: inside }

09

Placeholder backgrounds

Lorem-ipsum for backgrounds. Pulls a random photo from picsum.photos at three aspect ratios. For prototyping; don't ship to production.

.random-image
.random-image-landscape
.random-image-portrait

10

Writing-mode

Rotate a block of text onto a vertical axis — spine labels, edge nav, section markers. .sideways-lr reads bottom-to-top with Latin-friendly glyph orientation; .horizontal-tb resets to the default. Responsive variants query the nearest container.

.horizontal-tb { writing-mode: horizontal-tb }
.sideways-lr   { writing-mode: sideways-lr   }

11

Object-fit

The <img> counterpart to .cover/.contain. Pair with .aspect-ratio--* to crop images to a fixed ratio without distortion. Responsive variants query the nearest container.

.object-cover   { object-fit: cover   }
.object-contain { object-fit: contain }

<div class="aspect-ratio--4x5">
  <img class="db w-100 h-100 object-cover"
       src="…" alt="">
</div>

12

Cascade layers

Ships as @layer reset, tachyons, app, debug — reset below utilities, optional app styles above utilities, debug above app, all below your CSS. Layered rules always lose to unlayered ones, so a plain selector of yours beats any utility, whatever its specificity, whatever order the stylesheets load in. No !important, no specificity games — handy when a bundler decides load order for you.

One catch: an unlayered element reset of yours (say dialog { padding: 0 }) would beat a utility too. Drop such resets into @layer reset and utilities win again.

Debug helpers now live in their own layer: .debug outlines children with CSS variables, and .debug-grid uses adjustable gradients instead of embedded image tiles.

@layer reset, tachyons, app, debug; /* tachyons.css */

/* your component — unlayered, wins */
.btn { background: rebeccapurple }
<button class="btn bg-gold">  → purple

/* optional app.css — layered, beats utilities */
@layer app { .bg-action { background: var(--action) } }

/* your reset — layered, utilities win */
@layer reset { dialog { padding: 0 } }
<dialog class="pa4">          → 2rem

/* debug — layered above utilities */
.debug-grid { --grid-size: 8px }

13

Min-width / -height 0

Flex items and custom grid tracks can default to content-sized minimums, so a long string may blow a layout wide open and .truncate never clips. .min-w-0 / .min-h-0 let the item shrink. Responsive variants query the nearest container.

.flex-auto already bakes this in, and .truncate self-fixes via overflow:hidden — reach for these on the overflow:visible items in between.

.min-w-0 { min-width: 0 }
.min-h-0 { min-height: 0 }

<div class="grid gtc2">
  <div class="min-w-0">long-url…</div>
  <div>…</div>
</div>
/* .gtc* tracks are shrink-safe;
   use min-w-0 when the item itself
   still needs to clip */

14

Container queries

Responsive -ns, -m, and -l variants now query the nearest container instead of the viewport. Page-level behavior works by default because html is a query container, while body keeps a full-height page canvas; add .root to a component when it should respond to its own width.

<section class="grid-l gtc3-l">...</section>

<article class="root">
  <div class="db flex-m">...</div>
</article>

§ 03 Tokens

Every design value — spacing, type scale, colours, radii, shadows, durations — is exposed as a :root custom property. Reference them from your own CSS via var(--spacing-3), var(--dark-pink), var(--lh-copy).

Spacing

--spacing-0   0
--spacing-1   .25rem
--spacing-2   .5rem
--spacing-3   1rem
--spacing-4   2rem
--spacing-5   4rem
--spacing-6   8rem
--spacing-7   16rem

Font size

--font-size-headline       6rem
--font-size-subheadline    5rem
--font-size-1              3rem
--font-size-2              2.25rem
--font-size-3              1.5rem
--font-size-4              1.25rem
--font-size-5              1rem
--font-size-6              .875rem
--font-size-7              .75rem

Measure & max-width

--measure          30em
--measure-wide     34em
--measure-narrow   20em
--mw-6             32rem
--mw-7             48rem
--mw-8             64rem
--mw-9             96rem

Line-height

--lh-solid      1
--lh-title      1.25
--lh-copy       1.5
--lh-headline   .85

Letter-spacing

--tracked         .1em
--tracked-tight   -.05em
--tracked-mega    .25em

Radius

--radius-0      0
--radius-1      .125rem
--radius-2      .25rem
--radius-3      .5rem
--radius-4      1rem
--radius-100    100%
--radius-pill   9999px

Border width

--border-width-0   0
--border-width-1   .125rem
--border-width-2   .25rem
--border-width-3   .5rem
--border-width-4   1rem
--border-width-5   2rem

Shadow

--shadow-1   0 1px 2px rgba(0,0,0,.06)
--shadow-2   0 2px 4px rgba(0,0,0,.08)
--shadow-3   0 1px 2px rgba(0,0,0,.06), 0 4px  8px  rgba(0,0,0,.08)
--shadow-4   0 2px 4px rgba(0,0,0,.06), 0 8px  16px rgba(0,0,0,.10)
--shadow-5   0 4px 8px rgba(0,0,0,.08), 0 16px 32px rgba(0,0,0,.12)

Duration

--duration-fast     .15s
--duration-medium   .25s
--duration-slow     .5s

Grayscale

--black          #000
--near-black     #111
--dark-gray      #333
--mid-gray       #555
--gray           #777
--silver         #999
--light-silver   #aaa
--moon-gray      #ccc
--light-gray     #eee
--near-white     #f4f4f4
--white          #fff

Black alpha

--black-90    rgba(0,0,0,.9)
--black-80    rgba(0,0,0,.8)
--black-70    rgba(0,0,0,.7)
--black-60    rgba(0,0,0,.6)
--black-50    rgba(0,0,0,.5)
--black-40    rgba(0,0,0,.4)
--black-30    rgba(0,0,0,.3)
--black-20    rgba(0,0,0,.2)
--black-10    rgba(0,0,0,.1)
--black-05    rgba(0,0,0,.05)
--black-025   rgba(0,0,0,.025)
--black-0125  rgba(0,0,0,.0125)

White alpha

--white-90    hsla(0,0%,100%,.9)
--white-80    hsla(0,0%,100%,.8)
--white-70    hsla(0,0%,100%,.7)
--white-60    hsla(0,0%,100%,.6)
--white-50    hsla(0,0%,100%,.5)
--white-40    hsla(0,0%,100%,.4)
--white-30    hsla(0,0%,100%,.3)
--white-20    hsla(0,0%,100%,.2)
--white-10    hsla(0,0%,100%,.1)
--white-05    hsla(0,0%,100%,.05)
--white-025   hsla(0,0%,100%,.025)
--white-0125  hsla(0,0%,100%,.0125)

Warm

--dark-red       #e7040f
--red            #ff4136
--light-red      #ff725c
--orange         #ff6300
--gold           #ffb700
--yellow         gold
--light-yellow   #fbf1a9

Purple & pink

--purple         #5e2ca5
--light-purple   #a463f2
--dark-pink      #d5008f
--hot-pink       #ff41b4
--pink           #ff80cc
--light-pink     #ffa3d7

Green

--dark-green    #137752
--green         #19a974
--light-green   #9eebcf

Blue

--navy           #001b44
--dark-blue      #00449e
--blue           #357edd
--light-blue     #96ccff
--lightest-blue  #cdecff

Washed

--washed-blue     #f6fffe
--washed-green    #e8fdf5
--washed-yellow   #fffceb
--washed-red      #ffdfdf

Font families

--font-sans-serif
--font-serif
--font-system-sans-serif
--font-system-serif
--font-code

§ 04 Application CSS

app.css is an optional semantic layer for product UI. It maps the core tokens into theme-aware names for surfaces, text, borders, actions, states, and focus rings. Neutral text, surface, and border ramps use the black/white transparency ladder; action and focus use Apple-style System Blue with a Display P3 override. Load it after tachyons.css; use data-theme on the root or any subtree to force light or dark.

Brand, action, and state colours expose seven utilities: .color, .bg-color, .b--color, .on-color, .hover-color, .hover-bg-color, and .hover-b--color. Text, surface, and border ramps omit on-* and expose the other six utilities.

Invoice export

Queued for finance

Ready

Gate B handhelds

Last check-in 18 seconds ago

Live

Pattern

<main class="bg-surface-base text-1">
  <button class="button-reset bg-action on-action focus-ring">
    Save
  </button>
</main>

<aside data-theme="dark" class="bg-surface-1 text-1 b--border-1">
  Scoped dark surface
</aside>

§ 05 Changelog

Release notes, newest first. Each entry summarises the material changes since the previous tag.

  • Move grid helpers into utility order
  • Move grid display utilities into display group
  • Add grid-lanes display utility
  • use sizing var in form example
  • more fix
  • Responsive -ns, -m, and -l variants now use container queries instead of viewport media queries.
  • Make html an inline-size query container in the reset layer, so page-level responsive behavior works with only the stylesheet loaded.
  • Give body a reset-layer min-height: 100dvh so the page canvas remains at least the dynamic viewport height.
  • Add .root as the component query root for local responsive behavior.
  • Add Neo-native button and input demos for the stable v2 surface.
  • Add optional app.css companion with semantic application tokens, surface/text/border/action/state utilities, focus helpers, and scoped light/dark theming via data-theme.
  • Base neutral app text, surface, and border ramps on Tachyons' black/white transparency tokens.
  • Use Apple-style System Blue as the action, focus, and native accent-color default, with a Display P3 override where supported.
  • Reserve @layer app between core utilities and debug helpers in the layer order.
  • Add an application demo showing app.css in a dashboard-style product surface.
  • Patch #11 added: `.object-cover` / `.object-contain` (+ responsive), the <img> counterpart to `.cover`/`.contain`; patch list renumbered to thirteen (cascade layers → #12, min-w-0/min-h-0 → #13).
  • `.gtc1`–`.gtc4` tracks (all breakpoints) now use `repeat(n, minmax(0, 1fr))` instead of `repeat(n, 1fr)`, so columns shrink-safe and no longer blow out on long content.
  • Add `.min-w-0` / `.min-h-0` utilities (+ `-ns`/`-m`/`-l` responsive variants) so flex and grid items can shrink below their content — fixes blown-out `1fr` columns and lets a child `.truncate` clip.
  • Wrapped `tachyons.css` in `@layer reset, tachyons` — unlayered author CSS now beats any utility regardless of specificity or load order; added patch #11/#12 and tokens declared inside `@layer tachyons`
  • Dropped the stray `!important` from `.cover`, `.contain`, and `.clip` (plus their `-ns`/`-m`/`-l` variants)
  • this is a deliberate cascade-behavior change, so anyone relying on the old specificity/source-order model can pin to @v1.0.8
  • `.hide-child` now toggles `visibility` alongside `opacity` (with `allow-discrete` transition) and triggers on `:focus-within` instead of `:focus-visible`
  • Hero copy swaps "finer-grained colour steps" for "css variable design tokens"; patch-set count bumped 10 → 11
  • Header and hero recolored to `bg-black`/`bg-purple` white; brand renamed "Tachyons Neo" and the `Neo` stroke accent changed `dark-pink` → `yellow`
  • Add `.object-cover` / `.object-contain` utilities with `-ns`/`-m`/`-l` responsive variants, plus a new section 11 demo pairing them with `.aspect-ratio--4x5`
  • Drop the JetBrains Mono webfont; set `--font-sans-serif` to the system Helvetica stack and rely on system mono for code
  • Remove stray `bb` border on the section 10 (Writing-mode) article
  • Add `.aspect-ratio--4x5` utility with `-ns`, `-m`, `-l` responsive variants
  • Replaced `--yellow: gold` keyword with hex `#ffd700` in `:root` token block
  • Removed `antialiased` class from <body> in index.html
  • Removed `-webkit-font-smoothing: antialiased` from the `body` rule in the CSS reset
  • Add `.sideways-lr` and `.horizontal-tb` writing-mode utilities (Patch 10), with responsive `-ns/-m/-l` variants
  • Add `.mt-auto` and `.mb-auto` margin utilities, with responsive variants
  • Bump CDN pin example from `v1.0.1` to `v1.0.2`
  • Added `§ 01 Install` section to `index.html` and a jsDelivr <link> snippet to `README.md`
  • Rebuilt `--shadow-1` through `--shadow-5` tokens as layered elevation (softer alphas, dual-layer on 3–5)
  • Fixed self-referential `--ease-shadow` token to `cubic-bezier(.4, 0, .2, 1)`; bumped section borders to `bw2-ns`
  • Swapped `:focus` for `:focus-visible` on `.link`, all `.hover-*` color/bg utilities, and interactive helpers (`.dim`, `.glow`, `.grow`, `.grow-large`, `.hide-child`, `.underline-hover`, `.shadow-hover`, `.bg-animate`, `.nested-links a`) in `tachyons.css`.
  • Added a Changelog section (§ 03) to `index.html` and `README.md`; renumbered Colophon to § 04.
  • Linked the Source and Upstream entries in the Colophon and switched the footer Screen Island link to `dark-blue underline-hover`.
  • Initial release. Tachyons v4.13.0 with nine patches, a 118-token design system, and a small grid layer.

§ 06 Colophon

A Screen Island edition of Tachyons. Set in the system Helvetica stack at the body, with Systems Mono for code. Descended from Tachyons (tachyons.io, 2016–) under the long shadow of Müller-Brockmann, Hofmann, and Crouwel. Built for internal use at Screen Island; published in case it's useful to you.