Creating cool shadows with CSS

No more boring drop shadows

I recently had to work on something that needed to include some interesting text shadow styles. I spent some time exploring what is possible using the text shadow capabilities of CSS and it turns out that it's a lot more flexible than I realised.

See the Pen Shadows by Simon Harper (@simonharper) on CodePen.

This uses the ability to add multiple text-shadows within CSS. Since we are creating a hard shadow we only need to pass the offset and colour values.

 /* offset-x | offset-y | color */
text-shadow: 0px 0px #000000;
/* Multiple shadows example */
text-shadow: 0px 0px #0000000, -1px 1px #000000, -2px 2px #000000;

Using a function in SCSS we can automate the process to create a basic shadow. By passing two values (length and colour) to this function we can easily create shadows of any size that mimic a three dimensional effect.

Note: for this approach to work we need to use solid colours. Using colours with opacity will just end up with the opacities stacked on top of each other creating a very murky dark shadow.

@function createShadow($length, $color) {
	$val: 0px 0px #{$color};
	@for $i from 1 to $length + 1 {
		$val: #{$val}, -#{$i}px #{$i}px #{$color};
	}
	@return $val;
}

We can expand this to have multiple directions by adding a couple of additional inputs to the function.

@function createShadowWithShadow($length_a, $length_b, $color_a, $color_b) {
	$val: 0px 0px #{$color_a};
	@for $i from 1 to $length_a + 1 {
		$val: #{$val}, -#{$i}px #{$i}px #{$color_a};
	}
	@for $i from $length_a + 1 to $length_b + 1 {
		$val: #{$val}, #{(-$length_a) + ($i - $length_a)}px #{$i}px #{$color_b};
	}
	@return $val;
}

This is cool but we can expand this approach further. If we pass RGB values to the function for two colours we can create the stops in between to blend between the two colours.

@function createShadowBetweenColors($length, $r1, $g1, $b1, $r2, $g2, $b2) {
	$val: 0px 0px rgb($r1, $g1, $b1);
		@for $i from 1 to $length {
			$val: #{$val},
				-#{$i}px
					#{$i}px
					rgb(
						round($r1 - (($r1 - $r2) / $length) * $i),
						round($g1 - (($g1 - $g2) / $length) * $i),
						round($b1 - (($b1 - $b2) / $length) * $i)
					);
		}
	@return $val;
}

Using these basic approaches you could make any multitude of different shadow styles for text.

Note: This approach works in Figma too, but as I found out it only supports adding up to eight shadows which ultimately limits what you can do.