iPhone “slide to unlock” Text in WebKit/CSS3

Published by Chris Coyier

There are a couple of WebKit specific properties that make giving text a gradient background possible:

-webkit-background-clip: text;
-webkit-text-fill-color: transparent;

Those will allow the background of the parent element to become the background of the text inside. I gots to thinkin', if we made a made a horizontal gradient that faded in a gray-white-gray pattern, then animated it from left to right, we could make the iPhone/iPad's "slide to unlock" screen with no images at all!

WebKit only demo:

View Demo   Download Files

Gradient Structure

The text "slide to unlock" is an h2 tag. We'll be giving it the gradient background, which is structured like this, with 5 "color-stops":

background: 
   -webkit-gradient(linear,left top,right top,
        color-stop(0, #4d4d4d),
        color-stop(0.4, #4d4d4d),
        color-stop(0.5, white),
        color-stop(0.6, #4d4d4d),
        color-stop(1, #4d4d4d)); 

With the two properties from the beginning of this article, the text gets a highlight like this:

Notice that the width of the background is twice as wide as area. This gives us some gray to work with on either side of the highlight, so the white highlight part can slide by and the text can stay gray before and after. If we were to animate the background further left or right than what is available, the text goes black (bad).

The next step is to animate the position of that background from left to right.

The h2 tag sits within a "well" which takes care of getting us the black background behind the text (since we've stolen the background from the h2 itself). This controls the width of the h2 as well, since it defaults to 100% wide as a block-level element. The well has a fixed width. Then the h2 is double that width (200%). So our animation can start at negative the width of the well and end at positive the width of the well.

#well {
   width: 720px;
}

h2 {
   width: 200%;
  -webkit-animation: slidetounlock 5s infinite;
}

@-webkit-keyframes slidetounlock {
  0% {
    background-position: -720px 0;
  }
  100%{
    background-position: 720px 0;
  }
}

Yay! Animated highlight on the text! Here it all is together:

#well {
  padding: 14px 20px 20px 20px;
  -webkit-border-radius: 30px;
  background: -webkit-gradient(linear,left top,left bottom,color-stop(0, #010101),color-stop(1, #181818));
  border: 2px solid #454545; 
  overflow: hidden; 
}

h2 {
  font-size: 80px;
  background: -webkit-gradient(linear,left top,right top,color-stop(0, #4d4d4d),color-stop(0.4, #4d4d4d),color-stop(0.5, white),color-stop(0.6, #4d4d4d),color-stop(1, #4d4d4d)); 
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  -webkit-animation: slidetounlock 5s infinite;
  font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
  font-weight: 300;
  padding: 0;
  width: 200%;
}

@-webkit-keyframes slidetounlock {
  0% {
    background-position: -720px 0;
  }
  100% {
    background-position: 720px 0;
  }
}

Bonus: The unlocky thing in jQuery

To me, this was mostly about replicating the cool text effect without any images. Done and done. But hey we might as well tackle the sliding unlock part too eh? The little slider button with the arrow on it probably could be accomplished with pure CSS (using triangles, among other things. But, let's not go there today. The slider will remain an image, and go right inside the h2 itself.

<h2><img src="images/arrow.png" alt="slider" /> slide to unlock</h2>

We'll load up jQuery, jQuery UI, and our own custom script:

<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js'></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js"></script>
<script src='js/slidetounlock.js'></script>

We'll use the jQuery UI draggable function on the image. We'll restrict it's movement to the X-axis (horizontal). Like all good jQuery UI functions, this has callbacks. We'll attach one to the drag event which fires repeatedly as the element is dragged. With that, we'll test if it has made it far enough to be considered "unlocked." If it has, we'll fire off an action. In this case, fading out the well. For the "stop" callback, fired when the mouse button is released, we'll test if the element is under the our completion distance and snap it back to the left if not.

$(function() {
	$("h2 img").draggable({
		axis: 'x',
		containment: 'parent',
		drag: function(event, ui) {
			if (ui.position.left > 550) {
				$("#well").fadeOut();
			}
		},
		stop: function(event, ui) {
			if (ui.position.left < 551) {
				$(this).animate({
					left: 0
				})
			}
		}
	});
});

I tried to make the drag event also dim the opacity of the text as you slide it, like the iPhone/iPad, but it's seeming to me like WebKit isn't allowing partial opacity on text with background clip. Didn't do a ton of research, but I do know that wrapping the text in a span and trying to adjust the opacity of that span just wouldn't take (until it was zero).

Notes

  • Marco Kuiper has tackled this before as well, but with a different approach (animated GIF).
  • The code above is for desktop web browsers only, and won't work on mobile browsers. Evan Black took this example and added JavaScript touch events to it, making it work in Mobile Safari. I snagged his code and dropped in in the live example on this site, the only alternations being a little jQuerification
  • .