Skip to content

CSS transform: percentage translate values silently parsed as dips (translate(-50%) → -50dip) #11457

Description

@aleclarson

Issue Description

Runtime styling divergence — no error and no warning. Percentage arguments to translate()/translateX()/translateY()/translate3d() inside a transform declaration are parsed with parseFloat, which silently drops the % and applies the number as dips.

transform: translate(-50%, -50%) — the standard self-centering idiom — moves a view by −50dip instead of −50% of its own size.

Per CSS Transforms, translate arguments are <length> | <percentage>, where percentages resolve against the element's own reference box (width for x, height for y).

Root cause: convertTransformValue in packages/core/ui/styling/css-transform.ts does rawValue.split(',').map(parseFloat), so parseFloat('-50%') → -50. This path is reached by both the transform: shorthand (convertToTransform in style-properties.ts) and transform declarations inside @keyframes (css-animation-parser.ts). The translateX/translateY longhand properties behave the same way via FixedLength.parse.

Related: #3707 tracks percentage support as a feature request (open since 2017). Filing separately because the silent mis-parse is a correctness bug independent of whether % support lands — today the engine produces a plausible-looking but wrong dip offset with no signal. If full percentage support is out of scope, rejecting or warning on unsupported units would at least make shared stylesheets fail loudly.

Happy to PR either direction (percent-of-self support, or loud rejection of unsupported units) if maintainers indicate a preference.

Reproduction

<StackLayout width="200" height="200" class="box"/>
.box {
	transform: translate(-50%, -50%);
}
  1. ns run ios or ns run android
  2. The view is offset by −50dip on each axis
  3. Expected: offset by −100dip on each axis (50% of its own 200dip size)

Same through keyframes — the common slide-in-from-offscreen animation:

@keyframes slide-in {
	from {
		transform: translateY(100%);
	}
	to {
		transform: translateY(0);
	}
}

translateY(100%) starts the view 100dip lower instead of one full view-height lower, so tall views remain partially on screen.

Relevant log output (if applicable)

No output — the value is silently mis-parsed.

Environment

  • @nativescript/core 9.1.2; also verified against current master (convertTransformValue is unchanged)
  • Platforms: iOS and Android (platform-agnostic CSS parser)

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions