Skip to content

CSS Engine & Attribute Specification ​

This document provides the formal specification of the CSS styling engine implemented in RTXUI, defining value grammar, cascade and specificity rules, box-model semantics, and the exhaustive property reference.


1. Engine Formal Grammar ​

RTXUI implements an inline stylesheet parser and property resolver operating directly over terminal character cells.

ebnf
Declaration      ::= PropertyName ':' Value ('!important')? ';'
PropertyName     ::= [a-z-]+ | '--' [a-z0-9-]+
Value            ::= Token (Whitespace Token)*

Length           ::= Integer | Percentage | Fractional | 'auto' | CalcExpr | MinMaxExpr
Integer          ::= [-+]? [0-9]+
Percentage       ::= [-+]? [0-9]+ ('.' [0-9]+)? '%'
Fractional       ::= [0-9]+ ('.' [0-9]+)? 'fr'
Color            ::= HexColor | RgbColor | HslColor | ColorKeyword | ColorTransform

HexColor         ::= '#' ([0-9a-fA-F]{3} | [0-9a-fA-F]{4} | [0-9a-fA-F]{6} | [0-9a-fA-F]{8})
RgbColor         ::= ('rgb(' | 'rgba(') Number ',' Number ',' Number (',' Alpha)? ')'
                   | ('rgb(' | 'rgba(') Number Number Number ('/' Alpha)? ')'
HslColor         ::= ('hsl(' | 'hsla(') Angle (',' | Whitespace) Percentage (',' | Whitespace) Percentage (('/' | ',') Alpha)? ')'
ColorTransform   ::= ('lighten(' | 'darken(' | 'alpha(') (Percentage | Number) ')'
ColorKeyword     ::= 'transparent' | 'orange' | 'red' | 'white' | 'blue' | 'yellow' | 'green' | 'lime' | 'black' | 'gray' | 'grey' | 'cyan' | 'aqua' | 'magenta' | 'fuchsia' | 'silver' | 'maroon' | 'purple' | 'olive' | 'navy' | 'teal'

Coordinate & Dimensional Model ​

  • Grid Unit: 1 unit = 1 terminal character cell.
  • Physical Cell Aspect Ratio: Terminal cells are approximately 1:2 (width:height). An aspect ratio of 2 / 1 produces an approximately square visual block.
  • Default Box Model: Unlike web browsers which default to content-box, RTXUI defaults to border-box (box-sizing: border-box). Declared width and height define the outer dimensions including padding and borders.

2. Cascade, Inheritance & Specificity ​

2.1 Specificity Vector (A, B, C) ​

