Introducing GSS: Grid Style Sheets

Rafay Saeed Ansari
Share

You may have recently heard of Grid Style Sheets (GSS) in the world of HTML and CSS. GSS re-imagines CSS layout and replaces the browser’s layout engine with one that harnesses the Cassowary Constraint Solver. Those of you who didn’t understand a word of that…hello, and welcome!

GSS promises a better future. GSS promises relative positioning and sizing. GSS promises to center any element inside another with one line of code. And GSS delivers. The question is: How?

In this article, I’ll cover a brief history of GSS and an in-depth overview of the features it has to offer. I’ll also look at GSS for constraint-based layouts, the Cassowary constraint algorithm, and walk you through the process of installing and using GSS.

Those of you who’d rather not wait around for the W3C or browsers to catch up, I urge you to hang in there and pay close attention while I explain the mystery that is GSS. On that note, let’s start with a little history.

A Brief History

GSS is a creation of The Grid with Dan Tocchini as its founder and CEO. This answers why the not-so-grid-based style sheets are called Grid Style Sheets.

The war between web developers and front-end technology to present ideas onto the web has been going on for years. CSS has proved to be triumphant for the past decade. However, building increasingly complex user interfaces with tools that haven’t evolved with time is something web developers are expected to do on a regular basis. For example, vertically centering an element with CSS has not been the simplest of tasks, especially with variable-height elements.

Flexbox is one of the most recent solutions, but even small changes there require you to go deep within your HTML content and CSS presentation and make changes.

It’s time for GSS to take the arena. GSS tackles these problems and many more — problems that developers have had for over a decade.

Essentially, GSS is a CSS preprocessor and JavaScript runtime that exploits Cassowary.js. Those of you who don’t already know, Cassowary.js is the JavaScript port Apple uses in Cocoa Autolayout.

Both GSS and Cassowary are founded on constraint programming, making it ideal for empowering declarative languages like CSS. Constraint programming is a paradigm by which web developers are concerned with declaring the “what” and leaving the “how” up to a mathematical solver.

Constraint programming focuses on intentions, not implementation.

Now that we’ve established some background information, let’s move on to the features GSS offers.

Overview of GSS

One of the biggest problems with CSS is relativity. You can expect any CSS element to have an unending list of properties — padding, height, width, float, margins, borders, outlines — but none of this information tells us where the element will be located with reference to other elements on the page (or even the page as a whole). The endless list also doesn’t answer where the element will be displayed with different screen sizes.

This brings us to the first Feature of GSS: You define what you want the layout to be. Gone are the days of spending countless hours of trial-and-error, strategizing how the layout should be constructed.

Since we already discussed that GSS utilizes Cassowary.js, here is another great feature of GSS: An element can be centered within any other with one line of code. This makes a lot of workarounds unnecessary and things of the past.

For instance, if you want to add a Subscribe button in line vertically with, say, a heading on the right side of your site’s page, you would use the following code:

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

Another feature: GSS makes floats, table cells, clearfix, and horizontal/vertical centering obsolete. Bid farewell to the perilous pitfall that is a float because we’ve got the W3C itself saying that floats are not ideal for application layouts.

“As websites evolved from simple documents into complex, interactive applications, tools for document layout, e.g. floats, were not necessarily well suited for application layout.”
W3C Grid Layout Module (working draft)

What about CSS features like !important? The fourth feature of GSS does something similar: GSS employs constraint hierarchy to prioritize constraints with strengths. We’re talking about four built-in strength levels here:

  • !weak
  • !medium
  • !strong
  • !require

Note that !require is a special strength that ensures that the constraint will hold and if it doesn’t then everything breaks. It is advisable to use it carefully and infrequently.

The level of strength increases down the list and stronger constraints are given higher priority during execution. Let’s look at an example:

#light[years] == 50 !weak;
#light[years] == 20 !medium;
#light[years] == 35 !strong;

/* #light[years] will hold the value 35 */

