CSS Shake Animation

Example of CSS Shake Animation

Shaking an element can be very useful. It can call for attention and focus. For example, if you have a website and have introduced a new, important section in navigation, then just adding a New label may not feel convincing enough that the users, used to seeing the main content page, will notice it. You may have an e-store and introduce a brief sale offer, and you’d like the offer text to be ‘attention-seeking enough for the users to notice. In such cases, you can animate those elements to shake and stand out in terms of attention.

Let’s breakdown what properties build a shaking animation

  1. Translation - Moving position visually horizontally, vertically or both.
  2. Rotation - Continuous angle change
  3. Skewing - Alternating between positive and negative skewing

CSS provides both of these properties as animat-able for a DOM element.

Rotation 

Let’s write the code for a basic rotation shaking. What we need to do is:

@keyframes tilt-shaking {
  0% { transform: rotate(0deg); }
  25% { transform: rotate(5deg); }
  50% { transform: rotate(0eg); }
  75% { transform: rotate(-5deg); }
  100% { transform: rotate(0deg); }

 

Translation

Let’s write the code for a basic, horizontal translation based shaking.

The procedure is the same exactly as for above, only replacing rotation with x-axis translation.

@keyframes horizontal-shaking {
0% { transform: translateX(0) }
25% { transform: translateX(5px) }
50% { transform: translateX(-5px) }
75% { transform: translateX(5px) }
100% { transform: translateX(0) }
}

If we replace x-translation with y-translation, we get a vertical jumping shaking.

 

Skewing
Skewing is the distortion of shape. It can happen in 1 or 2 dimensions. Here is a great piece for understanding the theory of Skewing. 

Let's write the code of a basic skewing based shaking animation.

@keyframes skew-x-shake {
0% { transform: skewX(-15deg); }
5% { transform: skewX(15deg); }
10% { transform: skewX(-15deg); }
15% { transform: skewX(15deg); }
20% { transform: skewX(0deg); }
100% { transform: skewX(0deg); }
}

@keyframes skew-y-shake {
0% { transform: skewY(-15deg); }
5% { transform: skewY(15deg); }
10% { transform: skewY(-15deg); }
15% { transform: skewY(15deg); }
20% { transform: skewY(0deg); }
100% { transform: skewY(0deg); }
}

 

Combining Translation and Rotation

Let’s combine both to get a more defined shaking. The procedure is simple, we modify both the properties, translation and rotation, simultaneously.

@keyframes tilt-n-move-shaking {
  0% { transform: translate(0, 0) rotate(0deg); }
  25% { transform: translate(5px, 5px) rotate(5deg); }
  50% { transform: translate(0, 0) rotate(0eg); }
  75% { transform: translate(-5px, 5px) rotate(-5deg); }
  100% { transform: translate(0, 0) rotate(0deg); }
}

  

Let’s take a look at all the above code in action in the following codepen.


<div>
  <p> Vertical Shake</p>
  <span class="vertical-shake">ZZZZZ</span>
</div>

<div>
  <p> Horizontal Shake</p>
  <span class="horizontal-shake">ZZZZZ</span>
</div>

<div>
  <p> Jump & Shake</p>
  <span class="rise-shake">ZZZZZ</span>
</div>

<div>
  <p>Horizontal Skewed Shaking</p>
  <span class="skew-shake-x">ZZZZZ</span>
</div>

<div>
  <p>Vertical Skewed Shaking</p>
  <span class="skew-shake-y">ZZZZZ</span>
</div>

<div>
  <p> Gentle Tilt </p>
  <span class="gentle-hover-shake">Hover on me!</span>
</div>

<div>
  <p> Strong Tilt </p>
  <span class="strong-hover-shake">Hover on me!</span>
</div>

<div>
  <p> Gentle Tilt & Move</p>
  <span class="gentle-tilt-move-shake">Hover on me!</span>
</div>

<div>
  <p> Strong Tilt & Move</p>
  <span class="strong-tilt-move-shake">Hover on me!</span>
</div>

<div>
  <p> Constant Tilt</p>
  <span class="constant-tilt-shake">ZZZZZ</span>
</div>
body { font-family: sans-serif; }

div {
  text-align: center;
}


span {
  background: #48abe0;
  color: white;
  padding: 1.5rem;
  font-size: 1rem;
  display: inline-block;
}

span.strong-hover-shake:hover {
  animation: tilt-shaking 0.15s infinite;
}

span.gentle-hover-shake:hover {
  animation: tilt-shaking 0.25s infinite;
}

span.gentle-tilt-move-shake:hover {
  animation: tilt-n-move-shaking 0.25s infinite;
}

span.strong-tilt-move-shake:hover {
  animation: tilt-n-move-shaking 0.15s infinite;
}

span.constant-tilt-shake {
  animation: tilt-shaking 0.3s infinite;
}

span.vertical-shake {
  animation: vertical-shaking 0.35s infinite;
}

span.horizontal-shake {
  animation: horizontal-shaking 0.35s infinite;
}

span.rise-shake {
  animation: jump-shaking 0.83s infinite;
}

span.skew-shake-x {
  animation: skew-x-shake 1.3s infinite;
}

span.skew-shake-y {
  animation: skew-y-shake 1.3s infinite;
}

@keyframes tilt-shaking {
  0% { transform: rotate(0deg); }
  25% { transform: rotate(5deg); }
  50% { transform: rotate(0eg); }
  75% { transform: rotate(-5deg); }
  100% { transform: rotate(0deg); }
}

@keyframes tilt-n-move-shaking {
  0% { transform: translate(0, 0) rotate(0deg); }
  25% { transform: translate(5px, 5px) rotate(5deg); }
  50% { transform: translate(0, 0) rotate(0eg); }
  75% { transform: translate(-5px, 5px) rotate(-5deg); }
  100% { transform: translate(0, 0) rotate(0deg); }
}

@keyframes vertical-shaking {
  0% { transform: translateY(0) }
  25% { transform: translateY(5px) }
  50% { transform: translateY(-5px) }
  75% { transform: translateY(5px) }
  100% { transform: translateY(0) }
}

@keyframes horizontal-shaking {
  0% { transform: translateX(0) }
  25% { transform: translateX(5px) }
  50% { transform: translateX(-5px) }
  75% { transform: translateX(5px) }
  100% { transform: translateX(0) }
}

@keyframes jump-shaking {
  0% { transform: translateX(0) }
  25% { transform: translateY(-9px) }
  35% { transform: translateY(-9px) rotate(17deg) }
  55% { transform: translateY(-9px) rotate(-17deg) }
  65% { transform: translateY(-9px) rotate(17deg) }
  75% { transform: translateY(-9px) rotate(-17deg) }
  100% { transform: translateY(0) rotate(0) }
}

@keyframes skew-x-shake {
  0% { transform: skewX(-15deg); }
  5% { transform: skewX(15deg); }
  10% { transform: skewX(-15deg); }
  15% { transform: skewX(15deg); }
  20% { transform: skewX(0deg); }
  100% { transform: skewX(0deg); }  
}

@keyframes skew-y-shake {
  0% { transform: skewY(-15deg); }
  5% { transform: skewY(15deg); }
  10% { transform: skewY(-15deg); }
  15% { transform: skewY(15deg); }
  20% { transform: skewY(0deg); }
  100% { transform: skewY(0deg); }  
}