At the most simple level, SASS just makes CSS cleaner and clearer with less repetition. Instead of writing this:
.my-class { background-color: red; }
.my-class li { background-color: black; }
.my-class li a { color: white; }
...you can instead nest this repetitive mess of code into a nice, ordered, hierarchical structure:
.my-class { background-color: red;
li { background-color: black;
a { color: white; }
}
}
Styling becomes more modular, and much more readable - for instance, all your menu styling will be wrapped in in your .menu-class, and your footer styles will all be completely separate in your file structure. You have less chance of a conflicting CSS rule, because you can see that everything is nested within its parent class, and you have a structured layout in your CSS which actually mimics your DOM tree, with the same hierarchical representation and inheritance chains.
Variables, as you may be familiar with from other languages, make code maintenance much easier. In vanilla CSS, we often find ourselves a little stuck without variables. What happens when the client decides to change their brand colour? What about if the designer reviews the website and says all the headings need their font-size reduced by 1px? But in SASS, these problems melt away. I can define some variables, and from there I can just reference the variable, meaning that if a change is required, I only have to change it in one place. In Sass, a variable name must begin with a dollar ( $ ) sign, and is assigned a value using a colon ( : ), like CSS:
$default-color: #FFF;
$font-size-sm: 12px;
a {
color: $default-color;
font-size: $font-size-sm;
}
One of the great benefits of Sass is that you can calculate things like width, or padding. Calculations can be made using compatible units, for instance as pixels can be added to mm, or inches. However, invalid computations are those that involve relative units, so pixels could not be added to a percentage, or ems, these two could only be added to other values of the same type, or numbers without a unit. Its also worth noting that when calculating with compatible unit, the type of the
Let's consider a useful example. Imagine you have a container which is 800px wide. This container has 3 children, which should be evenly distributed across this container. We could do the maths ourselves, and work it out, but then what happens if we need to change the container to be 1200px wide? We have to do our maths all over again. It's not very future-proof.
Instead we could calculate the child widths quite simply:
$width: 800px;
.container { width: $width;
.child { width: ($width / 3); }
}
Then suppose we add some padding that needs to be taken into account:
$width: 800px;
$padding: 20px;
.container { width: ($width - ($padding * 2)); padding:$padding;
.child { width: (($width - ($padding * 2)) / 3); }
}
Then if we change the width, we only have to update one location, and recompile!
Importing Sass files into each other can be really useful. First off, it can allow for keeping much smaller Sass files, which are light-weight and easy to navigate for the developer, but without having an impact on page-load for the end-user by loading in multiple CSS files. Instead, I tend to create one master Sass file, which I switch to for live deployment. This Sass file contains no styles itself, but has a series of imports that pull all my Sass files together.
//aa.scss
@import "aa.fonts.scss";
@import "aa.site.scss";
@import "aa.menu.scss";
@import "aa.home.scss";
The .scss path can also be omitted when importing Sass files. As an aside, I tend to use namespacing for my Sass files, as you can see above, making my master file the namespace root. This just keeps things tidy in my folders, but means that my single master file logically will encompass all the sub files.
Secondly, imports allow for the use of 'global' variables. I put global in quotes, because they are not global in the same sense that a JavaScript variable can be global. In fact, they are local variables, but we just reference them in every Sass file.
@import "defaults";
a {
color:$default-color;
}
In the above example, I have created the $default-color variable in the defaults file, but I am using it in the current file.
As my defaults usually only contain variables, and references for the project (I will often load Compass and all other mixin libraries into my defaults file as well), I do not need it to be compiled and render a CSS file. In actuality, any CSS file it did render would be empty anyway! So to tell Sass to ignore the file when compiling, I can append an underscore ( _ ) to the front of it: _defaults.scss. Like the .scss, the underscore can be omitted from the import value.
Extending is where we can essentially copy the styles from a selector we styled earlier onto the current element.
.my-left-menu {
display: block;
background: $default-background;
position: fixed;
left: -200px;
top: 0;
width: 200px;
li { display:block; }
}
.my-right-menu {
@extend .my-left-menu;
left: auto;
right: -200px;
}
Its worth noting that the extend directive does not actually copy the styles, but instead adds the current selector to the prior one, compiling like so:
.my-right-menu, .my-left-menu {
display: block;
background: $default-background;
position: fixed;
left: -200px;
top: 0;
width: 200px;
}
.my-right-menu li, .my-left-menu li { display:block; }
.my-right-menu {
left: auto;
right: -200px;
}
This is a useful space-saver, compared to the LESS version of this directive which in fact does copy all the styles to the current selector. A point which seems to have led to much debate among peers because the Sass method can lead to messy CSS files being compiled where a commonly extended rule has lots of comma-separated selectors attached to it as well as all its child rules. I'm of the opinion that I am using SASS to avoid ever having to look at CSS again, so I am not too bothered how my CSS renders in the end, as long as its efficient.
We can also declare extend-only selectors, using the percent ( % ) sign:
%standard-text {
font-size: 12px;
font-weight: normal;
color: #000;
}
a {
@extend %standard-text;
font-weight: bold;
}
p {
@extend %standard-text;
}
This would not print out the extend-only selector, but would apply its styles to those selectors that use them, compiling like so:
a, p {
font-size: 12px;
font-weight: normal;
color: #000;
}
a { font-weight: bold; }
A mixin is a method that will take some inputs and return us an output. There are loads of mixins available on the web, and entire libraries you can install, like Compass.
One of my favourite uses, is to replace my media queries with a mixin. To use this as an example, here is a blow-by-blow of the steps involved in creating a mixin:
First, I have to declare that I am writing a mixin, and give it a name.
@mixin media () { }
Then the mixin would have to return something, which I can put inside my curly-braces:
@mixin media () {
@media only screen and (min-width: 768px) {
@content;
}
}
This is now a working (albeit not a very useful) mixin! Note the use of the @content; inside the media query; this just means that what ever I write inside my mixin inclusion statement will get printed out here. To make sense of this, it is easiest show an example of how this mixin would be used in the wild:
Suppose I am in the middle of my Sass file and I decide I want a media query. I would reference this mixin like this:
@include media() {}
Now, if I want anything to actually be included inside the media query, I need to give this include some content:
p {
font-size: 12px;
@include media() { font-size: 16px; }
}
Which would compile as:
p { font-size: 12px; }
@media only screen and (min-width: 768px) {
}
So whatever I put inside the curly-brackets of the @include, gets transferred into the @content placeholder I left in the mixin.
Now this mixin is very lazy at the moment - its only doing to work of a parrot, when it is can do so much more. For instance, I can make it accept a width variable:
@mixin media ($width) {
@media only screen and (max-width: #{$width}) {
@content;
}
}
Very simply, in my mixin I have created a variable called $width by declaring it as an argument inside the circle-brackets. When using this variable, I have had to use what is called "interpolation" (wrapping it in #{ }) when using the variable in the media query string, otherwise it would get compiled as the variable name, rather than its value as we want. Because this is part of a CSS string, the Sass compiler steps out of the way and doesn't look for any of its own variables. Interpolation just tells Sass to jump back in and convert this variable to its value.
The output of this is a more dynamic, reusable mixin which can be used for more than one situation:
p {
font-size: 12px;
@include media(768px) { font-size: 14px; }
@include media(1024px) { font-size: 16px; }
}
For loops are one of the biggest space savers.
dpijhfdoijhd