This article is not so much about how to create Pong, but how you can take advantage of browser implementation of HTML and usage of pseudo selectors.

Identifying the elements

So, first we need to identify what components a Pong game consists of.

From the image above we can identify following components:

  • The ball
  • Top paddle
  • Bottom paddle
  • Playing area (the black background)

For you who have finished college, you might see that’s 4 components. Lets see how we can create 4 components with only one HTML element.


The HTML

When I said one element, that was only half true.
We are gonna take advantage of the fact that browser automatically generates some elements if they are missing.

For valid HTML5 (or HTML 4.01) you only need two things; a Doctype and a title. That means a website without a <html>, <head> and <body> is perfectly valid. But if a browser notice that these elements are missing, they automatically generate them. Thanks browsers!

So, our HTML file will only contain one element. But we will take advantage of the auto generated <html> and <body> and style them too.

So, this is our code so far:

<hr>

Why a <hr>? Because it’s the best element, thats why.


Creating the ball

The simplest element of Pong is the ball itself, its just an element with lots of border radius and an animation to make it move.

Lets create it using the <hr> element!

hr {
 height: 20px;
 width: 20px;
 border-radius: 50%;
 background: white;
 position: absolute;
 z-index: 2;
 top: 50%;
 left: 50%;
 margin-left: -10px;
 margin-top: -10px;
 content: "";
 display: block;
}

Nothing special here, just a round ball thats positioned absolute and centred. We’ll save all the animations last, for simplicities sake.


The playing field

The playing field will be the <body> element. To make sure the background surrounding it will be white, we’ll add that background colour to the <html> element.

html {
 background: white;
}
body {
 width: 150px;
 height: 150px;
 background: black;
 position: absolute;
 top: 50%;
 left: 50%;
 margin-left: -75px;
 margin-top: -75px;
}

The paddles

We’re gonna create the paddles with the help of pseudo elements, :before and :after.

body:before {
 width: 40px;
 height: 5px;
 background: white;
 position: absolute;
 left: 50%;
 margin-left: -20px;
 top: 2px;
 content: "";
 display: block;
}
body:after {
 width: 40px;
 height: 5px;
 background: white;
 position: absolute;
 left: 50%;
 margin-left: -20px;
 bottom: 2px;
 content: "";
 display: block;
}

The code gets pretty repetitive, since they all have the same styling except for the top/bottom properties. But with the usage of pseudo elements, there isn’t much we can do about that.

What we have so far:

See the Pen EqJyL by sebastianekstrom (@sebastianekstrom) on CodePen.


Animate, animate all the things!

This is were it gets complicated. We have to time the paddle movement with the movement of the ball. How do you do that, you might ask? With trial and error, baby.


The ball

For a smoother animation, we’re going to use the translate3d property. To make the timing of easier, lets start with the ball.

For readabilities sake, we’ll only use the official property syntax. Remember to include the necessary vendor prefix for maximum browser compability.

hr {
 animation: WuTangClan 5s 0.3s linear infinite;
}
@keyframes WuTangClan {
 0%
 {transform: translate3d(0, 0, 0); }
 12.5%
 {transform: translate3d(14px, 62px, 0); }
 25%
 {transform: translate3d(66px, 0, 0); }
 37.5%
 {transform: translate3d(14px, -62px, 0); }
 50%
 {transform: translate3d(0, 0, 0); }
 62.5%
 {transform: translate3d(-14px, 62px, 0); }
 75%
 {transform: translate3d(-66px, 0, 0); }
 87.5%
 {transform: translate3d(-14px, -62px, 0); }
 100%
 {transform: translate3d(0, 0, 0); }
}

The translate3d property takes three values; x, y, z. So we make it move up and down using the Y value, and left/right with the X-value.


The paddles

The animation for the top paddle.

body:before {
 animation: top-paddle 6s .3s linear infinite;
}
@keyframes top-paddle {
 0%
 {transform: translate3d(0, 0, 0);}
 12.5%
 {transform: translate3d(-10px, 0, 0);}
 25%
 {transform: translate3d(0, 0, 0);}
 37.5%
 {transform: translate3d(14px, 0, 0);}
 50%
 {transform: translate3d(7px, 0, 0);}
 62.5%
 {transform: translate3d(0, 0, 0);}
 75%
 {transform: translate3d(-10px, 0, 0);}
 87.5%
 {transform: translate3d(10px, 0, 0);}
 100%
 {transform: translate3d(0, 0, 0);}
}

And for the bottom one:

body:after {
 animation: bottom-paddle 6s .3s linear infinite;
}
@keyframes bottom-paddle {
 0%
 {transform: translate3d(0, 0, 0);}
 12.5%
 {transform: translate3d(14px, 0, 0);}
 37.5%
 {transform: translate3d(7px, 0, 0);}
 50%
 {transform: translate3d(0, 0, 0);}
 62.5%
 {transform: translate3d(-14px, 0, 0);}
 75%
 {transform: translate3d(0, 0, 0);}
 87.5%
 {transform: translate3d(-7px, 0, 0);}
}

Putting it all together

With all that together, we now have our one element Pong!
Here’s the final demo, with some code cleanup and Sassify:

See the Pen One element Pong game in CSS by sebastianekstrom (@sebastianekstrom) on CodePen.