Stylus property lookup: one anchor value per component
Stylus property lookup lets one declared value drive derived padding and line height inside a rule. When that helps, when it silently breaks, and how to verify the compiled CSS.
07 Dec 2025, 02:25 UTC

One number, three places to change
A button rule often carries a font size, a line height and padding that are all ratios of the same number. Written out literally, a small type change turns into three edits, and the third one is the one people forget. Stylus has a feature aimed at exactly this: property lookup, written as @property-name, which reads a property value already declared in the same rule.
The thesis here is narrow. Property lookup is a good fit for tightly coupled values inside a single component, and a poor fit for values shared across components. Used inside that boundary it removes repetition; used outside it, it hides intent behind source order.
Which Stylus this is about
Stylus here means the CSS preprocessor: the Node-based compiler that reads .styl files and emits CSS, with indentation-tolerant syntax where braces, colons and semicolons are optional. It is not the Stylus browser extension for user styles, and it is not stylus-pen or digitizer input handling. The name is shared across unrelated tools, so package names and search results may point somewhere else.
Property lookup inside one rule
The construct is short. Declare the anchor property first, then reference it with @ plus the property name in a later declaration's value:
.button
font-size 16px
line-height (@font-size * 1.5)
padding (@font-size * 0.5) (@font-size * 1)
The same file written with braces and colons compiles the same way, which is the first thing to decide as a team: pick one convention. Stylus permits both, and a codebase that mixes them produces noisy diffs and slows onboarding.
Worked example: a button scale
Take the rule above as the whole experiment. The anchor is font-size 16px. Everything else is arithmetic on @font-size, so changing the anchor to 14px should move line height and padding with it.
Expected shape, derived by hand rather than observed from a compiler run:
/* expected shape — verify against your own compiler */
.button {
font-size: 16px;
line-height: 24px;
padding: 8px 16px;
}
Do not treat that block as a test result. Compile the file yourself and read the emitted CSS. If the numbers match the arithmetic, the lookup resolved as intended; if a value comes through unresolved or unchanged, the anchor was not visible at that point in the rule.
Where it helps, and where it hurts
Inside a component, the coupling is real: padding and line height genuinely are functions of the local font size, and the lookup expresses that without naming anything. Across components, the coupling is usually not real. A brand color or a spacing step shared by a card, a modal and a nav belongs in a named variable or a mixin, because the name is what communicates intent to the next reader.
The second cost is portability. Property lookup has no plain-CSS equivalent and does not survive conversion to SCSS, Less or plain CSS, so it raises the price of ever migrating away. CSS custom properties cover part of the same ground — --font-size: 16px with padding: calc(var(--font-size) * 0.5) — and they survive a migration and work at runtime. If your project is already committed to custom properties, the Stylus-only construct buys less than it costs.
Source order is the sharp edge
Resolution depends on source order and scope. Reordering declarations so the lookup appears before the anchor, moving the anchor into a mixin, or overriding the anchor inside a media query can silently change or break the lookup. Nothing errors; the CSS just comes out different. Exact behavior for lookups in nested selectors, in media queries, or after a mixin call can differ between compiler versions, so pin the version in your lockfile and check the official Stylus documentation section on property lookup for that version rather than assuming it is universal.
How to check it in your project
- Record the installed Stylus version from
package.jsonor the lockfile before you start. - Create a scratch
.stylfile with one rule, one anchor and one lookup. No build plugins involved. - Compile it with the same
styluscommand your project already uses (Node and npm must be available; no elevated permissions are needed). Read the emitted CSS. - Probe the edges: a lookup in a nested selector, one inside a media query, one after a mixin call, and one where the anchor is overridden later in the file. Note which cases still resolve.
- Re-run the same file through the real build pipeline, since bundler or framework plugins may wrap compilation.
A refactor you can keep or revert
Pick one component with repeated literals. Replace them with a single anchor plus lookups, compile, and diff the emitted CSS against the previous output. Keep the change only if the output is identical, or if the difference is one you intended. If the diff is noisy or the lookup breaks under a media query, revert and use named variables instead — the repetition you removed was cheaper than the coupling you added.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.