Articles by
Hugo Giraudel

Accessibility advocate, author, speaker.

Power Function

While very helpful with arithmetic, Sass falls a bit short with mathematical helper functions. There has been an open issue on the official repository to ask for more math-related functions for almost 3 years.

Some third-party vendors like Compass or SassyMath provide advanced support for math features, but they are external dependencies which could (should?) be avoided.

One of the most popular request on this matter is a power function or even a exponent operator. Unfortunately, there is still no support for this in Sass and while it is still under active discussion, it is unlikely to happen very soon.

Meanwhile, being able to raise a number to a certain power happens to be very useful in CSS. Here are a few examples where it would come in handy:

Sass implementation

Fortunately for us, it is possible (and quite simple) to create a power function with nothing but Sass. All we need is a loop and some basic mathematical operators (such as * and /).

Positive integer exponents

Our function (named pow) in its smallest form would look like this:

@function pow($number, $exponent) {
  $value: 1;

  @if $exponent > 0 {
    @for $i from 1 through $exponent {
      $value: $value * $number;
    }
  }

  @return $value;
}

Here is an example:

.foo {
  width: pow(20, 2) * 1px; // 400px
}

Positive or negative integer exponents

However it only works with a positive `$power` argument. Allowing negative exponents wouldn’t be so hard, we just need a small extra condition:

@function pow($number, $exponent) {
  $value: 1;

  @if $exponent > 0 {
    @for $i from 1 through $exponent {
      $value: $value * $number;
    }
  } @else if $exponent < 0 {
    @for $i from 1 through -$exponent {
      $value: $value / $number;
    }
  }

  @return $value;
}

Here is an example:

.foo {
  width: pow(10, -2) * 1px; // 0.0001px
}

Positive or negative exponents

Now, what if we want non-integer exponents? Such as 4.2 for instance? The truth is that it really is not easy. It still is doable, but it requires more than just a loop and a few operations.

This has been done on the Bourbon repository in order to complete the modular-scale(..) function from the framework (although has been declined). Here is the code:

@function pow($number, $exponent) {
  @if (round($exponent) != $exponent) {
    @return exp($exponent * ln($number));
  }
    
  $value: 1;
  
  @if $exponent > 0 {
    @for $i from 1 through $exponent {
     $value: $value * $number;
    }
  } @else if $exponent < 0 {
    @for $i from 1 through -$exponent {
      $value: $value / $number;
    }
  }

  @return $value;
}

@function factorial($value) {
  $result: 1;

  @if $value == 0 {
    @return $result;
  }
  
  @for $index from 1 through $value {
    $result: $result * $index;
  }
  
  @return $result;
}

@function summation($iteratee, $input, $initial: 0, $limit: 100) {
  $sum: 0;
  
  @for $index from $initial to $limit {
    $sum: $sum + call($iteratee, $input, $index);
  }
  
  @return $sum;
}

@function exp-maclaurin($x, $n) {
  @return (pow($x, $n) / factorial($n));
}

@function exp($value) {
  @return summation('exp-maclaurin', $value, 0, 100);
}

@function ln-maclaurin($x, $n) {
  @return (pow(-1, $n + 1) / $n) * (pow($x - 1, $n));
}

@function ln($value) {
  $ten-exp: 1;
  $ln-ten: 2.30258509;
  
  @while ($value > pow(10, $ten-exp)) {
    $ten-exp: $ten-exp + 1;
  }
  
  @return summation(ln-maclaurin, $value / pow(10, $ten-exp), 1, 100) + $ten-exp * $ln-ten;
}

Further considerations

Well, that was intense. If you happen to need support for non-integer exponents (like 4.2), I recommend you use an external dependency which provides it (such as sass-math-pow) instead of including all this code in your project. Not that it is a bad thing per se, but it is not really the role of your project to host such a large a mount of non-authored polyfilling code (that’s why we have package managers).

Also note that all these operations are quite intensive for such a thin layer as Sass. At this point, and if your design rely on advanced mathematical functions, it is probably better to pass the implementation of these helpers from the upper layer (Node.js, Ruby, etc.) down to Sass through a plugin system (Eyeglass, Ruby gem, etc.).

But for basic pow(..) usage, I can’t recommend the simple versions enough!

Mixin to Qualify a Selector

There is no easy way of qualifying a selector from within its associated ruleset. By qualifying I mean prepending an element name (e.g. a) to a class (e.g. .btn) so that a ruleset gets specific to a combination of an element selector and a class selector (e.g. a.btn) for instance.

As of today, the best (and so far only valid way) to do so is as follow:

.button {
  @at-root a#{&} {
    // Specific styles for `a.button`
  }
}

Wow, definitely not really elegant, is it? Ideally, you might want to hide this kind of horrific syntax behind a mixin so that you keep a clean and friendly API, especially if you have rookie developers in your team.

Doing so is extremely simple of course:

/// Since the current way to qualify a class from within its ruleset is quite
/// ugly, here is a mixin providing a friendly API to do so.
/// @author Hugo Giraudel
/// @param {String} $element-selector - Element selector
@mixin qualify($element-selector) {
  @at-root #{$element-selector + &} {
    @content;
  }
}

Now, rewriting our previous snippet:

.button {
  @include qualify(a) {
    // Specific styles for `a.button`
  }
}

Much better, right? Still, qualify can sound a bit tricky for inexperienced Sass tinkerers. You could provide an alias when a more descriptive name, such as when-is.

/// @alias qualify
@mixin when-is($args...) {
  @include qualify($args...) {
    @content;
  }
}

One final example:

.button {
  border: none;
  
  // Qualify `.button` with `button`
  @include qualify(button) {
    -webkit-appearance: none;
  }
  
  // Qualify `.button` with `a`
  @include when-is(a) {
    text-decoration: none;
  }
}

Placing Items on a Circle

It can be quite challenging to place items on a circle with CSS. Usually, we end up relying on JavaScript because some plugins do it all right away. However more often than not there is no good reason to do it in JavaScript rather than CSS. This is presentational purpose, let's go the CSS way.

The Mixin

Ana Tudor explained how she managed to do it in a Stack Overflow answer, using chained CSS transforms. Thereafter I turned her solution into a Sass mixin to make everything a breeze.

/// Mixin to place items on a circle
/// @author Hugo Giraudel
/// @author Ana Tudor
/// @param {Integer} $item-count - Number of items on the circle
/// @param {Length} $circle-size - Large circle size
/// @param {Length} $item-size - Single item size
@mixin on-circle($item-count, $circle-size, $item-size) {
  position: relative;
  width:  $circle-size;
  height: $circle-size;
  padding: 0;
  border-radius: 50%; 
  list-style: none;       
  
  > * {
    display: block;
    position: absolute;
    top:  50%; 
    left: 50%;
    width:  $item-size;
    height: $item-size;
    margin: -($item-size / 2);
  
    $angle: (360 / $item-count);
    $rot: 0;

    @for $i from 1 through $item-count {
      &:nth-of-type(#{$i}) {
        transform: 
          rotate($rot * 1deg) 
          translate($circle-size / 2) 
          rotate($rot * -1deg);
      }

      $rot: $rot + $angle;
    }
  }
}

Caution! Vendor prefixes have been omitted from this code snippet. Be sure to prefix transform if you do not use Autoprefix.

Demo

For demo purposes, we'll consider a list of 8 images but basically anything could work.

<ul class='circle-container'>
  <li><img src='http://lorempixel.com/100/100/city' alt="..." /></li>
  <li><img src='http://lorempixel.com/100/100/nature' alt="..." /></li>
  <li><img src='http://lorempixel.com/100/100/abstract' alt="..." /></li>
  <li><img src='http://lorempixel.com/100/100/cats' alt="..." /></li>
  <li><img src='http://lorempixel.com/100/100/food' alt="..." /></li>
  <li><img src='http://lorempixel.com/100/100/animals' alt="..." /></li>
  <li><img src='http://lorempixel.com/100/100/business' alt="..." /></li>
  <li><img src='http://lorempixel.com/100/100/people' alt="..." /></li>
</ul>
.circle-container {
  @include on-circle($item-count: 8, $circle-size: 20em, $item-size: 6em); 
  margin: 5em auto 0;
  border: solid 5px tomato;
  
  img { 
    display: block; 
    max-width: 100%; 
    border-radius: 50%;
    filter: grayscale(100%);
    border: solid 5px tomato;
    transition: .15s;
    
    &:hover,
    &:active {
      filter: grayscale(0);
    }
  }
}

