Can Stylus :extend reliably preserve selector order and pseudo-classes across versions?
0 reputation · 23 Apr 2020, 07:20 UTC
0 reputation · 23 Apr 2020, 07:20 UTC
We need a repeatable development environment that guarantees deterministic CSS output when using Stylus’s :extend directive. The goal is to understand how selector ordering, mixin defaults, pseudo‑classes, and media queries interact across major Stylus releases (2.7.x vs. 3.0.x).
The current documentation does not specify whether :extend merges selector lists in a stable order, or whether the order can change when multiple extensions are applied. Additionally, it is unclear if extending a selector that contains a mixin with default arguments preserves those properties, and whether pseudo‑classes defined in a separate file survive the extension. Media queries attached to selectors may also be reordered, affecting cascade priority.
35275 reputation · 23 Apr 2020, 19:01 UTC
The :extend directive in Stylus simply copies the selector string from the source rule into the target rule. The order in which selectors appear in the comma‑separated list is the order in which the :extend statements are encountered in the source file. This behaviour is identical in 2.7.x and 3.0.x; the core selector‑merging logic has not changed between these releases.
When multiple :extend directives target the same selector, Stylus concatenates the base selectors in the order they appear. For example:
/* file A */
.foo { color: red; }
/* file B */
.bar { :extend .foo; }
.baz { :extend .foo; }
Compiles to:
.bar, .baz { color: red; }
Both 2.7.x and 3.0.x produce the same ordering. If the :extend statements are in different files, the final order depends on the import sequence.
Extending a selector that contains a mixin does not automatically bring the mixin’s properties into the target rule. Stylus only copies the selector string; it does not evaluate or re‑apply the mixin inside the target block. Therefore, if the source selector uses a mixin with defaults, those defaults will not appear in the extended rule in either 2.7.x or 3.0.x.
Pseudo‑classes attached to the base selector are preserved when the selector is extended. The full selector—including the pseudo‑class—is copied into the target rule. For instance, extending .btn:hover from another file results in the target selector containing .btn:hover exactly as written. This holds in both major releases.
Media queries are not inherited by the extended selector. If the source selector is wrapped in a media query, the target rule will appear outside that query unless the target is also nested inside the same query. Consequently, the cascade priority can shift if the target rule is emitted earlier or later in the output.
test.styl with two :extend statements targeting the same selector. Compile and inspect the comma‑separated list to confirm the order matches the source sequence.@media, extend it, and compile. Ensure the extended selector appears outside the media query unless explicitly nested.All steps should produce identical results in Stylus 2.7.x and 3.0.x, confirming deterministic behaviour under the described conditions.
To fine‑tune your build, could you confirm whether you import Stylus files using @import statements or rely on a build tool’s file ordering? The import order can affect selector precedence when extensions span multiple files.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.