<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nicholas Stimpson</title>
    <description>The latest articles on DEV Community by Nicholas Stimpson (@alohci).</description>
    <link>https://dev.to/alohci</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F171183%2F2f3e63c8-4708-4388-8770-8252aab7e22a.JPG</url>
      <title>DEV Community: Nicholas Stimpson</title>
      <link>https://dev.to/alohci</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alohci"/>
    <language>en</language>
    <item>
      <title>"15 Puzzle" slider game in HTML and CSS</title>
      <dc:creator>Nicholas Stimpson</dc:creator>
      <pubDate>Mon, 29 Jul 2024 06:16:28 +0000</pubDate>
      <link>https://dev.to/alohci/15-puzzle-slider-game-in-html-and-css-5g2i</link>
      <guid>https://dev.to/alohci/15-puzzle-slider-game-in-html-and-css-5g2i</guid>
      <description>&lt;p&gt;Skip to puzzle&lt;/p&gt;

&lt;p&gt;The other day, a recollection popped into my mind of a small puzzle toy from my childhood, a slider puzzle where 15 square tiles are placed in a frame in a 4 x 4 arrangement of cells leaving one free space. A set of ridges and grooves on the edges of each tile and the frame allows the tiles to slide past one another whilst holding the tiles in the frame. At any given time any tile adjacent to the free space can move into that space, and otherwise the tiles are prevented from moving. Moving a tile into the free space then leaves a new free space where the tile came from and another tile can then move into that new space. The idea is by repeated sliding of the tiles in this way to arrange the tiles into some predetermined order.&lt;/p&gt;

&lt;p&gt;Apparently this is called a &lt;a href="https://en.wikipedia.org/wiki/15_puzzle" rel="noopener noreferrer"&gt;"15 Puzzle"&lt;/a&gt; and has been around since the 1870s. Searching the web returns a number of recreations written in a variety of programming languages and indeed there are several articles here on dev.to including &lt;a href="https://dev.to/artydev/let-us-code-a-sliding-puzzle-9n"&gt;https://dev.to/artydev/let-us-code-a-sliding-puzzle-9n&lt;/a&gt;, &lt;a href="https://dev.to/xzanderzone/making-a-slider-puzzle-in-java-script-83m"&gt;https://dev.to/xzanderzone/making-a-slider-puzzle-in-java-script-83m&lt;/a&gt;, and &lt;a href="https://dev.to/claurcia/slide-puzzle-5c55"&gt;https://dev.to/claurcia/slide-puzzle-5c55&lt;/a&gt; all in JavaScript and &lt;a href="https://dev.to/mfbmina/building-a-sliding-puzzle-with-go-3bnj"&gt;https://dev.to/mfbmina/building-a-sliding-puzzle-with-go-3bnj&lt;/a&gt; in Go. It's also presented as a good starter challenge for those learning JavaScript.&lt;/p&gt;

&lt;p&gt;What piqued my interest though was the idea that it ought to be recreatable on the web using no programming language at all! That is, an implementation using just pure HTML and CSS. So I present it below. The one compromise I had to make was that the 10 games provided have fixed pre-shuffled starting positions.&lt;/p&gt;

&lt;p&gt;For this, the predetermined order is to show a completed picture.&lt;/p&gt;

&lt;p&gt;The basic principle of this implementation is that each tile retains a state record of where it is within the frame. There aren't many ways to change and hold  state in HTML and CSS, but the most common is the "checkbox hack" and this implementation makes heavy use of it. For anyone unfamiliar with the checkbox hack, when a &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; element is clicked or tapped the activation behaviour of its associated form control, if it has one, is fired. When the associated control is a checkbox, the checkbox state is toggled, unchecked to checked and checked to unchecked. Similiarly, when the associated control is a radio button, that radio button is checked, and any other radio button in the same group that was checked is unchecked. Then a CSS selector can measure the checkedness of the control via the &lt;code&gt;:checked&lt;/code&gt; pseudo-class and apply different CSS to other elements depending on that state. &lt;/p&gt;

&lt;p&gt;So each tile has a pair of radio button groups each with four radio buttons. One of these groups retains the tile's position in the X-axis and the other its position in the Y-axis. (Or horizontal position and vertical position respectively, if you prefer.) The fifteen tiles are each initially given a different combination of X and Y coordinates via their radio buttons so that each one occupies a different cell in the frame.&lt;br&gt;
 &lt;br&gt;
The tiles are initially placed in the frame's top, left cell and are then moved within the frame via CSS measuring the state of the radio buttons by applying a translation transform to them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* "X" refers to the X-axis cell positions, "Y" to the Y-axis cell positions. 
 * 0, 1, 2, 3 refers to the position on that axis, 
 * 0 = left and top, 3 = right and bottom respectively.
 */&lt;/span&gt;

