10

I'm wondering if there is a way to load a single less sheet sometime after a page load. This question has an answer that explains how to reload all the sheets, but for my use-case existing sheets never have dependencies on newly loaded sheets, and it would be good to just add the sheet lazily. I'm thinking something like

less.sheets.push(mySheet);
less.loadStyleSheet(mySheet);

might represent a possible API? Cheers,

Colin

UPDATE 3rd Dec 2010:

I've tried out Livingston Samuel's fix of the less.js codebase, and while it does work, it doesn't appear to recognise definitions in already loaded stylesheets. Here are my sample files

a. index.html

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>Simple</title>

  <link rel="stylesheet/less" href="/static/less/style.less" id="abc123"/>
  <script src="/static/js/less-1.0.40.js"></script> 
</head>
<body>
  <div id="container">
    <div>Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet.</div>
  </div>
  <div id="abc"><div>Bingo</div></div>
</body>

<script>
console.log("loading new sheet");
less.loadStyleSheet("/static/less/style2.less", function() {
    console.log("Loaded!"); 
});

console.log("called");

</script>
</html>

b. style.less

@primary_color: green;

.rounded(@radius: 5px) {  
  -moz-border-radius: @radius;  
  -webkit-border-radius: @radius;  
  border-radius: @radius;  
}

#container {
  background: @primary_color;
  .rounded(5px);

  div {
    color: red;
  }
}

c. style2.less

#abc {
  background: @primary_color;
  .rounded(10px);

  div {
    margin: 2px;
    color: blue;
  }
}

So the second stylesheet does load lazily, but it has the following parsing error in style2.less

".rounded is undefined"

.rounded is defined style.less, and since I haven't unloaded that sheet, I was thinking it should be still available to the compiler in the current environment.

To put it another way, we don't want to start fresh, or to unload existing definitions, but build on the styles already loaded. Thanks,

Colin

Community
  • 1
  • 1
hawkett
  • 3,053
  • 5
  • 29
  • 39

6 Answers6

5

I wasn't able to figure this out with the explanations above so I'll provide my own.

So first. Load in your Less stylesheet after the page loads. Something like this:

$('head').append('<link rel="stylesheet/less" href="path/to/yourDynamicStyles.less" />');

Great. Now select your stylesheet and push it into the collection of sheets that Less.js already has. It is expecting a DOM object so I used a jQuery selector.

less.sheets.push($('link[href="path/to/yourDynamicStyles.less"]')[0]);

If someone knows a better way to do that please educate me. (I had to add the [0] in order to get it to the right one.) If you do this in the console it will return a number. That number is how many sheets less knows about so hopefully it returned a number one higher then what you already had on page load.

Next part is easy. You tell Less.js to reload all of it's lessy goodness sheets, this includes the sheet you just added to its stack.

less.refresh();

And there you go. That should have just dynamically loaded a stylesheet and told Less to compile it. Hope this helps.

MSaforrian
  • 599
  • 5
  • 7
3

Just adopted MatthewForr answer for my own needs:

$.each(['/css/style1.less', '/css/style2.less'], function (index, fileName) {
    var $sheet = $('<link />', {
        href: fileName,
        rel: 'stylesheet/less',
        type: 'text/css'
    }).appendTo('head');
    less.sheets.push($sheet[0]);
});
less.refresh();
sunrize531
  • 33
  • 3
3

less.js has a function loadStyleSheet in it's local scope which can be used to dynamically load and parse the less styles (lazy load).

The only problem is the function is in the closure created for defining less.js so you cannot access the function from your code.

Maybe it can exposed by extending the api.


Update:

I've created a forked version of less.js @ https://github.com/livingston/less.js

Using this version you can load any stylesheet using the method less.less.loadStyleSheet(YOUR_FILE_URL, CALLBACK)

I've also made a pull request to the actual library, hopefully they accept my changes.

Livingston Samuel
  • 2,422
  • 2
  • 20
  • 35
  • I've tested it out, and it does look to work, but definitions in already loaded stylesheets are unrecognised. Will update the question with more detail. Cheers. – hawkett Dec 03 '10 at 11:54
1

Alternatively you could write some server-side code which would convert your .less stylesheet into .css on the fly. From the client you would load it lazily as if it were any other .css stylesheet. This is the approach used by http://www.dotlesscss.org/ although it could be used by any flavor of .less.

Maybe not what you're looking for, but it's an option for some I think.

Allan Nienhuis
  • 3,961
  • 2
  • 23
  • 19
  • Yep def. an option - my app is on App Engine (python), and the style scripts are user contributed at runtime - so my only options for server side compiling are (a) a python library (I can't find anything that seems well maintained, current, or likely to follow less advancement reliably). (b) An external web service that accepts the source scripts and returns the compiled output. (c) choose something other than LESS that does have a python compiler. None of these options are very appealing, and the ease with which less.js solves these issues (if it could lazily load) is very appealing. Thx. – hawkett Dec 07 '10 at 00:14
  • The other thing is that because I need lazy loading, I need the parts to be separately available/compiled - e.g. userA may use only script1, while userB may use both script1 & script2 (script2 cannot be used on its own, as it depends on script1, but script2 may not be used by everyone). So when script2 loads, if it has been precompiled on the server, the css file will contain all the definitions in the already loaded script1. True they will just override, but unnecessarily large css files and smells pretty bad in general. – hawkett Dec 07 '10 at 00:29
0

You can use this lightweight library to lazy load less / css and js files ( disclaimer: i am the author).

This is as simple as:

lazy.load('/static/less/style.less');

It can also receive a callback, load some more assets with dependencies and takes care about cache.

Oren Yakobi
  • 279
  • 1
  • 4
  • 14
-2

All you have to do is add a new script tag to the DOM. It will then be downloaded and executed.

function addScript (id, url)    //  Adds scripts to the DOM
{
    var s = document.createElement('script');
    s.id = id;
    if (url)    s.src=url;
    s.type='text/javascript';

    document.getElementsByTagName('head')[0].appendChild(s)
    return s;
}

This what I use on my site but I call it on parse. For you to use it as a lazy loader it should work fine for you to call it onload or a similar way.

Youarefunny
  • 622
  • 5
  • 10
  • Sorry, I thought it was what you named your javascript file :( – Youarefunny Nov 26 '10 at 03:10
  • I don't quite get what you want to do? Do you want to add a stylesheet (be it a less.js stylesheet) to the DOM after page load? – Youarefunny Nov 26 '10 at 03:14
  • 1. Page load complete, 2. User does some stuff, and at some point in the future clicks a link that requires a new stylesheet to be loaded. A good example might the installation of a ui widget component. We don't want to reload the whole page, just the html and css required for the widget. – hawkett Dec 03 '10 at 11:33
  • In that case use the same code above but add a stylesheet. This is what I use. A copy of my exact implementation is at http://pastebin.com/ER1NYT31 – Youarefunny Dec 03 '10 at 21:26
  • You're mistaking a less style sheet with a css style sheet. Loading a css style sheet lazily is well understood (and what I currently do), but if I am to move to less, which I want to do, then I need to load less sheets lazily. There are now some example less stylesheets in the question. – hawkett Dec 05 '10 at 00:22