Article
0 comment

Build a SharePoint / Fluent UI compliant grid from scratch

Building a grid system in the past had a lot to do with math. Luckily, implementing a grid system has dramatically changed over the last years. You don’t rely on any framework such as Fluent UI to get your things done right.

SharePoint also has a concept of single part app pages. This page type gives you an entirely blank canvas, enabling the full potential and possibilities for an application. It also comes without any grid system, but this is something we can address.

CSS Grid

Before there were grid systems available in CSS, to be able to create such a page-wide system involved a lot of math. A common problem that frameworks such as Bootstrap, Office UI Fabric (before it became ReactJS only) solved for you.
CSS grid was, in this perspective a game-changer and especially with IE 11 out of the way, I think that is the only way to go forward.

Setting up the SharePoint / Fluent UI base grid

Microsoft has a good documentation on how the grid layout should look alike. Also, included in this documentation is the responsive behaviour of the grid system. So let’s set something up according to this documentation.

First step

A grid can get applied to any container on a page and is defined by the display property, so changing this ‘display: grid’ enables a grid.

The second requirement is to define the column layout. SharePoint uses 12 grid columns. So we need to divide the base container into twelve equal columns. We could do the math, as mentioned earlier or define it via a new unit named fraction(fr). So we need to define a template for the grid columns or in CSS spoken.

.fl-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
}

CSS has some function to divide the space equally. ‘repeat(12, 1fr)’ means nothing else then, we like to have 12 columns that have the same width, or in other words 1/12 of the full width.

Base Setup of the grid system

The final grid actually would look like, but there is one thing missing. Now that we decided the width into twelve grid columns, we also need to define a space between the grid columns, also know for designers as the gutter.

To define the gutter, for now, we focus just on the desktop version. For that, the documentation tells us to have a gutter of 32 pixels above a screen resolution of 1366 pixels. We can add this to the grid in the following way.

.fl-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: 32px;
}

The ‘column-gap’ defines the gutter of the grid, and we set it for now to 32 pixels. Now you have the grid defined in the previous screenshot.

Also defined in the documentation is that the grid in any scenarios should have a margin of 8 pixels. Since we already have determined the grid in relative units through fractions, we want to do the same for the margin.

.fl-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: 32px;
  margin: auto 0.5rem;
}

The margin first value set to ‘auto’ means that we don’t have any specific wish for our margin before or after the grid. The second value 0.5rem is calculated base on the fact that the browser has a default font size of 16 pixels define.

So 16 pixels multiplied by 0.5 equals than 8 pixels. Rem or root em also makes sure that no given font size outside of the container changes the 16-pixel constraint to be safe.

But wait the column gap still has pixels. Well, yes, and there is a small trick.

Convert pixel to rem

Thanks to SASS, we don’t need to do the calculation ourselves. Let’s say the designer insists on having exactly 32 pixels on the gutter. Works great in Photoshop but not in real life and you should always be cautious with this fixed pixel value. It is better and safer to use, for example ‘rem’.

SASS helps in this case, and you can write a small function for that.

@function px-to-rem($pixel){
  @return ($pixel / 16) * 1rem;
}

So you pass in the pixel value, and it returns the pixels in root em (rem) units—the function called directly on the column gap example.

column-gap: px-to-rem(32);

The row gap

Not only that we can define the gutter between the columns, but now with a CSS grid in place, we can also specify a gutter for each row. The property for that is ‘row-gap’, which then improves the overall grid layout in the following way.

.fl-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: px-to-rem(32);
  row-gap: px-to-rem(32);
  margin: auto px-to-rem(8);
}

By using the row-gap too, we can make the grid smarter as defined in the documentation.
Now everything is set, and we have a ready to use grid system on any occasion like, for example, on a single part app pages or a Microsoft Teams SharePoint web part integration.

Make grid responsive

Since SharePoint sadly don’t use a fluid grid and has only a semi-fluid grid with fixed gutters, we need media queries to take this into account.

