After I finished the previous post, it occurred to me that I might be able to use CSS to add the arrows to the table, rather than having to manually type them into each cell as appropriate. It’s not something CSS was meant to do. But, according to MDN:

One of the important advantages of CSS is that it helps you to separate a document’s style from its content. However, there are situations where it makes sense to specify certain content as part of the stylesheet, not as part of the document. You can specify text or image content within a stylesheet when that content is closely linked to the document’s structure.

I thought the arrows qualified as being closely linked to the table’s (document’s) structure. Though I don’t know if I can get it to work as there can be significantly differring numbers of columns between crosswords. Don’t know if I can get CSS to do the required arithmetic. But, if necessary, I might be able to somehow specify the number of columns in a data field that CSS can access.

Where to Start

Okay let’s look at the HTML for a crossword table with clues left, right, top, and bottom.

<table class='xword'>
<thead>
<tr><td colspan=5>(o|p)\1\1</td><td></td></tr>
<tr><td colspan=4>[you?be]+</td><td>|</td><td></td></tr>
<tr><td colspan=3>(a|\?|\?p|np)+</td><td>|</td><td>|</td><td></td></tr>
<tr><td colspan=2>[mensa?]+</td><td>&darr;</td><td>&darr;</td><td>&darr;</td><td></td></tr>
</thead>
<tbody>
<tr><td>[^ape]+.?</td><td></td><td></td><td></td><td></td><td>[m-q].[a-e][m-q]</td></tr>
<tr><td>[snake]+.</td><td></td><td></td><td></td><td></td><td>[^naked].?(uo|duo)</td></tr>
<tr><td>(\!|\'|\.|\?)?p[yo!]+</td><td></td><td></td><td></td><td></td><td>.+[m-w]+</td></tr>
<tbody>
<tfoot>
<tr><td colspan=2>[^nap\s]+.</td><td>&uarr;</td><td>&uarr;</td><td>&uarr;</td><td></td></tr>
<tr><td colspan=3>[pen\sa?]+</td><td>|</td><td>|</td><td></td></tr>
<tr><td colspan=4>.+(y|be)</td><td>|</td><td></td></tr>
<tr><td colspan=5>[^bat's?]+</td><td></td></tr>
</tfoot>
</table>

Okay for the very last row in the thead element all the columns except the first and last get a down arrow. The rest of the rows in the thead element get the | character except for the first and last columns. For the column clues in the tfoot element things are reversed. So hopefully using child selectors on the rows will get the job done quickly and easily.

Let’s Give It a Shot

So, let’s select the last row in thead and the appropriate columns. The latter we have seen in the previous article. I’ll try using last-child selector to select the last row in the thead element.

table.xword > thead > tr:last-child > td:nth-of-type(n+2):nth-last-of-type(n+2)::after {
  content: "↓";
}

Then we can use nth-last-of-type(n+2) selector to get the 2nd last row back up to the top. With the same column selector used above.

table.xword > thead > tr:nth-last-of-type(n+2) > td:nth-of-type(n+2):nth-last-of-type(n+2)::after {
  content: "|";
}

And for the lower column regexes, something similar. But the arrows (pointing in the other direction) are in the first row of the tfoot section. The first-child selector should do the trick. Then nth-of-type(n+2) should select the second row through to the last.

table.xword > tfoot > tr:first-child > td:nth-of-type(n+2):nth-last-of-type(n+2)::after {
  content: "↑";
}

table.xword > tfoot > tr:nth-of-type(n+2) > td:nth-of-type(n+2):nth-last-of-type(n+2)::after {
  content: "|";
}

Once I add the above to the correct CSS file, I get the following. I have not yet removed the hardcoded arrow bits from the HTML for the crossword table, so the arrow bits should be duplicated.

(o|p)\1\1
[you?be]+|
(a|\?|\?p|np)+||
[mensa?]+
[^ape]+.?[m-q].[a-e][m-q]
[snake]+.[^naked].?(uo|duo)
(\!|\'|\.|\?)?p[yo!]+.+[m-w]+
[^nap\s]+.
[pen\sa?]+||
.+(y|be)|
[^bat's?]+

And, bingo. That was almost painless.

Remove Hardcoded Arrow Characters

Okay, let’s see if it still works once I remove the hardcoded arrows. Might not, as there won’t be anything for which to place characters after. Though I expect browsers add a blank space in any cells without specified content.

(o|p)\1\1
[you?be]+
(a|\?|\?p|np)+
[mensa?]+
[^ape]+.?[m-q].[a-e][m-q]
[snake]+.[^naked].?(uo|duo)
(\!|\'|\.|\?)?p[yo!]+.+[m-w]+
[^nap\s]+.
[pen\sa?]+
.+(y|be)
[^bat's?]+

Well, still seems to work as desired.

Current CSS File

/* remove alternate row colouring of default table style */
table.xword tbody > tr:nth-child(2n+1) > td {
  background-color:white;
}


/* set width and alignment for crossword row clue cell */
table.xword td:nth-child(1) {
  width:30ch;
  text-align: right;
}

/* style actual crossword character cells */
table.xword tbody tr > td:nth-of-type(n+2):nth-last-of-type(n+2) {
  border:1px black solid;
  width:1.1rem;
  height:1.1rem;
  text-align:center;
}


/* upper column clue cells */
table.xword thead td {
  text-align:right;
  line-height: .5;
}

/* color arrows in thead cells accordingly */
table.xword thead tr > td:nth-last-of-type(2n+1) {
  color: blue;
}
table.xword thead tr > td:nth-last-of-type(2n+2) {
  color: green;
}
/* but don't want to change the colour of the clue cell */
table.xword thead tr > td:nth-child(1) {
  color: #424242;
}

/* add top clue arrow characters to crossword as appropriate */
table.xword > thead > tr:last-child > td:nth-of-type(n+2):nth-last-of-type(n+2)::after {
  content: "↓";
}

table.xword > thead > tr:nth-last-of-type(n+2) > td:nth-of-type(n+2):nth-last-of-type(n+2)::after {
  content: "|";
}


/* lower column clue cells */
table.xword tfoot td, table.xword1 tfoot td {
  text-align:right;
  line-height: .5;
}
table.xword tfoot tr > td:nth-last-of-type(2n+1) {
  color: blue;
}
table.xword tfoot tr > td:nth-last-of-type(2n+2) {
  color: green;
}
/* but don't want to change the colour of the clue cell */
table.xword tfoot tr > td:nth-child(1) {
  color: #424242;
}

/* add bottom clue arrow characters to crossword as appropriate */
table.xword > tfoot > tr:first-child > td:nth-of-type(n+2):nth-last-of-type(n+2)::after {
  content: "↑";
}

table.xword > tfoot > tr:nth-of-type(n+2) > td:nth-of-type(n+2):nth-last-of-type(n+2)::after {
  content: "|";
}

Done

I am quite amazed at how easy that turned out to be. Well, except for fixing all the posts (published or draft) that will now have duplicate arrows. Yet to be done.

But, feels good. And makes for a nice short post.

Until next time, may all your days feel as good as mine did today.

Resources