Instantly share code, notes, and snippets.

Embed
What would you like to do?
Advanced SCSS, or, 16 cool things you may not have known your stylesheets could do

⇐ back to the gist-blog at jrw.fi

Advanced SCSS

Or, 16 cool things you may not have known your stylesheets could do. I'd rather have kept it to a nice round number like 10, but they just kept coming. Sorry.

I've been using SCSS/SASS for most of my styling work since 2009, and I'm a huge fan of Compass (by the great @chriseppstein). It really helped many of us through the darkest cross-browser crap. Even though browsers are increasingly playing nice with CSS, another problem has become very topical: managing the complexity in stylesheets as our in-browser apps get larger and larger. SCSS is an indispensable tool for dealing with this.

This isn't an introduction to the language by a long shot; many things probably won't make sense unless you have some SCSS under your belt already. That said, if you're not yet comfy with the basics, check out the awesome CSS extensions you've always wished you had:

The tips are vaguely ordered from basic to more advanced. If you're immediately bored, feel free to skip ahead to the deep end of the pool. Also, if you have any questions, comments or corrections, leave a comment below, or fork this gist and let me know!

So without further ado, on to the cool things.

1. Prefixing parent selector references

This is the familiar way you're probably using &:

a {
    &:hover {
        color: red;
    }
}
/* compiled CSS */
a:hover {
  color: red;
}

But & can be used with a prefix just as well:

p {
    body.no-touch & {
        display: none; // hide the message if not on a touch device
    }
}
/* compiled CSS */
body.no-touch p {
  display: none;
}

This can be very useful when you have a deep nesting of rules, and you want to effect a change to the styling of an element based on a selector match much closer to the DOM root. Client capability flags such as the Modernizr no-touch class are often applied this way to the <body> element. This way you don't have to back out of your nesting just to be able to change your <p> styling based on a class on the <body>.

2. Variable expansion in selectors

Variables can be expanded in selectors, too:

$alertClass: "error";

p.message-#{$alertClass} {
    color: red;
}
/* compiled CSS */
p.message-error {
  color: red;
}

...or almost anywhere else for that matter, like in media queries or CSS comments:

$breakpoint: 768px;

@media (max-width: #{$breakpoint}) {
    /* This block only applies to viewports <= #{$breakpoint} wide... */
}
/* compiled CSS */
@media (max-width: 768px) {
  /* This block only applies to viewports <= 768px wide... */
}

The media query example is particularly useful if the $breakpoint variable is defined in a settings partial somewhere (say, _settings.scss), so the breakpoints of the entire application are configurable from one file.

3. Variable defaults

If your SCSS module can be configured using globals (which tends to be the SCSS way), you can declare them with a default value:

// _my-module.scss:
$message-color: blue !default;

p.message {
    color: $message-color;
}
/* compiled CSS */
p.message {
  color: blue;
}

But you can then optionally override the module defaults before its inclusion:

$message-color: black;
@import 'my-module';
/* compiled CSS */
p.message {
  color: black;
}

That is, an assignment with a !default will only take effect if such a variable didn't have a value before (in contrast to the standard assignment, which will always overwrite a possible previous value).

This is how many SCSS modules (including most that ship with Compass) are configured.

4. Control directives

SCSS sports the standard set of flow control directives, such as if:

$debug: false; // TODO: move to _settings.scss

article {
    color: black;

    @if ($debug) { // visualizing layout internals
        border: 1px dotted red;
    }
}
/* compiled CSS */
article {
  color: black;
}

Having such compile-time flags in your project's styling can help debug complex layout issues visually, faster than just inspecting the page an element at a time.

There's also @for, @each and @while. They're good for a number of use cases that would otherwise need lots of repetitive (S)CSS, like:

@each $name in 'save' 'cancel' 'help' {
    .icon-#{$name} {
        background-image: url('/images/#{$name}.png');
    }
}
/* compiled CSS */
.icon-save {
  background-image: url("/images/save.png");
}
.icon-cancel {
  background-image: url("/images/cancel.png");
}
.icon-help {
  background-image: url("/images/help.png");
}

...and much more. Keep in mind, though, that if you need them in your daily styling work you're probably overdoing it a bit. Instead, the added complexity is usually justified when building configurable SCSS modules and such.

The interested reader can check out the full documentation on control directives.

5. The list data type

