Kilian Valkhof

Front-end & user experience developer, Jedi.

CSS is like music to me

CSS & HTML, 2 August 2007, 3 minute read

The thing with semantic code is, once you care about it, you really care about it. It becomes something you carry with you everywhere. You wake up with it, and you go to bed with it. it’s there when you eat, when you work, when you dream. So you automatically imagine the semantic way of describing, say, a keyboard.

A keyboard?

A keyboard isn’t so hard to semantically describe. There is row of keys surrounded by a nice casing. Let’s rephrase that sentence to HTML elements: They’re an ordered list surrounded by a container. Luckily for us, the ol element is in itself a container already. This leaves us with:


 <ol class="keyboard">
  <li>c</li>
  <li>#/b</li>
  <li>d</li>
  ...add a lot of keys here...
  <li>b</li>
 </ol>

There, a nice list of keys. But: there are black keys as well. And we do need to be able to target those with CSS.


 <ol class="keyboard">
  <li>c</li>
  <li class="black">#/b</li>
  <li>d</li>
  ...add a lot of keys here...
  <li>b</li>
 </ol>

You might say that “black” is a presentational class name based on colour, and that you should call them fis or bes. But, because the black keys are widely known as “black keys”, I consider the classname to be identifying the name of the keys, not the colour. ( ;) )

All right then, now that we have the entire structure, it’s time to head to the presentational layer. Floating all the white keys, giving them a good size and a nice border, all not too complicated:


li {
  float:left;
  position:relative;
  width:20px;
  height:15px;
  padding-top:45px;
  border:1px solid #999;
  color:#000;
  background:#fff;
  text-align:center;
}

Here is where we have to destroy some of the nice and lean code. The black keys look different from the white. They’re a bit smaller, and take a part out of the surrounding white keys. To properly emulate this, we need to add an extra span. As a span is meaningless we’re still as semantic as possible, but the lean code suffers a bit. (Also, don’t forget that span‘s are inline elements, so you need to add display:block; to the CSS.)

The only way to overlap both white keys surrounding the black one is by using position:absolute;. Most of the time you have to specify two offset points (left/right and top/bottom), meaning we would have to target each key individually. But this is where the fun starts:

The trick

Some time ago I found a nice CSS trick that allowed me to make a CSS keyboard fairly easy. When you combine floats and position:absolute;, elements implicitly get a value for the left and top attributes. So you can style multiple elements to look the same, but their left-offset is dependent on their place in the source. Ideal for our keyboard!

This is how the CSS for the black keys looks like:


li.black span {
  position:absolute;
  z-index:2;
  color:#fff;
  background:#000;
  width:10px;
  height:35px;
  padding-top:5px;
  margin-left:-6px;
  border-bottom:2px solid #999;
  margin-top:-1px;
  font-style:italic;
}

We set the position to absolute, the z-index to 2 to make sure that it overlaps it’s right neighbour as well. After that we shift it half it’s width to the left using margin-left:-6px;. The rest is just for looks.

We add a little more styling, some hover and pressing (:active) effects, and we end up with this: A semantic keyboard in html and css. You can play it, too!

Thanks for Reading!

I am Kilian Valkhof, a front-end and user experience developer from the Netherlands.
Contact me or ping me on twitter.

  1. I won’t be using this but it’s great!

  2. Since I play piano, I have to say that I adore this! Beautifully done!

    Man, I can’t stop playing with it!

  3. Great way of describing it. A very unique way of showing classes in CSS.

  4. I thought the li-element is a block element by default, so why also setting it in the style sheet?

    But I have to say, it looks nice :p A pity that I can’t use multiple keys at the same time :p

  5. @arjan, You are right, the li does not require display:block, but the span in the real example does, which is why I added it in the article as well.

  6. I didn’t look at the actual CSS code of the page, only the CSS mentioned in this article, but now I have and see a wrong selector in the article. That needs to be li span ;)

  7. update: I removed the display:block and added an aside noting that it should be added for the span. :)

  8. Now that’s nice :) Good Job!

Be the first to know about new releases!

Newsletter subscribers will be the first to know about new apps I release or new articles I write, here or elsewhere.

Low-volume. I will only email you when I have something exciting to share.