What are the best Sass features

Roberto Bez7

CSS preprocessors complement CSS with variables, functions and mixins to create a well-rounded language and help to keep the code lean. The popular LESS, Sass and Stylus projects are 80 percent identical in terms of their functions, the remaining 20 are in the details.

Many small and large web applications have been using the concept of CSS preprocessors for several years. And yet before each project is started, thorough research and evaluation is carried out to determine whether LESS, Sass or Stylus is the perfect choice. Aside from personal preferences, all three candidates offer a similar range of options and the decision is usually made on the basis of details.

The point of CSS can be summarized in one sentence: Bringing the elements of a document into shape using selectors and attributes. While its use can be an advantage for designers without a technical background, CSS is, on the other hand, a not very powerful language that contradicts one of the most important programming principles. Contrary to the DRY principle (Don't repeat yourself), properties must be repeated for each selector.

In this context, CSS preprocessors open up a completely new world: With the help of variables, mixins and functions, properties and patterns that have been defined can suddenly be used again and again.

CSS yes, preprocessors maybe

CSS preprocessors aren't the panacea for bad code, they just wrap it up nicely. So it's pure superstition that CSS, and thus the website, benefits from its mere use. The following code shows a typical example:

.Container {
font-size: 12px;
}

.container .important {
font-size: 14px;
}

.container .important span {
color: red;
}

And simply using a preprocessor:

.Container {
font-size: 12px;
.important {
font-size: 14px;
span {
color: red;
}
}
}

The class Container is no longer repeated and the code looks nicer and, above all, tidier at first glance. Such an ill-considered nesting can quickly become dangerous, because another developer could misunderstand the idea and expand the code as follows:

.container2 {
font-size: 11px;
.important {
@extend container.important; // copies all
// styles of the class important
// inside the container
}
}

By the extend-Concept (more on this later) were all properties of the class important out Container in a class of the same name in container2 copied.

Clearly this is an interesting preprocessor feature. In this context, however, it brings more complexity into the code than it should actually remove, because in any future important-Class the step is to be repeated now. Just because CSS preprocessors offer the possibility of nesting doesn't mean that you absolutely have to use them. Nesting up to a maximum of four levels can make sense; anything beyond that remains practicable only in the rarest of cases.

Back to the origins, now with simple CSS code:

.Container {
font-size: 12px;
}

.important {
fonz-size: 14px;
color: red;
}

The class important can now be used in any context and if it should differ, the programmer can always create an additional class. This may be a somewhat far-fetched example, but it shows that a CSS preprocessor cannot prevent a developer from turning less beautiful code into less beautiful code. Since this "bad practice" is now known, all prerequisites are in place to be able to work properly with CSS preprocessors.

Before use

LESS and Sass were originally developed in Ruby. LESS is now a JavaScript library, which simplifies installation, especially under Windows, because Ruby - in contrast to the Mac - still has to be explicitly installed under Windows. If the language is available in the system, Sass can be set up via the command prompt or the terminal.

LESS can also be integrated into an HTML document by referencing a JavaScript file - understandably, however, such a procedure is not possible for productive systems.

In order to be able to install the stylus, the program Node.js ahead. Accordingly, the young preprocessor has established itself as a popular competitor in the node community. The corresponding npm module (Node Package Manager) can be installed with a simple command:

npm install stylus -g

For LESS and Sass, npm modules are also available for integration into Node.js applications.

syntax

Syntactic basics

All three languages ​​understand the regular CSS syntax, which makes converting existing CSS files comparatively uncomplicated. Both Sass and Stylus go a step further and offer a slightly shorter spelling:

LESS - usual CSS syntax:

h1 {
color: # 000000;
}

Sass - dispenses with brackets and semicolons (file extension * .sass), but, as mentioned, can also work with the regular CSS syntax (file extension * .scss)

h1 {
color: # 000000;
}

h1
color: # 000000

Stylus makes the greatest compromise and allows normal CSS syntax, with brackets, colons and semicolons being optional:

h1 {
color: # 000000;
}

h2
color blue

Even mixed use within a file is permitted and the result compiles without errors.

Variables in use

For variable names, LESS uses the @-, Sass that $- and an optional stylus $-Prefix. The dollar sign has no meaning in CSS and can be used without any problems, while the @ by using at @ media- and other information can cause confusion.

LESS:

@siteColor: black;
@borderStyle: dotted;

body {
color: @siteColor;
border: 1px @borderStyle @siteColor;
}

Sass:

$ siteColor: black;
$ borderStyle: dotted;

body {
color: $ siteColor;
border: 1px $ borderStyle $ siteColor;
}

Stylus:

siteColor = black;
borderStyle = dotted;

body {
color: siteColor;
border: 1px borderStyle siteColor;
}

The compiled output looks identical for all of them:

body {
color: black;
border: 1px dotted black;
}

Sass has another special feature with the Scope: There are only global variables. So if global variables are overwritten by local variables, the global variable gets the value of the local:

$ color: black;
.header {
$ color: white;
color: $ color;
}
.content {
color: $ color;
// With LESS and Stylus, $ color has the value black (global)
// For Sass, $ color has the value white (overwritten)
}

Stylus supports another feature called property lookup. It enables properties to be referenced without having set their value in a variable:

.box {
width: 150px
height: 80px
margin-left: - (@ width / 2)
margin-top: - (@ height / 2)
}

The only requirement here is to have a value that has already been set, since the calculation takes place during compilation and it is therefore useless if, for example, the width is changed afterwards. Not only did users apply for the feature once for Sass, but the developers rejected it for precisely the reason that a correct value can only be determined after it has been calculated in the browser. The variables that are not required are therefore the only advantage that this convenience feature brings with it.

Mixins and extend

Mixins

Mixins should allow the properties of one rule set to be incorporated into another. In this way, they enable properties to be reused within different stylesheets. Thanks to the unique mixin definition, annoying searching through the code is a thing of the past, especially when changes are made.

In Sass, developers can use the @mixin-Use directives, in LESS they are defined via a class selector. Stylus, on the other hand, does not have a prefix at all:

LESS

.crop (@width: 100px) {
overflow: hidden;
white-space: nowrap;
text overflow: ellipsis;
width: @width;
}

.title {
.crop ();
}

.text {
.crop (200px);
}

Sass

@mixin crop ($ width: 100px) {
overflow: hidden;
white-space: nowrap;
text overflow: ellipsis;
width: $ width;
}

.title {
@include crop ();
}

.text {
@include crop (200px);
}

Stylus

crop (width = 100px) {
overflow: hidden;
white-space: nowrap;
text overflow: ellipsis;
width: width;
}

.title {
crop ();
}

.text {
crop (200px);
}

Tidy code thanks to extend

In order to set styles to several selectors at the same time, the following code is used in the standard CSS:

p, ul, ol {
/* … */
}

While the approach works wonderfully, reusing the classes can make the code difficult to maintain. The CSS preprocessors counteract Inheritancewhich basically means nothing more than inheriting properties of one selector to another. Sass and Stylus show how it is done:

.nav {
padding: 5px;
}
.side-nav {
@extend .nav;
}

The compiled output:

.nav,
.side-nav {
padding: 5px;
}

LESS has only included an extend function since a newer version (> 1.4) and its implementation differs slightly: instead of the at-rule (@extend) As with Sass and Stylus, LESS implements a syntax for pseudo-classes that can be used on or in the selector:

.nav {
padding: 5px;
}
.side-nav: extend (.nav);

// Alternatively:
.sidebar-nav {
&: extend (.nav);
}

The compiled output:

.nav,
.side-nav {
padding: 5px;
}

Several classes can be passed separated by a comma. An additional parameter Alles ensures that the nested classes are also "extended":

.main-nav {
&: extend (.nav all, .side-nav);
}

Import and grinding

Controlled import

CSS files with the @import-Importing syntax directly is not a good idea in most cases, because the resulting requests (one http request per file) also slow down the loading process. Import CSS preprocessors (also with the @importCommand) in a completely different way: During the compilation process, the content of the imported file is included directly in order to deliver only a single CSS file at the end. By concatenating it is completely sufficient to define mixins and variables in a central location so that they can be used from anywhere.

Attention: CSS preprocessors ignore the @importCommand files with a .cssEnding. Only proprietary files can be imported, for example on .less, .scss, .sat or .styl end up.

/ * file. {type} * /
body {
background: black;
}

@import "reset.css";
@import "file. {type}";
p {
background: white;
}

The compiled output shows that reset.css was not taken into account:

@import "reset.css";
body {
background: black;
}
p {
background: white;
}

Color and math

Color Functions are built-in functions that can change colors at compile time. You can use color gradients or : hoverEffects will be useful.

lighten ($ color, 10%); / * returns a color that is 10% lighter than $ color * /
darken ($ color, 10%); / * returns a color that is 10% darker than $ color * /

saturate (@color, 10%);
desaturate (@color, 10%);

$ color: # 0982C1;
h1 {
background: $ color;
border: 3px solid darken ($ color, 50%);
}

These are by far not all of the included color functions - more information can be found in the LESS, Sass and Stylus documentation.

Mathematical operations can be carried out in all languages. Sass and Stylus support arithmetic operations between different units. The preprocessors are not only suitable for simple math, but can also solve more complex tasks, such as rounding or determining a minimum or maximum value from a list.

body {
margin: (14px / 2);
top: 50px + 100px;
right: 100px - 50px;
left: 10 * 10;
}

Grinding of all kinds

In the Sass and Stylus you can use normal if / else- Use instructions. LESS, on the other hand, relies on so-called CSS guards, which are helpful when matching not to simple values ​​but to expressions, just like the @media- Describes query feature specification.

Sass

@if lightness ($ color)> 30% {
background-color: black;
}
@else {
background-color: white;
}

LESS

.mixin (@color) when (lightness (@color)> 30%) {
background-color: black;
}
.mixin (@color) when (lightness (@color) = <; 30%) {
background-color: white;
}

Stylus

if lightness (color)> 30% {
background-color black;
} else {
background-color white;
}

Both Sass and Stylus support the for-Directive. LESS, in turn, relies on CSS guards and recursive mixins:

Sass

@ for $ counter from 1px to 3px {
.border - # {counter} {
border: $ counter solid black;
}
}

LESS

.loop (@counter) when (@counter> 0) {
.loop ((@ counter - 1));

.border - @ {counter} {
border: 1px * @counter solid black;
}
}

Stylus

for counter in (1..3) {
.border- {counter} {
border: 1px * counter solid black;
}
}

Nesting

Everything well packed

Nesting classes reduces writing effort and keeps the code lean. In addition, such an approach helps to keep the styles independent of each other. Particularly when adhering to the DRY principle, nesting is used to avoid repetition of class names:

nav {
margin: 0;
width: 100%;
ul {
padding: 0;
margin: 0;
}
}

Sass goes one step further and allows properties to be nested within one another:

nav {
margin: 0;
width: 100%;
ul {
padding: 0;
margin: 0;
}
border: {
style: solid;
left: {
width: 1px;
color: #aaa;
}
right: {
width: 2px;
color: # 000;
}
}
}

The compiled output looks like this:

nav {
margin: 0;
width: 100%;
border-style: solid;
border-left-width: 1px;
border-left-color: #aaa;
border-right-width: 2px;
border-right-color: # 000;
}
nav ul {
padding: 0;
margin: 0;
}

In addition, the &Symbol select the parent component, for example styles on pseudo-elements such as : hover to be able to apply - similar to that this in JavaScript.

button {
background-color: green;
&: hover {
background-color: blue;
}
}