Selector precedence is determined by a 3-component specificity vector (A, B, C):

  1. $A$ (ID Component): Count of ID selectors (#id).
  2. $B$ (Class & Pseudo Component): Count of class selectors (.class), attribute selectors ([attr]), and pseudo-classes (:hover, :focus, :active, :checked, :disabled, :first-child, etc.).
  3. $C$ (Type Component): Count of element type selectors (div, button, span).

Note: Pseudo-elements (::part(...)) participate in target isolation rather than global specificity weighting. Negation (:not(X)) contributes the specificity of its inner argument $X$.

2.2 Precedence Order (Descending) ​

  1. Declarations with !important (resolved in reverse cascade order).
  2. Inline element styles (style="...").
  3. Higher specificity vector (A, B, C) (evaluated lexicographically: $A_1 > A_2$, then $B_1 > B_2$, then $C_1 > C_2$).
  4. Source declaration order (later rules override earlier rules).
  5. Inherited values from parent elements (only properties marked as inherited).
  6. Engine initial property defaults.

3. Spacing, Sizing, and Box Model ​

margin: <length> | auto⧉ shorthandInitial: `0`. Shorthand margin width on all sides.
margin-top: <length> | autoInitial: `0`. Vertical space above the element.
margin-bottom: <length> | autoInitial: `0`. Vertical space below the element.
margin-left: <length> | autoInitial: `0`. Horizontal space to the left.
margin-right: <length> | autoInitial: `0`. Horizontal space to the right.
padding: <integer>⧉ shorthandInitial: `0`. Shorthand internal padding on all sides.
padding-top: <integer>Initial: `0`. Internal vertical padding at the top.
padding-bottom: <integer>Initial: `0`. Internal vertical padding at the bottom.
padding-left: <integer>Initial: `0`. Internal horizontal padding at the left.
padding-right: <integer>Initial: `0`. Internal horizontal padding at the right.
width: <length>✦ animatableInitial: `auto`. Constrains element layout width.
height: <length>✦ animatableInitial: `auto`. Constrains element layout height.
min-width: <length>Initial: `auto`. Minimum layout width constraint.
max-width: <length>Initial: `none`. Maximum layout width constraint.
min-height: <length>Initial: `auto`. Minimum layout height constraint.
max-height: <length>Initial: `none`. Maximum layout height constraint.
box-sizing: content-box | border-boxInitial: `border-box`. Whether width/height (and their min/max variants) describe the content box or the border box. Default is border-box, unlike web CSS.

calc() Expressions ​

Length properties accept calc() expressions combining discrete cells and percentages:

css
.sidebar { width: calc(100% - 20); }
.split   { height: calc((100% - 1) / 2); }

min(), max(), and clamp() ​

  • min(a, b): Evaluates to the smaller resolved length.
  • max(a, b): Evaluates to the larger resolved length.
  • clamp(min, preferred, max): Clamps preferred between lower and upper bounds.
css
.responsive-box { width: clamp(20, 50%, 80); }

4. Borders and Frames ​

border: <border-style> | <integer>⧉ shorthandInitial: `none`. Shorthand to configure borders on all sides.
border-width: <integer>Initial: `0`. Border frame cell thickness on all sides.
border-top: <border-style> | <integer>Initial: `0`. Top border frame thickness. A <border-style> keyword selects the frame character set and gives this side a thickness of 1.
border-bottom: <border-style> | <integer>Initial: `0`. Bottom border frame thickness. A <border-style> keyword selects the frame character set and gives this side a thickness of 1.
border-left: <border-style> | <integer>Initial: `0`. Left border frame thickness. A <border-style> keyword selects the frame character set and gives this side a thickness of 1.
border-right: <border-style> | <integer>Initial: `0`. Right border frame thickness. A <border-style> keyword selects the frame character set and gives this side a thickness of 1.
border-style: <border-style>Initial: `none`. Character set mapping style of the frame.
border-color: <color>✦ animatableInitial: `currentcolor`. Color of all border frame lines.
border-color-top: <color>✦ animatableInitial: `currentcolor`. Color of the top border line.
border-color-bottom: <color>✦ animatableInitial: `currentcolor`. Color of the bottom border line.
border-color-left: <color>✦ animatableInitial: `currentcolor`. Color of the left border line.
border-color-right: <color>✦ animatableInitial: `currentcolor`. Color of the right border line.

4.1 Border Style Glyph Matrix ​

RTXUI supports 30 border style keywords mapping directly to Unicode box-drawing and block elements:

Style KeywordCanonical AliasVisual Glyphs / Behavior Description
nonehiddenNo border rendered; 0 cells allocated.
blank—Reserves 1 cell perimeter without drawing lines (background passes through).
ascii—Plain ASCII fallback: +, -, |.
solid—Standard light box-drawing lines: ┌, ─, ┐, │, └, ┘.
roundroundedCurved corner box-drawing lines: ╭, ─, ╮, │, ╰, ╯.
heavythickBold / heavy stroke lines: ┏, ━, ┓, ┃, ┗, ┛.
double—Double parallel lines: ╔, ═, ╗, ║, ╚, ╝.
double-horizontal—Double lines on horizontal axes; single line on vertical axes.
double-vertical—Double lines on vertical axes; single line on horizontal axes.
dashed—Heavy dashed stroke lines (╌, ╎).
dotted—Centered dot perimeter (·).
squigglewaveWavy perimeter line (~).
outer—Half-cell block hugging outer cell edge (▀, ▄, ▌, ▐).
inner—Half-cell block hugging inner cell edge.
tall—Quarter-block vertical bars; eighth-block horizontal lines.
widetabQuarter-block vertical bars with inset horizontal lines.
panel—Tall border structure featuring a solid top bar for title integration.
hkey—Horizontal-only boundary lines on top and bottom.
vkey—Vertical-only boundary lines on left and right.
shade-light—25% stippled block fill (░).
shade-medium—50% stippled block fill (▒).
shade-dark—75% stippled block fill (▓).
shadow3dLight shading top/left; dark shading bottom/right (depth effect).
block—Full block vertical columns (█) with half-block horizontals.
Fullscreen Demo
cpp
// Copyright 2026 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
//
// Every border style: solid, double, dashed, round, tall, vkey and more.
//
// Each tile names the style it draws, so this doubles as a lookup table.
#include <rtxui/rtxui.hpp>

using namespace rtxui;

class BorderBox : public Component<BorderBox> {
 public:
  struct Props {
    std::string title = "Border";
    std::string border_class = "solid";
  } props;

  std::string_view view = R"html(
      <div class="box-wrapper">
        <div class="label">{title}</div>
      </div>

      <style>
        self {
          display: block;
          flex-grow: 1;
        }
        .box-wrapper {
          border: {border_class};
          background-color:red;
          border-color: rgb(100, 200, 255);
          padding: 1;
          margin: 1;
          display: block;
        }
        .label {
          font-weight: bold;
          color: rgb(100, 200, 255);
          text-align: center;
        }
      </style>
    )html";

  BorderBox() {
    Bind(props.title);
    Bind(props.border_class);
  }
};

