Skip to content

fix(compiler): convert absolute length units to pixels - #492

Open
YevheniiKotyrlo wants to merge 1 commit into
nativewind:mainfrom
YevheniiKotyrlo:fix/absolute-length-units
Open

YevheniiKotyrlo wants to merge 1 commit into
nativewind:mainfrom
YevheniiKotyrlo:fix/absolute-length-units

Conversation

@YevheniiKotyrlo

@YevheniiKotyrlo YevheniiKotyrlo commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Problem

in, cm, mm, Q, pt and pc are absolute lengths: css-values-4 §6.2 fixes each against the inch, 1in = 96px, so each has an exact pixel value. parseLength warns and drops all six, so on native a declaration holding one sets nothing - width: 1in, border-top-width: 3pt, margin: 1in 1pc - and neither does a variable that resolves at runtime or a media query such as (min-width: 4in).

Solution

parseLength converts the six units to pixels through one table, ABSOLUTE_UNIT_PIXELS in src/utilities/absolute-units.ts. Every route reads a length through parseLength, so declarations, shorthands, transforms, shadows, font sizes, variables and media queries all convert, with or without inlineRem; lightningcss already folds a calc() mixing them with px.

Tests

src/__tests__/native/absolute-units.test.tsx renders each unit as a declaration and through a variable declared twice, with inlineRem: false, in a media query and in a shorthand. All 15 fail on main. The expected values are css-values-4's ratios, rounded as the compiler rounds every length.

Verification

On Ubuntu with the workflow's steps - build, lint, typecheck, yarn test, node --test node/__tests__/*.mjs, both library builds, the web export, the unstaged-changes checks and commitlint - everything passes.

Not run: the iOS and Android example builds.

Unchanged: an absolute length set from JavaScript through vars() reaches React Native as the string it was given.

Device evidence, before and after: #492 (comment)

Merge order

It shares lines with #389 (compiler/declarations.ts, utilities/index.ts), #391 (compiler/declarations.ts, utilities/index.ts), #413 (compiler/declarations.ts), #417 (compiler/declarations.ts), #420 (compiler/declarations.ts, utilities/index.ts), #491 (compiler/declarations.ts, utilities/index.ts), #494 (compiler/declarations.ts, utilities/index.ts), #495 (compiler/declarations.ts, utilities/index.ts); whichever lands second rebases.

css-values-4 fixes in, cm, mm, Q, pt and pc against the inch (1in =
96px), so each has an exact pixel value. parseLength warned and dropped
all six, so a declaration, a variable and a media query holding one set
nothing on native.
@YevheniiKotyrlo

Copy link
Copy Markdown
Contributor Author

Device evidence — before / after

UNFIXED — Only the control is 96 pixels wide. Every other bar spans the row, because a width in an absolute unit other than px is dropped.

FIXED — Every bar is as wide as the control: an inch is 96 pixels, and centimetres, millimetres, quarter-millimetres, points and picas convert through it.

before — 3.1.0-rc.0 after — with this PR

Android 16 emulator (API 36, GLES on the host GPU), 1140×2400 @ 480dpi, both frames from one run. before is the published 3.1.0-rc.0 plus what my test app needs from my other patches to run: the native and native-internal subpath exports, PR 459, cascade-layer ranking, and a shim that compiles a class-qualified :root inert. after adds the rest of my open PRs, this one included. One of them shows on every screen: PR 417 narrows a var()-valued font-family to one family, so the after sets its text in the theme's face where the before falls back to the platform's.

@YevheniiKotyrlo
YevheniiKotyrlo marked this pull request as ready for review October 16, 2026 15:00

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant