A mobile-first responsive design with SASS and SMACSS

Background

The NET-A-PORTER iPad app is, to a large extent, a native app. However, some parts of it use a webview and load the NET-A-PORTER website; for example, the account section and the purchase path.

The app currently only supports a landscape orientation, so, in the past, no major changes have had to be made to the website when showing it in the app; only the footer and header have had to be stripped out. However, as our iOS developers churn out more and more apps, some supporting landscape, others portrait, compounded with the adaptive app designs Apple are currently edging towards (i.e. iDevices with various screen sizes), we have had to change our approach from a static one to a more responsive one.

The aim of this project was to make our current static design responsive. This had to be done quickly, so there was no time for a complete redesign of the different views; instead I just had to make it work. This of course wasn’t ideal and probably affected a few of the decisions I made during the process. But, hey, technology has a steep learning curve.

Shipping page

Shipping page

SASS and SMACSS

At NET-A-PORTER, we have a CSS Working Group that meets once a month. The purpose of this group is to discuss, test and decide on what CSS approaches we should take. The outcome from one of our meetings was that we should adopt SASS as our preprocessing language and SMACSS as our architecture.

Before this project, I had never used SASS or SMACCS. Thus, my first task was to get my head around these two techniques.

Mobile First

When you develop Mobile First, you begin by styling your page for a small viewport. Then, with media queries, you apply styles as the viewport grows. This is in contrast to the previous method of beginning with the desktop site and then adapting that for a smaller window.

The decision to go Mobile First was based on previous experiences. Often, when building a project, you begin with resetting all styles. For example, Eric Meyer’s “Reset CSS” or normalize. If you then add the desktop styling and thereafter try to adapt it for mobile, you often end up resetting the styling again. When developing Mobile First, you instead gradually add the styles without having to repeat the same thing. To me, it’s also a more natural, easier way of developing responsive sites.

Folder structure

Deciding on the folder structure was one of the things that had my head spinning in the beginning. In both SASS and SMACSS you tend to separate your files into smaller files. In SASS, this is mainly to make it easier to reuse mixins and functions; in SMACSS, it is used to make things more modular. Deciding on which files to put into which folders therefore needed some thinking. In the end, Jonathan Path’s github project helped me a lot, and I pretty much followed his way of structuring a SASS and SMACSS project.

The folder structure looks like this:

  
base
    _elements.scss
    _forms.scss
    _settings.scss
layouts
    purchase-path
        _layout.scss
    my-account
    _site-layout.scss
modules
    _help-nav.scss
    _adress-list.scss
    ...
theme
    themeName
        _theme.scss
        purchase-path.scss
        my-account.scss
    ...
_base.scss
_helpers.scss
_global.scss
purchase-path.scss
my-account.scss

For each section of the site (purchase path, account, and so on) only one CSS file is created. For example, the purchase path SASS file looks something like this.

// Imports
/*
 Helpers and settings
*/
@import "compass";
@import "helpers";
@import "base/settings";
 
/*
 Global
*/
@import "global";
 
/*
 Modules
*/
@import "modules/address-list";
@import "modules/help-nav";
@import ...
 
/*
 Layouts
*/
@import "layouts/purchase-path/layout";
 
/*
 Theme
*/
@import "theme/theme-name/purchase-path.scss";
 
/*
 none modular and non-repeated styling
*/
 
.purchase-path-header{
    border-top: 1px solid black;
    border-bottom: 1px solid black;
    padding: 10px;
    margin-bottom: 30px;
}
 
.purchase-path-packaging-image{
    float: left;
    margin: 0 10px 10px 0;
} 
...

SMACSS

Base

Base in SMACSS “is applied to an element using an element selector, a descendent selector, or a child selector, along with any pseudo-classes”.

In the base folder there are two different file types: those that result in actual CSS selectors such as “_forms.scss” and “_elements.scss”, and those that only contain SASS variables such as “_settings.scss”. In my initial approach the variables were spread out in the different base files, but as I needed to reference the variables later on in other SASS files, this didn’t work. I couldn’t import the files containing the variables as that would result in the duplication of selectors within the CSS file. Having all the variables in one file and not printing out any selectors allowed me to import my variables into other SASS files.

Global styling

The base files are all imported into the global SASS file after the reset (we are using the compass reset) and after the base files, any Module that could be considered global is also imported. Lastly, in the global file there is the import of the site-wide layout file and a couple of definitions for states, all of which make the file look like this:

@import "compass/reset";
@import "base/elements";
@import "base/forms";
@import "modules/error-list";
@import "modules/button";
@import "layouts/site-layout";
 
/*
    States
*/
 
.is-disabled{
    opacity: 0.5;
}
 
.is-hidden{
    display: none;
}

The global file is then imported on top of the account and purchase path file.

In my initial approach I had a separate global CSS file. The idea was that when the user first visited any of the sections, the global CSS file would be downloaded. After it had been cached along with the rest of the sections, only the specific CSS section would be downloaded.

However, the global CSS file ended up being quite small. As a result, I thought it would be better to save an HTTP request and include the global as a SASS file wherever needed.

Layouts

Layout rules in SMACSS are the major components of the web page. Layout styles can also be divided into major and minor styles based on reuse. Traditionally, layout styles are styled with IDs.

My approach to layout styling was to have one site-wide layout file with page- or section-specific files. The layout folder therefore looks something like this:

  
layouts
    my-account
        _layout.scss
    purchase-path
        _layout.scss
    _site-layout.scss

Since it will be used on every page, the site-wide layout file is imported in “_global.scss”; the page-specific ones will only be imported when needed.

Every layout rule is prefixed with a “layout-”. Initially, I was going for just “l-”, but I think writing out the whole word makes it easier to spot the different SMACSS rules within the HTML. Even though IDs can be used for styling layout elements, I’ve chosen to use only class names, since mixing IDs and classes for layouts can get messy. Solely using classes with a “layout-“ (or “l-“) prefix makes it 100% clear that it is a layout rule you are working with.

The “_site-layout.scss” looks something like this:

 
@import "../helpers";
 
.layout-content{
    margin: 0 auto;
    max-width: 900px;
    @include box-sizing(border-box);
    padding: 30px 10px;
    overflow: hidden;
}
 
.layout-table{
    margin: 10px;
}
 
.layout-table-full {
    margin: 10px auto;
    width: 100%;
    th, td{
    font-size: em($nap-ipad-font-size-table);
        padding-left: 0;
    }
}
 
.layout-list{
    margin-bottom: 20px;
}
 
.layout-half{
  width: 100%;
  @media (min-width: 900px){
    width: 50%;
  }
}
 
.layout-help-nav{
    padding: 20px 0;
    clear: both;
}

A page-specific layout looks like this:

.layout-progress-bar{
    padding: 20px 0;
}
 
/*
    Manage account page
*/
.layout-my-account-box{
    width: 100%;
    @include box-sizing(border-box);
    padding: 10px 10px 10px 0;
    @media (min-width: 600px) {
        width: 50%;
        float: left;
        padding-bottom:30px;
        padding-top:30px;
        &:nth-child(2n){
            padding-right: 0;
            padding-left: 10px;
        }
    }
}
 
/*
    Customer order page
*/
 
.layout-orders{
  margin: 30px 0;
  text-transform:none;
  font-size:$base-font-size;
  width:auto;
  float:none;
}

Modules

Module rules are the “meat” of the page. In our case, these refer to the buttons, help navigation, address lists, and so on. For us, it’s also where most of the styling takes place and, in my opinion, this is the case for most SMACSS projects.

The folder structure for the Modules is very simple, and looks a little like this:

  
modules
    _address-box.scss
    _button.scss
    _help-nav.scss
    …

Every Module gets its own file. Sometimes these can be very small: “_address-list.scss”, for example, only contains one CSS rule, but I don’t think this is a big problem. I’d prefer to keep every Module in a separate file rather than putting all the small ones into one, as it gives a nice overview of all the Modules within the project. You’ll never know if a seemingly simple Module might turn into something much more complex later.

In the beginning, I did not prefix my Module classes, but realised soon enough that it would be better to do so as the code becomes easier to read. Since some of my Module class names were already long, I decided to prefix every Module with “m-“. Each prefix is followed by the name of the Module, and then the actual name.

A Module SASS file can therefore look like this:

 
@import "compass";
@import "../helpers";
 
/* modules/m-help-nav */
.m-help-nav{
    text-align: center;
    display: inline-block;
    @media (min-width: 850px){
        @include horizontal-list();
    }
}
.m-help-nav-item{
    padding: 5px;
    font-size: em($nap-ipad-font-size-small);
 
    @media (min-width: 850px){
        float:none;
        border-right: 1px solid $nap-ipad-black;
        padding: 0px 5px;
        font-size: em($nap-ipad-font-size-normal);
        line-height: em($nap-ipad-font-size-normal);
        &:last-child{
            border-right: none;
        }
    }
}

Each Module needed to be imported into that page’s SASS file. At the beginning of the project this was not a problem since there weren’t that many Modules. But as the project grew larger and larger, this approach began to cause bugs as it’s quite easy to forget and leave out a Module.

In the SMACSS definition of Modules it states: “Each Module should be designed to exist as a standalone component”. By doing so, the page will be more flexible. If implemented correctly, Modules can easily be moved to different parts of the layout without breaking.” This is the part that I like the most about SMACSS, and this is what I think makes SMACSS a great approach.

First of all, keeping each Module as a standalone component makes all your styling very predictable. Wherever you place your Module, it will look the same and you don’t have to worry about any other styles interfering with your Module.

It also makes it easier to have more than one person working on the same project. If you work on one Module whilst your colleague works on another, you don’t have to worry about each other’s styling conflicts. This approach can, however, cause some styling to be repeated and therefore adds to your CSS file size. The addition to the file size is minimal and, with SASS mixins, no styling has to be done more than once.

So in theory, the Module approach with standalone components is great and works really well; problems only begin when you start adding media queries to your Modules. The initial approach for media queries in this project was that there wouldn’t be any global breakpoints at all — every layout and every Module would have their own media queries and their own breakpoints. I thought this was a great idea; I would be able to build each component by itself, make it work on any screen size, and, when everything was finally put together, the whole page would be responsive.

However, I realised that this would be quite hard to explain to your UX and visual designers, since it is quite a different way of working to what they are used to. It’s also hard to visualise what the final page will look like. As it stands with responsive design, the tools for designers to work with are not that great; they often create multiple components in different sizes within Photoshop.
However, the tools will eventually come (there are already alternatives) and the understanding of an approach to responsive design will be better across teams if all the information is communicated well.

The first issue can be overcome, but the second issue is more of a technical one. What if we have made our components, they all work perfectly on their own within any screen size, but then you put your payment form Module into a 200px-wide sidenav? There’s a big chance that your payment Module will now be broken. This is because, with media queries, you can only know the size of the window, not the size of the element holding your Module. So even though your payment form looks good within a 200px-wide window, there is no way of knowing if the sidenav is currently within a 200px box. Instead, you will need to expand to the whole size of the window. Ian Storm Taylor explains the problem with examples in this blog post.

After realising this, I first tried to create a Javascript solution, but quickly discovered that this wouldn’t be feasible. The solution I finally went for was a straightforward one: any Module using media queries has to be site wide. This way, I ensure that there won’t be any nasty surprises later. Modules that do not use media queries will be fine as long as they expand into the remaining space. This approach worked quite well for this project as the project was quite small, and most of the Modules would have stretched over the whole page anyway. The only Module that was a little too big was the payment section, which originally was three different modules that I had to merge together to make the payment section stretch across the whole page.

The Payment Section

The Payment Section

Later, I also started to use a global breakpoint to define a small screen (less than 600px) where more radical style changes would have happened. In doing so, it was easier to anticipate how my Module would change. It also makes it easier for your designer to define how they want pages to look within a smaller screen versus a larger one.

For a larger site, it would be a good idea to set up a couple of global breakpoints that all the Modules could use and react to, which your designer could use when working on different designs.

Theme

With Theme rules, you can vary the look of your site. These might not always be used, and they are not included in the core SMACSS types, but we actually needed to use them since the pages in the project are currently used in a couple of apps.

The theme folder structure for this project looks like this:

 
theme
    themeName
        _theme.scss
        purchase-path.scss
        my-account.scss

In the “_theme file”, all the global styling that needed to be overridden is done. This includes Globals, Layout, Modules and so on. This file is then imported to a page-specific SASS file where page specific styles are overridden. That file can look something like this:

@import "../../my-account.scss";
@import "theme";
 
.layout-my-account-box{
    width: 100%;
    @include box-sizing(border-box);
    padding-right: 10px;
    @media (min-width: 600px) {
        width: 50%;
        height: 170px;
        overflow-y: auto;
        &:nth-child(2n){
            padding-right: 0;
            padding-left: 10px;
        }
    }
}

This worked out pretty well, but in the end I think the “_theme” file grew too large, and was too hard to maintain. If I could do it again, I would create separate files for the Layouts and Module and override their styling. This would keep the size of the “_theme” file down, and it would also be easier to see what Modules this theme was overriding just by looking at the file structure.

Purchase Path with a theme

Purchase Path with a theme

States

State in SMACSS is a class that overrides other classes and describes what state the page or element is in. It is often prefixed with a “is-“. For example, an error state, hidden or shown, collapsed or expanded. In this project, not many state rules were used, so the one created was added to the end of the Global file.

Helpers

The last files we have yet to mention are the helpers (_helpers.scss). These have nothing to do with SMACSS but are just a common approach in SASS.

The helpers are just a collection of mixins that can make a developer’s life easier, and can be imported to other SASS files when needed.

Side Notes

  • In this project, I used Compass which added a lot or helpers and mixins for reusable patterns. Most of the time it worked great but created a couple of weird outputs, and I ended up creating some mixins myself instead of using the compass one.

  • Remember to check your CSS files. I ended up importing the same SASS file ten times, making my CSS file enormous. It’s also very easy to forget about the actual CSS file as you only work in the SASS files. My advice is not to minimize your CSS file until the end of the project, and keep coming back to the CSS file to check that nothing looks funny.

  • Our sites are available in multiple languages, which means that each component has to look good and not break no matter how long or short the copy is. Therefore, when working on this project, I found myself using the web inspector to modify the content buttons, navigation items titles, and so on. This was very time-consuming, so I decided to build a Chrome plugin which makes this task a bit easier.

Conclusion

As I mentioned in the beginning, this was my first SASS project and also my first SMACSS project. After getting my head around the two, I really enjoyed working in this way. After getting into SASS, it really speeds up your work and it’s nice not having to think about writing out browser prefixes; instead, you just create a mixin and use that.

By using SMACSS, I think a lot of common CSS bugs were also avoided. Keeping everything separated in different components makes it easier to work together with other people on a project, and you end up with code that’s easier to reuse and debug. By using prefixes in your CSS classes, the HTML code also becomes more readable. The only downside I can think of is that there might be some repetitions in your CSS code when using SMACSS but after minifying; the increase in file size is minimal.

Print Friendly

One thought on “A mobile-first responsive design with SASS and SMACSS

  1. Pingback: Using SMACSS | Outside the Bracket

Leave a Reply