Wednesday, April 03, 2013

Animations with SASS and @while

Animations with SASS and @while
A few months ago I was working on a looping Wi-Fi signal animation for Karma. Initially I wrote a bunch of SASS with a few mixins, until I discovered the @while directive which repeatedly outputs a given number nested blocks of styling. Resulting in 20 lines of SASS that generates as many animated signals as you could possibly want and automating the math as well.

See the animation in action on codepen.io. And let's get started.

Markup (HAML)

First, we're going to need some markup.

.signal-container
 .signals
  %span.signal-1
  %span.signal-2
  %span.signal-3
  %span.signal-4
  %span.signal-5
  %span.signal-6
  %span.signal-7
  %span.signal-8

Styling

Start with positioning the signals.

.signals
 position: absolute
 top: -30px
 right: 0
 bottom: 0
 left: -4px
 opacity: .6

Make the signals look like signals.

.signals
 span
  display: block
  position: absolute
  left: 50%
  border: 2px solid #74bbdc
  +opacity(0)
  +border-radius(100%)
  +box-shadow(0 0 80px #a8e3ff)
  -webkit-animation: signal 2.4s infinite alternate ease-in-out
  -moz-animation: signal 2.4s infinite alternate ease-in-out
  animation: signal 2.4s infinite alternate ease-in-out

@while

The value on the first line (8) is the amount nested blocks of styling I want SASS to output. Line 7 makes sure each block gets its own unique class starting at .signal-8 down to .signal-1.

$signals: 8
$signal-size: 50px
$signal-increment: 20px
$signal-delay: 0s

@while $signals > 0
 .signal-#{$signals}

Size and positioning

The width, height and margin of each signal is determined by the $size variable which increases in size for each $signal by 40 pixels starting at 20: 60, 100, 140, 180 and so on.

To position each signal in the centre of the wrapping element simply split the $size value in half and set it as a negative top and left margin.

$size: $signal-size + ($signals * $signals * $signal-increment)

width: $size
height: $size
margin-top: - ($size / 2)
margin-left: - ($size / 2)

Fading each signal

The bigger the signal gets, the weaker it gets. To achieve this effect simply decrease the alpha value of the border and box-shadow rgba color by 10.

border-color: rgba(116,187,220,(1 - ($signals * .10)))

+box-shadow(0 0 80px rgba(107,208,255,(1 - ($signals * .10))))

Delaying the animation

In order to make the signal animation look convincing each signal needs a longer delay. The following calculation increases the delay of each signal by .3s.

-sswebkit-animation-delay: $signal-delay + ($signals * .3)
-moz-animation-delay: $signal-delay + ($signals * .3)
animation-delay: $signal-delay + ($signals * .3)