Fun with -webkit-background-clip and @font-face



I just saw an awesome post by Trent Walton, who recreated a Photoshop design with pure CSS3, making fab use of the background-clip property to add a criss-cross-textured shadow effect to the text. Figuring it’s definitely time to get on board the background-clip gravy-train, I decided to give it a shot – although ended up with a slightly different method.

Today I’ll be recreating one of the slides from the CSSReset.com homepage in CSS3, with a full breakdown. Here’s the image I’m trying to recreate:

CSSReset.com - Great CSS Now 100% Free slide

Read on to find out how you can use @font-face, -webkit-background-clip, text-shadow and a few other little tricks to create this kind of effect in pure CSS.

Pressed for time? Click here to jump to the big reveal, or read on for some CSS3 fun…

@font-face

First things first – the @font-face embedding.

The original fonts used in the design aren’t available for embedding (shock horror!) – so, first of all, I flipped over to the trusty FontSquirrel.com and found two similar typefaces that are unrestricted for web use. In case you haven’t yet used FontSquirrel, it’s dynamite for anybody interested in embedding non-standard typefaces via the @font-face rule.

FontSquirrel.com provides the full kits, making it as easy as copy/paste, and ends up looking like this, one @font-face rule for each of your embedded typefaces:

/* ChunkFive Regular */
@font-face {
	font-family: 'ChunkFiveRegular';
	src: url('fonts/chunkfive/Chunkfive-webfont.eot');
	src: local('☺'), url('fonts/chunkfive/Chunkfive-webfont.woff') format('woff'), url('fonts/chunkfive/Chunkfive-webfont.ttf') format('truetype'), url('fonts/chunkfive/Chunkfive-webfont.svg#webfontb5K2fJwj') format('svg');
	font-weight: normal;
	font-style: normal;
}

There’s a detailed @font-face guide coming soon on CSSReset.com, so I’ll leave full explanations for that. Do remind me to link it up if I forget : )

-webkit-text-stroke

A text-stroke is a kind of border – a fixed-width line of a certain colour and opacity that traces the edges of the letters, as seen in the design we’re trying to recreate in CSS.

Although text-stroke looks set for wider adoption in the future, it’s currently only supported by Webkit with a proprietary property (try saying that fast when hammered!). That means that it flat out won’t render in Firefox, IE or any other browser. If that really bugs you, there’s an excellent CSS-Tricks article by Chris Coyler devoted to fallbacks for -webkit-text-stroke.

I’ll explore fallback options later – for now, let’s just make it look hot in Chrome and Safari. There are two elements needing the text-stroke – one above and one below – and since they have different amounts of text but need to be the same width, we’ll need to distinguish them by giving one a class of “top”.

Here’s some CSS, followed by explanations:

span.stroke-me {
	font-size: 55px;
	font-family:"SFBurlingtonScriptBold";
	word-spacing: -0.15em;
	display:block;
	color:#fff;
	text-stroke: 2px rgba(0, 0, 0, 0.7);
	position:absolute;
	left:2px;
	bottom:0;
}

This sets a rule for <span class="stroke-me">. The value for font-family references one of my @font-face embedded fonts by name. I’ve set a 2px black text-stroke at 70% opacity – using an RGBA (red, green, blue, alpha) value for the colour - and positioned it absolutely.

Next I need a rule for .stroke-me.top which will adjust the upper <span>:

span.stroke-me.top {
	font-size:74px;
	word-spacing: -0.12em;
	top:0;
}

Consider those <span>s thoroughly stroked. So far, with a basic CSS Reset, a tiled background image and a simple structure, it looks something like this:

Getting There - webkit text-stroke and CSS font-face

-webkit-background-clip

Now for the really fun stuff. Have another look at the original Photoshop design above, and you’ll see a few things going on on the ‘FREE’ text: there’s an obvious dark text-shadow, a not-so-obvious inset white text-shadow (creating an embossed effect) and a horizontal-lined background that clips to the text.

What was that about clipping to the text? In case you’re new to this concept, check this out:

Background-clip Example - CSSReset.com
In CSS3, we can (well, only in Safari and Chrome, for now) add a background to an element and set it to “clip” to the area of the text, i.e. to only be displayed inside the individual letters.

Here’s the CSS I’ll use to make the background clip to the text:

span.clip-me {
	font: normal 152px "ChunkFiveRegular"; /* References my other @font-face embedded typeface */
	background:url('text-bg.jpg');
	-webkit-background-clip:text;
	-webkit-text-fill-color:transparent;
}

The above CSS instructs the targeted <span> element to have a background, but to ‘clip’ that background to the letterforms of the text. The reason I’ve set -webkit-text-fill-color:transparent is that, if the text is not transparent, you won’t be able to see the background behind all that pretty colour! On that note, a caveat:

CSS background-clip is not the same as Photoshop clipping masks! In Photoshop, “clipping masks” overlay the layer underneath, clipping their content to the shape of the layer below (you could almost call it “foreground-clip” – ha). -webkit-background-clip on the other hand clips the background of the layer to the shape. Anything in front of the background (like non-transparent text) will obscure the background..

So here’s how it looks with -webkit-background-clip and transparent text:

CSS3 webkit-background-clip on CSSReset.comSo here, the text is transparent, but we can still see it because the background of the <span> element is clipped to the letters. Enough said about that I think.

@text-shadow, please play nice

The only issue with this, as I discovered when experimenting with this, is that it seems to be impossible to add a text-shadow to a piece of text that is already using -webkit-background-clip. If you try, it looks kinda like this:

Webkit-background-clip + text-shadow FAILI figured this might be a bug, but since -webkit-background-clip has been around since 2006, I decided it probably isn’t, and investigated further.

