Scalable Squares

My work on the W3C's Introduction to Mobile Web Best Practices often throws up interesting challenges. Here's a question that got me thinking:

I have a question regarding keeping things square, or quadratic, in a scalable HTML page. Assuming I have design that requires square elements, like a board game, for example. If I let width and height of my HTML elements be proportional (percentual), how can I keep them square? Of course, I might use JavaScript to adjust width and/or height to keep them square, but is there a nice way using only CSS?

Well, I can't think of a way to keep things square using just CSS. If you use percentage measures then, given that the width and height of the screen are infinitely and independently variable, there's no way I know to keep width and height proportional (note to self — ask the CSS WG whether anyone has proposed an aspect ratio property for the CSS Box Model?). A bit of searching threw up a forum thread that said "no, you can't do it" and this method which uses a very big transparent image.

But… I wonder if we might be straying into using CSS — style — to define content?

If you're creating a game that needs a board then it strikes me that the shape of the board is likely to be an important feature. You could play, say, chess, on a board where each 'square' was actually a rectangle, or any other shape, but the game really should be played on a square board with chequered squares. So one could argue that this isn't style, it's content. If you agree with that then CSS isn't the right technology to be using here.

What we want is some sort of scalable graphic, preferably one that uses vectors. Hmm…

Take a look at this chessboard. On desktops, it's as wide as this article although I'm disappointed with the results on mobile.

Your browser has no SVG support which is a pain for both of us. You'd need to provide some sort of fallback image here. If you're using Internet Explorer you might want to install the Adobe SVG Viewer. If you're on mobile, erm... this may not be a good solution :-(

Whereas this one is only a quarter of the width, but they both use the same Scalable Vector Graphics (SVG) image. If you resize the window, look at this site on any size screen, the same will be true.

How is this done? Here's the SVG code (I've added line numbers for what follows). You can, of course, just go directly to the image and view source!

1  <svg xmlns="http://www.w3.org/2000/svg"
2       xmlns:xlink="http://www.w3.org/1999/xlink"
3       width="100%" height="100%" viewBox="0 0 800 800">

4  <line id="black" x1="0" y1="50" x2="800" y2="50" stroke="black" stroke-width="100" stroke-linecap="butt" stroke-dasharray="100,100" />
5  <line id="white" x1="100" y1="150" x2="800" y2="150" stroke="black" stroke-width="100" stroke-linecap="butt" stroke-dasharray="100,100" />
6  <use xlink:href="#black" transform="translate(0,200)" />
7  <use xlink:href="#white" transform="translate(0,200)" />
8  <use xlink:href="#black" transform="translate(0,400)" />
9  <use xlink:href="#white" transform="translate(0,400)" />
10 <use xlink:href="#black" transform="translate(0,600)" />
11 <use xlink:href="#white" transform="translate(0,600)" />

12 </svg>

Line 4 creates a dashed black line beginning at 0,50 (x1, y1) and ending at 800,50 (x2, y2). The stroke colour is black and the stroke width is 100 pixels. The stroke-dasharray attribute tells the SVG engine to "lift the pen" after 100 pixels, then put it down after another 100 pixels — which it repeats until it gets to the end of the line.

Incidentally, the y coordinates are 50 (50 pixels from the top of the screen) as the line is centred vertically so if you leave y at 0 then the top half of the line is missing from the top of the graphic.

Line 5 just repeats all that only it's shifted 100 pixels to the right so that the line begins with a white square.

Lines 6 - 11 are SVG's way of re-using code so we don't have to write everything out again. I'm sure I could use group methods to reduce the amount of code further but this will do for now.

Scaling

OK, that's one way to create a chess board 800 pixels square, how do we do the scaling bit? The key is in line 3.

If you're familiar with the idea of the viewport (and if you create sites that will work on mobile then you need to be), then you can think of this as SVG's way of setting that. It says "use the full width of the whatever container is being used to display the image; internally, we're going to make a box 800 pixels square".

For more on this, see the section in David Dailey's excellent SVG Primer called Putting SVG in a web page.

So we've created a scalable graphic — page content — that we can now decide how we want to display. And for that I'd say that we can legitimately use CSS width. The big version above has a css width of 100%, the second is 25% with a float:left.

Border

When I first created the SVG image I used CSS to stick a border round it but that felt like cheating. The defined edge is as much a part of a game board as anything else so I added a square around the whole thing with with stroke width of 2 pixels. Having done that I had to fiddle with the coordinates and view box a little adding 2 to various coordinates. But… my own example above made me rethink.

If the border is part of the graphic then it too will be scaled so if I have a 25% scaled version then the border width is going to be so tiny that many screens won't have the resolution to show it, and yet I always need a border. So I reverted to the CSS border method. Is that cheating? Possibly, but I prefer the word pragmatic!

Mobile

The point of doing this was to make something that would scale to any size screen but as noted above, the results on mobile are not good. My Android phone doesn't display SVG at all. My iOS devices do but they don't show the image across the whole width of the article. The border, yes, but not the SVG itself. I think I'll have to do some more investigation. I might get different results using embed rather than object which is what I've used here.