I’ve been working quite a lot lately with HTML and CSS and one of the things that I’m more than prepared to admit that I’m rubbish at is CSS-based layout.
For those without a black-belt, CSS layout feels like a set of incantations that you have to get in exactly the right order for your content to appear even vaguely near where you hoped it might.
For me, coming from a background of XAML based layouts, I’ve found this to be a challenge until I started to make use of the CSS grid layout. It’s worth saying up-front that this is available in IE 10 (see “can I use?”) which suits my current purpose but support isn’t widely available in other browsers.
For the full definition of CSS grid there’s the W3C document and there’s also a very decent guide to it as a developer feature of IE 10 – because of the current standards status the grid bits are all vendor prefixed -ms- in IE 10 right now.
I think if you’re used to XAML based grids then you’re going to feel right at home.
Choosing Grid
To set up some element to use Grid style layout you set the display style attribute to a value of -ms-grid;
<!DOCTYPE html> <html> <head> <style> body { height: 100%; margin: 0; background-color: #ff6a00; display: -ms-grid; overflow: hidden; } </style> <title>My Grid Page</title> </head> <body> </body> </html>
that gives me a big orange page that occupies 100% of the browser height (and width) without any scrollbar.
The body element is now acting in "grid" mode.
Setting Up Rows/Columns
This is very much like XAML in that we define a set of rows/columns and we define the dimensions for them as either;
- auto – i.e. size to the content in the row/column (this is auto in XAML)
- a size unit – i.e. 96px or 2em or whatever (this is the same in XAML)
- fr units – i.e. a fraction of the remaining vertical/horizontal space ( this is * in XAML )
- min-content – i.e. size to the the minimum width/height of elements in the row/column
- max-content – i.e. size to the maximum width/height of elements in the row/column
What's nice about all of this being defined in CSS is that the HTML content is left completely clean and devoid of anything related to layout. I’m not sure whether you could set the RowDefinitions and ColumnDefinitions of a XAML Grid via a style – I must admit that I don’t think I ever tried.
Adding and Positioning Content
Regardless, as an example if I have the content;
<!DOCTYPE html> <html> <head> <style> body { height: 100%; margin: 0; background-color: #ff6a00; display: -ms-grid; overflow: hidden; } </style> <title>My Grid Page</title> </head> <body> <div id="myGrid"> <div id="oneOne"> This is some content</div> <div id="twoTwo"> </div> <div id="threeThree"> </div> <div id="threeFour"> </div> <div id="fourFour"> </div> </div> </body> </html>
I can then leave it to styling to lay this content out into a grid via pure CSS (inlined here for simplicity);
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type" /> <title>Grid Example</title> <style type="text/css"> html { height:100%; } body { height: 100%; margin: 0; } #myGrid { height: 100%; background: orange; display: -ms-grid; -ms-grid-columns: auto 1fr 2fr 96px; -ms-grid-rows: auto 1fr 2fr 96px; } #oneOne { -ms-grid-row: 1; -ms-grid-column: 1; background-color:#ffd800; height:128px; } #twoTwo { -ms-grid-row: 2; -ms-grid-column: 2; background-color:#f00; } #threeThree { -ms-grid-row: 3; -ms-grid-column: 3; background-color:#0094ff; } #fourFour { -ms-grid-row: 4; -ms-grid-column: 4; background-color:#000; } </style> </head> <body> <div id="myGrid"> <div id="oneOne">This is some content</div> <div id="twoTwo"></div> <div id="threeThree"></div> <div id="threeFour"></div> <div id="fourFour"></div> </div> </body> </html>
giving me a layout of;
where the sizing is;
- first row and column sized to content
- last row and column are a fixed 96px
- 2nd row width and height and 3rd row width and height are ratio'd 1:2
just like a XAML based grid
Handling Alignment
It's also possible to decide how to align content within row/column if that content doesn't fill or overflow the row/column via;
–ms-grid-row-align and -ms-grid-column-align
which can be center, end, start and stretch which nicely gets around how this works in XAML where you had different enum values for vertical/horizontal alignment.
It's possible to have an element span more than one row or column via -ms-grid-column-span and -ms-grid-row-span and you can have more than one element in a single cell although it's more sophisicated than the XAML world because there's a specific -ms-grid-layer where -ve values are stacked to the back and +ve values to the front and 0 is the default.
So, with an additional element;
<body> <div id="myGrid"> <div id="oneOne">This is some content</div> <div id="twoTwo"></div> <div id="threeThree"></div> <div id="threeFour"></div> <div id="fourFour"></div> </div> </body>
and tweak with a little of the styling;
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type" /> <title>Grid Example</title> <style type="text/css"> html { height:100%; } body { height: 100%; margin: 0; } #myGrid { height: 100%; background: orange; display: -ms-grid; -ms-grid-columns: auto 1fr 2fr 96px; -ms-grid-rows: auto 1fr 2fr 96px; } #oneOne { -ms-grid-row: 1; -ms-grid-column: 1; background-color:#ffd800; height:128px; } #twoTwo { -ms-grid-row: 2; -ms-grid-column: 2; background-color:#f00; } #threeThree { -ms-grid-row: 3; -ms-grid-column: 3; -ms-grid-column-span:2; -ms-grid-row-span:2; -ms-grid-layer:1; background-color:#0094ff; } #fourFour { -ms-grid-row: 4; -ms-grid-column: 4; -ms-grid-layer:-1; background-color:#000; } #threeFour { -ms-grid-layer:1; -ms-grid-row: 4; -ms-grid-column: 3; background-color:red; opacity:0.5; width:48px; height:48px; -ms-grid-column-align:start; -ms-grid-row-align:end; } </style> </head> <body> <div id="myGrid"> <div id="oneOne">This is some content</div> <div id="twoTwo"></div> <div id="threeThree"></div> <div id="threeFour"></div> <div id="fourFour"></div> </div> </body> </html>
then we see;
and so the black square in row,column (4,4) has disappeared behind the blue square which is spanning [3,3],[3,4],[4,3],[4,4] and has a layer of 0 so covers the black square which is at -1.
There is a red square at 4,3 at layer +1 so it shows up but it has 50% opacity and so shows up as purple because of the red/blue mix.
Wrap Up
Generally – CSS Grid seems like a complete 100% win to me other than it’s obvious lack of availability right now. I’ve found that it makes standard layouts really easy and I’m making use of it everywhere that I can.