One year ago, I had posted a puzzle game called “Doraemon Puzzle”. It was developed with the help of most powerful JavaScript library i.e. jQuery. Now, I have developed a game using CSS only. Have you remembered a favorite game which we always played in school/collage days? Yes this is “Tic-Tac-Toe”.

My version works as any normal Tic-tac-toe game would: 2 players can play against each other, it can result in either a win or a tie. Players can also restart the game.

Creating-a-CSS-Game-Tic-Tac-Toe

HTML

<div class="tic-tac-toe">
  <input id="block1-1-1" type="radio" class="player-1 left first-column top first-row first-diagonal turn-1"/>
  <label for="block1-1-1" class="turn-1"></label>
  <input id="block1-1-2" type="radio" class="player-1 middle second-column top first-row turn-1"/>
  <label for="block1-1-2" class="turn-1"></label>
  <input id="block1-1-3" type="radio" class="player-1 right third-column top first-row second-diagonal turn-1"/>
  <label for="block1-1-3" class="turn-1"></label>
  <input id="block1-2-1" type="radio" class="player-1 left first-column center second-row turn-1"/>
  <label for="block1-2-1" class="turn-1"></label>
  <input id="block1-2-2" type="radio" class="player-1 middle second-column center second-row first-diagonal second-diagonal turn-1"/>
  <label for="block1-2-2" class="turn-1"></label>
  <input id="block1-2-3" type="radio" class="player-1 right third-column center second-row turn-1"/>
  <label for="block1-2-3" class="turn-1"></label>
  <input id="block1-3-1" type="radio" class="player-1 left first-column bottom third-row second-diagonal turn-1"/>
  <label for="block1-3-1" class="turn-1"></label>
  <input id="block1-3-2" type="radio" class="player-1 middle second-column bottom third-row turn-1"/>
  <label for="block1-3-2" class="turn-1"></label>
  <input id="block1-3-3" type="radio" class="player-1 right third-column bottom third-row first-diagonal turn-1"/>
  <label for="block1-3-3" class="turn-1"></label>
  <input id="block2-1-1" type="radio" class="player-2 left first-column top first-row first-diagonal turn-2"/>
  <label for="block2-1-1" class="turn-2"></label>
  <input id="block2-1-2" type="radio" class="player-2 middle second-column top first-row turn-2"/>
  <label for="block2-1-2" class="turn-2"></label>
  <input id="block2-1-3" type="radio" class="player-2 right third-column top first-row second-diagonal turn-2"/>
  <label for="block2-1-3" class="turn-2"></label>
  <input id="block2-2-1" type="radio" class="player-2 left first-column center second-row turn-2"/>
  <label for="block2-2-1" class="turn-2"></label>
  <input id="block2-2-2" type="radio" class="player-2 middle second-column center second-row first-diagonal second-diagonal turn-2"/>
  <label for="block2-2-2" class="turn-2"></label>
  <input id="block2-2-3" type="radio" class="player-2 right third-column center second-row turn-2"/>
  <label for="block2-2-3" class="turn-2"></label>
  <input id="block2-3-1" type="radio" class="player-2 left first-column bottom third-row second-diagonal turn-2"/>
  <label for="block2-3-1" class="turn-2"></label>
  <input id="block2-3-2" type="radio" class="player-2 middle second-column bottom third-row turn-2"/>
  <label for="block2-3-2" class="turn-2"></label>
  <input id="block2-3-3" type="radio" class="player-2 right third-column bottom third-row first-diagonal turn-2"/>
  <label for="block2-3-3" class="turn-2"></label>
  <input id="block3-1-1" type="radio" class="player-1 left first-column top first-row first-diagonal turn-3"/>
  <label for="block3-1-1" class="turn-3"></label>
  <input id="block3-1-2" type="radio" class="player-1 middle second-column top first-row turn-3"/>
  <label for="block3-1-2" class="turn-3"></label>
  <input id="block3-1-3" type="radio" class="player-1 right third-column top first-row second-diagonal turn-3"/>
  <label for="block3-1-3" class="turn-3"></label>
  <input id="block3-2-1" type="radio" class="player-1 left first-column center second-row turn-3"/>
  <label for="block3-2-1" class="turn-3"></label>
  <input id="block3-2-2" type="radio" class="player-1 middle second-column center second-row first-diagonal second-diagonal turn-3"/>
  <label for="block3-2-2" class="turn-3"></label>
  <input id="block3-2-3" type="radio" class="player-1 right third-column center second-row turn-3"/>
  <label for="block3-2-3" class="turn-3"></label>
  <input id="block3-3-1" type="radio" class="player-1 left first-column bottom third-row second-diagonal turn-3"/>
  <label for="block3-3-1" class="turn-3"></label>
  <input id="block3-3-2" type="radio" class="player-1 middle second-column bottom third-row turn-3"/>
  <label for="block3-3-2" class="turn-3"></label>
  <input id="block3-3-3" type="radio" class="player-1 right third-column bottom third-row first-diagonal turn-3"/>
  <label for="block3-3-3" class="turn-3"></label>
  <input id="block4-1-1" type="radio" class="player-2 left first-column top first-row first-diagonal turn-4"/>
  <label for="block4-1-1" class="turn-4"></label>
  <input id="block4-1-2" type="radio" class="player-2 middle second-column top first-row turn-4"/>
  <label for="block4-1-2" class="turn-4"></label>
  <input id="block4-1-3" type="radio" class="player-2 right third-column top first-row second-diagonal turn-4"/>
  <label for="block4-1-3" class="turn-4"></label>
  <input id="block4-2-1" type="radio" class="player-2 left first-column center second-row turn-4"/>
  <label for="block4-2-1" class="turn-4"></label>
  <input id="block4-2-2" type="radio" class="player-2 middle second-column center second-row first-diagonal second-diagonal turn-4"/>
  <label for="block4-2-2" class="turn-4"></label>
  <input id="block4-2-3" type="radio" class="player-2 right third-column center second-row turn-4"/>
  <label for="block4-2-3" class="turn-4"></label>
  <input id="block4-3-1" type="radio" class="player-2 left first-column bottom third-row second-diagonal turn-4"/>
  <label for="block4-3-1" class="turn-4"></label>
  <input id="block4-3-2" type="radio" class="player-2 middle second-column bottom third-row turn-4"/>
  <label for="block4-3-2" class="turn-4"></label>
  <input id="block4-3-3" type="radio" class="player-2 right third-column bottom third-row first-diagonal turn-4"/>
  <label for="block4-3-3" class="turn-4"></label>
  <input id="block5-1-1" type="radio" class="player-1 left first-column top first-row first-diagonal turn-5"/>
  <label for="block5-1-1" class="turn-5"></label>
  <input id="block5-1-2" type="radio" class="player-1 middle second-column top first-row turn-5"/>
  <label for="block5-1-2" class="turn-5"></label>
  <input id="block5-1-3" type="radio" class="player-1 right third-column top first-row second-diagonal turn-5"/>
  <label for="block5-1-3" class="turn-5"></label>
  <input id="block5-2-1" type="radio" class="player-1 left first-column center second-row turn-5"/>
  <label for="block5-2-1" class="turn-5"></label>
  <input id="block5-2-2" type="radio" class="player-1 middle second-column center second-row first-diagonal second-diagonal turn-5"/>
  <label for="block5-2-2" class="turn-5"></label>
  <input id="block5-2-3" type="radio" class="player-1 right third-column center second-row turn-5"/>
  <label for="block5-2-3" class="turn-5"></label>
  <input id="block5-3-1" type="radio" class="player-1 left first-column bottom third-row second-diagonal turn-5"/>
  <label for="block5-3-1" class="turn-5"></label>
  <input id="block5-3-2" type="radio" class="player-1 middle second-column bottom third-row turn-5"/>
  <label for="block5-3-2" class="turn-5"></label>
  <input id="block5-3-3" type="radio" class="player-1 right third-column bottom third-row first-diagonal turn-5"/>
  <label for="block5-3-3" class="turn-5"></label>
  <input id="block6-1-1" type="radio" class="player-2 left first-column top first-row first-diagonal turn-6"/>
  <label for="block6-1-1" class="turn-6"></label>
  <input id="block6-1-2" type="radio" class="player-2 middle second-column top first-row turn-6"/>
  <label for="block6-1-2" class="turn-6"></label>
  <input id="block6-1-3" type="radio" class="player-2 right third-column top first-row second-diagonal turn-6"/>
  <label for="block6-1-3" class="turn-6"></label>
  <input id="block6-2-1" type="radio" class="player-2 left first-column center second-row turn-6"/>
  <label for="block6-2-1" class="turn-6"></label>
  <input id="block6-2-2" type="radio" class="player-2 middle second-column center second-row first-diagonal second-diagonal turn-6"/>
  <label for="block6-2-2" class="turn-6"></label>
  <input id="block6-2-3" type="radio" class="player-2 right third-column center second-row turn-6"/>
  <label for="block6-2-3" class="turn-6"></label>
  <input id="block6-3-1" type="radio" class="player-2 left first-column bottom third-row second-diagonal turn-6"/>
  <label for="block6-3-1" class="turn-6"></label>
  <input id="block6-3-2" type="radio" class="player-2 middle second-column bottom third-row turn-6"/>
  <label for="block6-3-2" class="turn-6"></label>
  <input id="block6-3-3" type="radio" class="player-2 right third-column bottom third-row first-diagonal turn-6"/>
  <label for="block6-3-3" class="turn-6"></label>
  <input id="block7-1-1" type="radio" class="player-1 left first-column top first-row first-diagonal turn-7"/>
  <label for="block7-1-1" class="turn-7"></label>
  <input id="block7-1-2" type="radio" class="player-1 middle second-column top first-row turn-7"/>
  <label for="block7-1-2" class="turn-7"></label>
  <input id="block7-1-3" type="radio" class="player-1 right third-column top first-row second-diagonal turn-7"/>
  <label for="block7-1-3" class="turn-7"></label>
  <input id="block7-2-1" type="radio" class="player-1 left first-column center second-row turn-7"/>
  <label for="block7-2-1" class="turn-7"></label>
  <input id="block7-2-2" type="radio" class="player-1 middle second-column center second-row first-diagonal second-diagonal turn-7"/>
  <label for="block7-2-2" class="turn-7"></label>
  <input id="block7-2-3" type="radio" class="player-1 right third-column center second-row turn-7"/>
  <label for="block7-2-3" class="turn-7"></label>
  <input id="block7-3-1" type="radio" class="player-1 left first-column bottom third-row second-diagonal turn-7"/>
  <label for="block7-3-1" class="turn-7"></label>
  <input id="block7-3-2" type="radio" class="player-1 middle second-column bottom third-row turn-7"/>
  <label for="block7-3-2" class="turn-7"></label>
  <input id="block7-3-3" type="radio" class="player-1 right third-column bottom third-row first-diagonal turn-7"/>
  <label for="block7-3-3" class="turn-7"></label>
  <input id="block8-1-1" type="radio" class="player-2 left first-column top first-row first-diagonal turn-8"/>
  <label for="block8-1-1" class="turn-8"></label>
  <input id="block8-1-2" type="radio" class="player-2 middle second-column top first-row turn-8"/>
  <label for="block8-1-2" class="turn-8"></label>
  <input id="block8-1-3" type="radio" class="player-2 right third-column top first-row second-diagonal turn-8"/>
  <label for="block8-1-3" class="turn-8"></label>
  <input id="block8-2-1" type="radio" class="player-2 left first-column center second-row turn-8"/>
  <label for="block8-2-1" class="turn-8"></label>
  <input id="block8-2-2" type="radio" class="player-2 middle second-column center second-row first-diagonal second-diagonal turn-8"/>
  <label for="block8-2-2" class="turn-8"></label>
  <input id="block8-2-3" type="radio" class="player-2 right third-column center second-row turn-8"/>
  <label for="block8-2-3" class="turn-8"></label>
  <input id="block8-3-1" type="radio" class="player-2 left first-column bottom third-row second-diagonal turn-8"/>
  <label for="block8-3-1" class="turn-8"></label>
  <input id="block8-3-2" type="radio" class="player-2 middle second-column bottom third-row turn-8"/>
  <label for="block8-3-2" class="turn-8"></label>
  <input id="block8-3-3" type="radio" class="player-2 right third-column bottom third-row first-diagonal turn-8"/>
  <label for="block8-3-3" class="turn-8"></label>
  <input id="block9-1-1" type="radio" class="player-1 left first-column top first-row first-diagonal turn-9"/>
  <label for="block9-1-1" class="turn-9"></label>
  <input id="block9-1-2" type="radio" class="player-1 middle second-column top first-row turn-9"/>
  <label for="block9-1-2" class="turn-9"></label>
  <input id="block9-1-3" type="radio" class="player-1 right third-column top first-row second-diagonal turn-9"/>
  <label for="block9-1-3" class="turn-9"></label>
  <input id="block9-2-1" type="radio" class="player-1 left first-column center second-row turn-9"/>
  <label for="block9-2-1" class="turn-9"></label>
  <input id="block9-2-2" type="radio" class="player-1 middle second-column center second-row first-diagonal second-diagonal turn-9"/>
  <label for="block9-2-2" class="turn-9"></label>
  <input id="block9-2-3" type="radio" class="player-1 right third-column center second-row turn-9"/>
  <label for="block9-2-3" class="turn-9"></label>
  <input id="block9-3-1" type="radio" class="player-1 left first-column bottom third-row second-diagonal turn-9"/>
  <label for="block9-3-1" class="turn-9"></label>
  <input id="block9-3-2" type="radio" class="player-1 middle second-column bottom third-row turn-9"/>
  <label for="block9-3-2" class="turn-9"></label>
  <input id="block9-3-3" type="radio" class="player-1 right third-column bottom third-row first-diagonal turn-9"/>
  <label for="block9-3-3" class="turn-9"></label>
  <div class="end">
    <h3></h3>
    <a href="">Restart</a> </div>
