lesscake.com

Making a cheeseburger in CSS using one div

I enjoy challenging myself on some weird programming ideas. It's a good way to have fun and to learn new things. This time the challenge was to draw a cheeseburger in CSS using a single empty div.

After a lot of trials and errors, I ended up with this.

That's probably not the best looking burger ever, but I've been super impressed that it was actually possible to draw something as complex as this with a single div.

In this article we are going to make this cheeseburger, step by step.

The HTML

The HTML is very short: a charset, a title, a link to the CSS file, and a single div.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Cheesburger</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="burger"></div>
  </body>
</html>

That's it! Now we will focus our attention on the style.css file.

The CSS

The most basic CSS for our burger may look like this.

.burger {
  /* Contains all the parts of the burger */
  /* Bun, cheese, meat, lettuce, and sesame seeds */
}

But that's too limited, we won't be able to fit a whole burger inside a single selector. To find more space, we should use the :before and :after pseudo elements.

.burger {
  /* The cheese, meat, and lettuce */
}

.burger:before {
  /* The bun */
}

.burger:after {
  /* The sesame seeds */
}

That might not seem much, but that will be enough for our purpose.

The bun

The bun is made of 2 parts: the top bun and the bottom bun. So we have to find a way to draw 2 different shapes in a single CSS selector, which is not that complicated.

We start by drawing 2 rectangles using the border property.

.burger:before {
  content: ""; 
  display: block;

  /* Space between the buns */
  width: 400px;
  height: 55px;

  /* Top bun */
  border-top: 80px solid #f5b230;

  /* Bottom bun */
  border-bottom: 50px solid #f5b230;
}

Then we use border-radius to curve the bread nicely.

.burger:before {
  /* Same code as previously */
  content: ""; 
  display: block;
  width: 400px;
  height: 55px;
  border-top: 80px solid #f5b230;
  border-bottom: 50px solid #f5b230;

  /* New line */
  border-radius: 30% 30% 20% 20%; 
}

The ingredients

Next, we will add the main burger ingredients: cheese, meat, and lettuce. This time it's 3 shapes that we have to fit in a single CSS selector.

Let's focus on the meat for now.

.burger {
  /* Size */
  width: 380px;
  height: 40px;

  /* Color and shape */
  background-color: #681f24;
  border-radius: 15px; 
}

Well, that's not great. We have some meat, but it's not in the correct position. Unfortunately we can't use margin or padding to fix that, since it would move the whole burger and not just the steak.

Let's try something different: drawing the meat with a box-shadow.

.burger {
  /* Same as previously */
  /* We just removed the background color */
  width: 380px;
  height: 40px;
  border-radius: 15px;

  /* New line */ 
  /* The parameters: margin-left, margin-top, color */
  box-shadow: 10px 85px #681f24; 
}

That works! However we face another issue: how can we add the cheese and the lettuce in the same CSS selector? To answer that we need to realize 2 things:

So... we simply add more box shadows!

.burger {
  /* Same code as before */
  width: 380px;
  height: 40px;
  border-radius: 15px; 

  /* Updated box shadow */
  box-shadow: 
      10px 50px #fddb28, /* Cheese */
      10px 85px #681f24, /* Meat */
      10px 120px #82af15; /* Lettuce */
}

Note that the shadows' order is important, since the first one will have a higher z-index and will appear in front of the others.

The sesame seeds

Our burger is taking shape, but it currently looks a lot like a hot dog. We should fix that by adding some sesame seeds to the top bun.

First we draw a single sesame seed with a box-shadow.

.burger:after {
  content: "";
  display: block;

  /* Size and shape */
  width: 10px;
  height: 6px;
  border-radius: 40%;

  /* Position and color */
  box-shadow: 100px -165px #ffffff;
}

Then we duplicate it by using many box shadows.

.burger:after {
  /* Keep same code as before */
  content: "";
  display: block;
  width: 10px;
  height: 6px;
  border-radius: 40%;

  /* Add new box-shadow */
  box-shadow: 
      /* Top row */
      100px -165px #ffffff,
      160px -165px #ffffff,
      230px -165px #ffffff,
      290px -165px #ffffff,

      /* Bottom row */
      60px -135px #ffffff,
      125px -135px #ffffff,
      190px -135px #ffffff,
      255px -135px #ffffff,
      330px -135px #ffffff;
}

Better cheese

It would be nice if we could make our cheese look more like cheese. For example by showing one of the corners of the cheese slice. This means drawing a new shape (a yellow triangle) even though we already use all our CSS selectors.

If we look carefully at our code, we will notice that there's one thing we haven't really used so far: the content property. Let's see what happens when we add the character in it.

.burger:before {
  /* Change the content property */
  content: "▾";

  /* Color and Size of the ▾ */
  color: #fddb28;
  font-size: 120px;

  /* Then keep everything else the same */
}

We do get a new shape displayed, but it's in the wrong position. And once again we cannot use margin or padding to solve that.

But with some CSS tricks, we will make this work.

.burger:before {
  /* Add 8 spaces before the triangle */
  content: "        ▾";

  /* Actually display the spaces in the "content" */ 
  white-space: pre;

  /* Vertically position the ▾ */
  line-height: 25px;

  /* Then keep everything the same */
}

And we finished our cheeseburger!

Bonus

When emailing a friend about my challenge, she replied with this clever answer.

.burger:before {
  content: "🍔";
  font-size: 100px;
}

That's a lot less CSS for a better looking result.

Conclusion

I'm really impressed with what I managed to achieve with a single div and some CSS. Of course using SVG would have made more sense, but where's the fun in that?

For your information, the full source code of the cheeseburger is available on GitHub.

If you have any questions or feedback: thomas@lesscake.com :-)