As we saw in the previous example, @each can iterate over a list. Lists are in fact a fundamental part of the SCSS language, but a quick demonstration of their usefulness might be configuring some generated styling:

$buttonConfig: 'save' 50px, 'cancel' 50px, 'help' 100px; // TODO: move to _settings.scss

@each $tuple in $buttonConfig {
    .button-#{nth($tuple, 1)} {
        width: nth($tuple, 2);
    }
}
/* compiled CSS */
.button-save {
  width: 50px;
}
.button-cancel {
  width: 50px;
}
.button-help {
  width: 100px;
}

This demonstrates two features of the list data type, namely the nth() list accessor function, and more interestingly list nestability: in JavaScript notation, the above would be equivalent to:

var buttonConfig = [[ 'save', 50 ], [ 'cancel', 50 ], [ 'help', 100 ]];

That is, lists can be separated by both spaces and commas, and alternation between the two notations produces nested lists.

6. Defining custom functions

Mixins are a well-known part of the language, but SCSS also allows you to define custom functions. Contrary to what one might expect, this can also be done in pure SCSS, instead of extending SCSS in Ruby:

@function make-greener($value) {
    @return $value + rgb(0,50,0); // arithmetic with colors is totally fine, btw
}
p {
    background: make-greener(gray);
}
/* compiled CSS */
p {
  background: #80b280;
}

The above color is a gray with a slight green tint.

Custom functions are most useful in avoiding some repeated computation in an expression. It also implicitly documents that computation by giving it a name: the above example, while contrived, is still more understandable than just having arbitrary color arithmetic in the style block. SCSS ships with a ton of useful built-in functions, and Compass adds even more, so do first check whether there's a built-in equivalent before implementing your own.

7. Argument defaults

Mixins and functions support default values for arguments; the last zero-to-N arguments can be made optional by providing them with a default value:

@mixin foobar($a, $b, $padding: 20px) {
    padding: $padding;
    // ...and something with $a and $b
}

p {
    @include foobar(123, "abc"); // the default padding's fine
}

p.important {
    @include foobar(123, "abc", 50px); // override the default
}

8. Keyword arguments

If your mixin (or function) takes a lot of arguments, there's a similar call-time syntax for selecting specific arguments to override:

@mixin foobar($topPadding: 10px, $rightPadding: 20px,
    $bottomPadding: 10px, $leftPadding: 20px, $evenMorePadding: 10px) {
    // do something with all these arguments...
}

p {
    @include foobar($bottomPadding: 50px);
}

Without being able to name arguments call-time, you'd have to specify $topPadding and $rightPadding first. Now, you can instead override only the argument you want, leaving the rest to their default values.

Note, however, that in cases where a lot of the arguments are just for overriding specific CSS properties (such as top-padding, bottom-padding and so on), the "content block overrides" -pattern is likely a better fit (see below).

9. Variable arguments for functions/mixins

Var-args work much the same way as in other languages that support the feature; any extra arguments to a function/mixin call are wrapped into a list and assigned to the argument having a ... suffix:

@mixin config-icon-colors($prefix, $colors...) {
    @each $i in $colors {
        .#{$prefix}#{nth($i, 1)} {
            color: nth($i, 2);
        }
    }
}
@include config-icon-colors('icon-',
    'save'   green,
    'cancel' gray,
    'delete' red
);
/* compiled CSS */
.icon-save {
  color: green;
}
.icon-cancel {
  color: gray;
}
.icon-delete {
  color: red;
}

The above helper could be used to set up colors for your font icons, Font Awesome for example, without having to repeat yourself. The helper works by passing in a variable number of arguments (after the first, required one). Each of those arguments is expected to be a tuple of two items (again in JavaScript notation, for example [ "save", "green" ]).

In fact, the ... syntax also works during call-time, where it expands a list into separate arguments, to be fed into the target mixin:

@mixin foobar($a, $b, $c) {
    // receives args $a = 5px, $b = red, and so on
}

$myArgs: 5px red "bla bla";
// at this point, you could also programmatically add/remove arguments

@include foobar($myArgs...);

Personally, I have yet to find a use case for this, but the documentation has a nice use case for passing current arguments forward to another mixin.

10. Content block arguments for mixins

Since version 3.2.0, SCSS has had an implicit mixin argument accessible through the @content directive. It allows passing an entire SCSS content block as an argument to the mixin:

@mixin only-for-mobile {
    @media (max-width: 768px) {
        @content;
    }
}

