<!-- I made this pen to try out and illustrate some of the subtle shadow effects you can create using just text-shadow and transitions.  The pattern effect also uses a small piece of SVG.

Inspired by this animated gif I saw on dribbble (https://dribbble.com/shots/1881907-Love?list=shots&sort=recent&timeframe=now&offset=18).

I’ve included the Sass mixins I use to make the text-shadow effect, but you could also just use compass which has these mixins baked straight in.

The CSS only effects (first 4) work in Chrome/Firefox/Safari/IE10+.

The final pattern effect works perfectly in Chrome, Firefox and IE seems to lose the text-shadow for some reason and it completely flips out in Safari!
-->


<h1>A collection of CSS Text shadow and pattern effects <a href="https://twitter.com/AshNolan_" target="blank">created by @AshNolan_</a></h1>
<h2 class="headingOuter">Push down (shadow effect)</h2>
<div class="headingWrapper color-bright">
  <a href="" class="header header--pushDown header--shadow" title="HOVER ME">HOVER ME</a>
</div>
<div class="headingWrapper">
  <a href="" class="header header--pushDown header--shadow" title="HOVER ME">HOVER ME</a>
</div>

<h2 class="headingOuter">Raise up (shadow effect)</h2>
<div class="headingWrapper color-bright">
  <a href="" class="header header--raiseUp header--shadow">HOVER ME</a>
</div>
<div class="headingWrapper">
  <a href="" class="header header--raiseUp header--shadow">HOVER ME</a>
</div>

<h2 class="headingOuter">Push down (merging into page)</h2>
<div class="headingWrapper color-bright">
  <a href="" class="header header--pushDown">HOVER ME</a>
</div>
<div class="headingWrapper">
  <a href="" class="header header--pushDown">HOVER ME</a>
</div>


<h2 class="headingOuter">Raise up (emerging from page)</h2>
<div class="headingWrapper color-bright">
  <a href="" class="header header--raiseUp">HOVER ME</a>
</div>
<div class="headingWrapper">
  <a href="" class="header header--raiseUp">HOVER ME</a>
</div>

<h2 class="headingOuter">Raised up (emerging from bg) with pattern</h2>
<div class="headingWrapper color-bright">
  <a href="#" class="header header--raiseUp header--svg">
    <svg>
      <defs>
        <linearGradient id="stripedColor" x1="0" x2="0" y1="0%" y2="4%" spreadMethod="repeat">
          <stop offset="0%" stop-color="#e62915"/>
          <stop offset="50%" stop-color="#e62915"/>
          <stop offset="51%" stop-color="#fff"/>
          <stop offset="99%" stop-color="#fff"/>
          <stop offset="100%" stop-color="#e62915"/>
        </linearGradient>
      </defs>
      <text y="1.2em">Hover Me</text>
    </svg>
  </a>
</div>
<div class="headingWrapper">
  <a href="#" class="header header--raiseUp header--svg">
    <svg>
      <defs>
        <linearGradient id="striped" x1="0" x2="0" y1="0%" y2="4%" spreadMethod="repeat">
          <stop offset="0%" stop-color="#e62915"/>
          <stop offset="50%" stop-color="#e62915"/>
          <stop offset="51%" stop-color="#fff"/>
          <stop offset="99%" stop-color="#fff"/>
          <stop offset="100%" stop-color="#e62915"/>
        </linearGradient>
      </defs>
      <text y="1.2em">Hover Me</text>
    </svg>
  </a>
</div>


/*
  The following mixin is taken and edited from this pen - https://codepen.io/hugo/pen/xzjGB
  I have added outlineColor to allow the addition of a text-shadow outline for the text.
 */

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

@function fact($number) {
  $value: 1;
  @if $number > 0 {
    @for $i from 1 through $number {
      $value: $value * $i;
    }
  }
  @return $value;
}

@function pi() {
  @return 3.14159265359;
}

@function rad($angle) {
  $unit: unit($angle);
  $unitless: $angle / ($angle * 0 + 1);
  // If the angle has 'deg' as unit, convert to radians.
  @if $unit == deg {
    $unitless: $unitless / 180 * pi();
  }
  @return $unitless;
}


@function sin($angle) {
  $sin: 0;
  $angle: rad($angle);
  // Iterate a bunch of times.
  @for $i from 0 through 10 {
    $sin: $sin + pow(-1, $i) * pow($angle, (2 * $i + 1)) / fact(2 * $i + 1);
  }
  @return $sin;
}

@function cos($angle) {
  $cos: 0;
  $angle: rad($angle);
  // Iterate a bunch of times.
  @for $i from 0 through 10 {
    $cos: $cos + pow(-1, $i) * pow($angle, 2 * $i) / fact(2 * $i);
  }
  @return $cos;
}

@mixin shade($type, $color: #3498db, $borderColor: #fff, $depth: 20, $angle: 135deg, $long: false, $fade: false) {
    $angle: ($angle - 90);
    $x: 1.1 * cos($angle) + 0px;
    $y: 1.1 * sin($angle) + 0px;
    $darken: (lightness($color)/$depth)/2;
    $opacify: 0;
    $shadow: ();

    @if $long == true{
      $darken:0;
    }

    @if $fade == true {
      $opacify: (opacity($color)/$depth) ;
        // added this for rendering in some browsers, remove if you like.
      @include translateZ(0);
    }

    @for $i from 1 through $depth {
      $shadow: $shadow, $i*$x $i*$y 0 hsla(hue($color) , saturation($color), (lightness($color) - ($i * $darken)), 1 - ($i * $opacify));
    }
    #{$type}-shadow:  1.5px 1.5px 0 $borderColor,
                      0px 1.5px 0 $borderColor,
                      -1.5px -1.5px 0 $borderColor,
                      -1.5px -1.5px 0 $borderColor,
                      -1.5px 1.5px 0 $borderColor,
                       1.5px -1.5px 0 $borderColor,
                       $shadow;
}

//mixin to provide just a basic outline for the text
@mixin outline($color: #fff) {
  text-shadow: 1.5px 1.5px 0 $color,
           -1.5px -1.5px 0 $color,
           -1.5px -1.5px 0 $color,
           -1.5px 1.5px 0 $color,
           1.5px -1.5px 0 $color;
}


// Define the fonts used in the Pen
@import url(https://fonts.googleapis.com/css?family=Francois+One);
@import url(https://fonts.googleapis.com/css?family=PT+Sans);

// Define the colors
$pink   : #f89bb4;
$pinkPastel : #ebaca5;
$pinkDark : #e62915;
$pinkGrayed : #d38076;

$grayLight  : #cac6c5;
$offWhite : #e7e7e7;

* {
  box-sizing: border-box;
}

body {
  font-size: 62.5%;
}

//basic header styles
h1, h2, h3 {
  font-family: 'PT Sans', sans-serif;
  text-transform: uppercase;
}
h1 {
  font-size: 2.4em;
  background-color: rgba(41, 41, 41, 1);
  text-align: center;
  padding: 20px;
  margin: 0;
  color: #fff;
  
  a {
    display: block;
    margin-top: 10px;
    text-transform: none;
    color: #aaa;
    font-size: 16px;
    text-decoration: none;
  }
}
h2 {
  font-size: 1.6em;
  margin: 0;
  padding: 10px;
  border-top: 1px solid #ccc;
}
h3 {
  margin: 0;
  padding: 10px;
}

// Outer heading wrapper (for descriptions, not for the actual effects)
.headingOuter {
  background: #f1f1f1;
  text-align: center;
  margin-top: 30px;
  border-top: 1px solid #333;
  border-bottom: 1px solid #333;

  &:first-child {
    margin-top: 0;
  }
  h1 + & {
    margin-top: 10px;
  }
}
.headingWrapper {
  text-align: center;
  background-color: #fff;
  padding: 10px;
}

// default header class – used on all examples
.header {
  display: inline-block;
  text-align: center;
  font-family: 'Francois One', Helvetica, Arial, sans-serif;
  font-size: 96px;
  color: $offWhite;
  text-decoration: none;

  @include outline($grayLight);

  transition: all 400ms ease-in-out;
}

// effect for pushing the text down onto the page
// default is the letters emerging from the page and merging back down on hover
.header--pushDown {
  @include shade(text, #aaa, #333, 10, 135deg, true);

  &:hover {
    transform: translate(9px, 9px);
    @include outline($grayLight);
  }
}

// raising text from page when hovered, so flipped state to header--pushDown class
.header--raiseUp {
  &:hover {
    transform: translate(-9px, -9px);
    @include shade(text, #aaa, #333, 10, 135deg, true);
  }
}

// creates a shadow effect, rather than a raised lettering effect
// simply by adjusting the translate position a little
.header--shadow {
  &:hover {
    transform: translate(5px, 0);
  }

  &.header--raiseUp {
    &:hover {
      transform: translate(-5px, 0);
    }
  }
}


//Brighter colored text
.color-bright {
  background-color: $pinkPastel;

  & .header {
    color: $pink;
    @include outline($pinkGrayed);
  }
  
  //push down text
  & .header--pushDown {
    @include shade(text, $pinkDark, #fff, 10, 135deg, true);

    &:hover {
      @include outline($pinkGrayed);
    }
  }

  //raise up text
  & .header--raiseUp:hover {
    @include shade(text, $pinkDark, #fff, 10, 135deg, true);
  }
}

// SVG Pattern text effect
// Same as the above but with a pattern text effect on hover
// Played around with this for a while – cannot be done with background clip and a CSS gradient as the
// text-shadow always appears in front of the background (unless you have no background color on the wrapping element)
// Therefore, use SVG linearGradient and animate the stop points using CSS
svg {
  line-height: 1.2;
  width: 410px;
  height: 1.5em;
}
.header--svg {
  text,
  stop {
    transition: all 350ms ease-in-out;
  }
  text {
    text-transform: uppercase;
    fill: url(#striped);
    @include outline($grayLight);
  }
  &:hover text {
    @include shade(text, #aaa, #333, 10, 135deg, true);
  }

  //animate gradient stop points
  & stop {
    stop-color: $offWhite;
  }
  &:hover stop {
    stop-color: #fff;

    &:nth-child(2),
    &:nth-child(3) {
      stop-color: $pinkGrayed;
    }
  }
}


// Brighter version of the SVG pattern text
.color-bright {
  & .header--svg {
    text {
      fill: url(#stripedColor);
      @include outline($pinkGrayed);
    }
    &:hover text {
      @include shade(text, $pinkDark, #fff, 10, 135deg, true);
    }
  }
  & stop {
    stop-color: $pink;
  }
  & .header--svg:hover stop {
    &:nth-child(2),
    &:nth-child(3) {
      stop-color: #ed5751;
    }
  }
}



View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.