See the Pen Items on circle by Hugo Giraudel (@HugoGiraudel) on CodePen.

Custom Scrollbars Mixin

Scrollbars are one of those UI components that are present on almost every page of the internet, yet we (developers) have little to no control over it. Some browsers give us the ability to customize their appearance but for most browsers including Firefox it just is not possible.

Still, Chrome and Internet Explorer (yes) make it possible for us to define custom styles for scrollbars. However the syntax horribly complex, and of course, definitely not standard. Welcome to the proprietary world. This is why you might want to have a little mixin to easily customize your scrollbars. Right?

(more…)

@extend Wrapper a.k.a Mixtend

When extending a selector with the @extend directive, Sass doesn’t take the CSS content from the extended selector to put it in the extending one. It works the other way around. It takes the extending selector and append it to the extended one.

Because of how it works, it makes it impossible to use it from different scopes. For instance, you can’t extend a placeholder that has been declared in a @media block, nor can you extend a placeholder from root if you’re within a @media directive.

Surely we can find a way to use @extend when possible, mixin otherwise. Indeed, it's doable but it's a bit tricky, I call this the mixtend hack. You might want to think twice before implementing everywhere in your project. Perhaps using mixins only would be easier. I'll leave you the judge of that.

Wrapping @extend

The idea is actually quite simple to grasp. First we define the mixin. The only parameter is $extend, which defines whether or not the mixin should try extending rather than including. Obviously, it is a boolean (default to true).

If $extend is true, we extend a placeholder named after the mixin (unfortunately, this is not automagically computed). If it's false, we dump the CSS code as a regular mixin would do.

Out of the mixin, we define the aforementioned placeholder. To avoid repeating the CSS code in the placeholder, we only have to include the mixin by setting $extend to false so it dumps the CSS code in the placeholder’s core.

/// *Mixtend* hack
/// @author Hugo Giraudel
@mixin mixtend-boilerplate($extend: true) {
  @if $extend {
    @extend %mixtend-boilerplate-placeholder;
  } @else {
    // Mixtend content
  }
}

%mixtend-boilerplate-placeholder {
  @include mixtend-boilerplate($extend: false);
}

Example

As a simple example, we will use the micro-clearfix from Nicolas Gallagher.

@mixin clearfix($extend: true) {
  @if $extend {
    @extend %clearfix;
  } @else {
    &:after {
      content: '';
      display: table;
      clear: both;
    }
  }
}

%clearfix {
  @include clearfix($extend: false);
}

Using it is quite straightforward:

.a { @include clearfix; }
.b { @include clearfix; }

@media (min-width: 48em) {
  .c {
    @include clearfix(false);
  }
}

Result CSS:

.a:after, .b:after {
  content: '';
  display: table;
  clear: both;
}

@media (min-width: 48em) {
  .c:after {
    content: '';
    display: table;
    clear: both;
  }
}

Sublime Text Snippet

If you want to save the boilerplate in order to make it highly reusable, you will be pleased to know that it is very easy to create a Sublime Text snippet for this. In Sublime, head to Tools > New snippet... and paste the content below.

Feel free to change the <tabTrigger> key to put whatever floats your boat; it is the word to type before hitting tab to expand the snippet. I went with mixtend.

<snippet>
    <content><![CDATA[
@mixin ${1:mixtend}(\$extend: true) {
  @if $extend {
    @extend %${1:mixtend};
  } @else {
    ${2}
  }
}

%${1:mixtend} {
  @include ${1:mixtend}(\$extend: false);
}
]]></content>
    <tabTrigger>mixtend</tabTrigger>
    <scope>source.scss</scope>
</snippet>

Clamping a Number

In computer science, we use the word clamp as a way to restrict a number between two other numbers. When clamped, a number will either keep its own value if living in the range imposed by the two other values, take the lower value if initially lower than it, or the higher one if initially higher than it.

As a quick example before going any further:

$clamp: clamp(42, $min: 0, $max: 1337);    // 42
$clamp: clamp(42, $min: 1337, $max: 9000); // 1337
$clamp: clamp(42, $min: 0, $max: 1);       // 1

