How To Design Keyboard Keys In CSS

Today I was working on my CSS editor and wanted to display a quick pop-up note on the screen every time a short-cut key is pressed. I could simply use an image of a key, but why not design one in CSS? I’ll avoid extra HTTP request just to load the image… and you probably don’t want to create images for anything you can do in CSS (& don’t have to in SVG, so to speak.)

Here’s a list of my best web development tutorials.

Complete CSS flex tutorial on Hashnode.

Ultimate CSS grid tutorial on Hashnode.

Higher-order functions .map, .filter & .reduce on Hashnode.

Follow me @ Twitter, Instagram & fb to never miss premium articles.

Here is what I am aiming at. A simple pop-up message displayed when W key is pressed (In my case, it activates the “Draw Within” feature in CSS editor I’m currently working on:)

Image for post

All We Need Is 1 DIV Element

As you may know a DIV element is actually 3 elements in 1.

Each DIV element has :before and :after elements within them.

(Note: Not every HTML element has :before and :after)

They’re called pseudo-selectors & can be assigned position:absolute just like any regular HTML element. This gives us an opportunity to work with two extra elements (:before and :after) without defining them in the DOM.

You can use :before and :after only if either one of them you also set:

{ content: ""; }

Without adding this property to your :before or :after element it will simply not be shown in the browser at all.

The key CSS is pretty simple. For this example we only need :before element.


Knowing this we can split the DIV into two parts as follows:

#key {
position: absolute;
top: 0; left: 0;
width: 100px; height: 100px;
border-radius: 16px;
border: 0px;
font-size: 20px;
font-weight: bold;
color: gray;
background: conic-gradient(white 0%, white 5%, silver 16%, white 23%, white 24%, silver 28%, gray 34%, #666 50%, gray 65%, white 75%) transparent;}
#key:before {
content: attr(data-before);
position: absolute;
display: block;
top: 5px;
left: 10px;
width: 80px;
height: 80px;
border-radius: 16px;
box-sizing: border-box;
padding: 16px;
font-size: 35px;
font-family: Arial;
font-weight: normal;
box-shadow: inset 0 0 13px #fff, 0 0 13px #fff,
rgb(124, 124, 124) 0px 0px 43px inset;
background: linear-gradient(180deg, rgb(255, 255, 255) 16%, rgb(206, 206, 206) 92%, transparent 95%, rgb(206, 206, 206) 99%, rgb(206, 206, 206) 102%, rgb(206, 206, 206) 106%, rgb(206, 206, 206) 110%, rgb(206, 206, 206) 113%), linear-gradient(24.75deg, rgb(255, 255, 255) 33%, rgb(206, 206, 206) 37%, transparent 41%, rgb(206, 206, 206) 44%, rgb(206, 206, 206) 48%, rgb(206, 206, 206) 51%, rgb(206, 206, 206) 55%, rgb(206, 206, 206) 59%) transparent;}

And the result is:

Image for post

The :before element is used to create the inner part of the key. I used two subtle shadows (inset and outset) to smooth out the border of :before

In CSS, it is possible to add multiple shadows and gradients to the same element. For example, if you want multiple box shadows on same element, all you have to do is specify: box-shadow: value, value, value;

The same goes for background property. You can add multiple gradients to the same DIV element. You can even mix and match between linear, conic and repeatable gradients if you wish to generate some interesting patterns.

To prettify the key, just play around with linear-gradient, conic-gradient, and box-shadow until you want it to look the way you want to.

Changing Content Of :before With JavaScript

But wait, there is a catch.

You noticed how in the CSS style above I used content: attr(data-before);

This was done to dynamically plant the letter W into the :before element.

Sure, you can set content: “W” by hand in the CSS style, but in my case, I needed to generate a key DIV with a dynamically created letter within it. Because every time notification popped up, it had to display the actual letter of the key that was pressed.

Problem is… technically :before and :after are not part of DOM. They are generated by the browser itself. And for a period of time there wasn’t even native browser support for modifying {content: ””} outside of CSS.

However, it is currently possible to do it by using attr directive:

content: attr(data-before);

Now all we have to do is set attribute “data-before” on actual DIV element:

let v = "W";document.querySelector("#key").setAttribute('data-before', `${v}`);

Now content inside :before element inherits the value from data-before attribute set to the main #key element.

Thanks for reading! Hope this helps someone out there 😊.

Written by

Issues. Every webdev has them. Published author of CSS Visual Dictionary few others…

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store