Get Started

Lynx and mobile

What crisp ships for phones today, and how to emit the Lynx stylesheets.

crisp is a web design system first. Its mobile story is deliberately narrow, and this page says exactly how narrow.

Tokens reach every platform

The design tokens are published as data, so any platform can read them:

  • @crisp-ui-kit/crisp/tokens.css — the CSS custom properties.
  • @crisp-ui-kit/crisp/tokens.json — the same tokens as JSON.
  • @crisp-ui-kit/crisp/native — the tokens as a plain object for React Native. React Native gets tokens only: crisp ships no React Native components.

Lynx stylesheets are emitted, not installed

Lynx supports a subset of CSS, so the web stylesheets cannot be used as they are. crisp has an emitter that rewrites its CSS into the subset Lynx honours. The output goes to dist/lynx/, which is not part of the published npm package: you run the emitter in a checkout of the repository.

git clone https://github.com/carrot-systems/crisp
cd crisp
bun install
bun run lynx:emit   # writes dist/lynx/<component>.css and dist/lynx/tokens.css
bun run lynx        # reports every declaration Lynx still cannot honour

Only the components that make sense on a phone are emitted: badge, button, progress, switch, avatar, divider and spinner. Most of crisp is a desktop grid and has no Lynx equivalent.

What the emitter changes

  • Nested CSS is flattened, because Lynx has no &.
  • display: flex gets an explicit flex-direction: row, because Lynx defaults to column. inline-flex becomes flex.
  • Logical properties (padding-inline, padding-block, margin-*, inset-* and their -start / -end forms) become physical left / right / top / bottom, with start and end mapped to left and right (left-to-right only). Lynx drops the logical forms, so buttons, badges and kbd chips used to lose their horizontal padding on a device (crisp#1308).
  • cursor, every :hover rule and every :focus-visible rule are dropped. A phone has no pointer and no keyboard focus ring; Lynx's pseudo-classes are :active, :hover, :not and :root.
  • outline-offset, object-fit, user-select, box-sizing, the font-smoothing pair, text-decoration: none and text-transform are dropped.
  • @keyframes pass through; every other at-rule (such as @media) is dropped with its block.
  • A ::before or ::after rule is dropped and reported by component, since Lynx has no generated boxes.
  • dist/lynx/tokens.css does not declare VK Sans Display. That typeface is licensed to the owner and is not redistributable, and it is not installed on any phone, so the font stack falls back to Inter and then the system font. Bundle your own font and declare it in your app if you need it.

The web output is unchanged by any of this.

On this page