How I Built a Pure CSS Crossword Puzzle

CSS Crossword Puzzle

Recently I created a pure CSS crossword puzzle implemented using CSS grid that does not need JavaScript in order to work. It gained heavy interest pretty quickly on CodePen. As of this writing, it has more than 350 hearts and 24,000+ page views!

The great CSS Grid Garden tutorial inspired me to build something with Grid Layout features. I wondered if these features could be put to good use in building a crossword puzzle — then I thought, let’s try to create the whole thing without using JavaScript.

Building the Board/Grid

So, first thing’s first, let’s create the board itself!

I ended up with the following basic structure, with HTML comments included to show what the different sections will accomplish:

[code language=”html”]
<div class=”crossword-board-container”>

<div class=”crossword-board”>

<!– input elements go here. Uses CSS Grid as its layout –>

<div class=”crossword-board crossword-board–highlight crossword-board–highlight–across”>
<!– highlights for valid ‘across’ answers go here. Uses CSS Grid as its layout –>

<div class=”crossword-board crossword-board–highlight crossword-board–highlight-down”>
<!– highlights for valid ‘down’ answers go here. Uses CSS Grid as its layout –>

<div class=”crossword-board crossword-board–labels”>
<!– row and column number labels go here. Uses CSS Grid as its layout –>

<div class=”crossword-clues”>

<dl class=”crossword-clues__list crossword-clues__list–across”>
<!– clues for all the ‘across’ words go here –>

<dl class=”crossword-clues__list crossword-clues__list–down”>
<!– clues for all the ‘down’ words go here –>




That puts our basic skeleton in place so we can add more elements and start styling things.

Using Form Elements for the Squares

The crossword puzzle I’m creating is a 13×13 grid with 44 blank spaces so I need to create 125 input elements each with its own ID in the format item{row number}-{column number}, i.e. item4-12. Here’s what the grid will look like:

Empty crossword

Each of the inputs will get have a minlength and maxlength of “1” to emulate the behaviour of a crossword puzzle (i.e. one letter per square). Each input will also have the required attribute so that HTML5 form validation will be used. I take advantage of all of these HTML5 attributes using CSS.

Using the General Sibling Selector

The input elements are visually laid out in groups (exactly how a crossword puzzle is). Each group of input elements represents a word in the crossword. If each of the elements in that group is valid (which can be verified using the :valid pseudo selector), then we can use CSS to style an element that appears later in the DOM (using an advanced CSS selector called the general sibling selector) that will indicate that the word is correct.

Due to how sibling selectors work, and how CSS works in general, this element has to appear later in the DOM. CSS can only style elements that are after the currently selected element. It cannot look backwards in the DOM (or up the DOM tree) and style something before the current element (at the moment at least anyway).

This means I can use the :valid pseudo-class to style valid elements:

[code language=”css”]
.input:valid {
border: 2px solid green;
.input:invalid {
border: 2px solid red;

See the Pen Valid Pseudo Selector Example by SitePoint (@SitePoint) on CodePen.

To style an element later on in the DOM that is a sibling of another element, I can use the ~ (tilde/general sibling) selector, e.g. A ~ B. This selector will select all elements that match B, that are a sibling of A and appear after A in the DOM. For example:

[code language=”css”]
#input1:valid ~ #input2:valid ~ #input3:valid ~ #input4:valid ~ #input5:valid ~ .valid-message {
display: block;

With this code, if all these input elements are valid, the valid-message element will be displayed.

See the Pen Using Sibling Selector to Display a Message by SitePoint (@SitePoint) on CodePen.

The general sibling selector is extremely useful here. To make the crossword work, I needed to make sure that everything was laid out in a way that allowed me to take advantage of the general sibling selector.

Continue reading %How I Built a Pure CSS Crossword Puzzle%

Source: Sitepoint