rgb(from … r g b / <alpha>) throws under --math=always (Operation on an invalid type)
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 17k
- Forks
- 3.4k
- Avg merge
- 7h 42m
- Merged PRs (30d)
- 26
Description
To reproduce:
CSS Color Level 5 relative-color syntax with an alpha slash. This is valid CSS that should be left for the browser.
Playground (4.9.1, --math=always):
https://lesscss.org/less-preview/#eyJjb2RlIjoiLmNhcmQge1xuICAvKiBDU1MgQ29sb3IgTGV2ZWwgNSByZWxhdGl2ZSBjb2xvciArIGFscGhhICovXG4gIGJhY2tncm91bmQ6IHJnYihmcm9tIHZhcigtLXN1cmZhY2UpIHIgZyBiIC8gMC45KTtcbn1cbiIsImFjdGl2ZVZlcnNpb24iOiI0LjkuMSIsIm1hdGgiOiJhbHdheXMiLCJzdHJpY3RVbml0cyI6ZmFsc2V9
Or locally:
.card {
background: rgb(from var(--surface) r g b / 0.9);
}
npx lessc --math=always input.less
The origin does not have to be var(). A literal hex fails the same way:
.card {
background: rgb(from #112233 r g b / 0.9);
}
Current behavior:
Less 4.4.0+ with --math=always throws:
Error evaluating function `rgb`: Operation on an invalid type
Less treats the CSS alpha slash as division. After #4346, b is a colorOperand, so b / 0.9 becomes a Less Operation and eval blows up.
Expected behavior:
Emit the declaration unchanged, same as 4.3.0 and same as 4.9.1 with --math=parens-division:
.card {
background: rgb(from var(--surface) r g b / 0.9);
}
That matches the pass-through already expected by the tests added in #4346 / #4434 for rgb(from #0000FF calc(r + 1) g b).
Environment information:
lessversion: 4.9.1 (also reproduced on 4.4.0+. 4.3.0 is fine)nodejsversion: 24.12.0operating system: macOS
Additional context:
rgb() as a Less color constructor is not new. The regression is that relative-color CSS started parsing as a Less rgb() call, then the / <alpha> slash is evaluated as math.
| Input | 4.3.0 --math=always |
4.9.1 --math=always |
4.9.1 --math=parens-division |
|---|---|---|---|
rgb(from var(--x) r g b / 0.9) |
pass-through | error | pass-through |
rgb(from #112233 r g b / 0.9) |
pass-through | error | pass-through |
rgb(from var(--x) r g b) (no slash) |
pass-through | pass-through | pass-through |
rgb(17, 34, 51) (Less constructor) |
#112233 |
#112233 |
#112233 |
Related:
- #4343 / #4346 (v4.4.0): added
colorOperand([lchrgbs]) sooklch(from …)/rgb(from … calc(r + 1) …)would parse instead ofCould not parse call arguments or missing ')'. - #4316 / #4434 (v4.6.6): tightened the operand regex so
bmatches before/. - #4479 (v4.8.1): same class of bug for math functions (
sin(var(--x))etc.). Those now return nothing and leave the call for the browser.rgb()does not get that treatment.
Workaround that should not be required: quote the value so Less does not parse it (~'rgb(from var(--surface) r g b / 0.9)'), or compile with --math=parens-division.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the rgb() handling and colorOperand parsing described in #4346 and #4434, then compare the math=always path with the existing pass-through behavior for relative colors. Add a regression test for the alpha-slash form and verify that it emits the declaration unchanged without breaking ordinary Less rgb() construction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- css, javascript
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100