refactor fix: forbid zero with a length unit across tokens, lint and docs - #830
Merged
Conversation
robsongajunior
approved these changes
Jul 29, 2026
robsongajunior
requested changes
Jul 29, 2026
robsongajunior
left a comment
Contributor
There was a problem hiding this comment.
pr está poluído. nao sei onde termina o review
isaquebock
force-pushed
the
fix/zero-length-no-unit
branch
from
July 29, 2026 13:41
3d93d4d to
4f29d7a
Compare
…n build:tokens A zero length is identical in every unit, so the unit is noise: --tracking-normal shipped as 0em. Tokens are authored in JS and compiled, so no linter reads them — build:tokens now asserts the generated CSS carries no zero with a length unit and fails with the offending custom property. Units that mean something at zero (0%, 0s, 0deg, 0fr) are out of scope.
…ylelint config Adds a zero-with-unit check to the shared token-checks engine, so the write-time hook and the check-authoring CI ratchet both block it, and length-zero-no-unit to the shipped stylelint config so consumers inherit the rule. The config sets it without stylelint's default ignore of custom properties: a design system is authored almost entirely as custom properties, which is where the drift appeared. Fixes the three call sites the new check surfaced (accordion-content, toaster), which set a height of '0px' through inline style. Only length units are in scope, matching stylelint — 0%, 0s, 0deg and 0fr are untouched.
Overrides the stylelint-config-standard-scss default, which ignores custom properties, to plain true — the ignore is precisely why --tracking-normal: 0em passed. The canary fixture uses a custom property on purpose, so reintroducing the ignore breaks the lint-canary job.
…d DOC_LINTS styling.md gains the rule plus the four surfaces that enforce it; webkit-tokens.md carries the consumer-facing form; component-scaffold and token-map gain the prescription and a checklist item, with token-map told to map a Figma 0px/0em to 0; DOC_LINTS documents the stylelint rule and why the custom-property ignore was dropped.
A bare 0 inside calc()/min()/max()/clamp() is a number, not a length, so CSS requires the unit there — stylelint's length-zero-no-unit skips math functions for that reason and therefore accepts calc(100% - 0px). The two engines we own now close that: a new zero-unit-in-calc token check and the build:tokens assertion flag any non-rem unit on a zero inside a math function, while zero-with-unit stops reporting the zeros that legitimately keep a unit there. Documents the carve-out in styling.md, webkit-tokens.md, DOC_LINTS.md and the two skills, pins the stylelint skip with a test, and drops the verbose explanatory comments from both guards.
…op its canary The fixture now carries only unit-less zeros, so it no longer violates length-zero-no-unit and cannot act as a canary — its registry entry is removed and styling.md points at the stylelint-config tests as what keeps the rule from being relaxed.
…o and drop its canary" This reverts commit 8f6a242.
isaquebock
force-pushed
the
fix/zero-length-no-unit
branch
from
July 29, 2026 13:44
4f29d7a to
90ba4a0
Compare
- webkit-tokens.md: the Wrong example shows m-[0px] — m-0 is the correct form and read as a fourth violation - token-checks + build:tokens: i flag on both zero regexes (CSS units are case-insensitive), with comments pinning the one-level nesting limit and the cross-package sync requirement - validate-tokens hook: scope via the shared tokenChecksApply so test files are exempt like the CI ratchet (the browser serializes a collapsed height as '0px'; type tests use @ts-expect-error) - token-checks.test.mjs: pins both regexes and the shared file filter
robsongajunior
approved these changes
Jul 29, 2026
paulo-sobrinho-azion
approved these changes
Jul 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A zero length is identical in every unit, so the unit is pure noise — and it made the same zero read three different ways across the codebase (
0px,0rem,0em). This forbids zero with a length unit and gates it on every authoring surface, so no path escapes it..claude/rules/styling.mdgains the "A zero length carries no unit" section (length units only;0%,0s/0ms,0deg,0frare untouched). Mirrored into the shippedwebkit-tokens.mdand documented inpackages/webkit/docs/DOC_LINTS.md.zero-with-unitadded to the shared engine intoken-checks.js, so it blocks write-time (hook) and in thecheck-authoringCI ratchet over component sources.length-zero-no-unitenabled in.stylelintrc.jsonand in the shippedstylelint-config.js, set to plaintrueso the preset'signore: ['custom-properties']does not apply (a design system is authored almost entirely as custom properties). Alint-canaries/stylelint/length-zero-no-unit.cssfixture keeps that from being silently relaxed.tracking.normalemits0instead of0em, with a build-time assertion inbuild:tokens. Token values are authored in JS and compiled, sobuild:tokensis the only gate that sees them.accordion-content.vue,toaster.vue).Notes
themeandwebkit..claude/rules+ skills edits ship with the code on purpose:packages/webkit/test/standards/invariant.test.mjspairs each rule to its gates, so splitting the doc from the enforcement would fail CI on whichever side landed first.packages/theme/dist/v4/globals.{css,scss}changes are the regenerated build output of thetracking.normaltoken.The one carve-out: a zero inside a math function
Inside
calc()/min()/max()/clamp()a bare0is a number, not a length, so CSS requires the unit and the whole expression is invalid without it. Stylelint'slength-zero-no-unitskips math functions for exactly that reason — which means it acceptscalc(100% - 0px).So where the unit is unavoidable, it is
rem(the one length unit this system scales in), and the two engines we own enforce it: a newzero-unit-in-calctoken check and the same assertion inbuild:tokensflag any non-remunit on a zero inside a math function, whilezero-with-unitstops reporting the zeros that legitimately keep a unit there. A test pins stylelint's skip so the split of responsibility stays visible.