Sass

CSS on its own can be fun, but stylesheets are getting larger, more complex, and harder to maintain. This is where a preprocessor can help. Sass lets you use features that don’t exist in CSS yet like variables, nesting, mixins, inheritance and other nifty goodies that make writing CSS fun again.

Sass: Syntactically Awesome Style Sheets

BEM class selectors and the Sass ampersand

The Sass ampersand is incredibly useful in building selectors based on the parent selector, but it has a limitation. Take the following nested BEM-style selectors:

Code language: Sass

.component {
  // A BEM modifier.
  &--reversed {
    background: white;
    border-color: lightgray;
 
    // Target a descendent only when the parent has the modifier? Not exactly...
    &__child-element {
      background: rebeccapurple;
    }
  }
}

The linked post explains the problem:

Wait, why is this not working? The problem is that the & has a scope of .component--reversed, so &__child-element compiles to .component--reversed__child-element, which doesn’t [exist] in the markup.

The fix is to save the & to a variable in the parent and use that in the child selector:

Code language: Sass

.component {
  // Save the current value of & as $self.
  $self: &;
 
  &--reversed {
    background: white;
    border-color: lightgray;
 
    // Print $self in place of & to get the correct scope of the parent above.
    #{$self}__child-element {
      background: rebeccapurple;
    }
  }
}

The compiled CSS for that element is now .component--reversed .component__child-element[.]

CSS Variables Are A Sometimes Food

This article makes the important point that CSS custom properties - a.k.a. variables - are not a complete and ideal replacement for variables in preprocessors like Sass: they have different but overlapping use-cases, and custom properties are far better if used when cascading or changing the values in the browser are needed, while preprocessor variables are more performant for the browser when they perform the same role as custom properties, i.e. not repeating oneself. There’s also the issue of browser support for custom properties, but that’s another story.

Bevelled box corners with CSS and Sass

Say you’re trying to pull off a design effect where the corner of an element are cut off. Maybe you’re a Battlestar Galactica fan? Or maybe you just like the unusual effect of it, since it avoids looking like a typical rectangle.

[…]

I suspect there are many ways to do it. Certainly, you could use multiple backgrounds to place images in the corners. You could just as well use a flexible SVG shape placed in the background. I bet there is also an exotic way to use gradients to pull it off.

But, I like the idea of simply taking some scissors and clipping off the dang corners. We essentially can do just that thanks to clip-path. We can use the polygon() function, provide it a list of X and Y coordinates and clip away what is outside of them.

Code language: CSS

.box {
  --notch-size: 2em;
 
  clip-path: polygon(
    0% var(--notch-size),
    var(--notch-size) 0%,
    calc(100% - var(--notch-size)) 0%,
    100% var(--notch-size),
    100% calc(100% - var(--notch-size)),
    calc(100% - var(--notch-size)) 100%,
    var(--notch-size) 100%,
    0% calc(100% - var(--notch-size))
  );
}

I’ve written a Sass mixin to make this easier to reuse:

Code language: Sass