Coming back to CSS. There are a few ways where you might need a number to be restricted between two others. Take the opacity property for instance: it must be a float (between 0 and 1). This is typically the kind of value you would want to clamp to make sure it's neither negative nor higher than 1.

Implementing a clamp function in Sass can be done in two ways, both strictly equivalent yet one is much more elegant than the other. Let's start with the not so great one.

The dirty one

This version relies on nested if function calls. Basically we say: if $number is lower than $min, then keep $min, else if $number is higher than $max, then keep $max, else keep $number.

/// Clamp `$number` between `$min` and `$max`
/// @param {Number} $number - Number to clamp
/// @param {Number} $min - Minimum value
/// @param {Number} $max - Maximum value
/// @return {Number}
@function clamp($number, $min, $max) {
  @return if($number < $min, $min, if($number > $max, $max, $number));
}

If you are not very confident with nested if calls, think of the previous statement as:

@if $number < $min {
  @return $min;
} @else if $number > $max {
  @return $max;
}

@return $number;

The clean one

This version is much more elegant since it makes a good use of both min and max functions from Sass.

/// Clamp `$number` between `$min` and `$max`
/// @param {Number} $number - Number to clamp
/// @param {Number} $min - Minimum value
/// @param {Number} $max - Maximum value
/// @return {Number}
@function clamp($number, $min, $max) {
  @return min(max($number, $min), $max);
}

Literally means keep the minimum between $max and the maximum between $number and $min.

Example

Now, let's create a little opacity mixin just for the sake of demonstration:

/// Opacity mixin
/// @param {Float} $value - Opacity value
/// @output `opacity`
@mixin opacity($value) {
  $clamped-value: clamp($value, 0, 1);

  @if $value != $clamped-value {
    @warn "Mixin `opacity` needs a float; #{$value} given, clamped to #{$clamped-value}.";
  }

  opacity: $clamped-value;
}

Strip-unit Function

There is a lot of confusion around the way units work in Sass. Yet, they work exactly as they do in real life. If you want to remove the unit of value, you have to divide it by 1 unit. For instance, to remove the cm unit of 42cm, you have to divide it by 1cm. It works exactly the same in Sass.

$length: 42px;
$value: $length / 1px;
// -> 42

But what if you don't know the unit in use? Let's say it could be anything, from pixels to em or even vw and ch. Then we need to abstract the logic in a function:

/// Remove the unit of a length
/// @param {Number} $number - Number to remove unit from
/// @return {Number} - Unitless number
@function strip-unit($number) {
  @if type-of($number) == 'number' and not unitless($number) {
    @return $number / ($number * 0 + 1);
  }

  @return $number;
}

The calculation might look odd but it actually makes sense. In order to have 1 of the unit of $number, we can multiply $number by 0 and then add 1.

Usage

$length: 42px;
$value: strip-unit($length);
// -> 42

Striped Gradient Mixin

A popular way to draw stripes in CSS it to define a linear-gradient with overlapping color-stops. It works very well but is not very convenient to write by hand... Billion dollar idea: using Sass to automatically generate it from a list of colors!

/// Stripe builder
/// @author Hugo Giraudel
/// @param {Direction} $direction - Gradient direction
/// @param {List} $colors - List of colors
/// @output `background-image` if several colors, `background-color` if only one
@mixin stripes($direction, $colors) {
  $length: length($colors);
  
  @if $length > 1 {
    $stripes: ();
    
    @for $i from 1 through $length {
      $stripe: (100% / $length) * ($i - 1);
      
      @if $i > 1 {
        $stripes: append($stripes, nth($colors, $i - 1) $stripe, comma);
      }
      
      $stripes: append($stripes, nth($colors, $i) $stripe, comma);
    }
    
    background-image: linear-gradient($direction, $stripes);
  } @else if $length == 1 {
    background-color: $colors;
  }
}

Usage

