





















































In this article by Bass Jobsen, author of the book Less Web Development Cookbook, you will learn:
(For more resources related to this topic, see here.)
The !important statement in CSS can be used to get some style rules always applied no matter where that rules appears in the CSS code. In Less, the !important statement can be applied with mixins and variable declarations too.
You can write the Less code for this recipe with your favorite editor. After that, you can use the command-line lessc compiler to compile the Less code. Finally, you can inspect the compiled CSS code to see where the !important statements appear. To see the real effect of the !important statements, you should compile the Less code client side, with the client-side compiler less.js and watch the effect in your web browser.
.mixin() { color: red; font-size: 2em; } p { &.important { .mixin() !important; } &.unimportant { .mixin(); } }
p.important { color: red !important; font-size: 2em !important; } p.unimportant { color: red; font-size: 2em; }
<p class="important" style="color:green;font-size:4em;">important</p> <p class="unimportant" style="color:green;font-size:4em;">unimportant</p>
Your HTML document should also include the important.less and less.js files, as follows:
<link rel="stylesheet/less" type="text/css" href="important.less"> <script src="less.js" type="text/javascript"></script>
In Less, you can use the !important statement not only for properties, but also with mixins. When !important is set for a certain mixin, all properties of this mixin will be declared with the !important statement. You can easily see this effect when inspecting the properties of the p.important selector, both the color and size property got the !important statement after compiling the code.
You should use the !important statements with care as the only way to overrule an !important statement is to use another !important statement. The !important statement overrules the normal CSS cascading, specificity rules, and even the inline styles. Any incorrect or unnecessary use of the !important statements in your Less (or CCS) code will make your code messy and difficult to maintain.
In most cases where you try to overrule a style rule, you should give preference to selectors with a higher specificity and not use the !important statements at all.
With Less V2, you can also use the !important statement when declaring your variables. A declaration with the !important statement can look like the following code:
@main-color: darkblue !important;
In this section, you will learn how to use mixins with more than one parameter.
For this recipe, you will have to create a Less file, for instance, mixins.less. You can compile this mixins.less file with the command-line lessc compiler.
.mixin(@color; @background: black;) { background-color: @background; color: @color; } div { .mixin(red; white;); }
lessc mixins.less
div { background-color: #ffffff; color: #ff0000; }
In Less, parameters are either semicolon-separated or comma-separated. Using a semicolon as a separator will be preferred because the usage of the comma will be ambiguous. The comma separator is not used only to separate parameters, but is also used to define a csv list, which can be an argument itself.
The mixin in this recipe accepts two arguments. The first parameter sets the @color variable, while the second parameter sets the @background variable and has a default value that has been set to black. In the argument list, the default values are defined by writing a colon behind the variable's name, followed by the value. Parameters with a default value are optional when calling the mixins. So the .color mixin in this recipe can also be called with the following line of code:
.mixin(red);
Because the second argument has a default value set to black, the .mixin(red); call also matches the .mixin(@color; @background:black){} mixin, as described in the Building a switch leveraging argument matching recipe.
Only variables set as parameter of a mixin are set inside the scope of the mixin. You can see this when compiling the following Less code:
.mixin(@color:blue){ color2: @color; } @color: red; div { color1: @color; .mixin; }
The preceding Less code compiles into the following CSS code:
div { color1: #ff0000; color2: #0000ff; }
As you can see in the preceding example, setting @color inside the mixin to its default value does not influence the value of @color assigned in the main scope. So lazy loading is applied on only variables inside the same scope; nevertheless, you will have to note that variables assigned in a mixin will leak into the caller. The leaking of variables can be used to use mixins as functions, as described in the Using mixins as functions recipe.
Consider the mixin definition in the following Less code:
.mixin(@font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;) { font-family: @font-family; }
The semicolon added at the end of the list prevents the fonts after the "Helvetica Neue" font name in the csv list from being read as arguments for this mixin. If the argument list contains any semicolon, the Less compiler will use semicolons as a separator. In the CSS3 specification, among others, the border and background shorthand properties accepts csv.
Also, note that the Less compiler allows you to use the named parameters when calling mixins. This can be seen in the following Less code that uses the @color variable as a named parameter:
.mixin(@width:50px; @color: yellow) { width: @width; color: @color; } span { .mixin(@color: green); }
The preceding Less code will compile into the following CSS code:
span { width: 50px; color: #008000; }
Note that in the preceding code, #008000 is the hexadecimal representation for the green color. When using the named parameters, their order does not matter.
When your Less code contains one or more mixins with the same name, the Less compiler compiles them all into the CSS code. If the mixin has parameters (see the Building a switch leveraging argument matching recipe) the number of parameters will also match.
Use your favorite text editor to create and edit the Less files used in this recipe.
.mixin(){ height:50px; } .mixin(@color) { color: @color; } .mixin(@width) { color: green; width: @width; } .mixin(@color; @width) { color: @color; width: @width; } .selector-1 { .mixin(red); } .selector-2 { .mixin(red; 500px); }
lessc mixins.less
.selector-1 { color: #ff0000; color: green; width: #ff0000; } .selector-2 { color: #ff0000; width: 500px; }
The .selector-1 selector contains the .mixin(red); call. The .mixin(red); call does not match the .mixin(){}; mixin as the number of arguments does not match. On the other hand, both .mixin(@color){}; and .mixin(@width){}; match the color. For this reason, these mixins will compile into the CSS code. The .mixin(red; 500px); call inside the .selector-2 selector will match only the .mixin(@color; @width){}; mixin, so all other mixins with the same .mixin name will be ignored by the compiler when building the .selector-2 selector.
The compiled CSS code for the .selector-1 selector also contains the width: #ff0000; property value as the .mixin(@width){}; mixin matches the call too. Setting the width property to a color value makes no sense in CSS as the Less compiler does not check for this kind of errors. In this recipe, you can also rewrite the .mixin(@width){}; mixin, as follows: .mixin(@width) when (ispixel(@width)){};.
Maybe you have noted that the .selector-1 selector contains two color properties. The Less compiler does not remove duplicate properties unless the value also is the same. The CSS code sometimes should contain duplicate properties in order to provide a fallback for older browsers.
The Less mixin will compile into the final CSS code only when the number of arguments of the caller and the mixins match. This feature of Less can be used to build switches. Switches enable you to change the behavior of a mixin conditionally. In this recipe, you will create a mixin, or better yet, three mixins with the same name.
Use the command-line lessc compiler to evaluate the effect of this mixin. The compiler will output the final CSS to the console. You can use your favorite text editor to edit the Less code.
This recipe makes use of browser-vendor prefixes, such as the -ms-transform prefix. CSS3 introduced vendor-specific rules, which offer you the possibility to write some additional CSS, applicable for only one browser. These rules allow browsers to implement proprietary CSS properties that would otherwise have no working standard (and might never actually become the standard). To find out which prefixes should be used for a certain property, you can consult the Can I use database (available at http://caniuse.com/).
@browserversion: ie9; .mixin(ie9; @degrees){ transform:rotate(@degrees); -ms-transform:rotate(@degrees); -webkit-transform:rotate(@degrees); } .mixin(ie10; @degrees){ transform:rotate(@degrees); -webkit-transform:rotate(@degrees); } .mixin(@_; @degrees){ transform:rotate(@degrees); } div { .mixin(@browserversion; 70deg); }
lessc switch.less
div { -ms-transform: rotate(70deg); -webkit-transform: rotate(70deg); transform: rotate(70deg); }
lessc --modify-var="browserversion=ie10" switch.less
Now the compiled CSS code will look like the following code snippet:
div { -webkit-transform: rotate(70deg); transform: rotate(70deg); }
The switch in this recipe is the @browserversion variable that can easily be changed just before compiling your code. Instead of changing your code, you can also set the --modify-var option of the compiler.
Depending on the value of the @browserversion variable, the mixins that match will be compiled, and the other mixins will be ignored by the compiler. The .mixin(ie10; @degrees){} mixin matches the .mixin(@browserversion; 70deg); call only when the value of the @browserversion variable is equal to ie10. Note that the first ie10 argument of the mixin will be used only for matching (argument = ie10) and does not assign any value.
You will note that the .mixin(@_; @degrees){} mixin will match each call no matter what the value of the @browserversion variable is. The .mixin(ie9,70deg); call also compiles the .mixin(@_; @degrees){} mixin. Although this should result in the transform: rotate(70deg); property output twice, you will find only one. Since the property got exactly the same value twice, the compiler outputs the property only once.
Not only switches, but also mixin guards, as described in the Using mixin guards (as an alternative for the if…else statements) recipe, can be used to set some properties conditionally.
Current versions of Less also support JavaScript evaluating; JavaScript code put between back quotes will be evaluated by the compiler, as can be seen in the following Less code example:
@string: "example in lower case"; p { &:after { content: "`@{string}.toUpperCase()`"; } }
The preceding code will be compiled into CSS, as follows:
p:after { content: "EXAMPLE IN LOWER CASE"; }
When using client-side compiling, JavaScript evaluating can also be used to get some information from the browser environment, such as the screen width (screen.width), but as mentioned already, you should not use client-side compiling for production environments.
Because you can't be sure that future versions of Less still support JavaScript evaluating, and alternative compilers not written in JavaScript cannot evaluate the JavaScript code, you should always try to write your Less code without JavaScript.
In the Less code, the @arguments variable has a special meaning inside mixins. The @arguments variable contains all arguments passed to the mixin. In this recipe, you will use the @arguments variable together with the the CSS url() function to set a background image for a selector.
You can inspect the compiled CSS code in this recipe after compiling the Less code with the command-line lessc compiler. Alternatively, you can inspect the results in your browser using the client-side less.js compiler. When inspecting the result in your browser, you will also need an example image that can be used as a background image. Use your favorite text editor to create and edit the Less files used in this recipe.
.background(@color; @image; @repeat: no-repeat; @position: top right;) { background: @arguments; } div { .background(#000; url("./images/bg.png")); width:300px; height:300px; }
div { background: #000000 url("./images/bg.png") no-repeat top right; width: 300px; height: 300px; }
The four parameters of the .background() mixin are assigned as a space-separated list to the @arguments variable. After that, the @arguments variable can be used to set the background property. Also, other CSS properties accept space-separated lists, for example, the margin and padding properties.
Note that the @arguments variable does not contain only the parameters that have been set explicit by the caller, but also the parameters set by their default value. You can easily see this when inspecting the compiled CSS code of this recipe. The .background(#000; url("./images/bg.png")); caller doesn't set the @repeat or @position argument, but you will find their values in the compiled CSS code.
As you can also see in the Using mixins with multiple parameters and Using duplicate mixin names recipes, only matching mixins are compiled into the final CSS code. In some situations, you don't know the number of parameters or want to use mixins for some style rules no matter the number of parameters. In these situations, you can use the special ... syntax or the @rest... variable to create mixins that match independent of the number of parameters.
You will have to create a file called rest.less, and this file can be compiled with the command-line lessc compiler. You can edit the Less code with your favorite editor.
.mixin(@a...) { .set(@a) when (iscolor(@a)) { color: @a; } .set(@a) when (length(@a) = 2) { margin: @a; } .set(@a); } p{ .mixin(red); } p { .mixin(2px;4px); }
lessc rest.less
p { color: #ff0000; } p { margin: 2px 4px; }
The special ... syntax (three dots) can be used as an argument for a mixin. Mixins with the ... syntax in their argument list match any number of arguments. When you put a variable name starting with an @ in front of the ... syntax, all parameters are assigned to that variable.
You will find a list of examples of mixins that use the special ... syntax as follows:
Because the @rest... variable contains a space-separated list, you can use the Less built-in list function.
People who are used to functional programming expect a mixin to change or return a value. In this recipe, you will learn to use mixins as a function that returns a value.
In this recipe, the value of the width property inside the div.small and div.big selectors will be set to the length of the longest side of a right-angled triangle based on the length of the two shortest sides of this triangle using the Pythagoras theorem.
The best and easiest way to inspect the results of this recipe will be compiling the Less code with the command-line lessc compiler. You can edit the Less code with your favorite editor.
.longestSide(@a,@b) { @length: sqrt(pow(@a,2) + pow(@b,2)); } div { &.small { .longestSide(3,4); width: @length; } &.big { .longestSide(6,7); width: @length; } }
lessc pyhagoras.less
div.small { width: 5; } div.big { width: 9.21954446; }
Variables set inside a mixin become available inside the scope of the caller. This specific behavior of the Less compiler was used in this recipe to set the @length variable and to make it available in the scope of the div.small and div.big selectors and the caller.
As you can see, you can use the mixin in this recipe more than once. With every call, a new scope is created and both selectors get their own value of @length.
Also, note that variables set inside the mixin do not overwrite variables with the same name that are set in the caller itself. Take, for instance, the following code:
.mixin() { @variable: 1; } .selector { @variable: 2; .mixin; property: @variable; }
The preceding code will compile into the CSS code, as follows:
.selector { property: 2; }
Note that variables won't leak from the mixins to the caller in the following two situations:
Since Version 1.7, Less allows you to pass complete rulesets as an argument for mixins. Rulesets, including the Less code, can be assigned to variables and passed into mixins, which also allow you to wrap blocks of the CSS code defined inside mixins. In this recipe, you will learn how to do this.
For this recipe, you will have to create a Less file called keyframes.less, for instance. You can compile this mixins.less file with the command-line lessc compiler. Finally, inspect the Less code output to the console.
// Keyframes .keyframe(@name; @roules) { @-webkit-keyframes @name { @roules(); } @-o-keyframes @name { @roules(); } @keyframes @name { @roules(); } } .keyframe(progress-bar-stripes; { from { background-position: 40px 0; } to { background-position: 0 0; } });
lessc keyframes.less
@-webkit-keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } @-o-keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } @keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } }
Rulesets wrapped between curly brackets are passed as an argument to the mixin. A mixin's arguments are assigned to a (local) variable. When you assign the ruleset to the @ruleset variable, you are enabled to call @ruleset(); to "mixin" the ruleset.
Note that the passed rulesets can contain the Less code, such as built-in functions too. You can see this by compiling the following Less code:
.mixin(@color; @rules) { @othercolor: green; @media (print) { @rules(); } } p { .mixin(red; {color: lighten(@othercolor,20%); background-color:darken(@color,20%);}) }
The preceding Less code will compile into the following CSS code:
@media (print) { p { color: #00e600; background-color: #990000; } }
A group of CSS properties, nested rulesets, or media declarations stored in a variable is called a detached ruleset. Less offers support for the detached rulesets since Version 1.7.
As you could see in the last example in the previous section, rulesets passed as an argument can be wrapped in the @media declarations too. This enables you to create mixins that, for instance, wrap any passed ruleset into a @media declaration or class. Consider the example Less code shown here:
.smallscreens-and-olderbrowsers(@rules) { .lt-ie9 & { @rules(); } @media (min-width:768px) { @rules(); } } nav { float: left; width: 20%; .smallscreens-and-olderbrowsers({ float: none; width:100%; }); }
The preceding Less code will compile into the CSS code, as follows:
nav { float: left; width: 20%; } .lt-ie9 nav { float: none; width: 100%; } @media (min-width: 768px) { nav { float: none; width: 100%; } }
The style rules wrapped in the .lt-ie9 class can, for instance, be used with Paul Irish's <html> conditional classes technique or Modernizr. Now you can call the .smallscreens-and-olderbrowsers(){} mixin anywhere in your code and pass any ruleset to it. All passed rulesets get wrapped in the .lt-ie9 class or the @media (min-width: 768px) declaration now. When your requirements change, you possibly have to change only these wrappers once.
Most programmers are used to and familiar with the if…else statements in their code. Less does not have these if…else statements. Less tries to follow the declarative nature of CSS when possible and for that reason uses guards for matching expressions. In Less, conditional execution has been implemented with guarded mixins. Guarded mixins use the same logical and comparison operators as the @media feature in CSS does.
You can compile the Less code in this recipe with the command-line lessc compiler. Also, check the compiler options; you can find them by running the lessc command in the console without any argument. In this recipe, you will have to use the –modify-var option.
@color: white; .mixin(@color) when (luma(@color) >= 50%) { color: black; } .mixin(@color) when (luma(@color) < 50%) { color: white; } p { .mixin(@color); }
lessc guards.less
p { color: black; }
lessc --modify-var="color=green" guards.less
The preceding command will produce the following CSS code:
p { color: white; }
lessc --modify-var="color=lightgreen" guards.less
With the color set to light green, it will again produce the following CSS code:
p { color: black; }
The use of guards to build an if…else construct can easily be compared with the switch expression, which can be found in the programming languages, such as PHP, C#, and pretty much any other object-oriented programming language.
Guards are written with the when keyword followed by one or more conditions. When the condition(s) evaluates true, the code will be mixed in. Also note that the arguments should match, as described in the Building a switch leveraging argument matching recipe, before the mixin gets compiled.
The syntax and logic of guards is the same as that of the CSS @media feature.
A condition can contain the following comparison operators:
>, >=, =, =<, and <
Additionally, the keyword true is the only value that evaluates as true.
Two or more conditionals can be combined with the and keyword, which is equivalent to the logical and operator or, on the other hand, with a comma as the logical or operator. The following code will show you an example of the combined conditionals:
.mixin(@a; @color) when (@a<10) and (luma(@color) >= 50%) { }
The following code contains the not keyword that can be used to negate conditions:
.mixin(@a; @color) when not (luma(@color) >= 50%) { }
Inside the guard conditions, (global) variables can also be compared. The following Less code example shows you how to use variables inside guards:
@a: 10; .mixin() when (@a >= 10) {}
The preceding code will also enable you to compile the different CSS versions with the same code base when using the modify-var option of the compiler. The effect of the guarded mixin described in the preceding code will be very similar with the mixins built in the Building a switch leveraging argument matching recipe.
Note that in the preceding example, variables in the mixin's scope overwrite variables from the global scope, as can be seen when compiling the following code:
@a: 10; .mixin(@a) when (@a < 10) {property: @a;} selector { .mixin(5); }
The preceding Less code will compile into the following CSS code:
selector { property: 5; }
When you compare guarded mixins with the if…else constructs or switch expressions in other programming languages, you will also need a manner to create a conditional for the default situations. The built-in Less default() function can be used to create such a default conditional that is functionally equal to the else statement in the if…else constructs or the default statement in the switch expressions. The default() function returns true when no other mixins match (matching also takes the guards into account) and can be evaluated as the guard condition.
Mixin guards, as described besides others in the Using mixin guards (as an alternative for the if…else statements) recipe, can also be used to dynamically build a set of CSS classes. In this recipe, you will learn how to do this.
You can use your favorite editor to create the Less code in this recipe.
.shadesofblue(@number; @blue:100%) when (@number > 0) { .shadesofblue(@number - 1, @blue - 10%); @classname: e(%(".color-%a",@number)); @{classname} { background-color: rgb(0, 0, @blue); height:30px; } } .shadesofblue(10);
<div class="color-1"></div> <div class="color-2"></div> <div class="color-3"></div> <div class="color-4"></div> <div class="color-5"></div> <div class="color-6"></div> <div class="color-7"></div> <div class="color-8"></div> <div class="color-9"></div> <div class="color-10"></div>
Your HTML document should also include the shadesofblue.less and less.js files, as follows:
<link rel="stylesheet/less" type="text/css" href="shadesofblue.less">
<script src="less.js" type="text/javascript"></script>
The CSS classes in this recipe are built with recursion. The recursion here has been done by the .shadesofblue(){} mixin calling itself with different parameters. The loop starts with the .shadesofblue(10); call. When the compiler reaches the .shadesofblue(@number - 1, @blue – 10%); line of code, it stops the current code and starts compiling the .shadesofblue(){} mixin again with @number decreased by one and @blue decreased by 10 percent. The process will be repeated till @number < 1. Finally, when the @number variable becomes equal to 0, the compiler tries to call the .shadesofblue(0,0); mixin, which does not match the when (@number > 0) guard. When no matching mixin is found, the compiler stops, compiles the rest of the code, and writes the first class into the CSS code, as follows:
.color-1 { background-color: #00001a; height: 30px; }
Then, the compiler starts again where it stopped before, at the .shadesofblue(2,20); call, and writes the next class into the CSS code, as follows:
.color-2 { background-color: #000033; height: 30px; }
The preceding code will be repeated until the tenth class.
When inspecting the compiled CSS code, you will find that the height property has been repeated ten times, too. This kind of code repeating can be prevented using the :extend Less pseudo class. The following code will show you an example of the usage of the :extend Less pseudo class:
.baseheight { height: 30px; } .mixin(@i: 2) when(@i > 0) { .mixin(@i - 1); .class@{i} { width: 10*@i; &:extend(.baseheight); } } .mixin();
Alternatively, in this situation, you can create a more generic selector, which sets the height property as follows:
div[class^="color"-] { height: 30px; }
Recursive loops are also useful when iterating over a list of values. Max Mikhailov, one of the members of the Less core team, wrote a wrapper mixin for recursive Less loops, which can be found at https://github.com/seven-phases-max. This wrapper contains the .for and .-each mixins that can be used to build loops. The following code will show you how to write a nested loop:
@import "for"; #nested-loops { .for(3, 1); .-each(@i) { .for(0, 2); .-each(@j) { x: (10 * @i + @j); } } }
The preceding Less code will produce the following CSS code:
#nested-loops { x: 30; x: 31; x: 32; x: 20; x: 21; x: 22; x: 10; x: 11; x: 12; }
Finally, you can use a list of mixins as your data provider in some situations. The following Less code gives an example about using mixins to avoid recursion:
.data() { .-("dark"; black); .-("light"; white); .-("accent"; pink); } div { .data(); .-(@class-name; @color){ @class: e(@class-name); &.@{class} { color: @color; } } }
The preceding Less code will compile into the CSS code, as follows:
div.dark { color: black; } div.light { color: white; } div.accent { color: pink; }
Since Version 1.5 of Less, guards can be applied not only on mixins, but also on the CSS selectors. This recipe will show you how to apply guards on the CSS selectors directly to create conditional rulesets for these selectors.
The easiest way to inspect the effect of the guarded selector in this recipe will be using the command-line lessc compiler.
@dark: true; button when (@dark){ background-color: black; color: white; }
lessc darkbutton.less
button { background-color: black; color: white; }
lessc --modify-var="dark=false" darkbutton.less
The guarded CSS selectors are ignored by the compiler and so not compiled into the CSS code when the guard evaluates false. Guards for the CSS selectors and mixins leverage the same comparison and logical operators. You can read in more detail how to create guards with these operators in Using mixin guards (as an alternative for the if…else statements) recipe.
Note that the true keyword will be the only value that evaluates true. So the following command, which sets @dark equal to 1, will not generate the button selector as the guard evaluates false:
lessc --modify-var="dark=1" darkbutton.less
The following Less code will give you another example of applying a guard on a selector:
@width: 700px; div when (@width >= 600px ){ border: 1px solid black; }
The preceding code will output the following CSS code:
div { border: 1px solid black; }
On the other hand, nothing will be output when setting @width to a value smaller than 600 pixels.
You can also rewrite the preceding code with the & feature referencing the selector, as follows:
@width: 700px; div { & when (@width >= 600px ){ border: 1px solid black; } }
Although the CSS code produced of the latest code does not differ from the first, it will enable you to add more properties without the need to repeat the selector. You can also add the code in a mixin, as follows:
.conditional-border(@width: 700px) { & when (@width >= 600px ){ border: 1px solid black; } width: @width; }
Color contrasts play an important role in the first impression of your website or web application. Color contrasts are also important for web accessibility. Using high contrasts between background and text will help the visually disabled, color blind, and even people with dyslexia to read your content more easily.
The contrast() function returns a light (white by default) or dark (black by default) color depending on the input color. The contrast function can help you to write a dynamical Less code that always outputs the CSS styles that create enough contrast between the background and text colors. Setting your text color to white or black depending on the background color enables you to meet the highest accessibility guidelines for every color. A sample can be found at http://www.msfw.com/accessibility/tools/contrastratiocalculator.aspx, which shows you that either black or white always gives enough color contrast.
When you use Less to create a set of buttons, for instance, you don't want some buttons with white text while others have black text. In this recipe, you solve this situation by adding a stroke to the button text (text shadow) when the contrast ratio between the button background and button text color is too low to meet your requirements.
You can inspect the results of this recipe in your browser using the client-side less.js compiler. You will have to create some HTML and Less code, and you can use your favorite editor to do this. You will have to create the following file structure:
@safe: green; @danger: red; @warning: orange; @buttonTextColor: white; @ContrastRatio: 7; //AAA, small texts .setcontrast(@backgroundcolor) when (luma(@backgroundcolor) =< luma(@buttonTextColor)) and (((luma(@buttonTextColor)+5)/ (luma(@backgroundcolor)+5)) < @ContrastRatio) { color:@buttonTextColor; text-shadow: 0 0 2px black; } .setcontrast(@backgroundcolor) when (luma(@backgroundcolor) =< luma(@buttonTextColor)) and (((luma(@buttonTextColor)+5)/ (luma(@backgroundcolor)+5)) >= @ContrastRatio) { color:@buttonTextColor; } .setcontrast(@backgroundcolor) when (luma(@backgroundcolor) >= luma(@buttonTextColor)) and (((luma(@backgroundcolor)+5)/ (luma(@buttonTextColor)+5)) < @ContrastRatio) { color:@buttonTextColor; text-shadow: 0 0 2px white; } .setcontrast(@backgroundcolor) when (luma(@backgroundcolor) >= luma(@buttonTextColor)) and (((luma(@backgroundcolor)+5)/ (luma(@buttonTextColor)+5)) >= @ContrastRatio) { color:@buttonTextColor; } button { padding:10px; border-radius:10px; color: @buttonTextColor; width:200px; } .safe { .setcontrast(@safe); background-color: @safe; } .danger { .setcontrast(@danger); background-color: @danger; } .warning { .setcontrast(@warning); background-color: @warning; }
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>High contrast buttons</title> <link rel="stylesheet/less" type="text/css" href="contraststrokes.less"> <script src="less.min.js" type="text/javascript"></script> </head> <body> <button style="background-color:green;">safe</button> <button class="safe">safe</button><br> <button style="background-color:red;">danger</button> <button class="danger">danger</button><br> <button style="background-color:orange;"> warning</button> <button class="warning">warning</button> </body> </html>
On the left-hand side of the preceding screenshot, you will see the original colored buttons, and on the right-hand side, you will find the high-contrast buttons.
The main purpose of this recipe is to show you how to write dynamical code based on the color contrast ratio.
Web Content Accessibility Guidelines (WCAG) 2.0 covers a wide range of recommendations to make web content more accessible. They have defined the following three conformance levels:
If you focus only on the color contrast aspect, you will find the following paragraphs in the WCAG 2.0 guidelines.
The contrast ratio can be calculated with a formula that can be found at http://www.w3.org/TR/WCAG20/#contrast-ratiodef:
(L1 + 0.05) / (L2 + 0.05)
In the preceding formula, L1 is the relative luminance of the lighter of the colors, and L2 is the relative luminance of the darker of the colors.
In Less, the relative luminance of a color can be found with the built-in luma() function. In the Less code of this recipe are the four guarded .setcontrast(){} mixins. The guard conditions, such as (luma(@backgroundcolor) =< luma(@buttonTextColor)) are used to find which of the @backgroundcolor and @buttonTextColor colors is the lighter one. Then the (((luma({the lighter color})+5)/(luma({the darker color})+5)) < @ContrastRatio) condition can, according to the preceding formula, be used to determine whether the contrast ratio between these colors meets the requirement (@ContrastRatio) or not. When the value of the calculated contrast ratio is lower than the value set by the @ContrastRatio, the text-shadow: 0 0 2px {color}; ruleset will be mixed in, where {color} will be white or black depending on the relative luminance of the color set by the @buttonTextColor variable.
In this recipe, you added a stroke to the web text to improve the accessibility. First, you will have to bear in mind that improving the accessibility by adding a stroke to your text is not a proven method. Also, automatic testing of the accessibility (by calculating the color contrast ratios) cannot be done.
Other options to solve this issue are to increase the font size or change the background color itself. You can read how to change the background color dynamically based on color contrast ratios in the Changing the background color dynamically recipe.
When you read the exceptions of the 1.4.6 Contrast (Enhanced) paragraph of the WCAG 2.0 guidelines, you will find that large-scale text requires a color contrast ratio of 4.5 instead of 7.0 to meet the requirements of the AAA Level. Large-scaled text is defined as at least 18 point or 14 point bold or font size that would yield the equivalent size for Chinese, Japanese, and Korean (CJK) fonts. To try this, you could replace the text-shadow properties in the Less code of step 1 of this recipe with the font-size, 14pt, and font-weight, bold; declarations. After this, you can inspect the results in your browser again. Depending on, among others, the values you have chosen for the @buttonTextColor and @ContrastRatio variables, you will find something like the following screenshot:
On the left-hand side of the preceding screenshot, you will see the original colored buttons, and on the right-hand side, you will find the high-contrast buttons. Note that when you set the @ContrastRatio variable to 7.0, the code does not check whether the larger font indeed meets the 4.5 contrast ratio requirement.
When you define some basic colors to generate, for instance, a set of button elements, you can use the built-in contrast() function to set the font color. The built-in contrast() function provides the highest possible contrast, but does not guarantee that the contrast ratio is also high enough to meet your accessibility requirements. In this recipe, you will learn how to change your basic color automatically to meet the required contrast ratio.
You can inspect the results of this recipe in your browser using the client-side less.js compiler. Use your favorite editor to create the HTML and Less code in this recipe. You will have to create the following file structure:
@safe: green; @danger: red; @warning: orange; @ContrastRatio: 7.0; //AAA @precision: 1%; @buttonTextColor: black; @threshold: 43; .setcontrastcolor(@startcolor) when (luma(@buttonTextColor) < @threshold) { .contrastcolor(@startcolor) when (luma(@startcolor) < 100 ) and (((luma(@startcolor)+5)/ (luma(@buttonTextColor)+5)) < @ContrastRatio) { .contrastcolor(lighten(@startcolor,@precision)); } .contrastcolor(@startcolor) when (@startcolor = color("white")),(((luma(@startcolor)+5)/ (luma(@buttonTextColor)+5)) >= @ContrastRatio) { @contrastcolor: @startcolor; } .contrastcolor(@startcolor); } .setcontrastcolor(@startcolor) when (default()) { .contrastcolor(@startcolor) when (luma(@startcolor) < 100 ) and (((luma(@buttonTextColor)+5)/ (luma(@startcolor)+5)) < @ContrastRatio) { .contrastcolor(darken(@startcolor,@precision)); } .contrastcolor(@startcolor) when (luma(@startcolor) = 100 ),(((luma(@buttonTextColor)+5)/(luma(@startcolor)+5)) >= @ContrastRatio) { @contrastcolor: @startcolor; } .contrastcolor(@startcolor); } button { padding:10px; border-radius:10px; color:@buttonTextColor; width:200px; } .safe { .setcontrastcolor(@safe); background-color: @contrastcolor; } .danger { .setcontrastcolor(@danger); background-color: @contrastcolor; } .warning { .setcontrastcolor(@warning); background-color: @contrastcolor; }
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>High contrast buttons</title> <link rel="stylesheet/less" type="text/css" href="backgroundcolors.less"> <script src="less.min.js" type="text/javascript"></script> </head> <body> <button style="background-color:green;">safe</button> <button class="safe">safe</button><br> <button style="background-color:red;">danger</button> <button class="danger">danger</button><br> <button style="background-color:orange;">warning </button> <button class="warning">warning</button> </body> </html>
On the left-hand side of the preceding figure, you will see the original colored buttons, and on the right-hand side, you will find the high contrast buttons.
The guarded .setcontrastcolor(){} mixins are used to determine the color set depending upon whether the @buttonTextColor variable is a dark color or not. When the color set by @buttonTextColor is a dark color, with a relative luminance below the threshold value set by the @threshold variable, the background colors should be made lighter. For light colors, the background colors should be made darker.
Inside each .setcontrastcolor(){} mixin, a second set of mixins has been defined. These guarded .contrastcolor(){} mixins construct a recursive loop, as described in the Building loops leveraging mixin guards recipe. In each step of the recursion, the guards test whether the contrast ratio that is set by the @ContrastRatio variable has been reached or not. When the contrast ratio does not meet the requirements, the @startcolor variable will darken or lighten by the number of percent set by the @precision variable with the built-in darken() and lighten() functions. When the required contrast ratio has been reached or the color defining the @startcolor variable has become white or black, the modified color value of @startcolor will be assigned to the @contrastcolor variable. The guarded .contrastcolor(){} mixins are used as functions, as described in the Using mixins as functions recipe to assign the @contrastcolor variable that will be used to set the background-color property of the button selectors.
A small value of the @precision variable will increase the number of recursions (possible) needed to find the required colors as there will be more and smaller steps needed. With the number of recursions also, the compilation time will increase. When you choose a bigger value for @precision, the contrast color found might differ from the start color more than needed to meet the contrast ratio requirement.
When you choose, for instance, a dark button text color, which is not black, all or some base background colors will be set to white. The chances of finding the highest contrast for white increase for high values of the @ContrastRatio variable. The recursions will stop when white (or black) has been reached as you cannot make the white color lighter. When the recursion stops on reaching white or black, the colors set by the mixins in this recipe don't meet the required color contrast ratios.
The merge feature of Less enables you to merge property values into a list under a single property. Each list can be either space-separated or comma-separated. The merge feature can be useful to define a property that accepts a list as a value. For instance, the background accepts a comma-separated list of backgrounds.
For this recipe, you will need a text editor and a Less compiler.
.default-fonts() { font-family+: Helvetica, Arial, sans-serif; } p { font-family+: "Helvetica Neue"; .default-fonts(); }
lessc defaultfonts.less
p { font-family: "Helvetica Neue", Helvetica, Arial, sans- serif; }
When the compiler finds the plus sign (+) before the assignment sign (:), it will merge the values into a CSV list and will not create a new property into the CSS code.
Since Version 1.7 of Less, you can also merge the property's values separated by a space instead of a comma. For space-separated values, you should use the +_ sign instead of a + sign, as can be seen in the following code:
.text-overflow(@text-overflow: ellipsis) { text-overflow+_ : @text-overflow; } p, .text-overflow { .text-overflow(); text-overflow+_ : ellipsis; }
The preceding Less code will compile into the CSS code, as follows:
p, .text-overflow { text-overlow: ellipsis ellipsis; }
Note that the text-overflow property doesn't force an overflow to occur; you will have to explicitly set, for instance, the overflow property to hidden for the element.
This article walks you through the process of parameterized mixins and shows you how to use guards. A guard can be used with as if-else statements and make it possible to construct interactive loops in Less.
Further resources on this subject: