Next-gen constraint layouts in the browser with Grid Style Sheets

| 9 min. (1879 words)

Complex layouts, positioning, making beautiful UI’s for the web – it all gets pretty challenging for a complex web app. Could there be an easier way? In this post I want to share on possible future tech you can try today.

As a presentation technology, CSS has been remarkably successful the past decade-and-a-half, in no small part due to its simplicity, and often in spite of its quirks and the browser implementations. People have been battling with front-end tech for years when attempting to bring their designs from their heads to the web, and few would argue the web of today is a vastly different place from when the markup and styling standards were introduced.

The evolution from document-based content with simple formatting and layout requirements has progressed to the point where the web has a good claim to being the most pervasive app platform available. The tools CSS3 provides to present content on the alarmingly huge range of devices in use today are fairly simplistic and contain many quirks and pitfalls that a practitioner must be aware of when designing and implementing an app or site – not to mention the QA time needed to ensure a solid experience across the many browser and device versions.

CSS manages features like color and font selection quite well. But there’s an important fault at the core of CSS that rears its head when designing the actual layout of pages. Despite its declarative syntax it merely describes how a page will fit together, almost in an imperative way. An element will have so many pixels of padding, be a certain width, be floated right – but this doesn’t say anything about where it fits in relation to its neighbours and the page as a whole. It certainly doesn’t account for where it should be displayed on different sized screens, as this requires multiple definitions for a selector with media queries controlling the breakpoints.

Fortunately, there’s a better way. The solution is nothing short of the drastic solution of bypassing the entire browser layout engine, and replacing it with one that doesn’t suck. This way, we get to define what we want the layout to be, not how the layout should be constructed. This simple idea results in a model that’s far more natural and easier to reason about, with the additional benefit of ditching the hacks and workarounds needed to implement relatively simple concepts that are full of pitfalls in CSS – no more floats, clearfixes and table cells – for instance horizontal and vertical centering can now be constructed with one liners.

Grid Style Sheets for Constraint-based Layouts

The solution is a JS library Grid Style Sheets, and it’s available right now for use in today’s browsers. It’s an implementation of the Cassowary constraint solver algorithm – the very same one used by Apple in its recent Auto Layout tooling – and it feels like something from the future. Note that this has nothing to do with traditional Layout Grids as used by designers, and available in CSS form – The Grid is the startup who has created GSS.

Constraints allow you to specifiy what you want the layout to be for each element, not how they should be constructed – one for each rule. Imagine you have two columns, and you want their top vertical positions to be equal, and their width to be the same. The syntax looks pretty natural:

.column1[top] == .column2[top];
.column1[width] == .column2[width];

Say you have headings, and you want them all horizontally centered in the middle of your page. You define this by adding a constraint:

h1[center-x] == body[center-x];

Want to add a signup button in line vertically with that heading, up against the right of the page? Again, just one line for each constraint:

.signup-button[right] == ::window[width];
.signup-button[center-y] == .header[center-y];

Note that these aren’t conditionals – they’re equalities. They represent the relationship between two elements that GSS will do its best to ensure it always holds, no matter what the dimensions of the screen, even as they change.

Cassowary constraint algorithm

GSS does this by using a JavaScript port of the Cassowary linear programming solver algorithm, as developed by Badros & Borning circa 1999. Essentially its job is to find the most optimal solution given the layout constraints specified by you. These constraints can be contradicting, for instance with circular references. Normally this could be solved manually by the user, but that adds mental overhead. The algorithm’s magic is that it finds the most optimal solution (the best layout of the elements) to these constraints in an incremental manner, automatically, at interactive speeds.

The authors of the technique gave several nice examples of constraints in their abstract to their 1999 paper – these could be ‘a pane occupies leftmost 3rd of the window’, ‘one element exists above another’, ‘two elements have equal heights and are vertically centered’. GSS features syntax to support all of these and more, in the natural way as shown above.

Combined with the fast JS engines in the modern browsers, and hardware-accelerated DOM rendering and transforms, a brand-new way to design user interfaces for the web is now available, free of the past’s baggage.

Apple and Auto Layout

This technique, despite being present at the time of the dot-com boom, pre-Web 2.0, remained in academia, until Apple introduced it in the Xcode 5/iOS 6 era, for devices and Cocoa applications. GSS uses the exact same algorithm, and even has similar features as it has adopted Apple’s Visual Format Language which acts as an even more natural shorthand syntax for declaring constraints – more about this below. If you’re an OS X/iOS dev you are no doubt familiar, but in case you’re not Apple’s GUI tooling looks like this:

The same relationships are declared in the browser in style sheets with GSS.

Grid Style Sheets implementation today

