Going to take a short break from regular expressions.

When I started working on the first of the Regex Crossword posts, I decided to use an HTML table with in-line styles. The choice of in-line styles was primarily due to the fact that I use Hugo and one of their free themes to generate the posts and related website. Because I have had issues adding styles to the theme stylesheet, I kinda backed off using CSS files for styling anything I added to pages that the theme did not cover. Hence my decision. And a bad one it was.

In-line Styles

On the Regex Cross­word site the regexes for the columns where displayed as vertical text. I didn’t really like the result. It is a bit difficult to read and since I was aiming my posts at regex beginners, I thought it would be better to display the column regexes in the usual horizontal format used by the English language. I figured I could just arrange them on the necessary number of rows and have some arrows point to the appropriate column.

So, let’s have a look at building that part of the crossword table for one of the beginner puzzles. A simple 2x2 crossword.

Basic Crossword Row

But to see how things align, we will need at least one row of the actual crossword area. Something like the following.

<tr><td>clue</td><td style="border:1px black solid;width:1.1rem;height:1.1rem;">&nbsp;</td><td style="border:1px black solid;width:1.1rem;height:1.1rem;">&nbsp;</td><tr>

And that looks like the following. In the old days, you pretty much had to put that blank space in table cells to ensure things looked right. I believe that is no longer necessary. Let’s find out.

clue

Not exactly what I want. And, I don’t really want to mess with styling the width of the table. So, let’s just add another table cell at the end of the row. And, set the clue text to display on the right end of the table cell.

<tr><td style='text-align:right;'>clue</td><td style="border:1px black solid;width:1.1rem;height:1.1rem;"></td><td style="border:1px black solid;width:1.1rem;height:1.1rem;"></td><td></td><tr>

And that seems to help. But it’s not quite there. The crossword cells are to far to the right. And, the background is not correct.

The latter is because the table style for the default theme colours odd rows differently from even rows. So we need to fix the background colour as well as the tables position.

clue

Let’s add a width limitation on that first table cell, say 30 characters. And, set the background for each cell to white. Setting the row colour won’t work because of how the theme CSS is set up.

<tr><td style='text-align:right;width:30ch;background-color:white;'>clue</td><td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;">&nbsp;</td><td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;">&nbsp;</td><td style="background-color:white;"></td><tr>

This looks much better.

clue  

On to the column regexes.

Column Regexes

I want to have the right end of each clue align with the right end of the appropriate column. I believe colspan= will come to my rescue. And, I am going to put the regex for the columns further to the right above those to the left. So, the first row in our table will be for the regex for the rightmost column. And, let’s not forget the text alignment.

And, because this is the first row in the table, we will need to deal with the background colour again.

<tr><td colspan=3 style="text-align:right;background-color:white;">ep|ip|ef</td><td style="background-color:white;"></td></tr>
ep|ip|ef
clue  

Okay, let’s add the first columns regex and an arrow from the one above down to the appropriate column.

<tr><td colspan=2 style="text-align:right;background-color:white;">[^speak]+</td><td style="background-color:white;">&darr;</td><td style="background-color:white;"></td></tr>

And the result?

ep|ip|ef
[^speak]+
clue  

Finish Crossword Rows

Okay, let’s add the second crossword row and the correct regex for each row.

<tr><td style='text-align:right;width:30ch;background-color:white;'>he|ll|o+</td><td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;">&nbsp;</td><td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;">&nbsp;</td><td style="background-color:white;"></td><tr>
<tr><td style='text-align:right;width:30ch;background-color:white;'>[please]+</td><td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;">&nbsp;</td><td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;">&nbsp;</td><td style="background-color:white;"></td><tr>

And we get the following.

ep|ip|ef
[^speak]+
he|ll|o+  
[please]+  

Horrible HTML

But look at the final result for the above simple crossword. I broke up all the row cells to make it easier to edit the crossword as I discussed the solution steps. This had to be repeated for every step in the solution’s discussion.

<table>
<tr>
  <td colspan=3 style="text-align:right;background-color:white;">ep|ip|ef</td>
  <td style="background-color:white;"></td>
</tr>
<tr>
  <td colspan=2 style="text-align:right;background-color:white;">[^speak]+</td>
  <td style="background-color:white;">&darr;</td>
  <td style="background-color:white;"></td>
