Description
This supplants this issue.
TODO - Does this repo need to exist? If it's just for meta-discussions, I think it could move into the DIscussions tab on the Less repo.
Less 4.x Roadmap
(Prep for Less 5.x)
Add deprecation warnings when parsing / evaluating
Changes
- Add support for
:extend(.foo !all)
vs:extend(.foo all)
- Added in #4319 but tests needed
- Add support for
--custom: @{variable};
(see below)- Added in #4319 but tests needed
- Add
selector()
function as special parsing in a (variable) declaration value or function argument- Deprecate plain "anything goes" permissive parsing fallback for regular values
- Add
custom()
function as special parsing of a custom declaration's value -- I'm not sure this is necessary, because~""
exists? The reason I think I added this is because it checks that you have matching braces... Therefore it would guarantee, during parsing, that the parsed value is a valid custom declaration value. - There are a number of examples in Less tests of invalid CSS for input CSS. There is no contractual guarantee that Less support invalid CSS (outside of known legacy hacks), so invalid CSS should be removed from
.less
tests, such that a more accurate spec-compliant parser doesn't bork on those tests - Add
@from
syntax (@plugin
to be deprecated)
Add a deprecation warnings for the following things. Note that warnings will be suppress-able with an additional option.
WARN when
- calling a mixin without parentheses e.g.
.mixin;
- when encountering unknown parsing in a variable declaration value (when falling back to permissive parsing)
- using
./
(forced division) operator. It's really not necessary and requiring parentheses around division is fine. - putting whitespace between mixin name and parentheses in a mixin call
- leaking (unlocking) variables and mixins into parent scope. There are accessors and other chaining features to be introduced in Less 5.x - Note: this is tricky to catch. It requires leaking the mixin/variable first, but only throwing the deprecation warning if we detect that the leaked var / mixin is actually referenced in the parent.
- leaking parent scope into caller scope. (Mixin calls have access to parent scope. This is unnecessary as you can just pass what you want into the mixin, and it also makes a mixin definition harder to reason about.) Similar to above, we should only throw the deprecation warning if we detect that the parent scope is referenced.
- using
:extend(.foo all)
instead ofextend(.foo !all)
- using
--custom: @variable
<-- this is ambiguous and problematic, the only supported form should be:--custom: @{variable};
- using
@plugin
(requires@from
as a feature) - using
Math.ALWAYS
- using
strictUnits: false
- putting
@charset
at any place other than the start of a.css
or.less
file, or using a variable in a@charset
ERROR ?
- Compiling a remote Less file should automatically disable
@plugin
and any other JavaScript evaluation - see this advisory. (Unless we figure out a way to isolate JS execution -- maybe running Deno.)
Less 5.x Roadmap
TODO - break out as separate, linked READMEs?
Changes
- Replace Less parsing / evaluation engine with Jess (a language-agnostic stylesheet engine).
- Replacing engine would bring a number of new features, including expression
#{}
syntax, better performance, and better chaining. - Discontinue support of Less plugins in favor of Jess plugins? (It's not clear there can be 100% compatibility since Less plugins are Less AST-specific. The only possible way to do this would be to do a lot of work to expose Jess AST nodes as Less AST nodes to a Less plugin, and Less AST nodes are very messy / inconsistent, so my preference would be migration documentation).
New
1. @from
as replacement for @plugin
- drop-in JS/TS modules
Uses native dynamic imports vs eval'd Function calls.
@from './values.ts' import (width);
2. Namespacing for Less functions
No more inherent conflict between Less functions and CSS functions. The author can signal exactly what they mean.
@from '#less' import (rgb);
.box {
color: rgb(fade(@my-color, 10%));
}
...or:
@from '#less' import * as less;
.box {
color: less.rgb(fade(@my-color, 10%));
background-color: rgb(var(--some-runtime-var));
}
3. @use
as replacement for @import
Polluting the @import
at-rule has had lots of unforeseen consequences, so continued use of it would be deprecated. Unlike @import
, @use
will not leak into child imports, making it easier for IDE features like auto-complete when opening a child import.
Old:
@import './variables.less';
@import './somefile.less'; // variables.less is leaked into somefile.less
@use './variables.less';
@use './somefile.less'; // no leakage ("somefile.less" must also call `@use './variables.less'`)
.box {
color: @some-var; // (from variables.less)
}
4. @include
as alternative replacement for @import
Will only render qualified rules, without importing variables or mixins.
5. @reference
as replacement for @import (reference)
Will only include variables and mixins. Like @use
, will not leak variables into child imports / references. Will also be able to be used repeatedly without an explicit (multiple)
flag.
6. Replacements for @import (css) './myfile.less'
and @import (less) './myfile.css'
features
@include (css) './myfile.less';
@include (less) './myfile.css';
// can also write:
@use (less) './myfile.css';
7. Unlike Sass, Less will support native CSS Nesting:
.box {
&.foo { color: blue; }
}
...evaluates to:
.box {
&.foo { color: blue; }
}
whereas:
.box {
// note the hyphen
&-1 { color: blue; }
}
...evaluates to:
.box-1 { color: blue; }
Note, however, that &-1
will be deprecated and will trigger a warning. The preferred form for Less moving forward for "merging" selectors will be a function-like &()
e.g.
.box {
&(-1) { color: blue; }
}
i.e. you can also force a merge by doing:
.foo {
&().bar { color: blue; }
}
...which will evaluate to (like classic Less):
.foo.bar { color: blue; }
8. Better :extend
-- converts to :is()
wrappers.
Example:
.one.two.three {
color: blue;
}
.foo:extend(.one);
.bar:extend(.two.three);
.four:extend(.two);
.five {
:extend(.one.two.three !all);
}
would evaluate to:
:is(:is(.one, .foo):is(:is(.two, .four).three, .bar), .five) {
color: blue;
}
Variable expansion in a selector
This should function similarly to above, where we don't have to combine imported variables with the other list. Meaning, we can just do:
@list: h2, a, li;
.child @{list} {
color: blue
}
This will result in (the much less computationally-expensive):
.child :is(h2, a, li) {
color: blue
}
Future feature: Extend should consider :is()
and :where()
Given this:
:is(.foo) {
color: blue;
}
.bar:extend(.foo);
This should result in:
:is(.foo, .bar) {
color: blue;
}