How I created the Victoria Skye Illusion in HTML

Amit Zur
Amit Zur
Aug 13, 2017 · 5 min read

So, Victoria Skye created the following wonderful optical illusion:

Naturally, this had to be re-implemented with HTML, and I took it upon myself to be the conveyor.

Choosing a rendering technique

I was faced with 3 options:

  1. Canvas
  2. SVG
  3. pure html+css

The first two felt a bit like missing the point. It’s already a drawing. What good would it do to just redraw it in a different encoding? The whole point was to use CSS. So I went with option #3, which led to another node down the decision tree:

  1. divs
  2. css magic

Magic is always better, but it’s a bit misleading the way I put it. It’s actually not a decision, but rather an approach: use as few html elements as possible, or in other words, implement as much as possible with just css.

I couldn’t find a way to do it with a single element, but I came close, I think.

Background gradient is the shit

The basis of the whole thing can be created with a single element and some background gradients, without any css preprocessor, as shown in this pen:

The technique here relies on 2 facts:

  1. If you specify 2 color stops at the same point, the color changes abruptly instead of smoothly. Or as the spec says:

If multiple color stops have the same position, they produce an infinitesimal transition from the one specified first in the rule to the one specified last. In effect, the color suddenly changes at that position rather than smoothly transitioning.

2. If you specify the color stops in % rather than px, then it is relative to the background size, therefore with a background-repeat it’s possible to craft a tiled pattern. Or as MDN likes to put it:

Gradient backgrounds are not affected by background-size if all points and lengths are specified using fixed units (as opposed to percentages or keywords, which are relative to the value of background-size).

Growing rhombi

Unfortunately, this is as far as it goes with the HTML element diet. From here on we gonna get fat. First thing to add is the rotated checkers patterned squares, and those have an element each.

To render these squares I needed to solve positioning and the pattern. The pattern was easier since the genius Lea Verou had already solved it and shared it with the world.

For positioning, I resorted to using Sass. Somehow it didn’t seem fair to my children to go absent for 2 months in order to write the :nth-child selector for each square. That’s why you see both css variables and Sass variables in the code. I was too lazy to switch them all to Sass.

The implementation was a matter of calculation. There are 14 squares in a row, so running in a loop I calculate left with $i%14 and top with floor($i/14), which turned out to be so handy later as a formula for the row number.

Those lines are still straight !?!?!!111

I was starting to wonder what visual element actually creates the illusion. Couldn’t figure it out. Unfortunately I bet on the weird looking shapes inside the squares. And for the life of me, I had no idea how to create those with css, as they look so randomly drawn. And that’s their charm. Also, just the thought of it made me tired. So I did the dirty work of just laying it half-transparent in sketch and manually creating the SVG by visually dragging the bezier control points.

Then I laid down those SVG’s, and was proud of myself for noticing that every row they alter their rotation. So I did that. And still there was no sign of an even slight optical illusion!

At this point I figured it’s not really going to help me create all those wonderful random looking hexagons and pentagons. I will save those for my vipassana retreat. So I looked closer, and lo and behold — the checkers squares are diversely rotated!

So the piece of css which does all the magic lies in this selector:

.rumbus:nth-child(#{2*$i+floor($i/14)%2}) {
transform: rotate(-45deg);

Of course, it didn’t start out that way. It started by me expediting the process by declaring an even/odd selector. But at each row the rotation differs — one row it’s the odds, on the next it’s the evens. So I make an even number and add the row number (remember that formula? I told you it would come in handy) modulo 2 to distinguish between odd and even rows.

And there it is. The optical illusion in its glory. I leave it to you, the rest of the world, to fork and add the remaining elements. My work here is done.

Oh, wait

What’s the whole point of implementing something with HTML and CSS if you don’t add javascript to it! So just for the fun of it — click anywhere to shuffle the color palette. Hours of fun, I promise!
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade