Article Archives

Musings on Preprocessing

I've been using Sass for pretty much everything I do recently. Here's some musings on the journey. From hold-ups, to trip-ups, to turn-offs. From apps and teams to workflows and syntax.


A proposal to drop browser vendor prefixes

Interesting idea by Felipe G on using a new at-rule, @-vendor-unlock, to tell the browser to use it's experimental implementation of any particular property, rather than using a vendor prefix on that property. Unfortunately at this point, even if you could get all the browsers on board, you'd need to use this and vendor prefixes to get deep support, which makes the problem worse. What we really need is for all browsers to implement auto-updating so eventually "supporting older browsers" is something we can look back and laugh at.

Digging Into WordPress 3.3

Digging Into WordPress (the book) is now updated to v3.3. Includes new chapters specially on what's new in 3.2 and 3.3, all the rest of the chapters tightened up and refreshed, better internal hyperlinking (in the PDF), and more. It's a free update (PDF) to all previous buyers. New print copies are on order and will be available soon.

ShopTalk Episode 4

Dave, Jonathan Longnecker, Nate Croft and I talk shop. Topics include website building apps, where to start designing, when not to design for modern browsers, and more.

Sponsored by LessAccounting.

New Poll: In The Next 10 Years, Will We See CSS Competitor?

What do you think folks? Is a new language going to come along in the next ten years that deals with layout / style / design and unseat CSS? Or at least give it a run for its money?

You should vote not based on if there will be any attempt at it, which there certainly will be and already has. But instead if you think one of those attempts will actually make it into native support by a browser with significant market share and see a significant number of web workers building web sites in it.

Full, real time results for this poll and all post polls are in the polls archive.

Real-World CSS

A very serious not at all tongue-in-cheek gallery of CSS3 techniques that poo-poos the fancy in favor of the practical.

Better Box Sizing

Paul Irish suggests the universal selector (*) to apply border-box box-sizing to every element. I've been wanting to try this forever because this box model is, in my opinion, just better. Imagine: elements with percentage widths and pixel padding without worry.

Firefox 10 now a stable release. It's notable because it's the first release with it's own built in developer tools (video overview). It's all HTML/CSS for now (not a Firebug replacement) but they are nicely designed and a great first step for a product that really should be in-house. Also, CSS 3D transforms! After you've upgraded, check out this demo using -moz-element and the just-now-supported 3D transforms.

Poll Results: Internet Connection Speed

In this latest poll, I asked people to test their own internet connection speed then vote in the poll based on their result. The speed choices ranged from (what I would consider) blazingly fast, to mediocre, to nearly unusably slow. I would have guessed a bell curve, with most people having mediocre speeds and just a few on the edges of extreme fast/slow. We didn't get that at all.


Twitter Bootstrap 2.0

If your web app doesn't look or work as well as Bootstrap does out of the box, it's time to have a pretty serious discussion with your team about why.

1000px Grid for Responsive Web Design

To figure out your grid width percentages for a fluid design, you start with a fixed design and divide the column widths by the container width. Elliot Jay Stocks calls for us to stop the self-torture and use 1000px for the container, so the math is super easy.

Pictos Server