body {
  @include stripes(to right, #8e44ad #2c3e50 #2980b9 #16a085 #27ae60);
}

See the Pen a990b82465115c2b556f1b86bf4692c7 by Hugo Giraudel (@HugoGiraudel) on CodePen.

CSS Triangle Mixin

There is a fairly popular CSS hack using transparent borders on a 0-width / 0-height element to mimic triangles. There is a CSS snippet here on CSS-Tricks that depicts it.

If, like me, you never quite remember how it works, be sure we can use Sass to help us.

/// Triangle helper mixin
/// @param {Direction} $direction - Triangle direction, either `top`, `right`, `bottom` or `left`
/// @param {Color} $color [currentcolor] - Triangle color 
/// @param {Length} $size [1em] - Triangle size
@mixin triangle($direction, $color: currentcolor, $size: 1em) {
  @if not index(top right bottom left, $direction) {
    @error "Direction must be either `top`, `right`, `bottom` or `left`.";
  }

  width: 0;
  height: 0;
  content: '';
  z-index: 2;
  border-#{opposite-position($direction)}: ($size * 1.5) solid $color;
  
  $perpendicular-borders: $size solid transparent;
  
  @if $direction == top or $direction == bottom {
    border-left:   $perpendicular-borders;
    border-right:  $perpendicular-borders;
  } @else if $direction == right or $direction == left {
    border-bottom: $perpendicular-borders;
    border-top:    $perpendicular-borders;
  }
}

Additional notes:

* The opposite-position function comes from Compass; if you do not use Compass, you might need to have your own;
* The mixin does not deal with positioning the triangle; it is perfectly fine to combine it with a positioning mixin though;
* The content directive is meant to allow it to be used on pseudo-elements, which actually ends up being most cases.

Usage

.foo::before {
  @include triangle(bottom);
  position: absolute;
  left: 50%;
  bottom: 100%;
}
.foo::before {
  width: 0;
  height: 0;
  content: '';
  z-index: 2;
  border-top: 1.5em solid currentColor;
  border-left: 1em solid transparent;
  border-right: 1em solid transparent;
  position: absolute;
  left: 50%;
  bottom: 100%;
}

Mixin for Offset Positioning

If there is one shorthand CSS dramatically misses, it is the one making it possible to define the position property, as well as the four offset properties (top, right, bottom, left).

Fortunately, this is typically something that can be solved with a CSS preprocessor such as Sass. We only have to build a simple mixin to save us from declaring the 5 properties manually.

/// Shorthand mixin for offset positioning
/// @param {String} $position - Either `relative`, `absolute` or `fixed`
/// @param {Length} $top [null] - Top offset
/// @param {Length} $right [null] - Right offset
/// @param {Length} $bottom [null] - Bottom offset
/// @param {Length} $left [null] - Left offset
@mixin position($position, $top: null, $right: null, $bottom: null, $left: null) {
  position: $position;
  top: $top;
  right: $right;
  bottom: $bottom;
  left: $left;
}

Now the thing is we rely on named arguments when using this mixin to avoid having to set them all when only one or two are desired. Consider the following code:

.foo {
  @include position(absolute, $top: 1em, $left: 50%);
}

... which compiles into:

.foo {
  position: absolute;
  top: 1em;
  left: 50%;
}

Indeed, Sass never outputs a property that has a value of null.

Simplifying the API

We could move the type of position to the mixin name instead of having to define it as first argument. To do so, we need three extra mixins that will serve as aliases to the `position` mixin we just defined.

/// Shorthand mixin for absolute positioning
/// Serves as an alias for `position(absolute, ...)`
/// @param {Arglist} $args - Offsets
/// @require {mixin} position
@mixin absolute($args...) {
  @include position(absolute, $args...);
}

/// Shorthand mixin for relative positioning
/// Serves as an alias for `position(relative, ...)`
/// @param {Arglist} $args - Offsets
/// @require {mixin} position
@mixin relative($args...) {
  @include position(relative, $args...);
}

/// Shorthand mixin for fixed positioning
/// Serves as an alias for `position(fixed, ...)`
/// @param {Arglist} $args - Offsets
/// @require {mixin} position
@mixin fixed($args...) {
  @include position(fixed, $args...);
}

Rewriting our previous example:

.foo {
  @include absolute($top: 1em, $left: 50%);
}

Going further

If you want a syntax closer to the one proposed by Nib (Stylus' framework), I recommend you have a look at this article.

.foo {
  @include absolute(top 1em left 50%);
}
icon-anchoricon-closeicon-emailicon-linkicon-logo-staricon-menuicon-nav-guideicon-searchicon-staricon-tag