&lt;span class="nc"&gt;.tile&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.X0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nc"&gt;.Y0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.tile&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.X0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nc"&gt;.Y1&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.tile&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.X0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nc"&gt;.Y2&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;200%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.tile&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.X0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nc"&gt;.Y3&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;300%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.tile&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.X1&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nc"&gt;.Y0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;/* and so on for the remainder of the sixteen combinations */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tile then also contains eight label elements, corresponding to the eight radio buttons. Each label is absolute positioned overlaying one another and each completely fills the tile. The labels are transparent, and are initially set up to not respond to clicks and taps by setting &lt;code&gt;pointer-events:none&lt;/code&gt; on all of them.&lt;/p&gt;

&lt;p&gt;The next step is for the CSS selectors to identify where the empty cell is. This is done by elimination, it's the cell for whose X,Y coordinates are not represented by the radio button group pair of any of the fifteen tiles.&lt;/p&gt;

&lt;p&gt;For example, if this matches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.frame&lt;/span&gt;&lt;span class="nd"&gt;:not&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.tile&lt;/span&gt; &lt;span class="nc"&gt;.X0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nc"&gt;.Y0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;....&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then the empty cell must currently be in the top left hand corner cell. Repeat this for each of the sixteen cells and exactly one of them will match.&lt;/p&gt;

