All Articles

Drawing With CSS

First of all, I must excuse myself here of being extremely kitch. Yes... When drawing with CSS properties I have this horrible tendency to forget aesthetics and to dive blindly into a doubtful taste of extreme effects, all mixed together. I want to believe that it comes from the fact that, today, the technique here is more importante than the final aesthetic result.

My tests made me think back about what I've learned about kitch. I've somehow understood why kitch icons like the painting of dogs playing poker was so popular:

Can you believe it? Don't you see it? The painter painted dogs playing poker! They are photo-perfect dogs, but they are playing poker! What a mastermind!"

Ha! Do you remember Homer Simpson seeing the painting?

So, in other words, the main goal of my tests - at least today - is to see how far can we go with CSS properties, putting aside good taste and, unavoidably, semantics.

Semantic Heresy, hu?

Oh, we can definitively say that.

The CSS properties apply to HTML elements and, if we want to draw something with those properties, we have to have tags.

The tricky point here is that HTML tags were created to "label" content based on their nature. For example, a paragraph of text must be labeled with the <p> HTML tag, which will tell all user agents to interpret this bunch of content as a paragraph. Once we've tagged our paragraph, we will use our CSS code to tell those same user agents how it should look: color, font family, font face, margins, etc.

When we try to "draw" something using CSS properties we'll often need much more elements than we have content. For example, if we need to draw an apple we would need, at least, three elements: one for the circle of the apple itself, another one for a little leave (yes... like that it can be much easier identified as an apple) and the last one for the little apple branch.

We could simply start with the word "apple", tagged as a paragraph:

<p class="apple">An apple</p>

And then we would apply some CSS properties to this paragraph tag to draw our apple:

p.apple {
  width: 30px;
  height: 30px;
  color: #FFF;
  background: #C33;
  border-radius: 30px;
}
					
An apple

As you see, we have only one element, the <p> tag. Only enough for our apple red circle. What can we do to add two more elements to our draw? Well, we can always add spans... or another inline-level tags - we'll come to that later - but it wouldn't be very nice, hu? It is just a simple apple after all.

Do you remember those interesting but somehow misregarded pseudo-elements ":after" and ":before" (I say misregarded because Internet Explorer didn't like them at all)? Those two pseudo-elements give us an amazing flexibility for CSS Draw: with them, we can add two more elements to a single one, without having to add useless tags to our content.

(Jan, 2014) Notice that, as per the W3C standards today, the CSS pseudo-elements now present two colons as in ::after

So now we know that we have exactly three elements to use as a draw source. Going back to our CSS, we can now add the leave and the branch:

p.apple {
  position: relative;
  width: 30px;
  height: 30px;
  color: #FFF;
  background: #C33;
  border-radius: 30px;
}
p.apple:before {
  position: absolute;
  top: -5px;
  left: 13px;
  width: 3px;
  height: 10px;
  content: "branch";
  text-indent: -9000px;
  background: #000;
}
p.apple:after {
  position: absolute;
  top: -5px;
  left: 16px;
  width: 10px;
  height: 10px;
  content: "leave";
  text-indent: -9000px;
  background: #80ff00;
  border-radius: 16px;
  -moz-transform: skewX(-15deg);
  -ms-transform: skewX(-15deg);
  -o-transform: skewX(-15deg);
  -webkit-transform: skewX(-15deg);
  transform: skewX(-15deg);
}
					

Two things are important to be noticed in our code:

  • Our pseudo-elements would most of the time be positionned "absolute" (like most of our draw elements). That's why we've add position: relative to our paragraph (the parent tag), so our pseudo-elements can be positionned having their parent as the position reference.
  • The :before and :ater pseudo-elements always need a content, otherwise they won't exist as an element. But this content, we don't want it, so we have to throw it away from our page using the text-indent property

(May, 2013) Today, most browsers accept an empty content, but you will always have to declare the content property, like in content: "";

An apple

And there we have our little, simple apple. Ain't that cool? - Well, ok, I've shown it to my twelve years old daughter and she wasn't as thrilled as I was... - Yes, that's cool when we know what's behind it. But we still have a little issue: our text, the source of everything, is still there and it looks lost. How can we deal with it?

We are dealing with an image, aren't we. So, what would you do if our apple was a simple png background image? Right! We would treat the text as we did with our :before and :ater pseudo-elements and throw it far away from the page. Oh, but wait! We can't do that because the text is holded by our paragraph, and if we throw this paragraph away, our cute little apple will go with it.

Do you remember what we've said back there about adding inline-level elements? Remember I've said that it wouldn't be nice? No, indeed it isn't nice, and that's exactly why drawing with CSS properties is a semantic heresy. We have to put aside all we know and cherish about semantics if we want to practice CSS Drawing, simply because in very few cases we will be able to do what we want without adding useless tags.

So, there we go to add a, let's say, <strong> tag - not completely semanticless, for our sake:

<p class="apple"><strong>An apple</strong></p>

And now we are able to finish our apple as we whish, just by adding this little declaration:

p.apple strong {
  position: absolute;
  text-indent: -9000px;
}
					

An apple

Ain't that cute? Yes, yes, but this was a very, very simple example that demanded only three (ok, four) elements. That's not the case if we really want to draw something a bit more complex. Then we have to add lot's of empty divs (or know how to use well the different tags that share a same relative parent) and there's no graceful degradation at all (our draw will simply disapear if we don't have the CSS properties interpreted). So, remember to consider the accessibility to your CSS drawings the same way you'd do with regular images.

Playing with CSS Draw will give you the hability to know exactly when and how to use it wisely, without corrupting HTML goals or semantics, and that's what is important, after all.

You may check some of my "kitch" CSS Drawings in my Tests'n Toys page, or a nice example of how to take profit of tags sharing the same relative parent to create more complex draws in my Professional Timeline, all done in CSS.