Less. The dynamic stylesheet language.

  • By Less
  • Last update: Sep 23, 2022
  • Comments: 17

Github Actions CI Downloads Twitter Follow


Chat with Less.js users and contributors

This is the Less.js monorepo, managed via Lerna.

More information

For general information on the language, configuration options or usage visit lesscss.org.

Here are other resources for using Less.js:

Contributing

Please read CONTRIBUTING.md. Add unit tests for any new or changed functionality. Lint and test your code using Grunt.

Reporting Issues

Before opening any issue, please search for existing issues and read the Issue Guidelines, written by Nicolas Gallagher. After that if you find a bug or would like to make feature request, please open a new issue.

Please report documentation issues in the documentation project.

Development

Read Developing Less.

Release History

See the changelog

Contributors

Code Contributors

This project exists thanks to all the people who contribute. [Contribute].

License

Copyright (c) 2009-2017 Alexis Sellier & The Core Less Team Licensed under the Apache License.

Github

https://github.com/less/less.js

Comments(17)

  • 1

    The way Extend works - more complicated selectors and change in matching

    From @DesignByOnyx

    I have finally gotten around to testing this and wanted to post my initial findings. I have been using the alpha version less-1.4.0-alpha.js on the client-side only (no command line yet - not that it should be any different really).

    So far, everything works as I would expect except for two major drawbacks which can be explained with one example. Take the following code which is located in one of my root LESS files:

    .container { margin: 0 auto; }
     .container.positioned { position: absolute }
    
    @media screen and (min-width: 30em) {
        .container.positioned { left: 50%; }
    }
    @media screen and (min-width: 30em) and (max-width: 48em) {
        .container { width: 30em; }
        .container.positioned { margin-left: -15em; }
    }
    @media screen and (min-width: 48em) and (max-width: 60em) {
        .container { width: 48em; }
        .container.positioned { margin-left: -24em; }
    }
    @media screen and (min-width: 60em) {
         .container { width: 60em; }
         .container.positioned { margin-left: -30em; }
    }
    

    Issue 1 - styles defined within media queries do not get extended. Anything trying to extend the .container class only gets the margin: 0 auto styles.

    .some-element:extend(.container);
    

    Issue 2 - compound selectors do not get extended. However, the first participant DOES get extended. For example, the following incorrectly extends the .container styles but not the intended .container.positioned styles.

    .some-element:extend(.container.positioned);
    

    I wish I could provide a solution. Hope this helps.

  • 2

    Allow parametrized mixins as detached rulesets to form 'lambdas'

    It seems that currently LESS only supports 'pure' rulesets to be passed along as mixin arguments or stored in variables as detached rulesets.

    I suggest to extend this support to incorporate parametrized mixins, essentially giving LESS the capability to work with lambdas.

    E.g. One would be able to write

    .list {
      .forEach(foo bar baz, (@item, @index) {
        @i : (@index + 1);
        > li:nth-child(@{i}):before {
          content : "@{item}";
        }
      });
    }
    

    where .forEach is defined as

    .forEach(@list, @lambda) {
      @n : length(@list);
    
      .for(0)
      .for(@index) {}
      .for(@index) when (@index < @n) {
        @lambda(extract(@list, @index), @index);
        .for(@index + 1);
      }
    }
    

    Lambda mixin support would also neatly resolve recurring issues with function return arguments and the ugly hack where variables 'bubble up' to parent scope if said variables are as of yet undefined in said parent scope.

    The suggested practice could become to adopt continuation style programming; passing 'return values' along into a lambda mixin to continue down the scope chain. This kind of mechanism is more transparent to users, less brittle by avoiding issues with potential variable name collisions and just fits in better with the overall functional programming paradigms that the LESS syntax is built on.

    [EDIT] Having just had a look at the way detached rulesets and calls are implemented in the AST, I think very little needs to happen to make this work. Even on the parser side of things, it seems fairly simple to just parse an optional block of mixin.args before blockRuleset in the detachedRuleset parser function and pass the arguments along to the tree.DetachedRuleset node instance. (The tree.DetachedRuleset would need to be extended with the params evaluation from tree.mixin.Definition, ofcourse.)

  • 3

    variable in @import statement

    The lastest version introduced the possibility to "access the value of an abstract property from a string using { } operators" (section "String interpolation" in http://lesscss.org/#-string-interpolation).

    But the problem is that it doesn't work in import statements. It would be great to write code such like this :

    //define the template @mainTemplate: "BaseTheme";

    //import the template @import "_templates/@{mainTemplate}/Config/_ConfigTemplateDefault.less";

    I don't know if it is possible to resolve this issue, but it would be great !

  • 4

    How to handle Maths

    1. We decided on strict maths going forward but there is general unease about forcing () around every calculation
    2. I don't think we want to change things massively or go back to the drawing board

    See #1872

    Possibility to add another case for calc which like font, with strict mode off, essentially turns strict mode on for a rule ? Too many exceptions in the future?

    @seven-phases-max : Well, there're a lot of other possibilities, e.g. ./ or require parens for division (e.g. 1/2->1/2 but (1/2)->0.5) etc... Also, the "special cases" (e.g. properties where x/y can appear as shorthand) are not so rare (starting at padding/margin and ending with background/border-radius and eventually there can be more) so we just can't hardcode them all like it's done for font (and because of that I think that the current font "workaround" is just a temporary and quite dirty kludge that ideally should be removed too).

  • 5

    Version 3.10.x uses significantly more memory and is significantly slower than 3.9.0

    Our builds recently started failing because we run about 80 Less builds in parallel during our project's build process and the new version of Less.js uses so much memory that Node crashes. We traced the crash to upgrading from Less.js from 3.9.0 to 3.10.3.

    I changed our Less script to compile the files sequentially (building 2 files at a time) and sampled Node's memory usage during the process and got the following results:

    less graph

    Less.js seems to use 130% more memory now and takes about 100% longer to compile for us.

    Just wondering if you've benchmarked Less.js and whether you see similar results

  • 6

    Public variables on namespaces

    I realize this isn't a new topic but it I think the time has come to consider implementing public variables on namespaces. Many prominent libraries for LESS (bootstrap, hat, etc.), have emerged, each with dozens of configuration variables which could very well overlap and conflict with each other.

    Currently, namespaces support private variables, the only way to get at them is via mixins within the namespace and those mixins can then be used externally; Sort of like a closure:

    #ns {
        @size: 10px;
        .box() {
            width: @size;
            height: @size;
        }
    }
    
    .icon {
        #ns > .box();
    }
    

    Which yields:

    .icon {
        width: 10px;
        height: 10px;
    }
    

    However, I think it would be very handy to do the following:

    #ns {
        @size: 10px;
    }
    
    .icon {
        width: #ns > @size;
        height: #ns > @size;
    }
    

    As well as update those variables within the namespace:

    #ns > @size: 20px;
    
  • 7

    Add Sass like extend

    Sass extend is here. http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#extend

    More simple syntax, use +.

    .foo {
      width: 100px;
    }
    .bar {
      +.foo;
    }
    

    converted this.

    .foo, bar {
      width: 100px;
    }
    

    See also test code.

  • 8

    Support file globbing for @imports

    See: https://github.com/isaacs/node-glob, and ~~https://github.com/isaacs/minimatch~~ https://github.com/jonschlinkert/micromatch

    I use these often in projects. It would be pretty awesome to be able to do the following and not have to specify individual files:

    @import "mixins/*.less";
    @import "components/**/*.less"; 
    

    After only a few minutes of using these patterns they become second nature. It might even help with some of the other import issues.


    Implemented via plugin: less-plugin-glob.

  • 9

    Import options

    We have decided that the best way to handle the import bugs is by having options.

    Given the scope of the bugs I feel strongly that the options need to be inline with the actual import statement

    I suggest removing @import-once and @import-multiple and allowing options to be passed to the @import statement

    Note that import can already be followed by media statements e.g.

    @import "file.css" (min-width:400px);
    

    The options I propose we support are

    1. treat as less or treat as css - people have to add ?.css onto the end of url's at the moment to treat as css - a bit of a hack
    2. import-multiple to replace @import-multiple though not so important if we want to drop
    3. whether to keep the import in place or import it - at the moment we keep css imports inline, but it would be nice to be able to include in css files (treated as an anymous node)
    4. The ability to include a less file, but not output anything - just make the classes available as mixins.

    so here are some options.

     @import (multiple: true, less: true, include: true) "file.less" (min-width:400px);
    

    downsides are its a bit confusing with the media query syntax. we could also put the options second and mix them with the media query, defining our own special media query options essentially, but I don't like that in case we conflict in the future with css.

    from @jonschlinkert

    @options (multiple: true, less: true, include: true) {
        @import "file.less" (min-width: 400px);
    }
    

    and variations on the above, such as using closer media query syntax like

    @import (multiple: true) and (less: true) "file.less";
    

    I initially disliked @jonschlinkert's options idea, but it does actually allow for setting defaults.. what I don't like is that it looks a bit verbose.

    we could also assume :true and have

    @import (multiple, less) "file.less" (min-width:400px);
    

    and I am open to any other suggestions.

  • 10

    Mixins should accept LESS blocks

    It would be helpful if mixins had access to a content block passed to them, so one could encapsulate media queries or browser hacks in a central place and reference them symbolically.

    This is basically the "Passing Content Blocks to a Mixin" feature of SASS: http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#mixin-content

    In LESS this would mean something like:

    .mobile() {
      @media all and (max-device-width: 480px) {
        @content
      }
    }
    .big-desktop-button {
      ...
      .mobile {
        display:none;
      }
    }
    
  • 11

    Class constructor FileManager cannot be invoked without 'new'.

    It seems that v3.10.0 breaks my build, webpack logs below:

    ERROR in ./src/pages/score/components/current/no-join/index.less
    Module build failed (from ./node_modules/[email protected]@mini-css-extract-plugin/dist/loader.js):
    ModuleBuildError: Module build failed (from ./node_modules/[email protected]@less-loader/dist/cjs.js):
    
    
    Class constructor FileManager cannot be invoked without 'new'
          in undefined (line undefined, column undefined)
        at runLoaders (/home/admin/build/node_modules/[email protected]@webpack/lib/NormalModule.js:313:20)
        at /home/admin/build/node_modules/[email protected]@loader-runner/lib/LoaderRunner.js:367:11
        at /home/admin/build/node_modules/[email protected]@loader-runner/lib/LoaderRunner.js:233:18
        at context.callback (/home/admin/build/node_modules/[email protected]@loader-runner/lib/LoaderRunner.js:111:13)
    

    Everything is ok when downgrade to v3.9.0, please investigate this issue and hope to fix it as soon as possible.

  • 12

    Importing less files from a third party library crashes the build.

    To reproduce:

    1. Create a new project folder.
    2. Run npm init -y.
    3. Install less and swiper.
    4. Create a main.less file in the root/src folder.
    5. Create a build script that runs lessc (src/)main.less output/styles.css.

    Add these lines in the main.less file.

    @import (less) 'swiper/less';
    @import (less) 'swiper/less/navigation';
    @import (less) 'swiper/less/pagination';
    

    Current behavior: The build script fails with the following error.

    FileError: 'swiper/less' wasn't found. Tried - path\swiper-package\swiper\less.less,path\swiper-package\swiper\less.less,npm://swiper\less,npm://swiper\less.less,swiper\less.less in path\swiper-package\main.less on line 1, column 1:
    1 @import (less) 'swiper/less';
    

    Expected behavior:

    Should have outputted the CSS. Not sure if this is because swiper is using exports in their package.json file. From reports I heard at work, this works fine on Mac.

    Environment information:

    • less version: 4.1.3
    • nodejs version: 16.15.0
    • operating system: Windows 10/11 x64
  • 13

    import styles from the library into the library

    Hello! We create a project with its own npm packages one of which is core (common package). I want to import bootstrap styles (from node_modules) into the core, but I'm having problems with imports in the base application

    To reproduce:

    core-package:

    // main.less
    @import "bootstrap/dist/css/bootstrap.min.css";
    // I have also tried this recording option
    @import "~bootstrap/dist/css/bootstrap.min.css";
    
    

    application-base:

    // main.less
    @import "core-package/dist/styles/main";
    // I have also tried this recording option
    @import "~core-package/dist/styles/main";
    

    Structure for greater understanding:

    src
    - node_modules
    -- bootstrap
    -- core-package
    --- main.less (core)
    - styles
    -- main.less (app)
    

    Current behavior:

    When I start application-base

     [email protected] start
    > concurrently --kill-others "less-watch-compiler --config less-watcher.config.json" "react-scripts start"
    [0] Config file /Users/User/Projects/application-base/app/less-watcher.config.json is loaded.
    [0] Watching directory for file changes.
    [0] node:internal/fs/utils:344
    [0]     throw err;
    [0]     ^
    [0] 
    [0] Error: ENOENT: no such file or directory, stat '/Users/User/Projects/application-base/app/src/styles/core-package/dist/styles/main'
    [0]     at Object.statSync (node:fs:1538:3)
    [0]     at Object.findLessImportsInFile (/Users/User/Projects/application-base/app/node_modules/less-watch-compiler/dist/lib/filesearch.js:15:20)
    [0]     at Object.fileWatcher (/Users/User/Projects/application-base/app/node_modules/less-watch-compiler/dist/lib/lessWatchCompilerUtils.js:235:38)
    [0]     at /Users/User/Projects/application-base/app/node_modules/less-watch-compiler/dist/lib/lessWatchCompilerUtils.js:86:40
    [0]     at /Users/User/Projects/application-base/app/node_modules/less-watch-compiler/dist/lib/lessWatchCompilerUtils.js:67:27
    [0]     at FSReqCallback.oncomplete (node:fs:199:5) {
    [0]   errno: -2,
    [0]   syscall: 'stat',
    [0]   code: 'ENOENT',
    [0]   path: '/Users/User/Projects/application-base/app/src/styles/core-package/dist/styles/main'
    [0] }
    [0] 
    [0] Node.js v17.3.0
    [0] less-watch-compiler --config less-watcher.config.json exited with code 1
    --> Sending SIGTERM to other processes..
    [1] react-scripts start exited with code SIGTERM
    

    Expected behavior:

    I want to enable importing bootstrap styles into a core less file and just import the core less file to connect all the styles

    Environment information:

    • less version: ^4.1.3
    • less-watch-compiler version: ^1.16.3
    • nodejs version: 17.3.0
    • react version: 18.0.2
    • operating system: MacOS
  • 14

    📝 Add logo alt & Remove link to image file

    What:

    Accessibility and Usability improvements.

    Why:

    As for the link, I expected it to link to https://lesscss.org/. However, it was linked to an image so I removed the link.

    ref. https://stackoverflow.com/a/48744957/9287284

    How:

    As per this change. Add alternative text to image and remove linking to image.

    Checklist:

    • [ ] Documentation "N/A"
    • [ ] Added/updated unit tests "N/A"
    • [ ] Code complete "N/A"
  • 15

    Mixin followed by !important is not correctly compiled

    Hi,

    I have noticed a inconsistency between the documentation and the functioning of less.

    In the documentation, adding !important to the mixin should result in the !important being added to all the css declarations inside the mixin. However, this is not the case. Upon compiling, the css does not contain the !important.

    image

  • 16

    fix ajax request error for urls created by createObjectURL

    What: enable possibility using urls created by URL.createObjectURL to less compilation

            let c = `h2 { color : green; cursor: pointer; }`
            let b = new Blob([c], {
                type: 'text/css'
            })
            let url =  URL.createObjectURL(b);
            
            const link = document.createElement('link')
            
            link.href = url;
            link.type = "text/x-less"
            link.rel = "stylesheet/less";
    
            document.body.appendChild(link)
    

    Why: without changes we have following error:

    image

    Sample code here https://codepen.io/Alsoo/pen/GRxjGZa (not reproduced on codepen)

    How: links created using createObjectURL always start with blob: and are automatically added to the base part of the host name. Therefore, the simplest and most effective way to identify such links is to check whether they start with the blob part, bypassing the extractUrlParts function:

    const href      = filename.startsWith('blob:') ? filename : hrefParts.url;
    

    instead of

    const href      = hrefParts.url;
    

    This solution does not break any test and total solves all problems with blob links (checked)

    • [ ] Documentation
    • [ ] Added/updated unit tests
    • [x] Code complete
  • 17

    fix: '..' shouldn't be ignored if directories is empty

    What:

    append .. to directories if directories is empty

    Why:

    pathDiff will broken if url startsWith ..

    AbstractFileManager.prototype.pathDiff('../assets/', '') returns assets/ now

    How:

    pop directories only if it is not empty

    Checklist:

    • [ ] Documentation
    • [ ] Added/updated unit tests
    • [x] Code complete