As mentioned, today’s tech is fast enough to replace the browser’s native layout engine with this constraint-based method. Gss.js does this by using Web Workers to perform the updates in background threads, along with hardware-accelerated Matrix3D transforms of the actual DOM elements.

This works everywhere (well, everywhere with a modern browser and JS enabled), today, as the library essentially acts as a CSS polyfill. Things get a little funky when you open up the dev tools in a page styled entirely with GSS and notice that every element is now absolutely positioned, with its width, height and the aforementioned matrix3d transform set as an inline style on the element. That’s a little ugly, and reveals that the library is a taste of the future (well, a possible one) and that currently it’s behaving as an enormous hack. In particular you sort-of lose the ability to manually style the DOM in the browser’s dev tools, as all the positioning is ‘magic’, and updated as you resize the window. But that’s understandable as brand-new tech always lacks good tooling, which proper adoption would correct.

You do, however, get the usual ability to hover over the DOM nodes in the tools and have them be highlighted in the browser window, complete with correct sizes. In many cases this is in fact easier to reason about with a small list of constraints when compared with piles of nested CSS/SASS/etc.

Another good thing is that the parsing of GSS is really good, and gives you nice error messages in the console when invalid syntax is found.

Getting GSS into your site

Grab it from bower:

bower install gss

Add the following to your markup’s head:

<script>
  GSS_CONFIG = {
    worker: "bower_components/gss/dist/worker.js"
  }
</script>
<script src="bower_components/gss/dist/gss.js"></script>

Then add some GSS:

<style type=”text/gss”>
...
</style>

Two syntaxes: vanilla CCSS and visual VFL

Grid Style Sheets features two ways to declare your constraints, which will go in the above style block. Constraint CSS is the first and is demoed in the examples above, and text/gss is a modernized implementation of the original idea suggested in 1999. Check out the CCSS guide on their site for the full details, but here’s some highlights:

Positioning an element beside another, with a gap:

.el1[right] + 20 <= .el2[left]

Special ::window pseudo selector use, to set a sidebar to a 3rd of the browser width:

.sidebar[width] == ::window[width] / 3;

Automatic declaration of custom variables, where col-size could then be used to set the width of other divs:

[col-size] == .sidebar[width] * 2;

Set one element to exist above another one:

.el1[bottom] <= .el2[top];

Set the height of all paragraphs to be their content’s height, using the this selector and intrinsic:

P {
  height: == ::[intrinsic-height];
}

That also shows the alternate syntax, where constraints can be mixed with regular CSS.

Strengths are used to give priority to certain constraints, so some rules override others if there is a conflict. These are weak, medium, strong and require.

This is but a taste of what is possible with CCSS, again check out the guide for the full feature list

VFL

As mentioned above, this is a port of Apple’s Visual Format Language from Auto Layout, where instead of entering them into the GUI, you can describe them tersely in stylesheets with GSS. There’s a couple of very useful directives, @horizontal, and @vertical, which allow you to align elements visually. The best illustration is from GSS’s docs:

@horizontal |-[#button1]-[#button2]-[#button3]-[#button4]-| in(#panel) gap(10);

You’ll notice quite quickly that it’s a visual representation of the UI, but in code (there’s also shorthand syntax available for repetitive declarations like this).

Another example: two elements can be connected vertically like this:

@v [#header][#content]

@v and @h are available for connecting elements vertically and horizontally, respectively. You can even specify both inner and outer gaps alongside the elements (what was traditionally done with margins in CSS).

Responsive with @if

CSS3’s media queries are nice for changing elements around depending on the size of the browser window. GSS brings one killer feature in that elements can be changed based on any property on any element:

@if .column1[width] <= 300 {
  .column2[top] >= .column1[bottom];
}

If the first column gets too small, the second will be placed below the first. As you’d expect there’s also an @else conditional, vastly increasing the power of the queries you can make.

A glimpse of the future

We’ve found this tech incredibly cool to explore and are interested to see if it takes hold in the community. Is it ready for primetime? Probably not at this stage- at writing gss.js is past its 1.0 release, but there may be enough quirks in its implementation to warrant holding off on building your next major greenfields project on it, or ripping out your entire stylesheet library and replacing it wholesale, especially considering support for older browsers. It is an absolute blast to try though for small prototypes, and allows you to tackle front-end web implementation with a completely different approach.

Have you used GSS or Auto Layout, and are you a fan? Got quibbles with it, or know of another alternative? Let us know in the comments below. We’re fans of new tech that helps remove old pain points, like Raygun itself which helps to fix bugs in your software regardless of which platform it runs on. Hope you found this post informative – until next time, keep blasting those errors.