class BordersDemo : public Component<BordersDemo> {
 public:
  std::string_view view = R"html(
      <div class="content">
        <h1>RTXUI Border Styles Gallery</h1>
        <p>This demo showcases the 24 different border styles supported by RTXUI.</p>

        <div class="row">
          <BorderBox title="ascii" border_class="ascii"></BorderBox>
          <BorderBox title="blank" border_class="blank"></BorderBox>
          <BorderBox title="dashed" border_class="dashed"></BorderBox>
          <BorderBox title="double" border_class="double"></BorderBox>
        </div>

        <div class="row">
          <BorderBox title="hkey" border_class="hkey"></BorderBox>
          <BorderBox title="heavy" border_class="heavy"></BorderBox>
          <BorderBox title="inner" border_class="inner"></BorderBox>
          <BorderBox title="none" border_class="none"></BorderBox>
        </div>

        <div class="row">
          <BorderBox title="outer" border_class="outer"></BorderBox>
          <BorderBox title="panel" border_class="panel"></BorderBox>
          <BorderBox title="round" border_class="round"></BorderBox>
          <BorderBox title="solid" border_class="solid"></BorderBox>
        </div>

        <div class="row">
          <BorderBox title="tall" border_class="tall"></BorderBox>
          <BorderBox title="thick" border_class="thick"></BorderBox>
          <BorderBox title="vkey" border_class="vkey"></BorderBox>
          <BorderBox title="wide" border_class="wide"></BorderBox>
        </div>

        <div class="row">
          <BorderBox title="dotted" border_class="dotted"></BorderBox>
          <BorderBox title="double-horiz" border_class="double-horizontal"></BorderBox>
          <BorderBox title="double-vert" border_class="double-vertical"></BorderBox>
          <BorderBox title="shadow (3d)" border_class="shadow"></BorderBox>
        </div>

        <div class="row">
          <BorderBox title="shade-light" border_class="shade-light"></BorderBox>
          <BorderBox title="shade-med" border_class="shade-medium"></BorderBox>
          <BorderBox title="shade-dark" border_class="shade-dark"></BorderBox>
          <BorderBox title="squiggle" border_class="squiggle"></BorderBox>
        </div>
      </div>