</tr>
<tr>
  <td style='text-align:right;width:30ch;background-color:white;'>he|ll|o+</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;">&nbsp;</td>
  <td style="background-color:white;"></td><tr>
<tr>
  <td style='text-align:right;width:30ch;background-color:white;'>[please]+</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;">&nbsp;</td>
  <td style="background-color:white;"></td><tr>
</table>

And, for the bigger puzzles things got even worse.

5 x 5 Crossword

In the second regex crossword post, I worked on a 5 column 5 row regex crossword. I also decided to use alternating colours for the arrow in each column. Well arrow is a bit of jump. And also added a text alignment for the crossword cells: text in the center. So more in-line styles. Lots of HTML for what is basically a very small table. And, as I developed the solution I copied that HTML multiple times in the post showing the letters I had sorted in the preceding text. Here’s the HTML and the result (initial puzzle state).

<table>
<tr>
  <td colspan=6 style='text-align:right;background-color:white;'>[lopity]*</td><td></td>
</tr>
<tr><td colspan=5 style='text-align:right;background-color:white;'>[faxus]*</td>
  <td style='text-align:right;background-color:white;color:blue;'>|</td>
  <td style="background-color:white;"></td>
</tr>
<tr><td colspan=4 style='text-align:right;background-color:white;'>(sod|do|ge)*</td>
  <td style='text-align:right;background-color:white;color:green;'>|</td>
  <td style='text-align:right;background-color:white;color:blue;'>|</td>
  <td style="background-color:white;"></td>
</tr>
<tr><td colspan=3 style='text-align:right;background-color:white;'>(.).*\1N\1</td>
  <td style='text-align:right;background-color:white;color:blue;'>|</td>
  <td style='text-align:right;background-color:white;color:green;'>|</td>
  <td style='text-align:right;background-color:white;color:blue;'>|</td>
  <td style="background-color:white;"></td>
</tr>
<tr><td colspan=2 style='text-align:right;background-color:white;'>[ark]*o.*</td>
  <td style='text-align:right;background-color:white;color:green;'>&darr;</td>
  <td style='text-align:right;background-color:white;color:blue;'>&darr;</td>
  <td style='text-align:right;background-color:white;color:green;'>&darr;</td>
  <td style='text-align:right;background-color:white;color:blue;'>&darr;</td>
  <td style="background-color:white;"></td>
<tr>
<tr><td style='text-align:right;background-color:white;width:30ch;'>[ugler]*</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="background-color:white;"></td>
</tr>
<tr><td style='text-align:right;background-color:white;'>[cast]*rex[pea]*</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="background-color:white;"></td>
</tr>
<tr><td style='text-align:right;background-color:white;'>[sires]*</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="background-color:white;"></td>
</tr>
<tr><td style='text-align:right;background-color:white;'>(l|oft|on|)*</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="background-color:white;"></td>
</tr>
<tr><td style='text-align:right;background-color:white;'>h*(ay|ed)*</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="border:1px black solid;width:1.1rem;height:1.1rem;background-color:white;text-align:center;">&nbsp;</td>
  <td style="background-color:white;"></td>
</tr>
</table>
[lopity]*
[faxus]*|
(sod|do|ge)*||
(.).*\1N\1|||
[ark]*o.*
[ugler]*     
[cast]*rex[pea]*     
[sires]*     
(l|oft|on|)*     
h*(ay|ed)*     

And as future post might have even larger puzzles, I decided it was time to use CSS for the purposes it was created to solve.

CSS Stylesheet

As mentioned I had some issues in the past playing with CSS. The main problem was when I added the CSS file in the page header, Hugo recompiled all the post pages, even those that didn’t really need the CSS in the referenced file. And, it was doing what it should. But, it meant I was going to be uploading a lot of pages that really didn’t need to be replaced.

However in this case, I realized I am already loading a CSS stylesheet in all the post pages. So, I am able to use it for the crossword table styles without affecting the hashes of all the sites files.

As I am not really a CSS expert there are, I am sure, going to be things in my CSS that could be done in better ways. But, my goal was just to get something working and reduce the amount of repeated in-line styles to as great a degree as possible.

I am going to go slow and easy. So a simple table with a few basic styles. Which will of course not generate what I am trying to produce.

Base Test Crossword

I am going to use a 3 row 4 column example to test my stylesheet. I am going to put the crossword rows in a tbody tag, and the column regexes in the thead tag.