&lt;p&gt;Once that is done, the cells of adjacent to the empty cell can be identified. If the empty cell is in a corner, then there are exactly two tiles that can move into that cell, otherwise, if the empty cell is against one of the frame's sides, there are three tiles that can move into the cell, otherwise the empty cell must be one of the four middle cells, and there are four tiles that can move to it. For each of those tiles,  exactly one of the tiles' eight labels will activate the correct radio button necessary to move the tile to the empty cell. That label is enabled by setting its&lt;code&gt;pointer-events&lt;/code&gt; value back to &lt;code&gt;auto&lt;/code&gt;. So as examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Top, left corner */&lt;/span&gt;
&lt;span class="nc"&gt;.frame&lt;/span&gt;&lt;span class="nd"&gt;:not&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.tile&lt;/span&gt; &lt;span class="nc"&gt;.X0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;:is(&lt;/span&gt;
&lt;span class="err"&gt;     &lt;/span&gt; &lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="py"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;X0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="err"&gt;~&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt;     &lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;X1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="err"&gt;~&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X0&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="n"&gt;pointer-events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* right most cell of row two */&lt;/span&gt;
&lt;span class="nc"&gt;.frame&lt;/span&gt;&lt;span class="nd"&gt;:not&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.tile&lt;/span&gt; &lt;span class="nc"&gt;.X1&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y3&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;:is(&lt;/span&gt;
&lt;span class="err"&gt;     &lt;/span&gt; &lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="py"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;X1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="err"&gt;~&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt;     &lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;X0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="err"&gt;~&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt;     &lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;X2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="err"&gt;~&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X1&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="n"&gt;pointer-events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* second cell from left on row three */&lt;/span&gt;
&lt;span class="nc"&gt;.frame&lt;/span&gt;&lt;span class="nd"&gt;:not&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.tile&lt;/span&gt; &lt;span class="nc"&gt;.X2&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y1&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;:is(&lt;/span&gt;
&lt;span class="err"&gt;     &lt;/span&gt; &lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="py"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;X2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="err"&gt;~&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt;     &lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;X2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="err"&gt;~&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt;     &lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;X1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="err"&gt;~&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt;     &lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="n"&gt;X3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="err"&gt;~&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X2&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="n"&gt;pointer-events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last step of the game is to identify when the puzzle is solved. This is simply a case of checking that the 15 tiles all have their expected X and Y axis radio buttons set to their "solved" position.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Each tile is assigned a letter "a" to "o". 
 * The puzzle is solved when the tiles are in alphabetical order
 * reading left to right and top to bottom
*/&lt;/span&gt;
&lt;span class="nc"&gt;.frame&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.a&lt;/span&gt; &lt;span class="nc"&gt;.X0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.b&lt;/span&gt; &lt;span class="nc"&gt;.X1&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="nc"&gt;.c&lt;/span&gt; &lt;span class="nc"&gt;.X2&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.d&lt;/span&gt; &lt;span class="nc"&gt;.X3&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.e&lt;/span&gt; &lt;span class="nc"&gt;.X0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y1&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="nc"&gt;.f&lt;/span&gt; &lt;span class="nc"&gt;.X1&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y1&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.g&lt;/span&gt; &lt;span class="nc"&gt;.X2&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y1&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.h&lt;/span&gt; &lt;span class="nc"&gt;.X3&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y1&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="nc"&gt;.i&lt;/span&gt; &lt;span class="nc"&gt;.X0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y2&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.j&lt;/span&gt; &lt;span class="nc"&gt;.X1&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y2&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.k&lt;/span&gt; &lt;span class="nc"&gt;.X2&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y2&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="nc"&gt;.l&lt;/span&gt; &lt;span class="nc"&gt;.X3&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y2&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.m&lt;/span&gt; &lt;span class="nc"&gt;.X0&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y3&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.n&lt;/span&gt; &lt;span class="nc"&gt;.X1&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y3&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="nc"&gt;.o&lt;/span&gt; &lt;span class="nc"&gt;.X2&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.Y3&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nc"&gt;.options&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nc"&gt;.success&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rest is cosmetic. The sliding is done with a simple transition of the transform described above&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.tile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5s&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt;@media&lt;/span&gt; &lt;span class="err"&gt;(prefers-reduced-motion)&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt; &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and each tile shows a portion of the game's image using &lt;code&gt;background-size&lt;/code&gt; and &lt;code&gt;background-position&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.tile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;background-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;#board1&lt;/span&gt; &lt;span class="nc"&gt;.tile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("https://alohci.net/image/dev.to/slidergame/mullermarc-k7bQqdUf954-unsplash.webp")&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;background-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.b&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;background-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;33.333%&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.c&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;background-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;66.667%&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.d&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;background-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.e&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nl"&gt;background-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt; &lt;span class="m"&gt;33.333%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;/* and so on for the remaining tiles */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and there's a single set of radio buttons to choose which of the ten games to play.&lt;/p&gt;

&lt;p&gt;To play the game, simply click or tap on the  tile you want to slide to the empty cell.&lt;/p&gt;

&lt;p&gt;I've also provided a "barebones" mode to show the tile letters and radio buttons which might help with the understanding of how the HTML and CSS works.&lt;/p&gt;

&lt;p&gt;So here's the completed puzzle game. Please let me know any feedback you have. &lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/alohci/embed/BagQbbe?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>html</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Hot Cross Buns</title>
      <dc:creator>Nicholas Stimpson</dc:creator>
      <pubDate>Fri, 29 Mar 2024 17:29:34 +0000</pubDate>
      <link>https://dev.to/alohci/hot-cross-buns-2j63</link>
      <guid>https://dev.to/alohci/hot-cross-buns-2j63</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for DEV Challenge v24.03.20, CSS Art: Favorite Snack.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspiration
&lt;/h2&gt;

&lt;p&gt;Easter is a time for Hot Cross Buns&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;(Note that codepen is quite slow in displaying this image)&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/alohci/embed/gOyGoOo?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;OK, here's the thing. While I consider myself competent at CSS, my artistic skill is close to zero. So I cheated.&lt;/p&gt;

&lt;p&gt;While the image created in the codepen above is formed in CSS, the text-shadow was not hand written. I photographed some real hot cross buns, loaded it in a canvas&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;canvas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drawImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getImageData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;...;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then looped over the image data pixel by pixel, and wrote it back out as a text-shadow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imageData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;imageData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;imageData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vmin &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vmin &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
         &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0vmin rgba(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
         &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
         &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
         &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
         &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The text-shadow is of a single character - the Unicode Character 'BLACK SQUARE' “■” (U+25A0) with a transparent colour.&lt;/p&gt;

&lt;p&gt;Licence: CC-BY&lt;/p&gt;

</description>
      <category>frontendchallenge</category>
      <category>devchallenge</category>
      <category>css</category>
    </item>
    <item>
      <title>Questions From The New Cascade</title>
      <dc:creator>Nicholas Stimpson</dc:creator>
      <pubDate>Sat, 05 Mar 2022 02:28:31 +0000</pubDate>
      <link>https://dev.to/alohci/questions-from-the-new-cascade-2050</link>
      <guid>https://dev.to/alohci/questions-from-the-new-cascade-2050</guid>
      <description>&lt;p&gt;Cascade layers is probably the biggest upgrade the CSS cascade has had since its inception. Now that Chrome has joined Firefox in having cascade layers enabled by default, and there's various articles available describing them, it's time to start thinking about how to use them. Have you grokked them yet?&lt;/p&gt;

&lt;p&gt;To test yourself, here's three small questions about them, plus explanations of the answers. Let's get started.&lt;/p&gt;

&lt;h2&gt;Question One&lt;/h2&gt;

&lt;p&gt;What colours are used for the foreground text and the page background in the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en-gb"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Question One&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="nb"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"data:text/css, \
    body.myBody { \
       background-color:blue; \
       font-size:4em; \
    } \
    * { \
       color:yellow !important; \
    } \
    "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"myBody"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
Hello World
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://codepen.io/alohci/pen/qBVggBm"&gt;Codepen with answer&lt;/a&gt;&lt;br&gt;
(Link, because it seems dev.to doesn't support embedding a codepen within a disclosure section.)&lt;/p&gt;

&lt;p&gt;
  Reveal Answer Explanation
  &lt;p&gt;The text colour is yellow and the background colour is red.&lt;/p&gt;

&lt;p&gt;The first thing to understand is the @import. Normally, this would link to an external style sheet, but here for the benefit of having everything in one place for demonstration purposes, I've used a data url. &lt;/p&gt;

&lt;p&gt;The "layer" keyword at the end tells the browser to place all the contents of the imported resource into a layer. The layer is not named, so it is an "anonymous" layer. Anonymous layers work like named ones, except they can't be referenced so once defined they can't be added to, and they can't be manipulated in the layer order.&lt;/p&gt;

&lt;p&gt;So in this case, the @import is exactly equivalent to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.myBody&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;4em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="no"&gt;yellow&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Taking the background colour first where all the declarations are non-important, if the layer was not involved and specificity was the determining factor, the &lt;code&gt;body.myBody { background-color:blue; }&lt;/code&gt; rule would beat the &lt;code&gt;body { background-color: red; }&lt;/code&gt; rule and the background would be blue. &lt;/p&gt;

&lt;p&gt;But for non-important declarations, rules in a layer are always lower precedence than rules not in a layer, so the &lt;code&gt;body { background-color: red; }&lt;/code&gt; rule wins.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;!important&lt;/code&gt; declarations like the text colour, the opposite applies. Layered rules take precedence over unlayered rules regardless of specificity, so the &lt;code&gt;* { color:yellow !important; }&lt;/code&gt; rule wins.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;Question Two&lt;/h2&gt;

&lt;p&gt;This question looks similar. The unlayered styles have been moved to be inline styles of the body element. Again, what are the final text and background colours? Is it the same answer?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en-gb"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Question Two&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="nb"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"data:text/css, \
    body.myBody { \
       background-color:blue; \
       font-size:4em; \
    } \
    * { \
       color:yellow !important; \
    } \
    "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"myBody"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background-color:red;color:white!important"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
Hello World
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://codepen.io/alohci/pen/YzEBMJx"&gt;Codepen with answer&lt;/a&gt;&lt;br&gt;

  Reveal Answer Explanation
  &lt;p&gt;The background is still red, but now the text color is white.&lt;/p&gt;

&lt;p&gt;In the answer to question one, I explain that &lt;code&gt;!important&lt;/code&gt; layered styles have precedence over &lt;code&gt;!important&lt;/code&gt; unlayered styles regardless of specificity. Yet here the inline style wins.&lt;/p&gt;

&lt;p&gt;In CSS 2, inline styles were unambiguously part of specificity. There any innumerous guides to specificity that will tell you that.&lt;/p&gt;

&lt;p&gt;Yet in CSS 3 until now, the relationship between inline styles and specificity has had a distinctly ambiguous air. The specifications have neither wholly placed inline styles as part of specificity, nor provided any alternative.&lt;/p&gt;

&lt;p&gt;With Cascade layers that ambiguity has finally been removed. Inline styles are no longer part of specificity! Instead they have their own precedence level in the cascade called "Element-Attached Styles". Element-Attached Styles have a precedence which is above both cascade layers and specificity. So an Element-Attached style wins over layered styles even when &lt;code&gt;!important&lt;/code&gt; is used on both. &lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;Question Three&lt;/h2&gt;

&lt;p&gt;Something different now. What are the rendered sizes of the three images? (For those not familiar with placeholder.com, the image supplied from &lt;a href="http://via.placeholder.com/100"&gt;http://via.placeholder.com/100&lt;/a&gt; will have intrinsic dimensions of 100px x 100px.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en-gb"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Question Three&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
      &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;200px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;.beta&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;revert&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
      &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;revert&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="nc"&gt;.gamma&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;revert-layer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
      &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;revert-layer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; 
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"alpha"&lt;/span&gt; 
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://via.placeholder.com/100"&lt;/span&gt;
    &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"150"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"150"&lt;/span&gt; 
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"100 pixel square placeholder"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; 
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"beta"&lt;/span&gt; 
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://via.placeholder.com/100"&lt;/span&gt;
    &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"150"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"150"&lt;/span&gt; 
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"100 pixel square placeholder"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; 
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"gamma"&lt;/span&gt; 
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://via.placeholder.com/100"&lt;/span&gt;
    &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"150"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"150"&lt;/span&gt; 
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"100 pixel square placeholder"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://codepen.io/alohci/pen/ExbrBBJ"&gt;Codepen with answer&lt;/a&gt;&lt;br&gt;

  Reveal Answer Explanation
  &lt;p&gt;The image sizes are 200px x 200px, 100px x 100px &amp;amp; 150px x 150px respectively.&lt;/p&gt;

&lt;p&gt;Image alpha is 200px x 200px. Until the introduction of cascade layers, the values of the HTML height and width attributes were treated as presentational hints at the start of the author origin style sheets with a specificity of 0, so any matching CSS rules would take precedence over them, and the HTML dimensions are only a resort to be used if CSS doesn't provide any. So the CSS provided dimensions win.&lt;/p&gt;

&lt;p&gt;Image beta is 100px x 100px. Introducing cascade layers produces a slight problem though. Because non-important layered styles have lower precedence that unlayered styles, if the HTML attribute presentational hints were treated as unlayered styles, then they'd have precedence over any CSS in a layer. That not ideal. So a new origin has been created for them called the "author presentational hint origin". This has precedence lower than all layered and unlayered styles. &lt;/p&gt;

&lt;p&gt;However, the "revert" keyword has well established behaviour. When effective in an author origin style sheet, it will revert the author origin matching styles including the presentational hints. So to maintain that behaviour, "revert" has been slightly redefined to include the reverting of the "author presentational hint origin".&lt;/p&gt;

&lt;p&gt;As a result, the "revert" has the effect of taking the size of the image back to its intrinsic dimensions.&lt;/p&gt;

&lt;p&gt;Image gamma is 150px x 150px. You might think that as there don't appear to be any cascade layers in use in the CSS, that "revert-layer" would either do nothing at all, or do the same as "revert". In fact, since it's in an unlayered style, it reverts the unlayered styles of the image dimensions. &lt;/p&gt;

&lt;p&gt;But it is free from any backward-compatibility restrictions, so it doesn't revert the styles of the "author presentational hint origin", and so the image is displayed using the dimensions taken from the HTML attributes. &lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

</description>
      <category>css</category>
    </item>
    <item>
      <title>Mapping HTML to CSS boxes.</title>
      <dc:creator>Nicholas Stimpson</dc:creator>
      <pubDate>Tue, 31 Dec 2019 18:27:49 +0000</pubDate>
      <link>https://dev.to/alohci/mapping-html-to-css-boxes-508i</link>
      <guid>https://dev.to/alohci/mapping-html-to-css-boxes-508i</guid>
      <description>&lt;p&gt;Let’s start with a quick quiz. You know everything in CSS is a box, right? A box being one of those things with a content area, and padding, borders and margins around it. Of course you do. So in this simple HTML example below, starting from the outer div and including its descendants,  how many block and inline boxes are used to render it?&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/alohci/embed/GRgMvaP?height=600&amp;amp;default-tab=html,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two?&lt;/strong&gt; Well, there’s two elements, the inner div and the outer div. An HTML element becomes a box in CSS right? So just the two block boxes then. Sorry, no. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Four?&lt;/strong&gt; All block boxes are block container boxes. Block container boxes contain as their children either (a) only block-level boxes or (b) only inline-level content. The inner div meets that requirement - it only contain inline-level content. But the outer div appears to be containing two inline-level text runs and one block box. When this happens, CSS automatically adds anonymous block boxes around the text runs. That way, the outer div contains only three block boxes and no inline-level content. And the two added anonymous block boxes contains only inline-level content, so now all the block boxes meet the requirement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Seven?&lt;/strong&gt; Block boxes cannot contain text runs directly though. Each one has a single child inline-level box called the "root inline box". So we have two block boxes for the divs, two anonymous block boxes, and three anonymous root inline boxes making a grand total of seven. Hurrah! we’re there.&lt;/p&gt;

&lt;p&gt;The actual box tree arrangement looks like this…&lt;/p&gt;

&lt;pre&gt;
DIV.outer block box (1)
  anonymous block box (2)
    anonymous root inline box (3)
      Text run: "The Vogons prepare to destroy the earth to make way for a hyperspace bypass."
  DIV.inner block box (4)
    anonymous root inline box (5)
      Text run "The dolphins depart."
  anonymous block box (6)
    anonymous root inline box (7)    
      Text run "So long and thanks for all the fish." 
&lt;/pre&gt;      

&lt;p&gt;So what’s the point of this? It’s just a reminder that the relationship between HTML elements and CSS boxes is rather more subtle than it may seem at first glance.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Boxes than Elements
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;display&lt;/code&gt; property has a profound effect on both the type and number of boxes to which an element maps. Here’s some more examples of situations where elements generate either more than a single box.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The generation of anonymous block boxes described above applies for all block containers. So computed display values of inline-block, table-cell and list-item can all generate those boxes when necessary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;display:list-item&lt;/code&gt; and the proposed but only currently implemented in Firefox &lt;code&gt;display:inline list-item&lt;/code&gt; also generate at least two boxes, a principal box and a marker box.&lt;br&gt;
(The marker box is always a child of the principal box, even when it’s positioned "outside".)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;display:table&lt;/code&gt; and &lt;code&gt;display:inline-table&lt;/code&gt; elements also generate at least two boxes. A table-wrapper box and inside that, a table grid box. When CSS properties are assigned to an element with &lt;code&gt;display:table&lt;/code&gt;, some of the properties are assigned to the table-wrapper box and some to the table box, but never both. For all the properties not assigned, the values used are the default ones for the property.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;
For example, any specified margin is applied to the table-wrapper box, so the margin of the table box is 0px all round. But any specified value of overflow is applied to the table box, so the overflow value for the table-wrapper box is always “visible”. As well as the table box, the table-wrapper box contains any boxes generated by the caption element if one exists.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Table layouts can also result in anonymous table objects. The structure for HTML tables is &lt;code&gt;table&lt;/code&gt; – &lt;code&gt;tbody&lt;/code&gt; – &lt;code&gt;tr&lt;/code&gt; – &lt;code&gt;td&lt;/code&gt;, which maps to the CSS display values &lt;code&gt;table&lt;/code&gt; - &lt;code&gt;table-row-group&lt;/code&gt; - &lt;code&gt;table-row&lt;/code&gt; - &lt;code&gt;table-cell&lt;/code&gt;. How each of these works within the layout depends on both their context and content.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;
So what happens if a div element is assigned &lt;code&gt;display:table-row&lt;/code&gt; on its own in the CSS? It generates three boxes: an anonymous &lt;code&gt;table&lt;/code&gt; or &lt;code&gt;inline-table&lt;/code&gt; box, which surrounds the &lt;code&gt;table-row&lt;/code&gt; box of the element, which in turn contains an anonymous &lt;code&gt;table-cell&lt;/code&gt; box, which contains the div’s contents. So if the HTML is:&lt;br&gt;
&lt;code&gt;&amp;lt;div style="display:table-row"&amp;gt;Lorem ipsum dolor sit amet&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt; the box structure is&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
Anonymous table box (1)
  DIV table row box (2)
    anonymous table cell box (3)
      anonymous root inline box (4)
        Text run: "Lorem ipsum dolor sit amet"
&lt;/pre&gt;


&lt;p&gt;Similarly, if a lone &lt;code&gt;display:table-cell&lt;/code&gt; element is present, it is wrapped in anonymous table-row and table boxes. Sufficient anonymous inside or outside boxes will always be generated to meet either the pattern &lt;code&gt;table&lt;/code&gt; - &lt;code&gt;table-row&lt;/code&gt; - &lt;code&gt;table-cell&lt;/code&gt; or &lt;code&gt;table&lt;/code&gt; - &lt;code&gt;table-row-group&lt;/code&gt; - &lt;code&gt;table-row&lt;/code&gt; - &lt;code&gt;table-cell&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;
So for another example, suppose we had:&lt;br&gt;&lt;code&gt;&amp;lt;div class="outer" style="display:table"&amp;gt;&lt;br&gt;
 &amp;lt;span class="inner" style="display:table-row-group"&amp;gt;&lt;br&gt;
   lorem ipsum dolor sit amet&lt;br&gt;
 &amp;lt;/span&amp;gt;&lt;br&gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;
that would form:&lt;/p&gt;

&lt;pre&gt;
DIV.outer table wrapper box (1)
  DIV.outer table grid box (2)
    SPAN.inner table row group box (3)
      anonymous table row box (4)
        anonymous table cell box (5)
          anonymous root inline box (6)
            Text run: "Lorem ipsum dolor sit amet"
&lt;/pre&gt;
&lt;h2&gt;
  
  
  Fewer Boxes than Elements
&lt;/h2&gt;

&lt;p&gt;On the other hand, there are a couple of display values that cause no box to be generated at all. &lt;code&gt;display:none&lt;/code&gt; and &lt;code&gt;display:contents&lt;/code&gt; do that. &lt;code&gt;display:none&lt;/code&gt; affects descendant elements as well so they do not generate boxes either, while the descendants of &lt;code&gt;display:contents&lt;/code&gt; elements generate boxes normally.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Boxes Matter
&lt;/h2&gt;

&lt;p&gt;So can we make use of knowing this? It can help us understand why CSS doesn't always do what we expect it to, and it can help us spot solutions to particular layout problems.&lt;/p&gt;

&lt;p&gt;For example, let’s suppose we have&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/alohci/embed/xxbXXMQ?height=600&amp;amp;default-tab=html,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;we might have expected that the &lt;code&gt;.cell&lt;/code&gt; element would be 200px tall and the text "Hello World" vertically centered in it, since that's how table cell vertical alignment normally works. But it’s at the top. That's because the table-cell’s height isn’t 100% of the &lt;code&gt;.outer&lt;/code&gt; element, but 100% of the anonymous table box. And because it’s anonymous, it can’t be styled to be anything other than the default &lt;code&gt;height:auto&lt;/code&gt;, and auto means that it's the height of its content. Which is just the height of the text.&lt;/p&gt;

&lt;p&gt;As a second example, suppose we have some nicely semantic HTML like this.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/alohci/embed/oNgGGRR?height=600&amp;amp;default-tab=html,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The default styling for displaying on a desktop might be just what we want. But on a mobile, we might want to compress it down a bit and for good responsiveness lay the title and list items using a flexbox layout. Now if we just give the div element &lt;code&gt;display:flex&lt;/code&gt;, it'll have two flex items, the first created by the h1 element and the second created by the ul element. Evening up the fonts and spacing, we get something like this:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/alohci/embed/WNbZXbO?height=600&amp;amp;default-tab=html,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;That's not compressed it much. If we wanted the list items to follow on from the heading horizontally we could try making the ul element display:flex as well. However, doing that the items won't wrap under the heading, so we still get this:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/alohci/embed/qBEPVOG?height=600&amp;amp;default-tab=html,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Which hasn't helped. If we want the items to wrap under the heading, we need the list items themselves to participate in &lt;em&gt;the same flexbox&lt;/em&gt; as the heading.  Fortunately, if we realise that the flex items are the boxes created by the elements rather than the elements themselves, then we can simply remove the box created by the ul element, and the boxes created by the li elements will become the flex items. The div flex container will then have six items instead of two. All we have to do to remove the box created by the ul element id to apply &lt;code&gt;display:contents&lt;/code&gt; to it. And the result is this:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/alohci/embed/jOEGaVZ?height=600&amp;amp;default-tab=html,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;br&gt;
&lt;/p&gt;


&lt;p&gt;This article is a revised version. The original article described the boxes that would be generated according to the CSS 2.1 specification. The CSS Inline Module Level 3 specification makes some changes to that. Most notibly, if we have this markup &lt;code&gt;&amp;lt;div&amp;gt;The &amp;lt;span&amp;gt;dolphins&amp;lt;/span&amp;gt; depart&amp;lt;/div&amp;gt;&lt;/code&gt; (with default styling), in CSS 2.1 "The" and "depart" would each be contained in their own dedicated inline box. In CSS 3, there's a single root inline box which surrounds "the", the inline box generated by the span, and "depart". So in total, CSS 3 defines there to be one fewer box than CSS 2.1 does.&lt;/p&gt;

&lt;p&gt;In addition, CSS 2.1 says that each rendered line contains a "strut" which is described as "as if" it were a zero width inline box. CSS 3 instead clarifies that, saying that the strut is a zero width glyph and only exists at all if there's no existing glyph that can do the job of applying a minimum height to the line.&lt;/p&gt;

&lt;p&gt;CSS3 also makes clearer that when text breaks across lines, the inline box does not become two inline boxes, but is still one box, fragmented.&lt;/p&gt;




&lt;br&gt;&lt;br&gt;
Comments, corrections and follow-up questions are most welcome. Even tl;dr.

</description>
      <category>css</category>
      <category>html</category>
    </item>
    <item>
      <title>Is this element visible?</title>
      <dc:creator>Nicholas Stimpson</dc:creator>
      <pubDate>Sat, 13 Jul 2019 15:30:37 +0000</pubDate>
      <link>https://dev.to/alohci/is-this-element-visible-2lpi</link>
      <guid>https://dev.to/alohci/is-this-element-visible-2lpi</guid>
      <description>&lt;p&gt;The sample couldn't be much simpler. The question is, is the div element containing the text "Hello World" visible or hidden?&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/alohci/embed/rEgaYa?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Visible right? Well maybe. jQuery begs to differ!&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/alohci/embed/OeYPVz?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The problem lies is jQuery's (and widely copied) definition and implementation of its check for visibility. &lt;a href="https://api.jquery.com/visible-selector/"&gt;The definition&lt;/a&gt; is&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Elements are considered visible if they consume space in the document. Visible elements have a width or height that is greater than zero.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The implementation is &lt;/p&gt;

&lt;p&gt;&lt;code&gt;!! (el.offsetWidth || el.offsetHeight || el.getClientRects().length)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The div in question has a CSS property display value of "contents", which means that it creates no layout box of its own. Its child elements' layout boxes are instead directly connected to its parent layout box. The CSSOM specifications say that offsetWidth, offsetHeight and getClientRects().length must all return zero for such an element&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetwidth"&gt;For both offsetWidth and offsetHeight&lt;/a&gt; If the element does not have any associated CSS layout box return zero and terminate this algorithm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://drafts.csswg.org/cssom-view/#dom-element-getclientrects"&gt;for getClientRects()&lt;/a&gt; If the element on which it was invoked does not have an associated layout box return an empty DOMRectList object and stop this algorithm.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So in the light of this, what should be done? The intuitive answer clearly doesn't tally with the technical details. And it's not clear to me from a developer perspective whether an element with no layout box really should be considered visible, just because its contents are. Yet from a user perspective it seems obvious that it should. Do we need a third state beyond "visible" and "hidden"?&lt;/p&gt;

</description>
      <category>css</category>
      <category>javascript</category>
      <category>discuss</category>
    </item>
    <item>
      <title>CSS concepts questions</title>
      <dc:creator>Nicholas Stimpson</dc:creator>
      <pubDate>Mon, 10 Jun 2019 16:45:23 +0000</pubDate>
      <link>https://dev.to/alohci/so-you-think-you-know-css-3bl2</link>
      <guid>https://dev.to/alohci/so-you-think-you-know-css-3bl2</guid>
      <description>&lt;p&gt;By the time I started creating web pages, CSS had been invented, but browser support was in its infancy. So I started styling in HTML at the same time as I was learning my HTML, approaching both largely with a suck-it-and-see attitude. &lt;/p&gt;

&lt;p&gt;Want to bold my text? Umm... &lt;code&gt;&amp;lt;B&amp;gt;...&amp;lt;/B&amp;gt;&lt;/code&gt;. Well, that seems easy enough. Italics? &lt;code&gt;&amp;lt;I&amp;gt;...&amp;lt;/I&amp;gt;&lt;/code&gt;. Check. Make my text red? Ah that's slightly trickier. I need to use &lt;code&gt;&amp;lt;font&amp;gt;&lt;/code&gt; with a color attribute, but OK, not too bad, and Ooh, there's a couple of other cute things I can do with that tag too.&lt;/p&gt;

&lt;p&gt;Then browser support starts to improve, and I'm told that I should be using CSS instead. Initial reaction was resentment. Give up these nice simple tags for some new, strange syntax? But I've got to do it, apparently. &lt;/p&gt;

&lt;p&gt;OK. So let's see. We've got a style attribute, and we can put it on any element. OK. So.. style="color:red". Maybe that's not so bad. What about a light grey background colour? Let's try style="color:red background-color:lightgrey"... Huh, well that didn't work, the text's not even red anymore. Ah, it needs a semicolon. Try style="color:red; background-color:lightgrey"... Yes that's got it. But the background's a bit tight to the text. Need to expand out the background a bit. Ah padding! Yes, that looks better.&lt;/p&gt;

&lt;p&gt;And so it goes on. Practically everyone learns CSS more or less this way. We learn more and more properties and how they interact and conflict, we learn about CSS rule sets, selectors, the cascade, inheritance, and gain a fuller grasp of the box model. And these are all learnt from cookbooks and, these days, how-to-do-X questions and answers from venues like Stack Overflow.&lt;/p&gt;

&lt;p&gt;Eventually though, I started to get frustrated. Some things I just couldn't get to work the way I expected them to, and the cookbooks didn't help. Many CSS devs hit this when they get to vertical alignment, and so did I, but there are other curiousities too. So I started reading the CSS specification. After several goes the words began to make sense, and I realised that I had missed out on learning practically all the CSS concepts that underpin the properties.&lt;/p&gt;

&lt;p&gt;To explain what I mean, here's ten questions about CSS concepts, rather than how-to-do-X. The answers can all be found in the CSS 2.x specification which is now more than two decades old and has excellent browser support. Given its age, there really should be no reason for anyone who works regularly with CSS not to know the answers. So, how many can you answer?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How big is the canvas?&lt;/li&gt;
&lt;li&gt;What is the subject of a selector?&lt;/li&gt;
&lt;li&gt;What is !important's place in the cascade?&lt;/li&gt;
&lt;li&gt;What are the location and dimensions of the initial containing block?&lt;/li&gt;
&lt;li&gt;What vertical alignment does the strut have?&lt;/li&gt;
&lt;li&gt;When does clear:left cause clearance to occur, and how does that affect margins?&lt;/li&gt;
&lt;li&gt;When the width of an non-replaced block-level element in normal flow is over-constrained and does not total exactly 100% of its containing block's width, which property's used value differs from its computed value?&lt;/li&gt;
&lt;li&gt;When does an anonymous table-row object get generated?&lt;/li&gt;
&lt;li&gt;When does a single element establish both a block formatting context and an inline formatting context at the same time?&lt;/li&gt;
&lt;li&gt;What is an inline element's aligned subtree?&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>css</category>
    </item>
  </channel>
</rss>