      <style>
        self {
          display: block;
          padding: 1;
          background-color: var(--bg);
          color: white;
          width: 100%;
          height: 100%;
          overflow-y: scroll;
        }
        .content {
          display: block;
          max-width: 80;
          margin: 0 auto;
        }
        h1 {
          font-weight: bold;
          margin-bottom: 1;
          color: rgb(100, 200, 255);
        }
        p {
          margin-bottom: 2;
          color: rgb(170, 200, 255);
        }
        .row {
          display: flex;
          width: 100%;
          gap: 2;
          margin-bottom: 2;
        }
      </style>
    )html";

  BordersDemo() { Import<BorderBox>(); }
};

int main() {
  auto app = Ref<BordersDemo>::New();
  Screen screen(app);
  screen.Loop();
  return 0;
}

5. Typography and Coloring ​

color: <color>✦ animatable↓ inheritedInitial: `white`. Foreground text character color.
foreground-color: <color>✦ animatable↓ inheritedInitial: `white`. Alias for color.
background-color: <color>✦ animatableInitial: `transparent`. Background block container cell color.
opacity: <number>✦ animatableInitial: `1.0`. Transparency value (0.0 for transparent to 1.0 for opaque).
text-align: left | right | center | justify↓ inheritedInitial: `left`. Horizontal alignment of inline text flows. justify widens space runs on soft-wrapped lines (never the last line or lines ended by an explicit newline).
white-space: normal | nowrap | pre | pre-wrap | pre-line | break-spaces↓ inheritedInitial: `normal`. nowrap/pre disable wrapping; pre-line collapses space runs while honoring newlines. Note: this engine preserves interior whitespace and newlines in all modes, so normal, pre-wrap, and break-spaces behave alike.
font-weight: bold | bolder | lighter | normal | <number>↓ inheritedInitial: `normal`. Text weight. bold/bolder/>=600 render bold; lighter/<=300 render with the terminal's dim attribute.
font-style: italic | oblique | normal↓ inheritedInitial: `normal`. Applies italic styling to text (rendered with the terminal's italic attribute).
text-decoration: underline | double-underline | overline | line-through | strikethrough | blink | none↓ inheritedInitial: `none`. Text decorations (can specify space-separated lists, e.g. `overline underline`). `overline` renders as SGR 53, which not every terminal implements; those that do not simply draw no line. `none` clears all of them.
text-transform: uppercase | lowercase | capitalize | none↓ inheritedInitial: `none`. Case transformation of text (ASCII letters; other characters pass through).
letter-spacing: <integer> | normal↓ inheritedInitial: `normal`. Blank cells inserted between characters. Whole cells only; negative values clamp to 0. Spaced words never wrap mid-word.
tab-size: <integer>↓ inheritedInitial: `8`. Cells between tab stops; 8 by default. A tab advances to the next multiple of this from the start of its line, counted in cells so a full-width glyph moves the stop by two. Tabs are expanded during layout and never handed to the terminal, so the engine's own column accounting is what decides where they land. Outside white-space: pre and pre-wrap a tab is collapsible whitespace and becomes a single space, as in CSS. 0 removes tabs entirely.
line-height: <integer> | normal↓ inheritedInitial: `normal`. Minimum rows each line box occupies (whole rows; values below 1 clamp to 1). Tall inline content can still grow a line further.
overflow-wrap: anywhere | break-word | normal↓ inheritedInitial: `anywhere`. How words longer than the line are handled. Unlike CSS the default is anywhere: break at the container edge. normal keeps the word intact and lets it overflow.
word-wrap: anywhere | break-word | normal↓ inheritedInitial: `anywhere`. Legacy alias for overflow-wrap.
word-break: normal | break-all↓ inheritedInitial: `normal`. break-all treats every character boundary as a break opportunity, wrapping immediately at the boundary of a full line instead of pushing an overflowing word whole to the next line (unlike overflow-wrap, a last-resort fallback for otherwise-unbreakable words).
text-overflow: clip | ellipsisInitial: `clip`. Behavior when text overflows its block container.
visibility: visible | hiddenInitial: `visible`. Controls element visibility. Hidden elements keep their layout size.
cursor: default | pointerInitial: `default`. Mouse pointer styling when hovering the element.

Color Transforms ​

  • lighten(amount): Interpolates toward #ffffff in sRGB space.
  • darken(amount): Interpolates toward #000000 in sRGB space.
  • alpha(amount): Sets the alpha transparency channel to amount.

6. Custom Properties (--* and var()) ​

Properties with a -- prefix declare custom variables. They inherit down the element hierarchy and resolve during style application.

css
self {
  --primary-color: rgb(59, 130, 246);
}
.header {
  color: var(--primary-color, white);
}
  • Fallback Semantics: If a variable is missing, var(--name, fallback) evaluates the fallback expression. Fallbacks may contain nested var() calls.
  • Substitution Limit: Recursive resolution is capped at 128 expansions to prevent cyclic reference hangs.

7. Flexbox Layout ​

display: none | block | inline | flex | grid | inline-block | inline-flex | inline-grid | flow-rootInitial: `inline`. Enables the flex/grid layout engine or hides elements.
flex-direction: row | column | row-reverse | column-reverseInitial: `row`. Main formatting axis direction.
flex-wrap: nowrap | wrap | wrap-reverseInitial: `nowrap`. Controls wrapping behavior of flex items.
flex-grow: <number>✦ animatableInitial: `0`. Portion of free space item claims along main axis.
flex-shrink: <number>✦ animatableInitial: `1`. Factor determining how much item shrinks.
flex-basis: <length>Initial: `auto`. Initial size of flex item before free space is distributed.
flex: shorthand⧉ shorthandInitial: `0 1 auto`. Shorthand for flex-grow, flex-shrink, and flex-basis.
order: <integer>Initial: `0`. Lays a flex item out earlier or later than its document position. May be negative; items sharing a value keep document order.
justify-items: stretch | start | center | endInitial: `stretch`. Inline-axis alignment of items inside their grid cell.
justify-self: auto | stretch | start | center | endInitial: `auto`. Per-item override of justify-items.
place-items: <align-items> <justify-items>?⧉ shorthandInitial: `stretch`. Shorthand for align-items + justify-items.
place-self: <align-self> <justify-self>?⧉ shorthandInitial: `auto`. Shorthand for align-self + justify-self.
align-items: stretch | flex-start | flex-end | center | baselineInitial: `stretch`. Alignment of items along the cross axis.
align-self: auto | stretch | flex-start | flex-end | center | baselineInitial: `auto`. Alignment of individual flex item along the cross axis.
align-content: stretch | flex-start (start) | flex-end (end) | center | space-between | space-around | space-evenlyInitial: `stretch`. Alignment of flex lines in multi-line flex container. `start` and `end` are accepted as aliases of `flex-start` and `flex-end`.
justify-content: flex-start (start) | flex-end (end) | center | space-between | space-around | space-evenlyInitial: `flex-start`. Alignment of items along the main axis. `start` and `end` are accepted as aliases of `flex-start` and `flex-end`.
place-content: <align-content> <justify-content>?⧉ shorthandInitial: `stretch flex-start`. Shorthand for align-content + justify-content. One value sets both axes; a value valid on only one axis (e.g. `stretch`) leaves the other unchanged.
gap: <length>⧉ shorthandInitial: `0`. Spacing between flex items.
row-gap: <length>Initial: `0`. Spacing between flex rows/lines.
column-gap: <length>Initial: `0`. Spacing between flex columns/items.

8. Grid Layout ​

grid-template-columns: list of <length>Initial: `none`. Defines the column tracks of the grid. Supports repeat(count, track_size).
grid-template-rows: list of <length>Initial: `none`. Defines the row tracks of the grid. Supports repeat(count, track_size).
grid-template: shorthand⧉ shorthandInitial: `none`. Shorthand for grid-template-rows and grid-template-columns (separated by /).
grid-column: span <integer> | <integer>Initial: `auto`. Sets the column span of the grid item.
grid-column-end: span <integer> | <integer>Initial: `auto`. Alias for grid-column.
grid-row: span <integer> | <integer>Initial: `auto`. Sets the row span of the grid item.
grid-row-end: span <integer> | <integer>Initial: `auto`. Alias for grid-row.
grid-gap: <length>⧉ shorthandInitial: `0`. Alias for gap.
grid-row-gap: <length>Initial: `0`. Alias for row-gap.
grid-column-gap: <length>Initial: `0`. Alias for column-gap.

9. Scrolling & Overflow Management ​

overflow: visible | hidden | scroll | auto⧉ shorthandInitial: `visible`. Shorthand to configure horizontal & vertical overflow.
overflow-x: visible | hidden | scroll | autoInitial: `visible`. Horizontal layout overflow (visible, hidden, scroll).
overflow-y: visible | hidden | scroll | autoInitial: `visible`. Vertical layout overflow (visible, hidden, scroll).
scrollbar-width: auto | noneInitial: `auto`. none hides visual scrollbars while keeping list scrollable.
scrollbar-color: <color> <color>✦ animatableInitial: `auto auto`. Foreground (thumb) and background (track) colors of scrollbars.
scroll-speed: <integer>Initial: `1`. Shorthand scroll step speed multiplier.
scroll-speed-x: <integer>Initial: `1`. Horizontal scroll step distance.
scroll-speed-y: <integer>Initial: `1`. Vertical scroll step distance.
scroll-behavior: auto | smoothInitial: `auto`. Smooth scrolling transitions configuration.

10. Positioning & Transitions ​

transition: property duration timing-function⧉ shorthandInitial: `none`. Shorthand (e.g. transition: background-color 0.2s linear). Easing keywords: linear, ease, ease-in, ease-out, ease-in-out, ease-in-sine, ease-out-sine, ease-in-out-sine, ease-in-quad, ease-out-quad, ease-in-out-quad, ease-in-cubic, ease-out-cubic, ease-in-quart, ease-out-quart, ease-in-quint, ease-out-quint, ease-in-expo, ease-out-expo, ease-in-circ, ease-out-circ, ease-in-back, ease-out-back.
position: static | relative | absolute | fixed | stickyInitial: `static`. Selects positioning flow model. An absolute/fixed box with an auto width or height sizes itself from its content, capped by the space available to it — it is free to be wider than the element it is anchored to, which is what lets a tooltip overhang a narrow trigger. Pinning both opposite edges (top and bottom, or left and right) stretches it between them instead, so inset: 0 fills the nearest positioned ancestor; auto margins on that axis opt back out, keeping the box content-sized and centering it between the edges.
inset: 1-4 <length> values⧉ shorthandInitial: `auto`. Shorthand setting top/right/bottom/left (same expansion as margin).
aspect-ratio: <w> / <h> | <number> | autoInitial: `auto`. Derives an element's auto dimension from whichever of width/height is definite: height-from-width in block, flex, and grid contexts (items and containers), and width-from-height in block contexts and on flex items/containers (grid containers only derive height from width). Ratios are in cells — terminal cells are ~2:1 tall, so 2 / 1 looks square. Content larger than the ratio overflows.
top: <length>Initial: `auto`. Offset relative to top boundary.
bottom: <length>Initial: `auto`. Offset relative to bottom boundary.
left: <length>Initial: `auto`. Offset relative to left boundary.
right: <length>Initial: `auto`. Offset relative to right boundary.
z-index: <integer> | autoInitial: `auto`. Determines rendering paint layers.

11. List Styling ​

list-style-type: disc | circle | square | decimal | noneInitial: `disc`. Sets the marker prefix style for list items (• , ○ , ■ , numbers, or none).
list-style: disc | circle | square | decimal | none⧉ shorthandInitial: `disc`. Shorthand configuration for list styling.