What’s really happening, is that – because the text is transparent (and it needs to be, so as not to hide the clipped background) – the text-shadow shows ‘underneath’ the transparent text, but on top of the clipped background, hence the above ugliness. How to fix this?

<span>, meet <h1>

We need a workaround. To create the effect – background-clipped text, with a white inner shadow and a dark drop shadow – we’ll need two elements with exactly the same CSS style and content, with only a few properties different. One will have the background-clip, and will lie on top of the other, which will have the shadows. <span>, meet <h1>:

h1,
span.clip-me {
	font: normal 152px "ChunkFiveRegular";
	position:absolute;
	top:64px;
	left:0;
	-webkit-text-fill-color:transparent;
}
h1 {
	text-shadow:-1px -1px 0 #fff, 5px 6px 0 #2d0202;
	z-index:5;
}
span.clip-me {
	background:url('text-bg.jpg');
	-webkit-background-clip:text;
	z-index:10;
}
span.clip-me:after {
	content: 'CSS3';
}

And the markup:

<div id="css3kthx">
	<h1>CSS3</h1>
	<span class="clip-me"></span>
</div><!-- #css3kthx -->

Now, you probably want to know what’s going on here (unless you worked it out already – top marks.)

The <h1> and the <span> have exactly the same font-size, font-family, and color (transparent). (NB: I’ve already used a CSS Reset script to make sure they’re exactly the same.) They’re also both set to position:absolute so they lie directly on top of one another.

To save putting the same text (“CSS3″) in the markup twice – and since I figured “Hey, we’re already abusing a bunch of under-supported properties, why not have one more!” – we’ll use the :after ‘pseudo-selector’ to insert content directly after the span. (Really it’s only IE that doesn’t support :after, but this isn’t really an IE tutorial. There’ll be IE tutorials… but this isn’t one of ‘em.)

So, we’ve got a full <h1>, and an empty <span>, whose content will be inserted via CSS. The <span> will have the background-clip, and be displayed on top (hence the higher z-index). The <h1> will have the text-shadow and will sit under the <span>, so as not to hide the background.

Since text-shadow doesn’t support inset shadows, we’ll just use a -1px -1px white shadow to push a 1px white shadow to the top right of the text, which gives roughly the same effect.

Finito! (or: The Big Reveal)

As promised, here’s the finished version (full code below!) – click the image to visit the demo page. If you skipped to here, and you’re interested to know how this was done, it’s explained step-by-step above.

If you’re not using Safari or Chrome, please do switch over to either of them before trying out this demo:

Finito - This design is now 100% CSS3 with background-clip and @font-face!Image not loading? Check out the demo here.

The Code & Downloads

Here’s the (semi-)full code for the above tutorial. It’s also all available as a download, with all the CSS, HTML, images and webfonts included, for you to play around with.

The HTML

<body>
	<div class="container">
		<div id="css3kthx">
			<span class="stroke-me top">This design is now 100%</span>
			<h1>CSS3</h1>
			<span class="clip-me"></span>
			<span class="stroke-me">with background-clip   @font-face!</span>
		</div><!-- #css3kthx -->
	</div><!-- .container -->
</body>

The CSS

/* NB: @font-face rules not included here - download the free .zip to get it all! */
/* Page setup: */
body {
	background:url('images/bg.jpg');
	font:14px "Helvetica Neue", Helvetica, Arial, sans-serif;
	text-rendering: optimizeLegibility;
}
.container {
	width:400px;
	margin:0 auto;
}
/* Demo-specific styles */
#css3kthx {
	position:relative;
	margin-top:120px;
	height:245px;
}
h1,
span.clip-me {
	font:normal 152px "ChunkFiveRegular";
	-webkit-text-fill-color:transparent;
	position:absolute;
	top:64px;
	left:0;
}
h1 {
	text-shadow:-1px -1px 0 #fff, 5px 6px 0 #2d0202;
	z-index:5;
}
span.clip-me {
	background:url('images/text-bg.jpg');
	-webkit-background-clip:text;
	z-index:10;
}
span.clip-me:after {
	content: 'CSS3';
}
span.stroke-me {
	display:block;
	font:55px "SFBurlingtonScriptBold";
	word-spacing:-0.15em;
	color:#fff;
	-webkit-text-stroke:2px rgba(0,0,0,0.7);
	position:absolute;
	left:2px;
	bottom:0;
}
span.stroke-me.top {
	font-size:74px;
	word-spacing:-0.12em;
	top:0;
}

Download:

That just about clears everything up. I’ll add something on to this later with regards to cross-browser fallbacks.

Thanks for your time!

Joss

6 thoughts on “Fun with -webkit-background-clip and @font-faceadd yours
  1. Pingback: October’s Best Resources for CSS3

  2. Pingback: Experiments with background-clip: text | Templates, Scripts, CMS, Graphics, Fonts, Flash, E-Books, 3D, Tutorials, Wallpapers.

  3. Hi Joss

    Thx for the tutorial. I have struggled for a very long time with this. I followed your tutorial and put it into my documents, but it won’t work. The shadow is placed under the text as you can see on my website. Do you have any idea of what causes this mistake?

    Thx
    Marc

  4. This is not getting enough love. Great write-up on a awesome technique.

  5. I usually do not leave a lot of remarks, however i did a few
    searching and wound up here Fun with -webkit-background-clip and @font-face.

    And I actually do have a couple of questions for you if it’s allright. Could it be only me or does it seem like a few of these responses appear like they are left by brain dead people? :-P And, if you are posting at other online social sites, I’d like to follow everything fresh you have to post.
    Could you list of all of your shared sites
    like your Facebook page, twitter feed, or linkedin profile?

Leave a reply
this will never be published
@