The compiled output looks like this:

button {
background-color: green;
}

button: hover {
background-color: blue;
}

More possibilities through extensions

Hardly any extension is as widespread as Compass for Sass. But there are also mixin libraries for LESS such as LESSHat and Stylus can come up with Nib.

Depending on the language selected, extensions have a lot of advantages. In addition to a large number of helpful mixins, which in particular simplify the use of the new CSS3 techniques, they also include uniform spellings, for example to translate properties with the prefixes of the individual browser manufacturers:

.box {
@include border-radius (4px, 4px);
}

// Output:
.box {
-webkit-border-radius: 4px 4px;
-moz-border-radius: 4px / 4px;
-khtml-border-radius: 4px / 4px;
border-radius: 4px / 4px;
}

Error messages and conclusion

A closer look at error messages

A clear error report can be worth its weight in gold, especially with large files. A short example shows how the individual preprocessors behave in the event of a missing quotation mark:

.Container {
.navigation {
background: url ("abc.gif);
}
}

Sass

Syntax error: Invalid CSS after "url (": expected ")", which is "" abc.gif); "
on line 3 of demo.less

LESS

ParseError: unmatched `` "in /Users/roberto/projects/test/demo.less
on line 3, column 25:
2 .navigation {
3 background: url ("abc.gif);
4 }

Stylus

/ usr / local / lib / node_modules / stylus / bin / stylus: 537
if (err) throw err;
^
ParseError: stdin: 3
1 | .Container {
2 | .navigation {
> 3 | background: url ("abc.gif);
4| }
5| }

In this example, all three point to the error and show an understandable output, whereby the type of error also depends on how precise and detailed the individual preprocessor acts.

Conclusion

CSS preprocessors are nothing new, but developers still have heated discussions about the right choice in numerous articles. In 80 percent of the functions, the three preprocessors Sass, LESS and Stylus correspond pretty well, even if they implement some things in different ways. If the remaining 20 percent do not provide a clear basis for decision-making, the environment used sometimes helps, because a node developer, for example, will most likely tend to use stylus due to the good interaction options.

Even if Stylus offers the most freedom in terms of syntax, it is advisable in many cases to use the regular CSS syntax or at least a consistent spelling. Because even if many are happy about the acceptance of the compiler with a missing semicolon, the spelling is fundamentally wrong.

Regardless of whether you favor LESS for your philosophy, Sass because of the diverse design options or Stylus as a newcomer from the Node.js corner - a preprocessor belongs in the toolbox of every web developer. (jul)

Roberto Bez
is a passionate web developer and enthusiastic about new technologies that he tries to bring into daily application development.

7 comments