CSS & Styling

Style your UI with CSS, the same way you’d style a web page. Cuttlefish understands a practical subset of CSS — the box model, flexbox, colors, typography, and selectors. All of it is resolved when you build (no CSS engine runs on the device): flexbox is laid out with Yoga (a layout library), styles are resolved, and the resulting draw commands are what the firmware runs.

Box model

PropertyValuesNotes
padding8px, 8px 16pxShorthand supported
margin8px, 8px 16pxShorthand supported
width / height100px, 50pxExplicit size
min-width / max-width / min-height / max-height100pxYoga constraints
aspect-ratio16 / 9, 1 / 1, 1.5Infers the missing dimension
box-sizingborder-boxYoga border-box
overflowhidden, scrollscroll enables touch-drag scrolling

Length units

px, bare numbers, and rem/em (multiplied by 16, the root font size — so 0.625rem = 10px). Percentages are honored where applicable. calc() evaluates + - * / on lengths after var() substitution, with operator precedence.

Flexbox (via Yoga)

PropertyValues
displayflex, none
flex-directionrow, row-reverse, column, column-reverse
gap8px (sets both row and column gap)
row-gap / column-gap8px (per-axis; overrides uniform gap)
flex-grow1
flex-shrink0
flex (shorthand)1, 1 0 auto, none
align-itemsflex-start, center, flex-end, stretch
align-selfflex-start, center, flex-end, stretch, baseline
align-contentflex-start, center, flex-end, stretch, space-between, space-around, space-evenly
justify-contentflex-start, center, flex-end, space-between, space-around, space-evenly
flex-wrapwrap, nowrap, wrap-reverse
order1, 2, …
positionrelative, absolute, static
top / right / bottom / left10px
z-indexnumeric layers (inherited by descendants)

display: none removes the element subtree from layout, drawing, and hit-testing while preserving generated node indices.

Colors

All standard CSS formats: #rrggbb, #rgb, #rrggbbaa (alpha ignored), rgb(r,g,b), rgba(r,g,b,a) (alpha ignored), hsl(...), hsla(...). Both comma and CSS4 space syntaxes work. The 147 CSS named colors (red, dodgerblue, transparent, …) are supported.

Typography

PropertyValuesNotes
colorany colorText foreground
font-family"MyFont"Uses a generated font when matched by @font-face; otherwise the built-in bitmap font
font-size16pxGenerated fonts rasterize at this pixel size
fontitalic bold 18px DeviceSansShorthand for style/weight/size/family
text-alignleft, center, right
text-decorationunderline, line-through, noneCombine: underline line-through
text-overflowellipsis, clipTruncates overflowing single-line text
text-transformuppercase, lowercase, capitalize, noneApplied at transpile time
line-height1.5, 150%, 24pxnormal = font default
letter-spacing2px, -1px
white-spacenormal, nowrap, pre, pre-line
font-weightnormal, bold, 400, 700Selects the matching @font-face variant
font-stylenormal, italic, oblique
font-smoothinganti aliased, noneOverrides display-level antialiasing
font-subsetexact, fallbackControls glyph selection for generated fonts

Fonts (@font-face)

Declare variants with @font-face. When you build, Cuttlefish keeps only the font characters you actually use:

@font-face {
  font-family: "DeviceSans";
  src: url("./assets/DeviceSans-Bold.ttf");
  font-weight: bold;
}
  • font-subset: exact — include only the exact glyphs used (smallest binary).
  • font-subset: fallback — include fallback glyphs for dynamic text that may contain unanticipated characters.
  • font-smoothing: antialiased — enables per-pixel alpha for the matched text.

Visual properties

PropertyValuesNotes
background / background-colorany color
border (shorthand)2px solid #808080
border-width / border-color / border-style2px / color / solid dashed noneDashed is approximated with segments
border-radius4pxUniform only (no per-corner)
outline1px solid #fffDrawn outside the element box
visibilityvisible, hidden
box-shadowinset 0 1px 0 #fff, 0 10px 0 #333Up to 4 rect shadows; approximated
transformtranslateY(10px), translate(0, 10px)Draw-time offset; no flex relayout
opacitynumberBlending requires a PSRAM framebuffer (PSRAM is extra memory on some ESP32 boards)

Transitions and :pressed

transition: background 300ms;
transition: color 120ms;

Smoothly transitions the property over the duration. The :pressed pseudo-class applies while a button’s .value is 1:

#ok { background: #2563eb; transition: background 120ms; }
#ok:pressed { background: #1e40af; transform: translateY(2px); }

:pressed rules may include top/left/right/bottom or transform: translate(...) as draw-time offsets (outset shadows stay anchored).

Selectors

KindExample
Elementscreen
ID#title
Class.card
Compound.card.active, button.primary
Descendantview text
Childview > text
Adjacent sibling.first + .second
General sibling.first ~ .later
Attribute[disabled], [type="number"]
Negationbutton:not(.disabled), .a:not(.b.c)
Pseudo-state:pressed, :disabled, :checked, :focus

Pseudo-states: :pressed (button held), :disabled, :checked (check/radio .value is 1), :focus.

Inline style="…" attributes and <style> blocks are both supported.

CSS variables and theming

Define variables in :root and reference with var():

:root {
  --bg: #111;
  --fg: #eee;
}
screen { background: var(--bg); color: var(--fg); }

Class-scoped themes select a variant at build time via themeClass in your cuttlefish.config.ts:

:root { --bg: #fff; --fg: #000; }
.dark { --bg: #111; --fg: #eee; }
display: { themeClass: 'dark', /* … */ }

@media performs compile-time variant selection (no runtime resizing). Supported conditions: min-width, max-width, min-height, max-height (in px). orientation is unsupported (warned and skipped).

@media (max-width: 200px) {
  screen { flex-direction: column; }
}

Unsupported (and why)

These are intentionally out of scope for microcontroller rendering:

  • display: grid — use flexbox
  • Full inline rich text (mixed inline spans)
  • background-image / CSS sprites — use <img> instead
  • position: fixed
  • ::before / ::after pseudo-elements
  • text-shadow on the built-in font
  • Per-corner border-radius (uniform only)
  • Runtime theme switching (themes are resolved at transpile time)
  • @import, @supports

Next: Display Configuration for wiring a physical display.