</div>

 

CSS

.tic-tac-toe {
	font-family: 'Open Sans', sans-serif;
	height: 300px;
	overflow: hidden;
	margin: 50px auto 30px auto;
	position: relative;
	width: 300px; background:rgba(255,255,255,.6); border-radius:10px;box-shadow: 0 0 8px rgba(0, 0, 0, 0.2)
}
@media (min-width: 450px) {
.tic-tac-toe {
	height: 450px;
	width: 450px}
}
.tic-tac-toe input[type="radio"] {
	display: none}
.tic-tac-toe input[type="radio"]:checked + label {
	cursor: default;
	z-index: 10 !important
}
.tic-tac-toe input[type="radio"].player-1 + label:after {content: "X"}
.tic-tac-toe input[type="radio"].player-2 + label:after {content: "O"}
.tic-tac-toe input[type="radio"].player-1:checked + label:after, .tic-tac-toe input[type="radio"].player-2:checked + label:after {
	opacity: 1
}
.tic-tac-toe input[type="radio"].player-1:checked + label {background-color: #dc685a}
.tic-tac-toe input[type="radio"].player-2:checked + label {background-color: #5acedc}
.tic-tac-toe input[type="radio"].turn-1 + label {z-index: 1}
.tic-tac-toe input[type="radio"].turn-2 + label {z-index: 2}
.tic-tac-toe input[type="radio"].turn-3 + label {z-index: 3}
.tic-tac-toe input[type="radio"].turn-4 + label {z-index: 4}
.tic-tac-toe input[type="radio"].turn-5 + label {z-index: 5}
.tic-tac-toe input[type="radio"].turn-6 + label {z-index: 6}
.tic-tac-toe input[type="radio"].turn-7 + label {z-index: 7}
.tic-tac-toe input[type="radio"].turn-8 + label {z-index: 8}
.tic-tac-toe input[type="radio"].turn-9 + label {z-index: 9}
.tic-tac-toe input[type="radio"].turn-1 + label {display: block}
.tic-tac-toe input[type="radio"].turn-1:checked ~ .turn-2 + label {display: block}
.tic-tac-toe input[type="radio"].turn-2:checked ~ .turn-3 + label {display: block}
.tic-tac-toe input[type="radio"].turn-3:checked ~ .turn-4 + label {display: block}
.tic-tac-toe input[type="radio"].turn-4:checked ~ .turn-5 + label {display: block}
.tic-tac-toe input[type="radio"].turn-5:checked ~ .turn-6 + label {display: block}
.tic-tac-toe input[type="radio"].turn-6:checked ~ .turn-7 + label {display: block}
.tic-tac-toe input[type="radio"].turn-7:checked ~ .turn-8 + label {display: block}
.tic-tac-toe input[type="radio"].turn-8:checked ~ .turn-9 + label {display: block}
.tic-tac-toe input[type="radio"].left + label {left: 0}
.tic-tac-toe input[type="radio"].top + label {top: 0}
.tic-tac-toe input[type="radio"].middle + label {left: 100px}
.tic-tac-toe input[type="radio"].right + label {left: 200px}
.tic-tac-toe input[type="radio"].center + label {top: 100px}
.tic-tac-toe input[type="radio"].bottom + label {top: 200px}
@media (min-width: 450px) {
.tic-tac-toe input[type="radio"].middle + label {left: 150px}
.tic-tac-toe input[type="radio"].right + label {left: 300px}
.tic-tac-toe input[type="radio"].center + label {top: 150px}
.tic-tac-toe input[type="radio"].bottom + label {top: 300px}
}
.tic-tac-toe input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ .end {
 display: block
}
.tic-tac-toe input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ input[type="radio"]:checked ~ .end > h3:before {
 content: "It is a tie!"
}
.tic-tac-toe .player-1.first-column:checked ~ .player-1.first-column:checked ~ .player-1.first-column:checked ~ .end, .tic-tac-toe .player-1.second-column:checked ~ .player-1.second-column:checked ~ .player-1.second-column:checked ~ .end, .tic-tac-toe .player-1.third-column:checked ~ .player-1.third-column:checked ~ .player-1.third-column:checked ~ .end, .tic-tac-toe .player-1.first-row:checked ~ .player-1.first-row:checked ~ .player-1.first-row:checked ~ .end, .tic-tac-toe .player-1.second-row:checked ~ .player-1.second-row:checked ~ .player-1.second-row:checked ~ .end, .tic-tac-toe .player-1.third-row:checked ~ .player-1.third-row:checked ~ .player-1.third-row:checked ~ .end, .tic-tac-toe .player-1.first-diagonal:checked ~ .player-1.first-diagonal:checked ~ .player-1.first-diagonal:checked ~ .end, .tic-tac-toe .player-1.second-diagonal:checked ~ .player-1.second-diagonal:checked ~ .player-1.second-diagonal:checked ~ .end {
 display: block
}
.tic-tac-toe .player-1.first-column:checked ~ .player-1.first-column:checked ~ .player-1.first-column:checked ~ .end h3:before, .tic-tac-toe .player-1.second-column:checked ~ .player-1.second-column:checked ~ .player-1.second-column:checked ~ .end h3:before, .tic-tac-toe .player-1.third-column:checked ~ .player-1.third-column:checked ~ .player-1.third-column:checked ~ .end h3:before, .tic-tac-toe .player-1.first-row:checked ~ .player-1.first-row:checked ~ .player-1.first-row:checked ~ .end h3:before, .tic-tac-toe .player-1.second-row:checked ~ .player-1.second-row:checked ~ .player-1.second-row:checked ~ .end h3:before, .tic-tac-toe .player-1.third-row:checked ~ .player-1.third-row:checked ~ .player-1.third-row:checked ~ .end h3:before, .tic-tac-toe .player-1.first-diagonal:checked ~ .player-1.first-diagonal:checked ~ .player-1.first-diagonal:checked ~ .end h3:before, .tic-tac-toe .player-1.second-diagonal:checked ~ .player-1.second-diagonal:checked ~ .player-1.second-diagonal:checked ~ .end h3:before {
 content: "Player 1 won!" !important
}
.tic-tac-toe .player-2.first-column:checked ~ .player-2.first-column:checked ~ .player-2.first-column:checked ~ .end, .tic-tac-toe .player-2.second-column:checked ~ .player-2.second-column:checked ~ .player-2.second-column:checked ~ .end, .tic-tac-toe .player-2.third-column:checked ~ .player-2.third-column:checked ~ .player-2.third-column:checked ~ .end, .tic-tac-toe .player-2.first-row:checked ~ .player-2.first-row:checked ~ .player-2.first-row:checked ~ .end, .tic-tac-toe .player-2.second-row:checked ~ .player-2.second-row:checked ~ .player-2.second-row:checked ~ .end, .tic-tac-toe .player-2.third-row:checked ~ .player-2.third-row:checked ~ .player-2.third-row:checked ~ .end, .tic-tac-toe .player-2.first-diagonal:checked ~ .player-2.first-diagonal:checked ~ .player-2.first-diagonal:checked ~ .end, .tic-tac-toe .player-2.second-diagonal:checked ~ .player-2.second-diagonal:checked ~ .player-2.second-diagonal:checked ~ .end {
 display: block
}
.tic-tac-toe .player-2.first-column:checked ~ .player-2.first-column:checked ~ .player-2.first-column:checked ~ .end h3:before, .tic-tac-toe .player-2.second-column:checked ~ .player-2.second-column:checked ~ .player-2.second-column:checked ~ .end h3:before, .tic-tac-toe .player-2.third-column:checked ~ .player-2.third-column:checked ~ .player-2.third-column:checked ~ .end h3:before, .tic-tac-toe .player-2.first-row:checked ~ .player-2.first-row:checked ~ .player-2.first-row:checked ~ .end h3:before, .tic-tac-toe .player-2.second-row:checked ~ .player-2.second-row:checked ~ .player-2.second-row:checked ~ .end h3:before, .tic-tac-toe .player-2.third-row:checked ~ .player-2.third-row:checked ~ .player-2.third-row:checked ~ .end h3:before, .tic-tac-toe .player-2.first-diagonal:checked ~ .player-2.first-diagonal:checked ~ .player-2.first-diagonal:checked ~ .end h3:before, .tic-tac-toe .player-2.second-diagonal:checked ~ .player-2.second-diagonal:checked ~ .player-2.second-diagonal:checked ~ .end h3:before {
 content: "Player 2 won!" !important
}
.tic-tac-toe label {
	background-color: #f2e0c4;
	border-radius: 14px;
	cursor: pointer;
	color: #fff;
	display: none;
	height: 90px;
	margin: 5px;
	position: absolute;
	width: 90px;
	-moz-transition: background-color 0.3s;
	-o-transition: background-color 0.3s;
	-webkit-transition: background-color 0.3s;
	transition: background-color 0.3s
}

How it works:

  • It uses hidden radio buttons for the states, and labels for the visible part.
  • There are 9 possible turns, in each turn a player can only click on one label.
  • Once the user clicks on a label, it changes the radio button state to :checked
  • When the :checked state is triggered, the CSS moves to the next turn by using z-index:
    • z-index: 1 for turn one,
    • z-index: 2 for turn two,
    • etc.

    It also pushes the clicked label on top (z-index: 10)

  • Player 1 plays on odd turns and player 2 plays on even turns. Each label has a class .turn-xadded to it, so we know which turn it is assigned to.
  • To determine which player won, we check for all posibble victories, for both players individually. In HTML we have classes added, so each label is a part of a column, row or diagonal. Example for player 1, first column victory:.player-1.first-column:checked ~ .player-1.first-column:checked ~ .player-1.first-column:checked ~ .end
  • To restart the game, I used a normal a tag, but left the href attribute empty, so it forces a refresh.

The game should work on any browser that supports CSS3 selectors.

Conclusion

This is my first game that uses only HTML and CSS. I already have a couple of ideas for creating some more Pure CSS games, so keep an eye out. If you liked this article, please share it by clicking on the share bar below. I’d appreciate it…

view demo

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.!

We respect your privacy. Your information will not be shared with any third party and you can unsubscribe at any time.
You can support this website by sharing. Thank you!