Here’s the base table.

<table>
<thead>
<tr><td colspan=5>(n|a)*</td><td></td></tr>
<tr><td colspan=4>(fo|a|r)*</td><td>|</td><td></td></tr>
<tr><td colspan=3>(d|fu|uf)+</td><td>|</td><td>|</td><td></td><tr>
<tr><td colspan=2>[^nru](no|on)</td><td>&darr;</td><td>&darr;</td><td>&darr;</td><td></td><tr>
</thead>
<tbody>
<tr><td>[runt]*</td><td></td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
<tr><td>o.*[hat]</td><td></td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
<tr><td>(.)*do\1</td><td></td><td></td><td></td><td>&nbsp;</td><td>&nbsp;</td></tr>
<tbody>
</table>
(n|a)*
(fo|a|r)*|
(d|fu|uf)+||
[^nru](no|on)
[runt]*    
o.*[hat]    
(.)*do\1  

Initial Styles

The crossword table will get a class name of xword. We can start by:

  • getting rid of the alternating row colour in the tbody section
  • give the first cell in the tbody a maximum fixed size
  • give the crossword cells a border and size
  • align the clue cells to the right (thead and tbody)
  • reduce column regex line size so parts of arrows are closer together

I was going to use a class for the crossword cells to control which ones got borders and such. But, then I figured there might be some other way to get the job done. I.E. by specifying all cells in tbody rows except the first and last. And, you know, it is possible.

table.xword tbody tr > td:nth-of-type(n+2):nth-last-of-type(n+2)

Essentially, starting from the front of the row select all the cells from the 2nd cell onwards. From that group starting at the end, select all the cells from the 2nd last cell to the front. It might be possible to use the :not selector, but I couldn’t get that to work.

table.xword {
  margin:0;
  margin-bottom:2rem;
  padding:0;
}

table.xword tbody > tr:nth-child(2n+1) > td {
  background-color:white;
}

table.xword tbody td:nth-child(1) {
  width:30ch;
  text-align: right;
}

table.xword thead td {
  text-align:right;
  line-height: .5;
}

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;
}

And, all that I’ve done is add class='xword' to the table tag. E.G. <table class='xword'>. And bingo.

(n|a)*
(fo|a|r)*|
(d|fu|uf)+||
[^nru](no|on)
[runt]*    
o.*[hat]    
(.)*do\1  

Wow! Now to colour those arrows.

Coloured Arrows

I tried a variety of options, but decided to see if the nth-last-of-type() selector would work. That is because I want the last and every second cell going towards the front of the row to be one colour (blue in this case). And the second last cell and every second cell going towards the front of the row to be another colour (green in this case).

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 first cell */
table.xword thead tr > td:nth-child(1) {
  color: #424242;
}
(n|a)*
(fo|a|r)*|
(d|fu|uf)+||
[^nru](no|on)
[runt]*    
o.*[hat]    
(.)*do\1  

And all of that nice formatting all by just adding a class attribute to the table tag. Amazing!

Done

And the CSS stylesheet is less than half the size of all the in-line styles I had in that 5x5 crossword table. I am truly amazed at the reduction in the style text size.

Wish I had done that from the start. Would have saved me a pile of refactoring of the two posts. Live and learn, eh?

That pretty much covers what I did and why. Now whether it is good CSS, that I don’t know. But it is very specific and will not affect any other table.

Hope you got near as much out of this exercise as I did. Keep those happy fingers tapping.

Resources

Final CSS and HTML for the 5x5 Crossword

/* 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;
}

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

/* 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;
}

/* 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;
}
<table class='xword'>
<thead>
<tr><td colspan=5>(n|a)*</td><td></td></tr>
<tr><td colspan=4>(fo|a|r)*	</td><td>|</td><td></td></tr>
<tr><td colspan=3>(d|fu|uf)+</td><td>|</td><td>|</td><td></td><tr>
<tr><td colspan=2>[^nru](no|on)	</td><td>&darr;</td><td>&darr;</td><td>&darr;</td><td></td><tr>
</thead>
<tbody>
<tr><td>[runt]*</td><td></td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
<tr><td>o.*[hat]</td><td></td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
<tr><td>(.)*do\1</td><td></td><td></td><td></td><td>&nbsp;</td><td>&nbsp;</td></tr>
<tbody>
</table>