You’ve made it this far, let’s look at some constraint-based layouts now.

GSS for Constraint-Based Layouts

Constraints are basically relationships between two or more variables that may or may not hold. All numeric properties of elements qualify to be constrained. Here’s an example:

p[line-height] >= 10;
p[line-height] <= ::window[height] / 20;
  • p is called a selector
  • line-height is the property that GSS will compute a value for
  • [] is used to access the property
  • <= and >= define inequality constraints
  • 10 and 20 are numerical values in pixels

In the example given above, both constraints hold valid. Here’s an example of constraints which do not hold.

#elementa[height] == 150;
#elementb[height] == 150;
#elementa[height] + #elementb[height] == 225;

Initially, both elements elementa and elementb are constrained to have a height of 150px. In the third line, the sum of the two elements is 225px. Therefore, one of the two element’s constraint’s will not hold.

Selectors in GSS

Selectors in GSS are queries over a group of HTML elements and they are used to determine the elements that will ultimately be affected by the constraint. Selectors are important because you have to select and observe elements from the DOM before you apply constraints to them.

The following fundamental selectors are supported by GSS.

#elementID[height] == 150;   /* id      */
div[height] == 150;         /* element */
.className[height] == 150; /* class   */

Rulesets in GSS

Rulesets will let you define multiple constraints over a single selector. You can nest them and use CSS properties in them too.

This nested ruleset:

section < article {
  .aclass {
    height: == 150;
  }
}

Is the same as:

(section < article .aclass)[height] == 150;

Properties in GSS

I’ve already covered properties in the examples above but let’s look at them a little more closely. In GSS, properties are the variables that belong to an element. When we use properties that are known by CSS, their corresponding GSS-calculated value is assigned as inline styles on the element.

Something like this:

.container {
  height: == #elm[height];
}

Would be equal to:

.container {
  &[height] == #elm[height];
}

An Introduction to the Cassowary Constraint Algorithm

GSS employs a JavaScript port (Cassowary.js) of the Cassowary Linear Arithmetic Constraint Solving Algorithm by Badros, Borning and Stuckey, 1999. The algorithm finds optimal solutions for layouts based on input constraints given in natural language by the user.

The user is not required to ensure that the input constraints do not contradict with one another. In fact, this is the essence of the Cassowary algorithm; it incrementally evaluates the constraints and discovers an optimal solution automatically.

Computational Limitations of the Cassowary Algorithm

The constraints solver behind GSS is called the Cassowary algorithm. This algorithm can only compute constraints that are linear (i.e. of the form y = mx + c). The basic operators ( +, -, *, /) are supported by the algorithm. Multiplication and division of two (or more) constrained variables is not linear and will, therefore, throw an error.

/* this expression is not linear */
#elementa[height] * #elementb[width] == newElement;

Installing GSS

For client-side installation, install via Bower:

$ bower install gss

Then add this code to your markup’s <head> section:

<script src="/bower_components/gss/dist/gss.js"></script>
<script type="text/javascript">
  window.engine = new GSS(document);
</script>

You can also download version 2.0.0 via GitHub as a zip file.

Once you’ve installed GSS, load your .gss stylesheets by adding type=text/gss on a <link> tag:

<link rel="stylesheet/gss" type="text/gss" href="my-first-gss-styles.gss"></link>

Or using a <style> element:

<style type="text/gss">

  /* GSS code ... */

</style>

Once you have everything up and running, you can start following along with some code examples. Below I’ll go over a beginner’s tutorial.

A GSS Beginner’s Tutorial

The examples I’ll be creating will be displayed via CodePen but I’ll go through the tutorial like a standard HTML document. First I’ll add the following line of code to my HTML to add the GSS engine script:

<!-- GSS engine script -->
<script src="gss.js"></script>

I’ll be using a CodePen-hosted version of the file, but you can find a CDN-hosted version here. Next I’ll add the following code under the GSS reference script (the line I just added above) to pass GSS the document object.