.fl-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  margin: auto px-to-rem(8);

  // > 1366 pixel
  column-gap: px-to-rem(32);
  row-gap: px-to-rem(32);

  // < 1366 pixel
  @media screen and (max-width: 1366px) {
    column-gap: px-to-rem(24);
    row-gap: px-to-rem(24);
  }
  // <= 640 pixel
  @media screen and (max-width: 640px) {
    column-gap: px-to-rem(16);
    row-gap: px-to-rem(16);
  }
}

So large screens, greater than 1366px, has a gutter of 32 pixels, below that it uses 24 pixels until the gutter became 16 pixels at a max-width of 640px.

That is all required to recreate a responsive grid system compliant to the definition defined by the SharePoint Design teams. Only one last thing is missing. Next up, let me tell you how to place elements onto the grid system.

Placing content on the grid

Again like we already did with the grid system, there is no need to bloat your components or HTML with helper CSS classes. The only thing that is needed is just some smart SCSS coding.

@mixin flUI-span($span, $start: auto, $row: auto) {
  grid-column: $start / span $span;
  grid-row: $row;
}

The mixing above covers all use cases. It takes the span, which allows us to define the width the content is on the grid.

In case you like to define your container to span across twelve columns, you pass in a span for twelve.

.fl-span12 {
  @include flUI-span(12);
}

The output is like this:

Placing elements on the grid – 12 columns

If you need to span across only four columns, you call the mixing like this.

.fl-span8{
  @include flUI-span(8);
}

Or maybe a combination of all of these:

.fl-span12 {
  @include flUI-span(12);
}
.fl-span4{
  @include flUI-span(4);
}

.fl-span8{
  @include flUI-span(8);
}

That results in the following:

Placing elements on the grid – 12, 4 and 8 columns as needed.

Let’s try something fancier and add a six-column span in the centre of the grid on the third row.

.fl-span6c{
  @include flUI-span(6, 4, 3);
}

Centred 6 column layout on the grid

So we only have to pass in 6 for the spanning, 4 for four columns as the start placing for the six columns and finally 3 for the third row. That is the all the magic needed here.

Make placement on the grid responsive

The last piece missing is the implementation of the responsive behaviour for smaller screen devices. The change is simple and only requires to add a media query in the mixin.

Microsoft Documentation on Screen Sizes and Column behaviour

According to the documentation provided by Microsoft, below 480 pixels, there is only one column instead of 12 and also no gutter. The information is not correct in this case.
We still have 12 grid columns, but in this case, we always span across 12 columns. Also, the gutter does not change and is still available but covered and overplayed by the content.

@mixin flUI-span($span, $start: auto, $row: auto) {
  grid-column: $start / span $span;
  grid-row: $row;

  /* media query for small devices */
  @media screen and (max-width: 480px){
    grid-column: 1 / span 12;
    grid-row: auto;
  }
}

Through SASS, we can directly add a media query to our @mixin. The benefit – it automatically updates this behaviour for all places this mixing got used.

Optimised version of the same grid system for mobile

With three more lines of “code”, we also have the defined responsive behaviour. A couple of more lines and we can even more fine grain and better control the grid behaviour at is determined at the moment.

The Playground

I set up a Codepen that contains all the code used in this blog post. Ready for you to play around.

See the Pen Fluent UI Grid by Stefan Bauer (@StfBauer) on CodePen.14928

Verdict

I cannot wait until the IE11 support get’s dropped. While the general grid layout presented here in this blog post works for internet explorer too, it still has some trouble with the placement. Again, polyfills are the key here for the next couple of month.

The general approach to grid systems back in the past was more complicated. Like I mentioned in the beginning, grid systems in the past require a lot of calculation. These calculation were possible in the CSS or relied on pre-calculated class names in a framework. Nowadays, there is no need for this framework grids anymore.

The presented code here has only a minimal impact of the overall size of your CSS. It is also performance optimised because everything happens directly in the browser engine.

Overall you might get out 150 – 200 lines of code for a complete implementation of your base setup of the grid.

Sadly, at the moment, we don’t have a way to leverage something like this for regular web part and pages. It only works correctly for full canvas app parts and SharePoint Framework Teams integrations.

One thing is for sure; it can be used by any development framework, no matter of personal preferences. May it be ReactJS, VueJS, Angular or the next new JavaScript framework.

More on grid systems? Check out A Complete Guide to Grid.