I've long been convinced icon fonts are awesome. Now Drew Wilson's new service (and article I'm linking to) put to rest any of the last possible arguments against them. Think they use unsemnatic markup? Apply them via pseudo element. Worried some screen readers still read those? Not if you use aria-hidden="true" or map them to an unused plane of unicode characters. Too heavy weight? Build your own icon font and serve only what you need with this service.

Responsive Design Testing Bookmarklet

Bookmarklet by Benjamin Keen which automates an idea by Lennart Schoors where the current page is loaded into a bunch of differently sized iframes, so when working on a large monitor, you can see what a design looks like at a bunch of different smaller sizes quickly and all at once.

Custom Fonts in Emails

A reader writes in:

Would it be possible to draw an entire typeface in CSS to be sent in emails? Our company needs to send out emails to about 20k people to introduce a new brand that we are launching. The emails will be in HTML/CSS. My CEO is very specific about the type of aesthetic he wants to achieve, and this includes using a typeface that is not native to either Mac or Windows computers. We do not want to use images in our email.

First off, it's pretty cool your CEO cares about type and aesthetics at all. It's usually a good thing to have the person steering the ship care about beauty and details down to that level. Let's consider the options.

The first thing that comes to mind in custom fonts these days is @font-face. The browser support for it is pretty darn good. Unfortunately, browser support isn't what we need here, it's email client support. According to some research by Campaign Monitor, @font-face is only working Apple's and the Mail app on iOS. You could try to make the progressive enhancement case to your CEO, but at that low level of support might be a tough sell.

Another thing you mentioned was trying to recreate the font through CSS somehow. Maybe something like this. I've even played around with this concept a little bit specifically with the idea of image-free emails in mind. This is the realm of big-pixel-art though. Recreating a font pixel by pixel with no anti-aliasing, as you are surely aware, is a fool's errand.

In reality I think there are two solutions.

The first is to reconsider this sentence: "We do not want to use images in our email." Why not? It seems like you are OK with sending HTML emails since you're specifically looking for clever solutions and text emails are capable of very little cleverness short of ASCII art. People use images in emails all the time. Admittedly, the fact users often have to specifically choose to view them is a bit of a turn off, but using proper ALT text on the images makes the email still work even if they never do that.

The second is to give up on this custom font in email thing. Not to sound defeatist here, but your branding will not be ruined by the lack of a specific typeface in an email. Anywhere where you all agree it is critical (e.g. a slogan?), use an image, otherwise, use a nice readable font that works OK in pairing with your brand typeface and move on with more important tasks.

Personally, I think I'd go with @font-face despite the current low support. Actively developing what you want to work helps build the desire momentum needed to get product vendors (in this case email clients) to improve their products and give us better CSS support.

Update, December 2012

Recent research again from Campaign Monitor. As of this update, support includes: iOS Mail, on OS X, Lotus Notes 8, default Mail on Android, Outlook 2000, and Thunderbird.

Burst Title

During the previews for a movie I saw recently, there was an advertisement for an Oprah-related something or another. I wasn't paying attention because I was trying to get out my phone so I could snap a picture of it. Which I failed to do. There was these neat title screens that I thought would be fun to recreate with CSS. (more…)


Back in the day, the CSS Zen Garden was a place to showcase the power of CSS. A single page was redesigned in vastly different ways with no change to the HTML. The CSS1k project (head up by Jacob Rask) is in that same vein only you are limited to only 1k of CSS. Fun, but the purpose is to get you thinking about how to be efficient and size economic with CSS.

YouTube Popup Buttons

There is a certain style of button on the latest YouTube design (most easily found in the footer) where the default state of the button has a very subtle bevel to it, but on :hover and :focus states the button pops up, eager to be clicked. (more…)

Shop Talk Episode 1

The inaugural episode of Shop Talk where Dave and I are joined by Jonathan Snook and we answer a bunch of listener questions. Sorry about the sniffles and other rough edges, we'll get better as we go. Sponsored by LessAccounting.

(Better) Tabs with Round Out Borders

The following is a guest post by Menno van Slooten. You might notice we've been down this road before, but I quite like Menno's approach here. The end result proves you can get a little fancier with the design than I originally did, with borders, gradients, and shadows and while actually using less elements.

A good-looking tab control usually has one feature that I've always found impossible to reproduce without images: borders that bend to the outside at the bottom of each tab. In this article I would like to show how you can use the CSS :before and :after pseudo elements to create this effect without using images. First, let's start with some basic markup.

The markup

<ul class="tabrow">
   <li class="selected">Sit amet</li>
   <li>Consectetur adipisicing</li>

This would be about as basic as you can get. Not a lot of elements to work with here, but it will do.

Getting started

To get started, let's get rid of the default <ul> and <li> styling and get these babies in line.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow {
  text-align: center;
  list-style: none;
  margin: 0;
  padding: 0;
  line-height: 24px;
.tabrow li {
  margin: 0 10px;
  padding: 0 10px;
  border: 1px solid #AAA;
  background: #ECECEC;
  display: inline-block;

Selecting a tab

The selected tab should of course be clearly visible.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow li.selected {
  background: #FFF;
  color: #000;

Getting to the bottom of things

Every tab control needs a well-defined bottom edge. It won't do much now, but later it will help emphasize the effect of the selected tab being on top.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow {
  position: relative;
.tabrow:after {
  position: absolute;
  content: "";
  width: 100%;
  bottom: 0;
  left: 0;
  border-bottom: 1px solid #AAA;
  z-index: 1;

Here we introduced our first :after pseudo-element. Basically, :after appends another child to an element. It's not in the DOM (which is why it's called a pseudo element), so it is not a real child but it is completely stylable, as long as you add some content, in this case a single space character.

In my opinion, the terms :before and :after are slightly confusing since the pseudo's aren't actually added before or after the element they apply to, but are inserted as children. This is also why you can't apply :before and :after to elements that can't contain children ("no content" elements), like <input>.

In this case, we use the pseudo element to create a bottom border that doesn't influence the tabs' positioning. We could have just put a bottom border on the <ul> but that would've made the next step a little trickier.

Above and beyond

Now, an essential part of a convincing looking tab control, is that the selected tab sits in front of the edge while the rest fall behind the edge. To do this, we change its bottom border and do some z-index magic.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow:before {
  z-index: 1;
.tabrow li {
    position: relative;
  z-index: 0;
.tabrow li.selected {
  z-index: 2;
  border-bottom-color: #FFF;

Around the bends

It is now time to add the elusive border that bends to the outside and we'll use :before and :after for this. Let's take this step by step and first just put everything in position.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow li:before,
.tabrow li:after {
  position: absolute;
  bottom: -1px;
  width: 6px;
  height: 6px;
  content: " ";
.tabrow li:before {
  left: -6px;
.tabrow li:after {
  right: -6px;
.tabrow li:after, .tabrow li:before {
  border: 1px solid #AAA;

Don't be such a square

You can probably see where this is going. Let's remove the borders we don't want and add some rounded corners.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow li {
  border-top-left-radius: 6px;
  border-top-right-radius: 6px;
.tabrow li:before {
  border-bottom-right-radius: 6px;
  border-width: 0 1px 1px 0;
.tabrow li:after {
  border-bottom-left-radius: 6px;
  border-width: 0 0 1px 1px;

Cutting corners

There's something not quite right about this result. Let's look at it up close. As you can see both the original straight corner as well as the rounded corner are visible. We need to somehow get rid of the straight corner. To do that, we will cover it up with a shadow. To illustrate what's going on, let's make the shadow stand out a little bit.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow li:before {
  box-shadow: 2px 2px 0 red;
.tabrow li:after {
  box-shadow: -2px 2px 0 red;

Almost there

As you can see, the red shadows completely cover up the square corners we would like to hide. If we give the shadow the correct colors the illusion is complete.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow li:before {
  box-shadow: 2px 2px 0 #ECECEC;
.tabrow li:after {
  box-shadow: -2px 2px 0 #ECECEC;
.tabrow li.selected:before {
  box-shadow: 2px 2px 0 #FFF;
.tabrow li.selected:after {
  box-shadow: -2px 2px 0 #FFF;

Pieces of flair

All that's left to do now is adding a sprinkling of gradients and shadows to spice it up just a little bit.

  • Lorem
  • Ipsum
  • Sit amet
  • Consectetur adipisicing
.tabrow li {
  background: linear-gradient(to bottom, #ECECEC 50%, #D1D1D1 100%);
  box-shadow: 0 3px 3px rgba(0, 0, 0, 0.4), inset 0 1px 0 #FFF;
  text-shadow: 0 1px #FFF;
  margin: 0 -5px;
  padding: 0 20px;

If you're wondering about browser compatibility, it's exactly as you'd expect: everything but IE. It's very possible that it'll work in IE10, but I haven't had the chance to test with a preview release. Since IE8 and IE9 do support :before and :after but not border-radius you'll have to create a separate stylesheet for them if you want to give their users a nice visual experience.

View Demo   Download Files

Editor's note: I added anchor links inside the tabs in the demo since I think it's the most likely case that tabbed navigation like this have them. Most likely, they would have an href attribute that would link to the content they go with by id, and that behavior would be controlled by JavaScript. The fact that this tutorial doesn't need the anchor links for the extra pseudo elements is further testament to it being better than my original.

Update: Allan Watkins sent me a variation of these that point downwards:

See the Pen Round Out Tabs that Point Down by Chris Coyier (@chriscoyier) on CodePen.

CSS Profiling and Optimization

Just as I got done saying how I hope we can soon stop talking about CSS selector performance, Juriy Zaytsev publishes some great research on selector performance using Opera and WebKit's new "style profiler" as part of the dev tools. He was able to save 650ms on page load time on a CSS3 heavy one-page app. Big difference makers: number of selectors, universal selectors, border-radius, and transforms. Worth a thorough read through.

HTML5 Progress Bars

Comprehensive research by Zoltan Hawryluk on the <progress> element. Screenshots of default styling across different browsers, overriding that default styling, shadow dom, polyfills, states, and fancy replacement tricks.

WebKit Selector Performance Changes

Nicole Sullivan covers some of Antti Koivisto's work on making CSS selectors faster in WebKit. Clever stuff, which Nicole helps make understandable for all of us. Mostly stuff that helps the browser "rule out" selectors more quickly. I hope other browsers can take the ideas and use them where they can and continue their own innovations. Selector performance is already something that we pretty much don't need to worry about it, I'd love it if we never had to think about it again.

Responsive Multi Column Data Tables

Maggie Costello Wachs from Filament Group shares the best approach to responsive data tables I've seen yet. Remember the problem: exploring a large data table on small screen devices means a bunch of horizontal and vertical scrolling, which sucks. Her solution involves marking columns as "essential" and "optional" with CSS classes and hiding the optional ones with media queries at smaller screen sizes. Then to keep all the data accessible, providing a (dynamically created) dropdown of checkboxes to reveal the hidden optional columns.

Update: changing the link to Filament Groups "Tablesaw" which is a collection of plugins that handles lots of different responsive table techniques.

Public Service Announcement: Watch Your @font-face font-weight

Let's say you're browsing Google Web Fonts for a free font to use on your website. You find one you like...

You think it will look nice as headings on your site. So you follow the directions on Google Web Fonts "quick use".

1) Copy/Paste CSS link to page:

<link href='' rel='stylesheet' type='text/css'>

2) Copy/Paste font-family CSS to your headings CSS:

h1, h2, h3, h4, h5 {
   font-family: 'Spicy Rice', cursive;

   /* Your other headings CSS */

And alas! You've done it, your headings are now in your specially picked out font:

But then you start to notice that the font is a bit muddier than you'd like. It might be hard to explain, but it just doesn't look as good as when you picked it off Google Web Fonts. Or maybe someone else notices and:

The problem is the font is muddier than you originally saw it, and it's all about font-weight.

You see, the default font-weight for headings in browsers is "bold" (or more specifically, 700). And if you looked carefully when choosing this font, you might have noticed:

You might fall prey to this if:

  1. You don't use a reset and didn't specify a font-weight for headings (defaults to user-agent style of bold).
  2. You use Normalize.css instead of a reset, which doesn't adjust the font-weight since bold is consistent cross-browser default.
  3. You explicity set font-weight to bold on headings (like you might if you use a reset).

This isn't Google Web Fonts or the font itself's fault. It's just this font doesn't come in a bold weight and you are asking for it specifically. That means the browser tries to bold the font for you, which is something it's able to do but isn't particularly good at (hence the muddiness).

Fixing it is as simple as being specific with your font-weight to match what the font offers.

h1, h2, h3, h4, h5 {
   font-family: 'Spicy Rice', cursive;
   font-weight: 400; /* Be specific */
   /* Your other headings CSS */

So yeah. In short:

This is a problem most common in decorative fonts where it's most common there is only one font-weight available. I'd say fonts from paid services like Typekit generally offer fonts with a wider variety of font-weights available, but that's not to say it can't be a problem with Typekit, as it's smart/recommended to load as few weights as you can get away with to lighten the load of your page.

Also note, this is a common problem with italics as well. Say you decide to load a normal, bold, and italic version of a font. If you then have text that is both bold and italic, the browser will have to fake it (because it doesn't have a bold-italic version available) and it will look bad. It happens to me on this site, but I don't think loading an extra whole version of the site is worth it so I just try to avoid it.

Get Value of CSS Rotation through JavaScript

A comment by aditya:

Is there a way to get the angle [through JavaScript] by which the element is rotated?

Seems like a reasonable request. So we have some HTML:

<div id="i-am-rotated">text</div>

And it's rotated through CSS:

#i-am-rotated {
  -webkit-transform: rotate(30deg); 
  -moz-transform:    rotate(30deg); 
  -ms-transform:     rotate(30deg); 
  -o-transform:      rotate(30deg);  

Our goal is to get the number "30" from that element via JavaScript. The modern way to access styling information from an element is getComputedStyle() (Supported in all modern browsers and IE 9+, older IE supported currentStyle()). Let's try and get it with getComputedStyle():

var el = document.getElementById("i-am-rotated");

var st = window.getComputedStyle(el, null);

var tr = st.getPropertyValue("-webkit-transform") ||
         st.getPropertyValue("-moz-transform") ||
         st.getPropertyValue("-ms-transform") ||
         st.getPropertyValue("-o-transform") ||
         st.getPropertyValue("transform") ||
         "Either no transform set, or browser doesn't do getComputedStyle";

You might think the value returned would be "rotate(30deg)" and we could run parseInt() on it and get "30". But unfortunately that doesn't work. The actual value we get back is this:

// matrix(0.8660254037844387, 0.49999999999999994, -0.49999999999999994, 0.8660254037844387, 0, 0)

The browser turns the CSS rotation transform into a matrix transform. I imagine it does this to simplify what could be multiple transforms on the single element into one value. So what are we to do?

Nicolas Gallager researched the matrix transformation for rotate transforms. Which is essentially this:

rotate(Xdeg) = matrix(cos(X), sin(X), -sin(X), cos(X), 0, 0);

We really just need one of these to make a quick equation. We need to get the arcsin (inverse of sin, sin-1) of the values, making sure to get it in radians.

First we get our hands on the separate individual matrix values:

// UPDATE: below was causing errors sometimes...
// var values = tr.split('(')[1].split(')')[0].split(',');
// Replace with... (thanks Thierry)
var values = tr.split('(')[1],
    values = values.split(')')[0],
    values = values.split(',');

var a = values[0]; // 0.866025
var b = values[1]; // 0.5
var c = values[2]; // -0.5
var d = values[3]; // 0.866025

Then we know sin(X) == 0.5 so asin(0.5) == radians and degrees == radians * 180/π.


var angle = Math.round(Math.asin(b) * (180/Math.PI));
// 30


Nicolas took it a bit further by accounting for scale as well. With the full code below, the rotation value can be extracted with any number of other transforms applied.

#complex-transform {
  -webkit-transform: rotate(30deg) scale(1.2) skew(10deg) translate(5px, 5px); 
  -moz-transform:    rotate(30deg) scale(1.2) skew(10deg) translate(5px, 5px); 
  -ms-transform:     rotate(30deg) scale(1.2) skew(10deg) translate(5px, 5px); 
  -o-transform:      rotate(30deg) scale(1.2) skew(10deg) translate(5px, 5px);  
var el = document.getElementById("complex-transform");
var st = window.getComputedStyle(el, null);
var tr = st.getPropertyValue("-webkit-transform") ||
         st.getPropertyValue("-moz-transform") ||
         st.getPropertyValue("-ms-transform") ||
         st.getPropertyValue("-o-transform") ||
         st.getPropertyValue("transform") ||

// With rotate(30deg)...
// matrix(0.866025, 0.5, -0.5, 0.866025, 0px, 0px)
console.log('Matrix: ' + tr);

// rotation matrix -

var values = tr.split('(')[1];
    values = values.split(')')[0];
    values = values.split(',');
var a = values[0];
var b = values[1];
var c = values[2];
var d = values[3];

var scale = Math.sqrt(a*a + b*b);

// arc sin, convert from radians to degrees, round
// DO NOT USE: see update below
var sin = b/scale;
var angle = Math.round(Math.asin(sin) * (180/Math.PI));

// works!
console.log('Rotate: ' + angle + 'deg');

UPDATE: Turns out this line is way more reliable for calculating angle:

var angle = Math.round(Math.atan2(b, a) * (180/Math.PI));

See the Pen Get Value of CSS Rotation through JavaScript by Chris Coyier (@chriscoyier) on CodePen.

Thanks Nicolas, Divya, and Oli for behind-the-scenes help.

ANOTHER UPDATE: Dieter Raber also tackled this idea.

See the Pen Get Value of CSS Rotation and Translation through JavaScript by Dieter Raber (@draber) on CodePen.

Thank You (2011 Edition)

Hey folks! It's that time of year again where I write a post to say thanks to every person visiting this site. CSS-Tricks is part of my career, so just by virtue of you visiting this site directly helps me.

Like families often send holiday letters to their relatives with a review of their year and the notable things family members have done, I like to write this blog post and review the year at CSS-Tricks through the numbers. (See 2007, 2008, 2009, 2010)


Custom Events are Pretty Cool

Let's say you are working on a web application in jQuery and you are tasked with writing an accordion suited to the needs of your web app. You decide to make it into a plugin. That way anywhere in this app that needs an accordion, they can load this plugin and call it upon semantic markup that is ready to become an accordion. Then ta-da, they have a lovely working accordion.

Now another developer is using your accordion and they want to be able to Ajax load some content into one of the sections of the accordion, but only when that section is opened. Together you decide that you should keep your code separate. The generic functionality of how an accordion works should be separate from code specific to one accordion on one page of an app.

Callbacks, the traditional way

One way to approach that would be to write "callbacks" into your plugin. The other developer would specify the name of a function that she wants run when certain actions happen on that accordion. So the calling of it might be like:

  panelOpen: myPanelOpenCallback,
  panelClose: myPanelCloseCallback;

And they would have created those callback functions themselves:

function myPanelOpenCallback() {
  // Do Ajax stuff 

Then the plugin itself would honor those callbacks in its related internal functions:

$.fn.accordion = function(options) {
	return this.each(function(i, el) {

	  var base = el;
	  base.init = function() {
	  	// Do initialization stuff
	  base.openPanel = function(panel) {
	  	// Open panel
		// Do callback;
	  base.closePanel = function(panel) {
	  	// Open panel
		// Do callback;

View Demo of Callback Model

Custom Events, a better way

Now let's say a third developer gets involved, and they also want to write a bit of JavaScript that reacts to a panel opening as well. For the sake of a use case, say what's inside the accordion panels are settings, and this developer wants to save those settings whenever keys are opened or closed automatically.

Now we're in an interesting position. We've already defined our callback for accordion panels opening and closing. So in the callback model, these developers are going to have to get together on that callback and run both of their code in that one callback. Not that big of a deal, but now we're forced to mix code when that might not be ideal. Remember we started this whole thing off by separating specific functionalities.

Here's where custom events are super rad. Instead of firing off a specified callback, the accordion functionality plugin fires off a custom event. Custom events are just like any other event (e.g. click) only they are only declared and called programmatically.

First, callbacks are gone, we just call the accordion plugin without them:


Now in place of where we called the callbacks, we'll trigger our Custom Event. Basically, just make up a name that makes sense (like you are naming a function).

// OUT

// IN

Now our other developers can bind their stuff to this custom event and do their own thing.

$(".panel").on("panelOpen", function() {
   // Developer 1: do Ajax stuff

// Meanwhile, in another part of town...
$(".panel").on("panelOpen", function() {
   // Developer 2: do saving stuff

Yay for freedom! Yay for separation of functionality!

In my opinion custom events are just better all around. I do think they require a bit more communication though. You'll probably have to write up some comments somewhere that explain what custom events are fired and when and make that easy to discover.

View Demo of Custom Events model

More Information

The scenario outlined above is very simple. The following two articles go way more into depth about Custom Events including more complex examples and more information on how they work.

Stuff you can do with the “Checkbox Hack”

The "Checkbox Hack" is where you use a connected label and checkbox input and usually some other element you are trying to control, like this:

<label for="toggle-1">Do Something</label>
<input type="checkbox" id="toggle-1">
<div>Control me</div>

Then with CSS, you hide the checkbox entirely. Probably by kicking it off the page with absolute positioning or setting its opacity to zero. But just because the checkbox is hidden, clicking the <label> still toggles its value on and off. Then you can use the adjacent sibling combinator to style the <div> differently based on the :checked state of the input.

input[type=checkbox] {
   position: absolute;
   top: -9999px;
   left: -9999px;
   /* For mobile, it's typically better to position checkbox on top of clickable
      area and turn opacity to 0 instead. */

/* Default State */
div {
   background: green;
   width: 400px;
   height: 100px;
   line-height: 100px;
   color: white;
   text-align: center;

/* Toggled State */
input[type=checkbox]:checked ~ div {
   background: red;

View Demo

So you can style an element completely differently depending on the state of that checkbox, which you don't even see. Pretty neat. Let's look at a bunch of things the "Checkbox Hack" can do.

Disclaimer: Some of this stuff crosses the line of what you "should" do with CSS and introduces some bad semantics. It's still wicked fun to play with and cool that it's possible, but in general functional behavior should be controlled by JavaScript.

Custom Designed Radio Buttons and Checkboxes

Hide the default UI of a radio button or checkbox, and display a custom version right on top of it. Probably not generally good practice, as users are familiar with default form elements and how they work. But can be good for enforcing cross browser consistency or in situations where the UI is so obvious anyway it's just for fun.

File system like "tree menu"

Demo by Ryan Seddon

Tabbed Areas

The "tabs" design pattern is just toggling on and off of areas, perfect for the checkbox hack. But instead of checkboxes, in which any checkbox can be on or off independently of one another, these tabs use radio buttons in which only one per group can be on at a time (like how only one tab can be active at a time).

Functional CSS tabs revisited

Dropdown Menus

Original by paullferguson and then Forked for betterness by me

Push Toggles

From What's My MPG?

Options from Dabblet

FAQ Answer Revealing

View Demo


A couple demos by Gene Locklin:

Adobe-like Arrow Headers

Adobe has some pretty cool header bars for modules on their site. The header bar is divided into left and right sections. The left being an explanatory title and the right being a related link. But let's get super critical of how they did it.

First of all, they use a non-sprited image to do it:

That means an extra HTTP request just for the headers. Worse, the :hover effect is a totally separate image. That means yet another HTTP request and a "flash of black" while the second image loads on your first hover.

We can do it with zero images! Here's our version:

View Demo   Download Files

The markup for the header is just a title with a link inside:

<div class="module">
  <h2>Community <a href="#">Blue</a></h2>
  <!-- stuff in module -->

Here's the basic setup of the header, with the link on the right with basic coloring, including the straight white line made by a border:

.module h2 {
	background: #ccc;
	padding: 0 0 0 10px;
	font-size: 16px;

	/* Thickness of the bar more easily achieved with line-height
	   since padding would push link inward.  */
	line-height: 2; 
.module h2 a {
	float: right;
	position: relative;
	text-decoration: none;
	color: #333;
	padding: 0 10px;
	border-left: 5px solid white;

Now the trick to getting the arrow within the line is just using CSS triangles applied via the ever-useful pseudo elements.

.module h2 a:before,
.module h2 a:after {
	content: "";
	position: absolute;
	/* Pushed down half way, will get pulled back up half height of triangle
	   ensures centering if font-size or line-height changes */
	top: 50%;
	width: 0;
	height: 0;
.module h2 a:before {
	left: -12px;
	/* Triangle */
	border-top: 8px solid transparent;
	border-bottom: 8px solid transparent;
	border-right: 8px solid white;
	/* Pull-up */
	margin-top: -8px;
.module h2 a:after {
	/* Smaller and different position triangle */
	left: -5px;
	border-top: 6px solid transparent;
	border-bottom: 6px solid transparent;
	border-right: 6px solid #a2d6eb;
	margin-top: -6px;

One significant difference between ours and theirs is that they have a gradient that goes right through the triangle. That's not possible with ours as it's not practical to apply gradient with the CSS triangle technique. That's not to say gradients are out though, you'd just need to make sure that where the triangle attaches to the main link, the color is solid.

For the demo page I added a few different colors, transitions, and examples where double-triangles could be used to fake an angled line.

View Demo   Download Files

Multiple Attribute Values

Elements can have multiple class names. For instance:

<div class="module accordion expand"></div>

Then in CSS, you could match that element based on any one of them:

/* All these match that */
.module { }
.accordion { }
.expand { }

You can limit your selectors to match only if several of them are present, for example:

// Will only match if element has both
.accordion.expand { }

But what about other attributes?

Class names are unique in the ability outlined above. Other attributes are not treated as "multiple values" just because they have a space in them. For instance:

<div data-type="module accordion expand"></div>

This element just has a data-type attribute with a value of "module accordion expand", not three unique values "module", "accordion" and "expand". But let's say we wanted to be able to select elements based on individual values like we can with class names.

We could do it by using a "*" substring matching attribute selector which will match if the provided string appears anywhere in the value:

[data-type*="module"] {


or only match when multiple of specific "values" are present:

[data-type*="accordion"][data-type*="expand"] {


Ever better, use the whitespace separated selector (e.g. [data-type~="expand"]). That way you won't get burned by something like "expand" matching "expander" when you didn't want to.

[data-type~="accordion"][data-type~="expand"] {


View Demo

Works in IE7+ (because IE 7 was first IE to support attribute selectors)


The best part about Lea Verou's new in-browser HTML/CSS demo tool? It saves your demos to your GitHub account as gists.

Auto Updating IE

Big news from Microsoft:

With automatic updates enabled through Windows Update, customers can receive IE9 and future versions of Internet Explorer seamlessly

Windows XP gets IE 8
Windows Vista and 7 get IE 9

Presumably every new release will happen the same way. So when IE 10 goes final the next Windows Update will include that too for the OS's it will run on.

Open a Window with Full Size Unscaled Image

For the gallery section of this site, I wanted people to have the ability to see the screenshot at its original size. Due to the fluid nature of this site, it's fairly common for the screenshot to be scaled down to fit into its column. So I put together this little solution.


New Poll: Your Internet Connection Speed

I think it would be interesting to get an idea of what the internet connection speeds are like for CSS-Tricks readers. Connection speed makes such a huge difference in the web browsing experience I hope that getting an understanding of what speeds people are getting will help us all kind that in mind when working on websites. (more…)