Write a Style Sheet Extension in LESS
Steps
Write a skin extension's style sheet in LESS so it can reuse the variables and mix-ins the skin already defines, instead of repeating their values as plain CSS.
- Set the style sheet extension object's "Content Type" field to "LESS". Only XWiki.StyleSheetExtension carries it, so there is no LESS mode for a JavaScript extension:

- Use the skin's variables and mix-ins directly. Before compiling, XWiki prepends @import (reference) "style.less.vm"; to the content, which is the main LESS file of the current skin, so everything it declares is in scope without being copied into the output. Under Flamingo that is the whole Bootstrap 3 set plus Flamingo's own additions, listed on Use LESS Variables:
.myClass { color: @brand-primary; .make-xs-column(12); .make-sm-column(6); }compiles to:
.myClass{color:#2f70a7;float:left;width:100%;position:relative;min-height:1px;padding-right:15px;padding-left:15px;} @media (min-width:768px){ .myClass{float:left;width:50%;}} - Pick the language by what you need to reach, and combine two of them when you need both.
Language Reach for it when CSS Plain rules are enough. Nothing to set. LESS You want the variables and mix-ins of the skin. Needs "Content Type" on "LESS". Velocity You need the XWiki API, the current user, or a value passed in through the pull call. Needs "Parse content" on "Yes"; see Generate Skin Extension Content with Velocity. LESS and Velocity combine: with "Parse content" on "Yes" the content is evaluated by Velocity first and the result is then compiled as LESS.
.parsed { #if ($xcontext.userReference) color: @brand-primary; #else color: @brand-danger; #end }For the colours of the active theme, prefer the LESS variables above or the CSS properties. The older Colibri ColorTheme variables still work, through Velocity rather than LESS, but they are deprecated.
- Let a parameter vary the style sheet without paying for a compilation on every request. The compiled result is cached per skin, per colour theme and per request parameter, so only a value that is not in the cache yet costs a compilation. The object below, pulled with different values of tone, serves a different colour each time and recompiles only once per value:
.themed { color: @brand-#if ($request.tone)$request.tone#{else}primary#end; }?minify=false -> .themed{color:#2f70a7;} ?minify=false&tone=danger -> .themed{color:#ca302c;} ?minify=false&tone=success -> .themed{color:#077537;}skin, colorTheme, colorThemeVersion, language, docVersion and the cache version are left out of the key, being accounted for already. Setting the caching policy to "No caching" recompiles on every request instead.
- Provide a plain CSS fallback if the extension has to survive a skin that ships no LESS. The import of step 2 is what makes the skin's variables available, so a skin that does not provide less/style.less.vm cannot compile a LESS extension at all. Put two objects on the page, the first plain CSS and the second LESS: they are concatenated in order, so the LESS one overrides the fallback wherever it does compile:
.fallback { color: blue; } .fallback{color:#2f70a7;} - Reuse a selector of the skin either by extending it or by calling it as a mix-in, knowing that the two do not give the same thing. &:extend() copies the rules of that selector alone, while calling it as a mix-in also brings in every rule nested under it, rewritten under yours:
.myExtend { &:extend(.alert); } .myMixin { .alert(); }.myExtend{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:7px;} .myMixin{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:7px;} .myMixin h4{margin-top:0;color:inherit;} .myMixin .alert-link{font-weight:bold;} .myMixin > p{margin-bottom:0;}A selector whose styling lives entirely in its nested rules therefore extends to nothing. Call it as a mix-in instead.
- Read the extension back at the address written into any page that pulls it. What comes back is CSS, with the skin's variables already resolved to their values and no LESS left in it. When nothing comes back at all, read it again with minify=false: a failed compilation is silent by default, because the error is written into a CSS comment and the minifier drops comments. The line to look for is the one naming the LESS error:
/* org.xwiki.lesscss.compiler.LESSCompilerException: Failed to compile the resource [...] with LESS. at org.xwiki.lesscss.internal.compiler.CachedLESSCompiler.compute(CachedLESSCompiler.java:137) ... Caused by: com.github.sommeri.less4j.Less4jException: Could not compile less. 1 error(s) occurred: ERROR 2:18 The variable "@this-variable-does-not-exist" was not declared. 2: .broken { color: @this-variable-does-not-exist; } ... */
FAQ
The same extension looks different under another skin. Why?
Because a variable the other skin sets to another value, or a mix-in it defines differently, compiles to another result. The colour theme counts the same way. An extension that has to look identical everywhere should not read the skin's variables at all.