Less 扩充了 CSS 语言,增加了诸如变量、混合(mixin)、运算、函数等功能。
... Essentially, each scope has a "final" value, similar to properties in the ...
Overview
VariablesOverview
VariableInterpolation
VariableVariables
LazyEvaluation
PropertiesasVariables(NEW!)
DefaultVariables
ParentSelectorsMultiple&
ChangingSelectorOrder
CombinatorialExplosion
ExtendExtendSyntax
ExtendAttachedtoSelector
ExtendInsideRuleset
ExtendingNestedSelectors
ExactMatchingwithExtend
nthExpression
Extend"all"
SelectorInterpolationwithExtend
Scoping/ExtendInside@media
DuplicationDetection
UseCasesforExtend
MergeComma
Space
MixinsNotOutputtingtheMixin
SelectorsinMixins
Namespaces
GuardedNamespaces
The!importantkeyword
ParametricMixins
Pattern-matching
UsingMixinsasFunctions
RecursiveMixins
MixinGuards
AliasingMixins
CSSGuards
DetachedRulesetsScoping
Property/variableaccessors
@importAt-RulesFileExtensions
ImportOptions
reference
inline
less
css
once
multiple
optional
@pluginAt-RulesWritingyourfirstplugin
PluginScope
NullFunctions
TheLess.jsPluginObject
Pre-LoadedPlugins
Maps(NEW!)Usingvariablevariablesinlookups
Overview
Editthemarkdownsourcefor"overview"
Anin-depthguidetofeaturesoftheLESSlanguage.SeetheOverviewforaquicksummaryofLess.
Foranin-depthguidetoinstallingandsettingupaLessenvironment,aswellasdocumentationondevelopingforLess,see:UsingLess.js.
Variables
Editthemarkdownsourcefor"variables"
Controlcommonlyusedvaluesinasinglelocation.
Overview
It'snotuncommontoseethesamevaluerepeateddozensifnothundredsoftimesacrossyourstylesheets:
a,
.link{
color:#428bca;
}
.widget{
color:#fff;
background:#428bca;
}
Variablesmakeyourcodeeasiertomaintainbygivingyouawaytocontrolthosevaluesfromasinglelocation:
//Variables
@link-color:#428bca;//seablue
@link-color-hover:darken(@link-color,10%);
//Usage
a,
.link{
color:@link-color;
}
a:hover{
color:@link-color-hover;
}
.widget{
color:#fff;
background:@link-color;
}
VariableInterpolation
TheexamplesabovefocusedonusingvariablestocontrolvaluesinCSSrules,buttheycanalsobeusedinotherplacesaswell,suchasselectornames,propertynames,URLsand@importstatements.
Selectors
v1.4.0
//Variables
@my-selector:banner;
//Usage
.@{my-selector}{
font-weight:bold;
line-height:40px;
margin:0auto;
}
Compilesto:
.banner{
font-weight:bold;
line-height:40px;
margin:0auto;
}
URLs
//Variables
@images:"../img";
//Usage
body{
color:#444;
background:url("@{images}/white-sand.png");
}
ImportStatements
v1.4.0
Syntax:@import"@{themes}/tidal-wave.less";
Notethatbeforev2.0.0,onlyvariableswhichhavebeendeclaredintherootorcurrentscopewereconsideredandthatonlythecurrentfileandcallingfileswereconsideredwhenlookingforavariable.
Example:
//Variables
@themes:"../../src/themes";
//Usage
@import"@{themes}/tidal-wave.less";
Properties
v1.6.0
@property:color;
.widget{
@{property}:#0ee;
background-@{property}:#999;
}
Compilesto:
.widget{
color:#0ee;
background-color:#999;
}
VariableVariables
InLess,youcandefineavariable'snameusinganothervariable.
@primary:green;
@secondary:blue;
.section{
@color:primary;
.element{
color:@@color;
}
}
Whichcompilesto:
.section.element{
color:green;
}
LazyEvaluation
Variablesdonothavetobedeclaredbeforebeingused.
ValidLesssnippet:
.lazy-eval{
width:@var;
}
@var:@a;
@a:9%;
thisisvalidLesstoo:
.lazy-eval{
width:@var;
@a:9%;
}
@var:@a;
@a:100%;
bothcompileinto:
.lazy-eval{
width:9%;
}
Whendefiningavariabletwice,thelastdefinitionofthevariableisused,searchingfromthecurrentscopeupwards.Thisissimilartocssitselfwherethelastpropertyinsideadefinitionisusedtodeterminethevalue.
Forinstance:
@var:0;
.class{
@var:1;
.brass{
@var:2;
three:@var;
@var:3;
}
one:@var;
}
Compilesto:
.class{
one:1;
}
.class.brass{
three:3;
}
Essentially,eachscopehasa"final"value,similartopropertiesinthebrowser,likethisexampleusingcustomproperties:
.header{
--color:white;
color:var(--color);//thecolorisblack
--color:black;
}
Thismeansthat,unlikeotherCSSpre-processinglanguages,LessvariablesbehaveverymuchlikeCSS's.
PropertiesasVariables(NEW!)
v3.0.0
Youcaneasilytreatpropertieslikevariablesusingthe$propsyntax.Sometimesthiscan
makeyourcodealittlelighter.
.widget{
color:#efefef;
background-color:$color;
}
Compilesto:
.widget{
color:#efefef;
background-color:#efefef;
}
Notethat,likevariables,Lesswillchoosethelastpropertywithinthecurrent/parentscope
asbeingthe"final"value.
.block{
color:red;
.inner{
background-color:$color;
}
color:blue;
}
Compilesto:
.block{
color:red;
color:blue;
}
.block.inner{
background-color:blue;
}
DefaultVariables
Wesometimesgetrequestsfordefaultvariables-anabilitytosetavariableonlyifitisnotalreadyset.Thisfeatureisnotrequiredbecauseyoucaneasilyoverrideavariablebyputtingthedefinitionafterwards.
Forinstance:
//library
@base-color:green;
@dark-color:darken(@base-color,10%);
//useoflibrary
@import"library.less";
@base-color:red;
ThisworksfinebecauseofLazyLoading-@base-colorisoverriddenand@dark-colorisadarkred.
ParentSelectors
Editthemarkdownsourcefor"parent-selectors"
Referencingparentselectorswith&
The&operatorrepresentstheparentselectorsofanestedruleandismostcommonlyusedwhenapplyingamodifyingclassorpseudo-classtoanexistingselector:
a{
color:blue;
&:hover{
color:green;
}
}
resultsin:
a{
color:blue;
}
a:hover{
color:green;
}
Noticethatwithoutthe&,theaboveexamplewouldresultina:hoverrule(adescendantselectorthatmatcheshoveredelementsinsideoftags)andthisisnotwhatwetypicallywouldwantwiththenested:hover.
The"parentselectors"operatorhasavarietyofuses.Basicallyanytimeyouneedtheselectorsofthenestedrulestobecombinedinotherwaysthanthedefault.Forexampleanothertypicaluseofthe&istoproducerepetitiveclassnames:
.button{
&-ok{
background-image:url("ok.png");
}
&-cancel{
background-image:url("cancel.png");
}
&-custom{
background-image:url("custom.png");
}
}
output:
.button-ok{
background-image:url("ok.png");
}
.button-cancel{
background-image:url("cancel.png");
}
.button-custom{
background-image:url("custom.png");
}
Multiple&
&mayappearmorethanoncewithinaselector.Thismakesitpossibletorepeatedlyrefertoaparentselectorwithoutrepeatingitsname.
.link{
&+&{
color:red;
}
&&{
color:green;
}
&&{
color:blue;
}
&,&ish{
color:cyan;
}
}
willoutput:
.link+.link{
color:red;
}
.link.link{
color:green;
}
.link.link{
color:blue;
}
.link,.linkish{
color:cyan;
}
Notethat&representsallparentselectors(notjustthenearestancestor)sothefollowingexample:
.grand{
.parent{
&>&{
color:red;
}
&&{
color:green;
}
&&{
color:blue;
}
&,&ish{
color:cyan;
}
}
}
resultsin:
.grand.parent>.grand.parent{
color:red;
}
.grand.parent.grand.parent{
color:green;
}
.grand.parent.grand.parent{
color:blue;
}
.grand.parent,
.grand.parentish{
color:cyan;
}
ChangingSelectorOrder
Itcanbeusefultoprependaselectortotheinherited(parent)selectors.Thiscanbedonebyputtingthe&aftercurrentselector.
Forexample,whenusingModernizr,youmightwanttospecifydifferentrulesbasedonsupportedfeatures:
.header{
.menu{
border-radius:5px;
.no-borderradius&{
background-image:url('images/button-background.png');
}
}
}
Theselector.no-borderradius&willprepend.no-borderradiustoitsparent.header.menutoformthe.no-borderradius.header.menuonoutput:
.header.menu{
border-radius:5px;
}
.no-borderradius.header.menu{
background-image:url('images/button-background.png');
}
CombinatorialExplosion
&canalsobeusedtogenerateeverypossiblepermutationofselectorsinacommaseparatedlist:
p,a,ul,li{
border-top:2pxdotted#366;
&+&{
border-top:0;
}
}
Thisexpandstoallpossible(16)combinationsofthespecifiedelements:
p,
a,
ul,
li{
border-top:2pxdotted#366;
}
p+p,
p+a,
p+ul,
p+li,
a+p,
a+a,
a+ul,
a+li,
ul+p,
ul+a,
ul+ul,
ul+li,
li+p,
li+a,
li+ul,
li+li{
border-top:0;
}
Extend
Editthemarkdownsourcefor"extend"
ExtendisaLesspseudo-classwhichmergestheselectoritisputonwithonesthatmatchwhatitreferences.
Releasedv1.4.0
navul{
&:extend(.inline);
background:blue;
}
Intherulesetabove,the:extendselectorwillapplythe"extendingselector"(navul)ontothe.inlineclasswhereverthe.inlineclassappears.Thedeclarationblockwillbekeptas-is,butwithoutanyreferencetotheextend(becauseextendisn'tcss).
Sothefollowing:
navul{
&:extend(.inline);
background:blue;
}
.inline{
color:red;
}
Outputs
navul{
background:blue;
}
.inline,
navul{
color:red;
}
Noticehowthenavul:extend(.inline)selectorgetsoutputasnavul-theextendgetsremovedbeforeoutputandtheselectorblockleftas-is.Ifnopropertiesareputinthatblockthenitgetsremovedfromtheoutput(buttheextendstillmayaffectotherselectors).
ExtendSyntax
Theextendiseitherattachedtoaselectororplacedintoaruleset.Itlookslikeapseudo-classwithselectorparameteroptionallyfollowedbythekeywordall:
Example:
.a:extend(.b){}
//theaboveblockdoesthesamethingasthebelowblock
.a{
&:extend(.b);
}
.c:extend(.dall){
//extendsallinstancesof".d"e.g.".x.d"or".d.x"
}
.c:extend(.d){
//extendsonlyinstanceswheretheselectorwillbeoutputasjust".d"
}
Itcancontainoneormoreclassestoextend,separatedbycommas.
Example:
.e:extend(.f){}
.e:extend(.g){}
//theaboveandthebelowdothesamething
.e:extend(.f,.g){}
ExtendAttachedtoSelector
Extendattachedtoaselectorlookslikeanordinarypseudo-classwithselectorasaparameter.Aselectorcancontainmultipleextendclauses,butallextendsmustbeattheendoftheselector.
Extendaftertheselector:pre:hover:extend(divpre).
Spacebetweenselectorandextendisallowed:pre:hover:extend(divpre).
Multipleextendsareallowed:pre:hover:extend(divpre):extend(.buckettr)-Notethisisthesameaspre:hover:extend(divpre,.buckettr)
ThisisNOTallowed:pre:hover:extend(divpre).nth-child(odd).Extendmustbelast.
Ifarulesetcontainsmultipleselectors,anyofthemcanhavetheextendkeyword.Multipleselectorswithextendinoneruleset:
.big-division,
.big-bag:extend(.bag),
.big-bucket:extend(.bucket){
//body
}
ExtendInsideRuleset
Extendcanbeplacedintoaruleset'sbodyusing&:extend(selector)syntax.Placingextendintoabodyisashortcutforplacingitintoeverysingleselectorofthatruleset.
Extendinsideabody:
pre:hover,
.some-class{
&:extend(divpre);
}
isexactlythesameasaddinganextendaftereachselector:
pre:hover:extend(divpre),
.some-class:extend(divpre){}
ExtendingNestedSelectors
Extendisabletomatchnestedselectors.Followingless:
Example:
.bucket{
tr{//nestedrulesetwithtargetselector
color:blue;
}
}
.some-class:extend(.buckettr){}//nestedrulesetisrecognized
Outputs
.buckettr,
.some-class{
color:blue;
}
Essentiallytheextendlooksatthecompiledcss,nottheoriginalless.
Example:
.bucket{
tr&{//nestedrulesetwithtargetselector
color:blue;
}
}
.some-class:extend(tr.bucket){}//nestedrulesetisrecognized
Outputs
tr.bucket,
.some-class{
color:blue;
}
ExactMatchingwithExtend
Extendbydefaultlooksforexactmatchbetweenselectors.Itdoesmatterwhetherselectorusesleadingstarornot.Itdoesnotmatterthattwonth-expressionshavethesamemeaning,theyneedtohavetosameforminordertobematched.Theonlyexceptionarequotesinattributeselector,lessknowstheyhavethesamemeaningandmatchesthem.
Example:
.a.class,
.class.a,
.class>.a{
color:blue;
}
.test:extend(.class){}//thiswillNOTmatchtheanyselectorsabove
Leadingstardoesmatter.Selectors*.classand.classareequivalent,butextendwillnotmatchthem:
*.class{
color:blue;
}
.noStar:extend(.class){}//thiswillNOTmatchthe*.classselector
Outputs
*.class{
color:blue;
}
Orderofpseudo-classesdoesmatter.Selectorslink:hover:visitedandlink:visited:hovermatchthesamesetofelements,butextendtreatsthemasdifferent:
link:hover:visited{
color:blue;
}
.selector:extend(link:visited:hover){}
Outputs
link:hover:visited{
color:blue;
}
nthExpression
Nthexpressionformdoesmatter.Nth-expressions1n+3andn+3areequivalent,butextendwillnotmatchthem:
:nth-child(1n+3){
color:blue;
}
.child:extend(:nth-child(n+3)){}
Outputs
:nth-child(1n+3){
color:blue;
}
Quotetypeinattributeselectordoesnotmatter.Allofthefollowingareequivalent.
[title=identifier]{
color:blue;
}
[title='identifier']{
color:blue;
}
[title="identifier"]{
color:blue;
}
.noQuote:extend([title=identifier]){}
.singleQuote:extend([title='identifier']){}
.doubleQuote:extend([title="identifier"]){}
Outputs
[title=identifier],
.noQuote,
.singleQuote,
.doubleQuote{
color:blue;
}
[title='identifier'],
.noQuote,
.singleQuote,
.doubleQuote{
color:blue;
}
[title="identifier"],
.noQuote,
.singleQuote,
.doubleQuote{
color:blue;
}
Extend"all"
WhenyouspecifytheallkeywordlastinanextendargumentittellsLesstomatchthatselectoraspartofanotherselector.Theselectorwillbecopiedandthematchedpartoftheselectoronlywillthenbereplacedwiththeextend,makinganewselector.
Example:
.a.b.test,
.test.c{
color:orange;
}
.test{
&:hover{
color:green;
}
}
.replacement:extend(.testall){}
Outputs
.a.b.test,
.test.c,
.a.b.replacement,
.replacement.c{
color:orange;
}
.test:hover,
.replacement:hover{
color:green;
}
Youcanthinkofthismodeofoperationasessentiallydoinganon-destructivesearchandreplace.
SelectorInterpolationwithExtend
Extendisnotabletomatchselectorswithvariables.Ifselectorcontainsvariable,extendwillignoreit.
However,extendcanbeattachedtointerpolatedselector.
Selectorwithvariablewillnotbematched:
@variable:.bucket;
@{variable}{//interpolatedselector
color:blue;
}
.some-class:extend(.bucket){}//doesnothing,nomatchisfound
andextendwithvariableintargetselectormatchesnothing:
.bucket{
color:blue;
}
.some-class:extend(@{variable}){}//interpolatedselectormatchesnothing
@variable:.bucket;
Bothoftheaboveexamplescompileinto:
.bucket{
color:blue;
}
However,:extendattachedtoaninterpolatedselectorworks:
.bucket{
color:blue;
}
@{variable}:extend(.bucket){}
@variable:.selector;
compilesto:
.bucket,.selector{
color:blue;
}
Scoping/ExtendInside@media
Currently,an:extendinsidea@mediadeclarationwillonlymatchselectorsinsidethesamemediadeclaration:
@mediaprint{
.screenClass:extend(.selector){}//extendinsidemedia
.selector{//thiswillbematched-itisinthesamemedia
color:black;
}
}
.selector{//rulesetontopofstylesheet-extendignoresit
color:red;
}
@mediascreen{
.selector{//rulesetinsideanothermedia-extendignoresit
color:blue;
}
}
compilesinto:
@mediaprint{
.selector,
.screenClass{/*rulesetinsidethesamemediawasextended*/
color:black;
}
}
.selector{/*rulesetontopofstylesheetwasignored*/
color:red;
}
@mediascreen{
.selector{/*rulesetinsideanothermediawasignored*/
color:blue;
}
}
Note:extendingdoesnotmatchselectorsinsideanested@mediadeclaration:
@mediascreen{
.screenClass:extend(.selector){}//extendinsidemedia
@media(min-width:1023px){
.selector{//rulesetinsidenestedmedia-extendignoresit
color:blue;
}
}
}
Thiscompilesinto:
@mediascreenand(min-width:1023px){
.selector{/*rulesetinsideanothernestedmediawasignored*/
color:blue;
}
}
Toplevelextendmatcheseverythingincludingselectorsinsidenestedmedia:
@mediascreen{
.selector{/*rulesetinsidenestedmedia-toplevelextendworks*/
color:blue;
}
@media(min-width:1023px){
.selector{/*rulesetinsidenestedmedia-toplevelextendworks*/
color:blue;
}
}
}
.topLevel:extend(.selector){}/*toplevelextendmatcheseverything*/
compilesinto:
@mediascreen{
.selector,
.topLevel{/*rulesetinsidemediawasextended*/
color:blue;
}
}
@mediascreenand(min-width:1023px){
.selector,
.topLevel{/*rulesetinsidenestedmediawasextended*/
color:blue;
}
}
DuplicationDetection
Currentlythereisnoduplicationdetection.
Example:
.alert-info,
.widget{
/*declarations*/
}
.alert:extend(.alert-info,.widget){}
Outputs
.alert-info,
.widget,
.alert,
.alert{
/*declarations*/
}
UseCasesforExtend
ClassicUseCase
Theclassicusecaseistoavoidaddingabaseclass.Forexample,ifyouhave
.animal{
background-color:black;
color:white;
}
andyouwanttohaveasubtypeofanimalwhichoverridesthebackgroundcolorthenyouhavetwooptions,firstlychangeyourHTML
Bear
.animal{
background-color:black;
color:white;
}
.bear{
background-color:brown;
}
orhavesimplifiedhtmlanduseextendinyourless.e.g.
Bear
.animal{
background-color:black;
color:white;
}
.bear{
&:extend(.animal);
background-color:brown;
}
ReducingCSSSize
Mixinscopyallofthepropertiesintoaselector,whichcanleadtounnecessaryduplication.Thereforeyoucanuseextendsinsteadofmixinstomovetheselectoruptothepropertiesyouwishtouse,whichleadstolessCSSbeinggenerated.
Example-withmixin:
.my-inline-block(){
display:inline-block;
font-size:0;
}
.thing1{
.my-inline-block;
}
.thing2{
.my-inline-block;
}
Outputs
.thing1{
display:inline-block;
font-size:0;
}
.thing2{
display:inline-block;
font-size:0;
}
Example(withextends):
.my-inline-block{
display:inline-block;
font-size:0;
}
.thing1{
&:extend(.my-inline-block);
}
.thing2{
&:extend(.my-inline-block);
}
Outputs
.my-inline-block,
.thing1,
.thing2{
display:inline-block;
font-size:0;
}
CombiningStyles/AMoreAdvancedMixin
Anotheruse-caseisasanalternativeforamixin-becausemixinscanonlybeusedwithsimpleselectors,ifyouhavetwodifferentblocksofhtml,butneedtoapplythesamestylestobothyoucanuseextendstorelatetwoareas.
Example:
li.list>a{
//liststyles
}
button.list-style{
&:extend(li.list>a);//usethesameliststyles
}
Merge
Editthemarkdownsourcefor"merge"
Combineproperties
Themergefeatureallowsforaggregatingvaluesfrommultiplepropertiesintoacommaorspaceseparatedlistunderasingleproperty.mergeisusefulforpropertiessuchasbackgroundandtransform.
Comma
Appendpropertyvaluewithcomma
Releasedv1.5.0
Example:
.mixin(){
box-shadow+:inset0010px#555;
}
.myclass{
.mixin();
box-shadow+:0020pxblack;
}
Outputs
.myclass{
box-shadow:inset0010px#555,0020pxblack;
}
Space
Appendpropertyvaluewithspace
Releasedv1.7.0
Example:
.mixin(){
transform+_:scale(2);
}
.myclass{
.mixin();
transform+_:rotate(15deg);
}
Outputs
.myclass{
transform:scale(2)rotate(15deg);
}
Toavoidanyunintentionaljoins,mergerequiresanexplicit+or+_flagoneachjoinpendingdeclaration.
Mixins
Editthemarkdownsourcefor"mixins"
"mix-in"propertiesfromexistingstyles
Youcanmix-inclassselectorsandidselectors,e.g.
.a,#b{
color:red;
}
.mixin-class{
.a();
}
.mixin-id{
#b();
}
whichresultsin:
.a,#b{
color:red;
}
.mixin-class{
color:red;
}
.mixin-id{
color:red;
}
Currentlyandhistorically,theparenthesesinamixincallareoptional,butoptionalparenthesesaredeprecatedandwillberequiredinafuturerelease.
.a();
.a;//currentlyworks,butdeprecated;don'tuse
NotOutputtingtheMixin
IfyouwanttocreateamixinbutyoudonotwantthatmixintobeinyourCSSoutput,putparenthesesafterthemixindefinition.
.my-mixin{
color:black;
}
.my-other-mixin(){
background:white;
}
.class{
.my-mixin();
.my-other-mixin();
}
outputs
.my-mixin{
color:black;
}
.class{
color:black;
background:white;
}
SelectorsinMixins
Mixinscancontainmorethanjustproperties,theycancontainselectorstoo.
Forexample:
.my-hover-mixin(){
&:hover{
border:1pxsolidred;
}
}
button{
.my-hover-mixin();
}
Outputs
button:hover{
border:1pxsolidred;
}
Namespaces
Ifyouwanttomixinpropertiesinsideamorecomplicatedselector,youcanstackupmultipleid'sorclasses.
#outer(){
.inner{
color:red;
}
}
.c{
#outer>.inner();
}
Both>andwhitespaceareoptional
//alldothesamething
#outer>.inner();
#outer.inner();
#outer.inner();
Namespacingyourmixinslikereducesconflictwithotherlibrarymixinsorusermixins,butitcanalsobeawayto"organize"groupsofmixins.
Example:
#my-library{
.my-mixin(){
color:black;
}
}
//whichcanbeusedlikethis
.class{
#my-library.my-mixin();
}
GuardedNamespaces
Ifanamespacehasaguard,mixinsdefinedbyitareusedonlyiftheguardconditionreturnstrue.Anamespaceguardisevaluatedexactlythesamewayasaguardonmixin,sothefollowingtwomixinsworkthesameway:
#namespacewhen(@mode=huge){
.mixin(){/**/}
}
#namespace{
.mixin()when(@mode=huge){/**/}
}
Thedefaultfunctionisassumedtohavethesamevalueforallnestednamespacesandmixin.Followingmixinisneverevaluated,oneofitsguardsisguaranteedtobefalse:
#sp_1when(default()){
#sp_2when(default()){
.mixin()whennot(default()){/**/}
}
}
The!importantkeyword
Usethe!importantkeywordaftermixincalltomarkallpropertiesinheritedbyitas!important:
Example:
.foo(@bg:#f5f5f5,@color:#900){
background:@bg;
color:@color;
}
.unimportant{
.foo();
}
.important{
.foo()!important;
}
Resultsin:
.unimportant{
background:#f5f5f5;
color:#900;
}
.important{
background:#f5f5f5!important;
color:#900!important;
}
ParametricMixins
Editthemarkdownsourcefor"mixins-parametric"
Howtopassargumentstomixins
Mixinscanalsotakearguments,whicharevariablespassedtotheblockofselectorswhenitismixedin.
Forexample:
.border-radius(@radius){
-webkit-border-radius:@radius;
-moz-border-radius:@radius;
border-radius:@radius;
}
Andhere'showwecanmixitintovariousrulesets:
#header{
.border-radius(4px);
}
.button{
.border-radius(6px);
}
Parametricmixinscanalsohavedefaultvaluesfortheirparameters:
.border-radius(@radius:5px){
-webkit-border-radius:@radius;
-moz-border-radius:@radius;
border-radius:@radius;
}
Wecaninvokeitlikethisnow:
#header{
.border-radius();
}
Anditwillincludea5pxborder-radius.
Youcanalsouseparametricmixinswhichdon'ttakeparameters.ThisisusefulifyouwanttohidetherulesetfromtheCSSoutput,butwanttoincludeitspropertiesinotherrulesets:
.wrap(){
text-wrap:wrap;
white-space:-moz-pre-wrap;
white-space:pre-wrap;
word-wrap:break-word;
}
pre{.wrap()}
Whichwouldoutput:
pre{
text-wrap:wrap;
white-space:-moz-pre-wrap;
white-space:pre-wrap;
word-wrap:break-word;
}
MixinswithMultipleParameters
Parametersareeithersemicolonorcommaseparated.Itisrecommendedtousesemicolon.Thesymbolcommahasdoublemeaning:itcanbeinterpretedeitherasamixinparametersseparatororcsslistseparator.
Usingcommaasmixinseparatormakesitimpossibletocreatecommaseparatedlistsasanargument.Ontheotherhand,ifthecompilerseesatleastonesemicoloninsidemixincallordeclaration,itassumesthatargumentsareseparatedbysemicolonsandallcommasbelongtocsslists:
twoargumentsandeachcontainscommaseparatedlist:.name(1,2,3;something,else),
threeargumentsandeachcontainsonenumber:.name(1,2,3),
usedummysemicolontocreatemixincallwithoneargumentcontainingcommaseparatedcsslist:.name(1,2,3;),
commaseparateddefaultvalue:.name(@param1:red,blue;).
Itislegaltodefinemultiplemixinswiththesamenameandnumberofparameters.Lesswillusepropertiesofallthatcanapply.Ifyouusedthemixinwithoneparametere.g..mixin(green);,thenpropertiesofallmixinswithexactlyonemandatoryparameterwillbeused:
.mixin(@color){
color-1:@color;
}
.mixin(@color;@padding:2){
color-2:@color;
padding-2:@padding;
}
.mixin(@color;@padding;@margin:2){
color-3:@color;
padding-3:@padding;
margin:@margin@margin@margin@margin;
}
.some.selectordiv{
.mixin(#008000);
}
compilesinto:
.some.selectordiv{
color-1:#008000;
color-2:#008000;
padding-2:2;
}
NamedParameters
Amixinreferencecansupplyparametersvaluesbytheirnamesinsteadofjustpositions.Anyparametercanbereferencedbyitsnameandtheydonothavetobeinanyspecialorder:
.mixin(@color:black;@margin:10px;@padding:20px){
color:@color;
margin:@margin;
padding:@padding;
}
.class1{
.mixin(@margin:20px;@color:#33acfe);
}
.class2{
.mixin(#efca44;@padding:40px);
}
compilesinto:
.class1{
color:#33acfe;
margin:20px;
padding:20px;
}
.class2{
color:#efca44;
margin:10px;
padding:40px;
}
The@argumentsVariable
@argumentshasaspecialmeaninginsidemixins,itcontainsalltheargumentspassed,whenthemixinwascalled.Thisisusefulifyoudon'twanttodealwithindividualparameters:
.box-shadow(@x:0;@y:0;@blur:1px;@color:#000){
-webkit-box-shadow:@arguments;
-moz-box-shadow:@arguments;
box-shadow:@arguments;
}
.big-block{
.box-shadow(2px;5px);
}
Whichresultsin:
.big-block{
-webkit-box-shadow:2px5px1px#000;
-moz-box-shadow:2px5px1px#000;
box-shadow:2px5px1px#000;
}
AdvancedArgumentsandthe@restVariable
Youcanuse...ifyouwantyourmixintotakeavariablenumberofarguments.Usingthisafteravariablenamewillassignthoseargumentstothevariable.
.mixin(...){//matches0-Narguments
.mixin(){//matchesexactly0arguments
.mixin(@a:1){//matches0-1arguments
.mixin(@a:1;...){//matches0-Narguments
.mixin(@a;...){//matches1-Narguments
Furthermore:
.mixin(@a;@rest...){
//@restisboundtoargumentsafter@a
//@argumentsisboundtoallarguments
}
Pattern-matching
Sometimes,youmaywanttochangethebehaviorofamixin,basedontheparametersyoupasstoit.Let'sstartwithsomethingbasic:
.mixin(@s;@color){...}
.class{
.mixin(@switch;#888);
}
Nowlet'ssaywewant.mixintobehavedifferently,basedonthevalueof@switch,wecoulddefine.mixinassuch:
.mixin(dark;@color){
color:darken(@color,10%);
}
.mixin(light;@color){
color:lighten(@color,10%);
}
.mixin(@_;@color){
display:block;
}
Now,ifwerun:
@switch:light;
.class{
.mixin(@switch;#888);
}
WewillgetthefollowingCSS:
.class{
color:#a2a2a2;
display:block;
}
Wherethecolorpassedto.mixinwaslightened.Ifthevalueof@switchwasdark,
theresultwouldbeadarkercolor.
Here'swhathappened:
Thefirstmixindefinitiondidn'tmatchbecauseitexpecteddarkasthefirstargument.
Thesecondmixindefinitionmatched,becauseitexpectedlight.
Thethirdmixindefinitionmatchedbecauseitexpectedanyvalue.
Onlymixindefinitionswhichmatchedwereused.Variablesmatchandbindtoanyvalue.
Anythingotherthanavariablematchesonlywithavalueequaltoitself.
Wecanalsomatchonarity,here'sanexample:
.mixin(@a){
color:@a;
}
.mixin(@a;@b){
color:fade(@a;@b);
}
Nowifwecall.mixinwithasingleargument,wewillgettheoutputofthefirstdefinition,
butifwecallitwithtwoarguments,wewillgettheseconddefinition,namely@afadedto@b.
UsingMixinsasFunctions
Editthemarkdownsourcefor"mixins-as-functions"
Selectingpropertiesandvariablesfrommixincalls
Property/valueaccessors
Releasedv3.5.0
StartinginLess3.5,youcanuseproperty/variableaccessorstoselectavaluefromanevaluatedmixin'srules.Thiscanallowyoutousemixinssimilartofunctions.
Example:
.average(@x,@y){
@result:((@x+@y)/2);
}
div{
//callamixinandlookupits"@result"value
padding:.average(16px,50px)[@result];
}
Resultsin:
div{
padding:33px;
}
Overridingmixinvalues
Ifyouhavemultiplematchingmixins,allrulesareevaluatedandmerged,andthelastmatchingvaluewiththatidentifierisreturned.ThisissimilartothecascadeinCSS,anditallowsyouto"override"mixinvalues.
//library.less
#library(){
.mixin(){
prop:foo;
}
}
//customize.less
@import"library";
#library(){
.mixin(){
prop:bar;
}
}
.box{
my-value:#library.mixin[prop];
}
Outputs:
.box{
my-value:bar;
}
Unnamedlookups
Ifyoudon'tspecifyalookupvaluein[@lookup]andinsteadwrite[]afteramixinorrulesetcall,allvalueswillcascadeandthelastdeclaredvaluewillbeselected.
Meaning:theaveragingmixinfromtheaboveexamplecouldbewrittenas:
.average(@x,@y){
@result:((@x+@y)/2);
}
div{
//callamixinandlookupitsfinalvalue
padding:.average(16px,50px)[];
}
Theoutputisthesame:
div{
padding:33px;
}
Thesamecascadingbehavioristrueforrulesetsorvariablesaliasedtomixincalls.
@dr:{
value:foo;
}
.box{
my-value:@dr[];
}
Thisoutputs:
.box{
my-value:foo;
}
Unlockingmixins&variablesintocallerscope
DEPRECATED-UseProperty/ValueAccessors
Variablesandmixinsdefinedinamixinarevisibleandcanbeusedincaller'sscope.Thereisonlyoneexception:avariableisnotcopiedifthecallercontainsavariablewiththesamename(thatincludesvariablesdefinedbyanothermixincall).Onlyvariablespresentincallerslocalscopeareprotected.Variablesinheritedfromparentscopesareoverridden.
Note:thisbehaviorisdeprecated,andinthefuture,variablesandmixinswillnotbemergedintothecallerscopeinthisway.
Example:
.mixin(){
@width:100%;
@height:200px;
}
.caller{
.mixin();
width:@width;
height:@height;
}
Resultsin:
.caller{
width:100%;
height:200px;
}
Variablesdefineddirectlyincallersscopecannotbeoverridden.However,variablesdefinedincallersparentscopeisnotprotectedandwillbeoverridden:
.mixin(){
@size:in-mixin;
@definedOnlyInMixin:in-mixin;
}
.class{
margin:@size@definedOnlyInMixin;
.mixin();
}
@size:globaly-defined-value;//callersparentscope-noprotection
Resultsin:
.class{
margin:in-mixinin-mixin;
}
Finally,mixindefinedinmixinactsasreturnvaluetoo:
.unlock(@value){//outermixin
.doSomething(){//nestedmixin
declaration:@value;
}
}
#namespace{
.unlock(5);//unlockdoSomethingmixin
.doSomething();//nestedmixinwascopiedhereandisusable
}
Resultsin:
#namespace{
declaration:5;
}
RecursiveMixins
Editthemarkdownsourcefor"mixin-loops"
Creatingloops
InLessamixincancallitself.Suchrecursivemixins,whencombinedwithGuardExpressionsandPatternMatching,canbeusedtocreatevariousiterative/loopstructures.
Example:
.loop(@counter)when(@counter>0){
.loop((@counter-1));//nextiteration
width:(10px*@counter);//codeforeachiteration
}
div{
.loop(5);//launchtheloop
}
Output:
div{
width:10px;
width:20px;
width:30px;
width:40px;
width:50px;
}
AgenericexampleofusingarecursivelooptogenerateCSSgridclasses:
.generate-columns(4);
.generate-columns(@n,@i:1)when(@i==50%){
background-color:black;
}
.mixin(@a)when(lightness(@a)<50%){
background-color:white;
}
.mixin(@a){
color:@a;
}
Thekeyisthewhenkeyword,whichintroducesaguardsequence(herewithonlyoneguard).Nowifwerunthefollowingcode:
.class1{.mixin(#ddd)}
.class2{.mixin(#555)}
Here'swhatwe'llget:
.class1{
background-color:black;
color:#ddd;
}
.class2{
background-color:white;
color:#555;
}
GuardComparisonOperators
Thefulllistofcomparisonoperatorsusableinguardsare:>,>=,=,=@b){width:@a}
.max(@a;@b)when(@a0){...}
Youcanemulatetheoroperatorbyseparatingguardswithacomma,.Ifanyoftheguardsevaluatetotrue,it'sconsideredamatch:
.mixin(@a)when(@a>10),(@a0){...}
TypeCheckingFunctions
Lastly,ifyouwanttomatchmixinsbasedonvaluetype,youcanusetheisfunctions:
.mixin(@a;@b:0)when(isnumber(@b)){...}
.mixin(@a;@b:black)when(iscolor(@b)){...}
Herearethebasictypecheckingfunctions:
iscolor
isnumber
isstring
iskeyword
isurl
Ifyouwanttocheckifavalueisinaspecificunitinadditiontobeinganumber,youmayuseoneof:
ispixel
ispercentage
isem
isunit
AliasingMixins
Editthemarkdownsourcefor"mixins-aliasing"
Releasedv3.5.0
Assigningmixincallstoavariable
Mixinscanbeassignedtoavariabletobecalledasavariablecall,orcanbeusedformaplookup.
#theme.dark.navbar{
.colors(light){
primary:purple;
}
.colors(dark){
primary:black;
secondary:grey;
}
}
.navbar{
@colors:#theme.dark.navbar.colors(dark);
background:@colors[primary];
border:1pxsolid@colors[secondary];
}
Thiswouldoutput:
.navbar{
background:black;
border:1pxsolidgrey;
}
Variablecalls
Entiremixincallscanbealiasedandcalledasvariablecalls.Asin:
#library(){
.rules(){
background:green;
}
}
.box{
@alias:#library.rules();
@alias();
}
Outputs:
.box{
background:green;
}
Note,unlikemixinsusedinroot,mixincallsassignedtovariablesandcalledwithnoargumentsalwaysrequireparentheses.Thefollowingisnotvalid.
#library(){
.rules(){
background:green;
}
}
.box{
@alias:#library.colors;
@alias();//ERROR:Couldnotevaluatevariablecall@alias
}
Thisisbecauseit'sambiguousifvariableisassignedalistofselectorsoramixincall.Forexample,inLess3.5+,thisvariablecouldbeusedthisway.
.box{
@alias:#library.colors;
@{alias}{
a:b;
}
}
Theabovewouldoutput:
.box#library.colors{
a:b;
}
CSSGuards
Editthemarkdownsourcefor"css-guards"
"if"'saroundselectors
Releasedv1.5.0
LikeMixinGuards,guardscanalsobeappliedtocssselectors,whichissyntacticsugarfordeclaringthemixinandthencallingitimmediately.
Forinstance,before1.5.0youwouldhavehadtodothis:
.my-optional-style()when(@my-option=true){
button{
color:white;
}
}
.my-optional-style();
Now,youcanapplytheguarddirectlytoastyle.
buttonwhen(@my-option=true){
color:white;
}
Youcanalsoachieveaniftypestatementbycombiningthiswiththe&feature,allowingyoutogroupmultipleguards.
&when(@my-option=true){
button{
color:white;
}
a{
color:blue;
}
}
Notethatyoucanalsoachieveasimilarpatternbyusingtheactualif()functionandavariablecall.Asin:
@dr:if(@my-option=true,{
button{
color:white;
}
a{
color:blue;
}
});
@dr();
DetachedRulesets
Editthemarkdownsourcefor"detached-rulesets"
Assignarulesettoavariable
Releasedv1.7.0
Adetachedrulesetisagroupofcssproperties,nestedrulesets,mediadeclarationsoranythingelsestoredinavariable.Youcanincludeitintoarulesetoranotherstructureandallitspropertiesaregoingtobecopiedthere.Youcanalsouseitasamixinargumentandpassitaroundasanyothervariable.
Simpleexample:
//declaredetachedruleset
@detached-ruleset:{background:red;};//semi-colonisoptionalin3.5.0+
//usedetachedruleset
.top{
@detached-ruleset();
}
compilesinto:
.top{
background:red;
}
Parenthesesafteradetachedrulesetcallaremandatory(exceptwhenfollowedbyalookupvalue).Thecall@detached-ruleset;wouldnotwork.
Itisusefulwhenyouwanttodefineamixinthatabstractsouteitherwrappingapieceofcodeinamediaqueryoranon-supportedbrowserclassname.Therulesetscanbepassedtomixinsothatthemixincanwrapthecontent,e.g.
.desktop-and-old-ie(@rules){
@mediascreenand(min-width:1200px){@rules();}
html.lt-ie9&{@rules();}
}
header{
background-color:blue;
.desktop-and-old-ie({
background-color:red;
});
}
Herethedesktop-and-old-iemixindefinesthemediaqueryandrootclasssothatyoucanuseamixintowrapapieceofcode.Thiswilloutput
header{
background-color:blue;
}
@mediascreenand(min-width:1200px){
header{
background-color:red;
}
}
html.lt-ie9header{
background-color:red;
}
ArulesetcanbenowassignedtoavariableorpassedintoamixinandcancontainthefullsetofLessfeatures,e.g.
@my-ruleset:{
.my-selector{
background-color:black;
}
};
Youcaneventakeadvantageofmediaquerybubbling,forinstance
@my-ruleset:{
.my-selector{
@mediatv{
background-color:black;
}
}
};
@media(orientation:portrait){
@my-ruleset();
}
whichwilloutput
@media(orientation:portrait)andtv{
.my-selector{
background-color:black;
}
}
Adetachedrulesetcallunlocks(returns)allitsmixinsintocallerthesamewayasmixincallsdo.However,itdoesnotreturnvariables.
Returnedmixin:
//detachedrulesetwithamixin
@detached-ruleset:{
.mixin(){
color:blue;
}
};
//calldetachedruleset
.caller{
@detached-ruleset();
.mixin();
}
Resultsin:
.caller{
color:blue;
}
Privatevariables:
@detached-ruleset:{
@color:blue;//thisvariableisprivate
};
.caller{
color:@color;//syntaxerror
}
Scoping
Adetachedrulesetcanuseallvariablesandmixinsaccessiblewhereitisdefinedandwhereitiscalled.Otherwisesaid,bothdefinitionandcallerscopesareavailabletoit.Ifbothscopescontainsthesamevariableormixin,declarationscopevaluetakesprecedence.
Declarationscopeistheonewheredetachedrulesetbodyisdefined.Copyingadetachedrulesetfromonevariableintoanothercannotmodifyitsscope.Therulesetdoesnotgainaccesstonewscopesjustbybeingreferencedthere.
Lastly,adetachedrulesetcangainaccesstoscopebybeingunlocked(imported)intoit.
Note:unlockingvariablesintoscopeviaacalledmixinisdeprecated.Useproperty/variableaccessors.
DefinitionandCallerScopeVisibility
Adetachedrulesetseesthecaller'svariablesandmixins:
@detached-ruleset:{
caller-variable:@caller-variable;//variableisundefinedhere
.caller-mixin();//mixinisundefinedhere
};
selector{
//usedetachedruleset
@detached-ruleset();
//definevariableandmixinneededinsidethedetachedruleset
@caller-variable:value;
.caller-mixin(){
variable:declaration;
}
}
compilesinto:
selector{
caller-variable:value;
variable:declaration;
}
Variableandmixinsaccessiblefromdefinitionwinoverthoseavailableinthecaller:
@variable:global;
@detached-ruleset:{
//willuseglobalvariable,becauseitisaccessible
//fromdetached-rulesetdefinition
variable:@variable;
};
selector{
@detached-ruleset();
@variable:value;//variabledefinedincaller-willbeignored
}
compilesinto:
selector{
variable:global;
}
ReferencingWon'tModifyDetachedRulesetScope
Arulesetdoesnotgainaccesstonewscopesjustbybeingreferencedthere:
@detached-1:{scope-detached:@one@two;};
.one{
@one:visible;
.two{
@detached-2:@detached-1;//copying/renamingruleset
@two:visible;//rulesetcannotseethisvariable
}
}
.use-place{
.one>.two();
@detached-2();
}
throwsanerror:
ERROR1:32Thevariable"@one"wasnotdeclared.
UnlockingWillModifyDetachedRulesetScope
Adetachedrulesetgainsaccessbybeingunlocked(imported)insideascope:
#space{
.importer-1(){
@detached:{scope-detached:@variable;};//definedetachedruleset
}
}
.importer-2(){
@variable:value;//unlockeddetachedrulesetCANseethisvariable
#space>.importer-1();//unlock/importdetachedruleset
}
.use-place{
.importer-2();//unlock/importdetachedrulesetsecondtime
@detached();
}
compilesinto:
.use-place{
scope-detached:value;
}
Property/variableaccessors
(Lookupvalues)
Releasedv3.5.0
StartinginLess3.5,youcanuseproperty/variableaccessors(alsocalled"lookups")toselectavaluefromvariable(detached)rulesets.
@config:{
option1:true;
option2:false;
}
.mixin()when(@config[option1]=true){
selected:value;
}
.box{
.mixin();
}
Outputs:
.box{
selected:value;
}
Ifwhatisreturnedfromalookupisanotherdetachedruleset,youcanuseasecondlookuptogetthatvalue.
@config:{
@colors:{
primary:blue;
}
}
.box{
color:@config[@colors][primary];
}
Variablevariablesinlookups
Thelookupvaluethatisreturnedcanitselfbevariable.Asin,youcanwrite:
@config:{
@dark:{
primary:darkblue;
}
@light:{
primary:lightblue;
}
}
.box{
@lookup:dark;
color:@config[@@lookup][primary];
}
Thiswilloutput:
.box{
color:darkblue;
}
@importAt-Rules
Editthemarkdownsourcefor"imports"
Importstylesfromotherstylesheets
InstandardCSS,@importat-rulesmustprecedeallothertypesofrules.ButLessdoesn'tcarewhereyouput@importstatements.
Example:
.foo{
background:#900;
}
@import"this-is-valid.less";
FileExtensions
@importstatementsmaybetreateddifferentlybyLessdependingonthefileextension:
Ifthefilehasa.cssextensionitwillbetreatedasCSSandthe@importstatementleftas-is(seetheinlineoptionbelow).
IfithasanyotherextensionitwillbetreatedasLessandimported.
Ifitdoesnothaveanextension,.lesswillbeappendedanditwillbeincludedasaimportedLessfile.
Examples:
@import"foo";//foo.lessisimported
@import"foo.less";//foo.lessisimported
@import"foo.php";//foo.phpimportedasaLessfile
@import"foo.css";//statementleftinplace,as-is
Thefollowingoptionscanbeusedtooverridethisbehavior.
ImportOptions
LessoffersseveralextensionstotheCSS@importCSSat-ruletoprovidemoreflexibilityoverwhatyoucandowithexternalfiles.
Syntax:@import(keyword)"filename";
Thefollowingimportoptionshavebeenimplemented:
reference:useaLessfilebutdonotoutputit
inline:includethesourcefileintheoutputbutdonotprocessit
less:treatthefileasaLessfile,nomatterwhatthefileextension
css:treatthefileasaCSSfile,nomatterwhatthefileextension
once:onlyincludethefileonce(thisisdefaultbehavior)
multiple:includethefilemultipletimes
optional:continuecompilingwhenfileisnotfound
Morethanonekeywordper@importisallowed,youwillhavetousecommastoseparatethekeywords:
Example:@import(optional,reference)"foo.less";
reference
Use@import(reference)toimportexternalfiles,butwithoutaddingtheimportedstylestothecompiledoutputunlessreferenced.
Releasedv1.5.0
Example:@import(reference)"foo.less";
Imaginethatreferencemarkseveryat-ruleandselectorwithareferenceflagintheimportedfile,importsasnormal,butwhentheCSSisgenerated,"reference"selectors(aswellasanymediaqueriescontainingonlyreferenceselectors)arenotoutput.referencestyleswillnotshowupinyourgeneratedCSSunlessthereferencestylesareusedasmixinsorextended.
Additionally,referenceproducesdifferentresultsdependingonwhichmethodwasused(mixinorextend):
extend:Whenaselectorisextended,onlythenewselectorismarkedasnotreferenced,anditispulledinatthepositionofthereference@importstatement.
mixins:Whenareferencestyleisusedasanimplicitmixin,itsrulesaremixed-in,marked"notreference",andappearinthereferencedplaceasnormal.
referenceexample
Thisallowsyoutopullinonlyspecific,targetedstylesfromalibrarysuchasBootstrapbydoingsomethinglikethis:
.navbar:extend(.navbarall){}
Andyouwillpullinonly.navbarrelatedstylesfromBootstrap.
inline
Use@import(inline)toincludeexternalfiles,butnotprocessthem.
Releasedv1.5.0
Example:@import(inline)"not-less-compatible.css";
YouwillusethiswhenaCSSfilemaynotbeLesscompatible;thisisbecausealthoughLesssupportsmostknownstandardsCSS,itdoesnotsupportcommentsinsomeplacesanddoesnotsupportallknownCSShackswithoutmodifyingtheCSS.
SoyoucanusethistoincludethefileintheoutputsothatallCSSwillbeinonefile.
less
Use@import(less)totreatimportedfilesasLess,regardlessoffileextension.
Releasedv1.4.0
Example:
@import(less)"foo.css";
css
Use@import(css)totreatimportedfilesasregularCSS,regardlessoffileextension.Thismeanstheimportstatementwillbeleftasitis.
Releasedv1.4.0
Example:
@import(css)"foo.less";
outputs
@import"foo.less";
once
Thedefaultbehaviorof@importstatements.Itmeansthefileisimportedonlyonceandsubsequentimportstatementsforthatfilewillbeignored.
Releasedv1.4.0
Thisisthedefaultbehaviorof@importstatements.
Example:
@import(once)"foo.less";
@import(once)"foo.less";//thisstatementwillbeignored
multiple
Use@import(multiple)toallowimportingofmultiplefileswiththesamename.Thisistheoppositebehaviortoonce.
Releasedv1.4.0
Example:
//file:foo.less
.a{
color:green;
}
//file:main.less
@import(multiple)"foo.less";
@import(multiple)"foo.less";
Outputs
.a{
color:green;
}
.a{
color:green;
}
optional
Use@import(optional)toallowimportingofafileonlywhenitexists.WithouttheoptionalkeywordLessthrowsaFileErrorandstopscompilingwhenimportingafilethatcannotbefound.
Releasedv2.3.0
@pluginAt-Rules
Editthemarkdownsourcefor"plugins"
Releasedv2.5.0
ImportJavaScriptpluginstoaddLess.jsfunctionsandfeatures
Writingyourfirstplugin
Usinga@[email protected].
@plugin"my-plugin";//automaticallyappends.jsifnoextension
SinceLesspluginsareevaluatedwithintheLessscope,theplugindefinitioncanbequitesimple.
registerPlugin({
install:function(less,pluginManager,functions){
functions.add('pi',function(){
returnMath.PI;
});
}
})
oryoucanusemodule.exports(shimmedtoworkinbrowseraswellasNode.js).
module.exports={
install:function(less,pluginManager,functions){
functions.add('pi',function(){
returnMath.PI;
});
}
};
NotethatotherNode.jsCommonJSconventions,likerequire()arenotavailableinthebrowser.Keepthisinmindwhenwritingcross-platformplugins.
Whatcanyoudowithaplugin?Alot,butlet'sstartwiththebasics.We'llfocusfirstonwhatyoumightputinsidetheinstallfunction.Let'ssayyouwritethis:
//my-plugin.js
install:function(less,pluginManager,functions){
functions.add('pi',function(){
returnMath.PI;
});
}
//etc
Congratulations!You'vewrittenaLessplugin!
Ifyouweretousethisinyourstylesheet:
@plugin"my-plugin";
.show-me-pi{
value:pi();
}
Youwouldget:
.show-me-pi{
value:3.141592653589793;
}
However,youwouldneedtoreturnaproperLessnodeifyouwantedto,say,multiplythatagainstothervaluesordootherLessoperations.Otherwisetheoutputinyourstylesheetisplaintext(whichmaybefineforyourpurposes).
Meaning,thisismorecorrect:
functions.add('pi',function(){
returnnewtree.Dimension(Math.PI);
});
Note:Adimensionisanumberwithorwithoutaunit,like"10px",whichwouldbeless.Dimension(10,"px").Foralistofunits,seetheLessAPI.
Nowyoucanuseyourfunctioninoperations.
@plugin"my-plugin";
.show-me-pi{
value:pi()*2;
}
Youmayhavenoticedthatthereareavailableglobalsforyourpluginfile,namelyafunctionregistry(functionsobject),andthelessobject.Thesearethereforconvenience.
PluginScope
Functionsaddedbya@pluginat-ruleadherestoLessscopingrules.ThisisgreatforLesslibraryauthorsthatwanttoaddfunctionalitywithoutintroducingnamingconflicts.
Forinstance,sayyouhave2pluginsfromtwothird-partylibrariesthatbothhaveafunctionnamed"foo".
//lib1.js
//...
functions.add('foo',function(){
return"foo";
});
//...
//lib2.js
//...
functions.add('foo',function(){
return"bar";
});
//...
That'sok!Youcanchoosewhichlibrary'sfunctioncreateswhichoutput.
.el-1{
@plugin"lib1";
value:foo();
}
.el-2{
@plugin"lib2";
value:foo();
}
Thiswillproduce:
.el-1{
value:foo;
}
.el-2{
value:bar;
}
Forpluginauthorssharingtheirplugins,thatmeansyoucanalsoeffectivelymakeprivatefunctionsbyplacingtheminaparticularscope.Asin,thiswillcauseanerror:
.el{
@plugin"lib1";
}
@value:foo();
AsofLess3.0,functionscanreturnanykindofNodetype,andcanbecalledatanylevel.
Meaning,thiswouldthrowanerrorin2.x,asfunctionshadtobepartofthevalueofapropertyorvariableassignment:
.block{
color:blue;
my-function-rules();
}
In3.x,that'snolongerthecase,andfunctionscanreturnAt-Rules,Rulesets,anyotherLessnode,strings,andnumbers(thelattertwoareconvertedtoAnonymousnodes).
NullFunctions
Therearetimeswhenyoumaywanttocallafunction,butyoudon'twantanythingoutput(suchasstoringavalueforlateruse).Inthatcase,youjustneedtoreturnfalsefromthefunction.
varcollection=[];
functions.add('store',function(val){
collection.push(val);//immastorethisforlater
returnfalse;
});
@plugin"collections";
@var:32;
store(@var);
Lateryoucoulddosomethinglike:
functions.add('retrieve',function(val){
returnnewtree.Value(collection);
});
.get-my-values{
@plugin"collections";
values:retrieve();
}
TheLess.jsPluginObject
ALess.jspluginshouldexportanobjectthathasoneormoreoftheseproperties.
{
/*Calledimmediatelyafterthepluginis
*firstimported,onlyonce.*/
install:function(less,pluginManager,functions){},
/*Calledforeachinstanceofyour@plugin.*/
use:function(context){},
/*Calledforeachinstanceofyour@plugin,
*whenrulesarebeingevaluated.
*It'sjustlaterintheevaluationlifecycle*/
eval:function(context){},
/*Passesanarbitrarystringtoyourplugin
*e.g.@plugin(args)"file";
*Thisstringisnotparsedforyou,
*soitcancontain(almost)anything*/
setOptions:function(argumentString){},
/*SetaminimumLesscompatibilitystring
*Youcanalsouseanarray,asin[3,0]*/
minVersion:['3.0'],
/*Usedforlessconly,toexplain
*optionsinaTerminal*/
printUsage:function(){},
}
ThePluginManagerinstancefortheinstall()functionprovidesmethodsforaddingvisitors,filemanagers,andpost-processors.
Herearesomeexamplereposshowingthedifferentplugintypes.
post-processor:https://github.com/less/less-plugin-clean-css
visitor:https://github.com/less/less-plugin-inline-urls
file-manager:https://github.com/less/less-plugin-npm-import
Pre-LoadedPlugins
Whilea@plugincallworkswellformostscenarios,therearetimeswhenyoumightwanttoloadapluginbeforeparsingstarts.
See:Pre-LoadedPluginsinthe"UsingLess.js"sectionforhowtodothat.
Maps(NEW!)
Editthemarkdownsourcefor"maps"
Releasedv3.5.0
Userulesetsandmixinsasmapsofvalues
Bycombiningnamespacingwiththelookup[]syntax,youcanturnyourrulesets/mixinsintomaps.
@sizes:{
mobile:320px;
tablet:768px;
desktop:1024px;
}
.navbar{
display:block;
@media(min-width:@sizes[tablet]){
display:inline-block;
}
}
Outputs:
.navbar{
display:block;
}
@media(min-width:768px){
.navbar{
display:inline-block;
}
}
Mixinsarealittlemoreversatileasmapsbecauseofnamespacingandtheabilitytooverloadmixins.
#library(){
.colors(){
primary:green;
secondary:blue;
}
}
#library(){
.colors(){primary:grey;}
}
.button{
color:#library.colors[primary];
border-color:#library.colors[secondary];
}
Outputs:
.button{
color:grey;
border-color:blue;
}
Youcanalsomakethiseasierbyaliasingmixins.Thatis:
.button{
@colors:#library.colors();
color:@colors[primary];
border-color:@colors[secondary];
}
Note,ifalookupvalueproducesanotherruleset,youcanappendasecond[]lookup,asin:
@config:{
@options:{
library-on:true
}
}
&when(@config[@options][library-on]=true){
.produce-ruleset{
prop:val;
}
}
Inthisway,rulesetsandvariablecallscanemulateatypeof"namespacing",similartomixins.
Asfaraswhethertousemixinsorrulesetsassignedtovariablesasmaps,it'suptoyou.Youmaywanttoreplaceentiremapsbyre-declaringavariableassignedtoarulset.Oryoumaywantto"merge"individualkey/valuepairs,inwhichcasemixinsasmapsmightbemoreappropriate.
Usingvariablevariablesinlookups
Oneimportantthingtonoticeisthatthevaluein[@lookup]isthekey(variable)name@lookup,andisnotevaluatedasavariable.Ifyouwantthekeynameitselftobevariable,youcanusethe@@variablesyntax.
E.g.
.foods(){
@dessert:icecream;
}
@key-to-lookup:dessert;
.lunch{
treat:.foods[@@key-to-lookup];
}
Thiswouldoutput:
.lunch{
treat:icecream;
}