@include only-for-mobile() /* note: @content begins here */ {
    p {
        font-size: 150%;
    }
} /* @content ends */
/* compiled CSS */
@media (max-width: 768px) {
  p {
    font-size: 150%;
  }
}

This is a very powerful language feature for framework authors, as it allows you to pass arbitrary blocks of styling around, which you can choose to wrap in specific selectors, repeat in loops, make conditional with @if, etc. You can mix standard and content block arguments, too:

@mixin only-for-mobile($breakpoint) {
    @media (max-width: #{$breakpoint}) {
        @content;
    }
}

@include only-for-mobile(480px) {
    p {
        font-size: 150%;
    }
}

11. Content block overrides -pattern

Consider a mixin that generates a selector and some styles for it, allowing the caller to customize the styling if needed:

@mixin message($class, $color: yellow, $margin: 20px, $padding: 10px) {
    .message-#{$class} {
        border: 1px dotted $color;
        color: $color;
        margin: $margin;
        padding: $padding;
    }
}

Calling this mixin using keyword arguments (see above) is quite convenient, because if the defaults are fine, no extra arguments need be provided. If they're not, you only need to specify the arguments you want to override:

@include message("subtle", $margin: 5px);

But this requires you to list all overridable properties in the mixin signature. However, content block arguments allow arbitrary overrides without the argument jungle:

@mixin message($class) {
    .message-#{$class} {
        border: 1px dotted yellow;
        color: yellow;
        margin: 20px;
        padding: 10px;
        @content;
    }
}

@include message("subtle") {
    margin: 5px;
}
/* compiled CSS */
.message-subtle {
  border: 1px dotted yellow;
  color: yellow;
  margin: 20px;
  padding: 10px;
  margin: 5px;
}

Here, we allow the good-ole CSS cascade to effect the property override (the latter margin overrides the former one). Also, we're not limited to overriding the properties the author of the mixin thought of. In fact, this allows passing in nested blocks as well:

@include message("actionable") {
    button { // actionable messages may contain buttons for taking action!
        float: right;
    }
}
/* compiled CSS */
.message-actionable {
  border: 1px dotted yellow;
  color: yellow;
  margin: 20px;
  padding: 10px;
}
.message-actionable button {
  float: right;
}

This pattern can be useful in any library code that outputs nontrivial styling with generated selectors, since it allows the user a customization point beyond what the library author foresaw. Note, though, that in simple cases (where no selectors are emitted within the mixin) it's rather unnecessary, as any overrides can be made just using the standard CSS cascade.

12. Media query bubbling

@media blocks do not need to be declared at the root level of the stylesheet:

body {
    article {
        p {
            font-size: 100%;
            color: black;
            padding: 10px;

            @media (max-width: 768px) {
                font-size: 150%; // use larger text for smaller screens
            }
        }
    }
}
/* compiled CSS */
body article p {
  font-size: 100%;
  color: black;
  padding: 10px;
}

@media (max-width: 768px) {
  body article p {
    font-size: 150%;
  }
}