///
/// Bevel all four corners of an element by the specified amount.
///
/// This is based on the linked article by Chris Coyier.
///
/// @author Matei "Ambient.Impact" Stanca
///
/// @link https://ambientimpact.com/web/snippets/bevelled-box-corners-with-css-and-sass
///
/// @param {Number} $size - The amount to bevel by.
///
@mixin bevel($size) {
  clip-path: polygon(
    // Top left corner points.
    0%          #{$size},
    #{$size}    0%,
    // Top right corner points.
    calc(100% - #{$size}) 0%,
    100%        #{$size},
    // Bottom right corner points.
    100%        calc(100% - #{$size}),
    calc(100% - #{$size}) 100%,
    // Bottom left corner points.
    #{$size}    100%,
    0%          calc(100% - #{$size})
  );
}

You can use it like so:

Code language: Sass

.box {
  // Really simple version:
  @include bevel(1em);
 
  // If you want to use CSS custom properties for browsers that support them,
  // you can do so. The benefits are that these cascade like other CSS
  // properties, so they can be inherited, and modified in real time. This must
  // come after the simple version.
  --bevel-amount: 1em;
  @include bevel(var(--bevel-amount));
}

include-media: Simple, elegant and maintainable media queries in Sass

I’ve just converted my Sass code to use this, and I can safely say it’s pretty excellent.

include-media is a Sass library for writing CSS media queries in an easy and maintainable way, using a natural and simplistic syntax.

[…]

Why another library?

I spent quite some time experimenting with different libraries and mixins available out there, but eventually all of them failed to do everything I needed in an elegant way. Some of them wouldn’t let me mix set breakpoints with case-specific values, others wouldn’t properly handle the CSS OR operator and most of them had a syntax that I found complicated and unnatural.

include-media was the result of that experience and it includes all the features I wish I had found before, whilst maintaining a simplistic and natural syntax.

I wrote an article on CSS-Tricks about this experience, where I explain in detail the problems I found with each of the solutions I experimented with. I also wrote on David Walsh’s blog about the implementation details of include-media.

Example usage:

Code language: Sass

$breakpoints: (small: 320px, medium: 768px, large: 1024px);
 
/* Inclusive and exclusive operators for a finer control over the intervals */
@include media(">medium", "<=large") {
	width: 100%;
}

Easing Linear Gradients

Linear gradients are easy to create in CSS and are extremely useful. As we’ll go through in this article, we can make them visually much smoother by creating them with non-linear gradients. Well, non-linear in the easing sense, anyway!

[…]

In Material Design style guidelines for images, the designers at Google talk about text protection gradients. They call them a scrim. They recommend:

[the] gradient should be long… with the center point about 3/10 towards the darker side of the gradient. This gives the gradient a natural falloff and avoids a sharp edge.

A scrim according to Material Design guidelines

We can’t create exactly that with linear gradients, but we can (and will) create a “low poly” approximation with more color stops.

A scrim with 5 color stops to show the principle

Using only 5 color stops (like in the illustration above) would create some serious banding. Adding more stops makes the gradient a lot smoother. This is exactly what I’ve done in the demo you saw in the first image in this article. Il buono has a 13 color-stop gradient, which makes it blend nicer into the image.

(See the comments in the source link for Sass mixins.)

See also the gradient easing generator by the same author.

Fluid Type on CodePen Blogs

It became more popular to “go fully responsive” with layouts, where widths were largely in percentages, so that you get to use as much room is available at any given screen size. To a point, anyway.

You can also “go fully responsive” with typography, in a sense. There are a number of Pens by Mike Riethmuller that tackle things like fluid type size, fluid modular scale, and even fluid vertical rhythm.

It’s worth reading up on Mike’s technique here, but a distilled Sass version is like:

Code language: Sass

@function strip-unit($value) {
  @return $value / ($value * 0 + 1);
}
 
@mixin fluid-type($min-vw, $max-vw, $min-font-size, $max-font-size) {
  $u1: unit($min-vw);
  $u2: unit($max-vw);
  $u3: unit($min-font-size);
  $u4: unit($max-font-size);
 
  @if $u1 == $u2 and $u1 == $u3 and $u1 == $u4 {
    & {
 
      font-size: $min-font-size;
      @media screen and (min-width: $min-vw) {
        font-size: calc(#{$min-font-size} + #{strip-unit($max-font-size - $min-font-size)} * ((100vw - #{$min-vw}) / #{strip-unit($max-vw - $min-vw)}));
      }
 
      @media screen and (min-width: $max-vw) {
        font-size: $max-font-size;
      }
    }
  }
}
 
$min_width: 320px;
$max_width: 1200px;
$min_font: 16px;
$max_font: 24px;
 
$mod_1: 1.2; // mobile
$mod_2: 1.5; // desktop
 
html {
  @include fluid-type($min_width, $max_width, $min_font, $max_font);
}
 
h1 {  
  font-size: $mod_1*$mod_1*$mod_1*$mod_1 *1rem; 
  @include fluid-type($min_width, $max_width, $mod_1*$mod_1*$mod_1 *$min_font, $mod_2*$mod_2*$mod_2 *$min_font);
}
h2 {  
  font-size: $mod_1*$mod_1*$mod_1 *1rem; 
  @include fluid-type($min_width, $max_width, $mod_1*$mod_1*$mod_1 *$min_font, $mod_2*$mod_2*$mod_2 *$min_font);
}
h3 { 
  font-size: $mod_1*$mod_1 *1rem;
  @include fluid-type($min_width, $max_width, $mod_1*$mod_1 *$min_font, $mod_2*$mod_2 *$min_font);
}