<!-- Giving GSS the document object -->
<script type="text/javascript">
  window.engine = new GSS(document);
</script>

If you prefer, this could be placed in a separate JavaScript file that gets included after the engine script.

Example 1: Vertically Centering an Element

I’ll create a div and enclose some text in h2 tags in the GSS layout and add this to the HTML:

<div class="foo">
  <h2>When in doubt, use GSS.</h2>
</div>

After adding some basic styling, I can get into adding some GSS to create the layout. This is where the fun starts.

My goal is to vertically center the .foo element inside the viewport, despite its size, and be able to keep the same alignment in place even if the size of the element changes.

Here are the constraints that I will apply to achieve this goal:

  • Use the ::window selector to center the element with the visible part of the page in the browser.
  • Use ::[intrinsic-height] attribute to get a relative value of the height of the element which will be used to determine the relative width.

First, I’ll add a <style> block to the HTML with the type attribute set to text/gss:

<style type="text/gss">
</style>

A <style> block is necessary to define the GSS I’m going to add. I’m going to position the element in the center of the screen by adding the following code inside the <style> tags:

<style type="text/gss">
  .foo {
    center: == ::window[center];
    height: == ::[intrinsic-height];
    width: == height / 2;
  }
</style>

And that’s all that’s needed. The element is now centered (with dynamic height) vertically using GSS. Below is the demo:

See the Pen Vertical Centering with GSS by SitePoint (@SitePoint) on CodePen.

Try the full screen demo and try resizing the browser vertically to see the element stay centered at any window size.

Example 2: Element Rotation Based on Dynamically Changing Window Width

For this next example, I’ll create a simple colored square shape and have it rotate dynamically. First let’s boot GSS by adding the following lines of code in the <head> section of the document:

<script>
  GSS_CONFIG = {
    worker: "/path/worker.js",
    useWorker: false,
    fractionalPixels: false
  }
</script>
<script src="/path/gss.js"></script>

Note that you would have to edit the code above to point to the correct location for the files. You can get the worker.js file here, and the gss.js file here.

Note: Due to some bugs, the above file paths point to pre-2.0.0 versions of GSS to get this to work.

Now let’s create the square shape by adding this to the HTML:

<div class="square"></div>

…and add some styling to it in the CSS:

.square {
  background: rgb(255, 0, 0);
}

Now I’ll go back to the HTML and add some GSS constraints.

Keep in mind that with GSS, you simply make an intention and leave the mathematical computation up to the algorithm. In this example, I’m trying to create a constraint between the element and the window by which a rotation is produced in the element when the width of the window changes dynamically.

Here are the constraints that I will apply to achieve this goal:

  • Use the ::window[center] selector to center the element inisde the visible part of the page in the browser.
  • Use ::window[width] to create a constraint with rotate-z, which will create the rotational effect on the element around its z-axis. Here, the value received from ::window[width] represents the degree of rotation.

I’ll add a style block to the HTML with a type set to text/gss, like I did in the first example. Remember that a style block is necessary to define the GSS I’m going to add.

<style type="text/gss">
</style>

I’m going to associate the square box with the screen using GSS constrains by adding the following code inside the style tags:

<style type="text/gss">
  .square {
    center: == ::window[center];
    rotate-z: == ::window[width];
    size: == 175;
  }
</style>

And with that, it’s done. Check out the final CodePen demo:

See the Pen Dynamic Rotation using GSS by SitePoint (@SitePoint) on CodePen.

If you view the full screen demo, try resizing the window. You’ll notice that the square box will change its rotation position when the width of the window is altered.

The Future of GSS

The future of GSS looks promising. It’s time we moved forward with front-end technology. I suggest that you practice on smaller scale prototypes before you rip apart your entire stylesheet library.

What I’ve covered here is only a small sample of what you can do with GSS, but I hope that you found this tutorial helpful and informative to get you started.

Have you used GSS yet? How was your experience? Let me know in the comments section.