Notice how the compiler "bubbles up" the @media block to the root level (since regular CSS doesn't support selector nesting), and within it, outputs all styling that was encountered within the @media block in the SCSS source.

This is very useful as it allows you to make media-specific tweaks almost anywhere in your styling, right where they're relevant, instead of collecting all those tweaks to the end of the stylesheet, and hoping that their selectors will stay in sync with the ones they're overriding (they won't).

13. Media query nesting

The aforementioned bubbling mechanism also takes nesting into account, and combines all applicable queries with the and operator:

p {
    @media (max-width: 768px) {
        font-size: 150%; // use larger text for smaller screens
        @media (orientation: landscape) {
            line-height: 75%; // condense text a bit because of small vertical space
        }
    }
}
/* compiled CSS */
@media (max-width: 768px) {
  p {
    font-size: 150%;
  }
}
@media (max-width: 768px) and (orientation: landscape) {
  p {
    line-height: 75%;
  }
}

14. Extending selectors

SCSS allows extending selectors, by copying and combining selectors in the CSS output. Interestingly, while the mechanism is (obviously) very different, the semantics of @extend are quite analogous to traditional object-oriented programming languages (such as Java & whatnot):

.animal {
    background: gray;
}
.cat {
    @extend .animal;
    color: white;
}
/* compiled CSS */
.animal, .cat {
  background: gray;
}
.cat {
  color: white;
}

That is, .cat has all the properties of its "parent class" .animal, plus any specific ones it adds or overrides. Whereas in normal CSS you would have to reference both the extending class and the parent class (e.g. <div class="animal cat">), now you can just name the exact class you want (<div class="cat">). What it does (or doesn't) inherit from depends on the definition of .cat, and can later change without touching the markup.

Classical inheritance, right? Overriding properties in the "child class" works due to the style cascade in the browser: styling for the same selector that comes later in the file always wins over the styling that came before it. Perhaps a bit unintuitively, this actually works out fine even if the combined selectors have differing specificity (think .class extending an #id). Extending selectors may often be preferable to using mixins to achieve the same effect:

@mixin animal {
    background: gray;
    border: 1px solid red;
    font-weight: bold;
    font-size: 50px;
    color: red;
    padding: 20px;
}
.cat {
    @include animal;
    color: white;
}
.dog {
    @include animal;
    color: black;
}
/* compiled CSS */
.cat {
  background: gray;
  border: 1px solid red;
  font-weight: bold;
  font-size: 50px;
  color: red;
  padding: 20px;
  color: white;
}
.dog {
  background: gray;
  border: 1px solid red;
  font-weight: bold;
  font-size: 50px;
  color: red;
  padding: 20px;
  color: black;
}

Notice how only the last property (color) is different, the rest is the same. As we define more types of animals, the amount of repeated style properties in the CSS output keeps growing. This is in contrast to how selector extension would solve the same problem:

.animal {
    background: gray;
    border: 1px solid red;
    font-weight: bold;
    font-size: 50px;
    color: red;
    padding: 20px;
}
.cat {
    @extend .animal;
    color: white;
}
.dog {
    @extend .animal;
    color: black;
}
/* compiled CSS */
.animal, .cat, .dog {
  background: gray;
  border: 1px solid red;
  font-weight: bold;
  font-size: 50px;
  color: red;
  padding: 20px;
}
.cat {
  color: white;
}
.dog {
  color: black;
}

Finally, selector extension allows for integrations into 3rd party CSS libraries, that need not be specifically designed for extension, or even be written in SCSS. Twitter Bootstrap, for example, includes nice styling for buttons with .btn, but doesn't apply it to <button> elements by default. In our quest to reduce unnecessary CSS classes, we can fix this simply with:

@import "bootstrap.scss"; // just a renamed .css file, so that @import works

button {
    @extend .btn;
}

This will add the button selector into the Bootstrap source wherever .btn is defined.

The extension mechanism is surprisingly clever even with more complex selectors, and allows chaining extends (think .cat extends .feline extends .animal), but with great power comes great responsibility: overly neat tricks with @extend may be hard to reason about when debugging styles. Use responsibly.

15. Placeholder selectors

Because in the above example(s) the .animal base class isn't used anywhere directly (only through its child classes), we might just as well get rid of it in the CSS output. SCSS allows this with placeholder selectors. Whereas .foo signifies a class, and #foo an ID, %foo is considered a placeholder, and gets special treatment by the compiler: its styles are never output on their own, only through extension.

%animal {
    background: gray;
    // and so on...
}
.cat {
    @extend %animal;
    color: white;
}
.dog {
    @extend %animal;
    color: black;
}
/* compiled CSS */
.cat, .dog {
  background: gray;
}
.cat {
  color: white;
}
.dog {
  color: black;
}

Because %animal was just a placeholder selector, it's disappeared from the output. More importantly, if you never define a selector that extends %animal, its styles (background: gray; and so on) are completely omitted from the output. This can be very useful for SCSS framework authors, as you can offer any number of base classes for opt-in extension, but only the ones actually used are output into the resulting CSS.

Placeholder selectors can actually do even more than this, namely expanding the %placeholder part into a more complex selector during @extend, but personally I've never had to use this feature. The interested reader can check out the docs on the subject.

16. Selector multiple inheritance

A selector can actually inherit from several other selectors - that is, SCSS supports multiple inheritance. For each @extend, the current selector is appended to the selector being extended. When combined with placeholder selectors, this allows powerful abstractions for styling framework authors. This is perhaps best explained through an example:

// in the framework files:
%mfw-standing-out {
    font-size: 150%;
    font-style: italic;
    padding: 25px;
}
%mfw-slightly-shadowed {
    @include box-shadow(black 2px 2px 10px); // from Compass
}
%mfw-rounded {
    @include border-radius(25px); // from Compass
}

// in the application files:
#join-button {
    @extend %mfw-standing-out;
    @extend %mfw-slightly-shadowed;
    @extend %mfw-rounded;
    background: green;
    color: white;
}

This way of constructing styling has a few notable benefits:

  • Self-documentation: Instead of writing out loads of anonymous style properties, the author instead lists the "traits" of the UI component he is designing. The names of the traits can be as long & descriptive as needed (they won't appear in the CSS output).
  • Naming isolation: The application can use whichever naming conventions and semantics in the HTML, while the framework naming conventions stay internal to the SCSS source. In the above example, the framework adopts a common prefix %mfw (for "my framework", or whatever) to avoid naming collisions with other SCSS libraries.
  • Reduced repetition: The #join-button could use the border-radius() and box-shadow() helpers directly to achieve the same stylistic effect. But for each additional component that does so, the box-shadow() helper would output the exact same lines of CSS, with all the vendor prefixes and whatnot. Extending %mfw-slightly-shadowed, however, would simply append the selector to the list of other selectors that should receive shadowing.
  • Opt-in: If a specific "trait" is never used to describe a UI component, its styles are never output. That is, if you just use 1% of the features of a bloated style framework, your CSS payload will only contain that 1%. Contrast this to the de-facto way of just including an entire Bootstrap or jQuery, because the site uses 1 or 2 features from each.

Potential downsides with this approach should be kept in mind:

  • Debuggability: Without properly configured source maps for SCSS, it may be harder to figure out how some styling ended up affecting a specific element (keeping in mind the above point about self-documentation no longer applies in the compiled CSS).
  • Arguments: This technique won't replace mixins when computation is required based on some arguments. While there can be several versions of each "trait" (think %mfw-slightly-shadowed vs %mfw-heavily-shadowed), they'll always be completely static in content.

And that's it

Hope you picked up something useful!

There may be more at my site or @jareware, depending on when you look. :)

Cheers,

- Jarno

![GA](https://ssl.google-analytics.com/__utm.gif?utmwv=5.4.3&utmn=47004&utmhn=gist.github.com&utmdt=Advanced%20SCSS%2C%20or%2C%2016%20cool%20things%20you%20may%20not%20have%20known%20your%20stylesheets%20could%20do&utmr=-&utmp=%2Fjareware%2F4738651&utmac=UA-42176157-3&utmcc=__utma%3D1.1828258468.1374783534.1374783534.1374783534.1%3B%2B__utmz%3D1.1374783534.1.1.utmcsr%3D(direct\)%7Cutmccn%3D(direct\)%7Cutmcmd%3D(none\)%3B)

@ddessaunet

This comment has been minimized.

ddessaunet commented Jun 19, 2014

Very helpfull!

@jareware

This comment has been minimized.

Owner

jareware commented Jun 27, 2014

@ddessaunet, thanks! :)

@AWaselnuk

This comment has been minimized.

AWaselnuk commented Feb 17, 2015

Definitely taught me some new things about a SCSS even though I have a lot of experience with it. Thank you!

@mattsince87

This comment has been minimized.

mattsince87 commented Mar 26, 2015

Good Resource :)

@Misplon

This comment has been minimized.

Misplon commented May 5, 2015

Awesome! Thanks :)

@yadav215

This comment has been minimized.

yadav215 commented Oct 21, 2015

sound good

@karasolga

This comment has been minimized.

karasolga commented Mar 1, 2016

Nice article, thanks

@desfero

This comment has been minimized.

desfero commented Nov 8, 2016

thanks

@henriquecholo

This comment has been minimized.

henriquecholo commented Feb 24, 2017

Great work

@czinco

This comment has been minimized.

czinco commented Apr 2, 2017

Awesome!

@KerryRuddock

This comment has been minimized.

KerryRuddock commented Apr 20, 2017

Hi Guy, in your 1st example you show us the familiar way of using & as a prefix and then you show us a way how to use it as a 'suffix' which is what I think you meant to say? Anyways... thanks for this as this is good to know.

I have a question perhaps you might answer or one of your colleagues. Is there a way for SASS to generate CSS that doesn't get placed in the css file, but instead get placed in the html header for 'above the fold content'? Just asking as I am facing this issue.

@mikemai2awesome

This comment has been minimized.

mikemai2awesome commented May 5, 2017

Very nice. I've been doing [dir=rtl] & a lot.

@AlexNodex

This comment has been minimized.

AlexNodex commented Jul 13, 2017

in your @include only-for-mobile() /* note: @content begins here */ { (number 10), the content begins after the { not before it

@soerenuhrbach

This comment has been minimized.

soerenuhrbach commented Jul 13, 2017

Good Work!

@dkrutsko

This comment has been minimized.

dkrutsko commented Jul 13, 2017

Super nice, thank you!

@oqx

This comment has been minimized.

oqx commented Jul 13, 2017

Nice write up! One thing that I've really enjoyed is Sass maps. I've been teaching a friend to program who has no experience, and Sass provides some great options to segue from markup to programming. For example, using maps to create a config object of a component's properties:

$config: ( color: '#fff', border: '1px solid #000', z-index: 10 )

You can then use the map-get function to retrieve the values, like this:
map-get($config, color)

Here's a more advanced example of this being used:
https://codepen.io/sodapop/pen/pPQNpQ

@aleciavogel

This comment has been minimized.

aleciavogel commented Jul 13, 2017

This is amazing, thank you! Just when I felt like I had SCSS figured out, this gist blew my mind.

@azinasili

This comment has been minimized.

azinasili commented Jul 13, 2017

+1 to @oqx. Maps can also be nested too making an even more elaborate setup.

@czinco

This comment has been minimized.

czinco commented Jul 14, 2017

Cheers, so helpful!

@filipbarak

This comment has been minimized.

filipbarak commented Jul 14, 2017

Awesome content. Learned a lot!

@ZhiliangGong

This comment has been minimized.

ZhiliangGong commented Jul 16, 2017

incredibly helpful! very well written!

@pau-ker

This comment has been minimized.

pau-ker commented Jul 17, 2017

Thanks a lot! Very handy.

BTW:

@import "bootstrap.scss"; // just a renamed .css file, so that @import works

Import .css files by writing no file extension. Works perfectly and you dont have to rename .css to .scss.
@import "bootstrap";

@kainanaina

This comment has been minimized.

kainanaina commented Jul 17, 2017

@pau-ker it's a two different imports. @import in SCSS just concatenates files before complication, while native CSS one is dynamic import with some legacy performance issues and should be avoided.

@pau-ker

This comment has been minimized.

pau-ker commented Jul 18, 2017

@kainanaina i know.
Therefore you have to make sure to skip the (.css) file extension.

@import "bootstrap.css";
Will compile to:
@import url("bootstrap.css");

but

@import "bootstrap";
Will compile to:
html{font-family:sans-serif;-webkit-text-size-adjust:100%;...

@tandavas

This comment has been minimized.

tandavas commented Jul 19, 2017

This is very helpful! I just added this to awesome-sass. 😃

@satrya

This comment has been minimized.

satrya commented Jul 20, 2017

Thanks, really helpful!
The only disadvantages using $placeholder is it can't be inside the @media

@pawelcybulski

This comment has been minimized.

pawelcybulski commented Jul 21, 2017

Me likes!

@robertpataki

This comment has been minimized.

robertpataki commented Jul 27, 2017

Sweet!

@josecarlospsh

This comment has been minimized.

josecarlospsh commented Jul 28, 2017

Great! 👍

@stephanoapiolaza

This comment has been minimized.

stephanoapiolaza commented Jul 30, 2017

Thanks!

@nsei

This comment has been minimized.

nsei commented Aug 10, 2017

Perfect!

@josefzacek

This comment has been minimized.

josefzacek commented Sep 6, 2017

Pretty cool. Thank you

@xiaobinwu

This comment has been minimized.

xiaobinwu commented Sep 7, 2017

thanks

@lucasgrey

This comment has been minimized.

lucasgrey commented Sep 10, 2017

Lovely article to brush up on some Sass tricks! I totally forgot I can use '&' nested selectors at end of class and it will bubble out.

@dikaseva

This comment has been minimized.

dikaseva commented Sep 28, 2017

Very helpful, Thanks!!!

@kongdigital

This comment has been minimized.

kongdigital commented Oct 12, 2017

Thanks that was enlightening

@dalenguyen

This comment has been minimized.

dalenguyen commented Oct 16, 2017

@KerryRuddock I believe that you are talking about critical-css in scss.

@johnking

This comment has been minimized.

johnking commented Oct 28, 2017

Thanks for the great post !

@Emilius449

This comment has been minimized.

Emilius449 commented Jan 26, 2018

Great Post... very helpful

@brunomac

This comment has been minimized.

brunomac commented Feb 23, 2018

Geeat job!

@Sainojin

This comment has been minimized.

Sainojin commented Feb 25, 2018

it useful. thank you.

@mgolkardev

This comment has been minimized.

mgolkardev commented Mar 6, 2018

it useful. thank you.

@alzintani

This comment has been minimized.

alzintani commented Mar 15, 2018

Perfect!
thank you.

@DoctypeRosenthal

This comment has been minimized.

DoctypeRosenthal commented Mar 23, 2018

Cool man! Thanks! This is awesome!

@rVizzini

This comment has been minimized.

rVizzini commented Apr 8, 2018

I've a question: I know that it's possible to add custom attributes to html page of ionic project (like attribute item-one) to manage a component in the scss, recalling that attribute with square bracket ([item-one]). Someone can link tutorial to understand how to do that in the better way???

@MFJonesX

This comment has been minimized.

MFJonesX commented Apr 12, 2018

Very helpful! Thanks man!

@rodgerpaulo

This comment has been minimized.

rodgerpaulo commented Apr 19, 2018

Awesom!

@Thor89

This comment has been minimized.

Thor89 commented May 4, 2018

Very helpful! Thank you!

@sarahRosannaBusch

This comment has been minimized.

sarahRosannaBusch commented May 4, 2018

Awesome reference!

I'm getting a weird error when I tried your "make-greener' example:
Error: Undefined operation "gray + #323232".

Has anyone else had an issue adding hex values?

@MukundhanSampath

This comment has been minimized.

MukundhanSampath commented May 9, 2018

Could be helpfull :)

$breakpoints: ( 'phone': 320px, 'tablet': 768px, 'desktop': 1024px, 'desktop-big':1440px) !default;

// Media Queries in Sass
$mobile-large:425px !default;
$mob-tab-break-min:425px !default;
$mob-tab-break-max:600px !default;
$mobile-medium:375px !default;
$mobile-small:320px !default;
$tablet:768px !default;
$laptop: 1024px !default;
$large-laptop: 1440px !default;
$desktop:2440px !default;
$mobile-portrait: 320px !default;
$mobile-landscape: 480px !default;
$tablet-portrait: 768px !default;
$tablet-landscape: 980px !default;

/** Example: Can be used to find which media, that a screen falls in
@include mobile-only {
background: $white;
}
@include mobile-small {
background: yellowgreen;
}
@include mobile-medium {
background: fuchsia;
}
@include mobile-tab-break {
background: green !important;
}
@include mobile-large {
background: hotpink;
}
@include tablet-only {
background: orange;
}
@include laptop-only {
background: blue;
}
@include largelaptop-only {
background: red;
}
@include desktop-only {
background: dimgrey;
}
@include large-screens {
background: aqua;
} **/

// ------------------------------
// mobile
// Both portrait and landscape
// ------------------------------
@mixin mobile-only {
@media only screen and (max-width: $mobile-large) {
@content;
}
}
// for small mobiles
@mixin mobile-small {
@media only screen and (min-width: 1px) and (max-width: $mobile-small) {
@content;
}
}

// For medium mobiles
@mixin mobile-medium {
@media only screen and (min-width: $mobile-small + 1) and (max-width: $mobile-medium) {
@content;
}
}

// for larger mobiles
@mixin mobile-large {
@media only screen and (min-width: $mobile-medium + 1) and (max-width: $mobile-large) {
@content;
}
}

@mixin mobile-tab-break {
@media only screen and (min-width: $mob-tab-break-min + 1) and (max-width: $mob-tab-break-max) {
@content;
}
}

// tablet
// Both the portrait and landscape width of the tablet
// Larger than a landscape mobile but less than or equal to a landscape tablet
@mixin tablet-only {
@media only screen and (min-width: $mobile-large + 1) and (max-width: $tablet) {
@content;
}
}

// For Laptop only
@mixin laptop-only {
@media only screen and (min-width: $tablet + 1) and (max-width: $laptop) {
@content;
}
}

// For Desktop Only
@mixin desktop-only {
@media only screen and (min-width: $laptop + 1) and (max-width: $desktop) {
@content;
}
}

// For Desktop Only
@mixin largelaptop-only {
@media only screen and (min-width: $laptop + 1) and (max-width: $large-laptop) {
@content;
}
}

// For Large-Screens
@mixin large-screens {
@media only screen and (min-width: $desktop + 1) {}
@content;
}

// Everything up to and including the portrait width of the phone
// Since it's the smallest query it doesn't need a min
@mixin mobile-portrait-only {
@media only screen and (max-width: $mobile-portrait) {
@content;
}
}

// Everything up to and including the mobile portrait
@mixin mobile-portrait-and-below {
@media only screen and (max-width: $mobile-portrait) {
@content;
}
}

// Everything above and including the mobile portrait
@mixin mobile-portrait-and-up {
@media only screen and (min-width: $mobile-portrait) {
@content;
}
}

// Everthing larger than a portrait mobile up until mobile landscape
@mixin mobile-landscape-only {
@media only screen and (min-width: $mobile-portrait + 1) and (max-width: $mobile-landscape) {
@content;
}
}

// Everything up to and including the mobile landscape width
@mixin mobile-landscape-and-below {
@media only screen and (max-width: $mobile-landscape) {
@content;
}
}

// Everything above and including the mobile landscape width
@mixin mobile-landscape-and-up {
@media only screen and (min-width: $mobile-portrait + 1) {
@content;
}
}

// Everything larger than mobile landscape up until the portrait width of the tablet
@mixin tablet-portrait-only {
@media only screen and (min-width: $mobile-landscape + 1) and (max-width: $tablet-portrait) {
@content;
}
}

// Everything below and including the portrait width of the tablet
@mixin tablet-portrait-and-below {
@media only screen and (max-width: $tablet-portrait) {
@content;
}
}

// Everything above and including the portrait width of the tablet
@mixin tablet-portrait-and-up {
@media only screen and (min-width: $mobile-landscape + 1) {
@content;
}
}

// Larger than portrait but less than or equal to the landscape width
@mixin tablet-landscape-only {
@media only screen and (min-width: $tablet-portrait + 1) and (max-width: $tablet-landscape) {
@content;
}
}

// Up to and including the tablet landscape
@mixin tablet-landscape-and-below {
@media only screen and (max-width: $tablet-landscape) {
@content;
}
}

// Everything larger than portrait tablet
@mixin tablet-landscape-and-up {
@media only screen and (min-width: $tablet-portrait + 1) {
@content;
}
}

@dansmill

This comment has been minimized.

dansmill commented May 28, 2018

Hey, you did just have 10. 0x10 :)

@Kerrys7777

This comment has been minimized.

Kerrys7777 commented May 30, 2018

In your 3 rd point, I think you have omitted the !important from the compiled CSS.

/* compiled CSS */
p.message {
  color: blue;
}

Would you mind rectifying this minor issue? Thanks

@nicoHersant

This comment has been minimized.

nicoHersant commented May 30, 2018

@jareware Thanks, that's some nice job.

@coleherzer

This comment has been minimized.

coleherzer commented Jun 12, 2018

Any of you Sass experts out there care to answer a question I've been struggling to find resources for?

I have an app with a bunch of sass, and some of my sass comes from a UI kit. (sass/codebase)
My app also has custom hand written sass. (sass/base)

There are some media queries handled by the UI kit that are actually causing more bad than good in my particular situation so I need to find a way to write sass in sass/base that ignores/overrides/disables two media queries in sass/codebase. Is there a way to do this? I've looked everywhere online and unfortunately while there's a lot of resources for learning about media queries, there's not a lot of resources out there for how to cancel media queries without actually removing them from the code. Any help would be spectacular

@azimiester

This comment has been minimized.

azimiester commented Jul 2, 2018

This is pretty good stuff! Thanks.

@ahoehma

This comment has been minimized.

ahoehma commented Jul 12, 2018

Nice! 👍

@green6erry

This comment has been minimized.

green6erry commented Aug 15, 2018

This is awesome! Thank you!!!

@BashaarUbaid

This comment has been minimized.

BashaarUbaid commented Aug 16, 2018

could anyone tell me how to set the alignment of an iframe using scss?

@Warlot-PQ

This comment has been minimized.

Warlot-PQ commented Sep 5, 2018

Amazing tutorial! Thanks

@michielsteeg

This comment has been minimized.

michielsteeg commented Sep 17, 2018

Pretty cool, thanks!

@ramkumarramarajbb

This comment has been minimized.

ramkumarramarajbb commented Sep 20, 2018

Awesome!!! Thanks...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment