CSS at Lonely Planet

Inspired by Mark Otto's post Github's CSS I thought I would quickly jot down how Lonely Planet’s CSS is structured. I thought it was interesting to read some of the parallels and it’s good to share how we work.

Quick Facts

  • We write in Sass (Indented syntax).
  • We have more than 150 source files.
  • The compiled CSS is split into two stylesheets to allow for stronger caching across apps.
  • The average weight of CSS per page is around 35kb (gzipped).
  • Rems and pixels are the unit of choice, with scattered ems.

Preprocessor

When I joined Lonely Planet we were already using the indented Sass syntax and have stuck with it since. Having used it for so long, writing SCSS seems like a chore.

Whilst we use Rails, we compile our Sass without Sprockets and just use Sass’s @import functionality to build up stylesheets.

Our use of Sass’s features is pretty low, mostly limited to variables and a few mixins. We originally started out with an architecture favouring extending placeholders over classes in the dom though this gradually caused our codebase to become too complex and we reverted our course to a more OOCSS approach.

We use autoprefixer to handle vendor prefixes and I encourage everyone to do the same. We don't use Compass or any other plugins.

Architecture

  • We use a version of BEM to distinguish between components and prevent style collisions.
  • We take a rough approach towards OOCSS. We started out with good intentions there but haven't stuck to it religiously.
  • We don't use IDs in CSS. We very rarely style anything but classes.
  • We use normalize.css.
  • We avoid styling elements and scope all our typographic styles to classes. Typographic elements don't get margins by default as it leads to too much overriding (in our design).

Frameworks

We don't use any CSS frameworks. If we were to begin again I would be tempted to use something like Inuit.css although ultimately I like the fact that we have no dependencies and are in complete control of our CSS.

Linting

We don't lint our CSS. It’s something that we should look into.

Bundles

Our CSS is distributed in two files:

  • core.css
  • application.css

Core is cached across the entirety of lonelyplanet.com whereas application.css is cached only within the specific application. Lonely Planet is served by more than 10 distinct applications so having this separation is crucial for us to render faster pages.

Core includes the base styles like fonts, grids and header/footer styles, and also includes some of our most commonly included component styles which we choose to cache across all the apps. These components and styles live in Rizzo which is accessible by all apps.

Application.css will include styles distinct to the specific application, as well as some Rizzo components which aren't used often enough to be included in core.css.

Performance

The above bundling is key to our CSS performance as is keeping the files small themselves. We have a performance monitoring section in Rizzo which trends file size changes. Currently it only trends for seven days as this is a new addition to Rizzo and we are still collecting data.

CSS Performance Trending

We collect this data every few hours using a few simple scripts which also allows us to run analysis on the stylesheets. We do this with Stylestats and again render the breakdown in Rizzo.

CSS Analysis

Documentation

I've written previously about our Maintainable Style Guide, Rizzo and it works very successfully.

We also self document our Sass by wrapping it in [doc]..[/doc] tags, and then statically analysing it. For example, this utility_classes.sass file creates this documentation in Rizzo.

CSS Documentation

Refactoring

Similarly to github, we like to get rid of as much code as we can and we’re not precious about keeping things around in case it might be needed. Refactoring is a part of our daily work though and we very rarely have specific refactoring tasks.

Other CSS Files

Our SVG icons and fonts are both loaded within CSS files, but these are deferred and not grouped with the rest of the styles.

A Maintainable Style Guide

Anyone who has attempted to maintain a UI Style Guide over a long period of time will attest that it is a very difficult process. They are generally prioritised below the maintenance of your applications themselves and as such are likely the first candidates to fall behind and the last to be brought out of tech debt.

This is bad because once your Style Guide falls out of sync with your application(s) it has entirely lost its purpose. It is no longer a trustworthy representation of the state of your UI and will quickly fall out of favour with the design and development team.

This is bad because Style Guides are more than a nicety for developers to show off their style. Done properly, they can be a collaboration tool bridging design and development teams as well as a tool to break down the user interface into its component parts rather than than thinking about it as a whole or as a series of pages. They also serve as a resource for new designers and developers to locate existing patterns for further use.

These benefits should be sought regardless of the size or scope of your project but in order to achieve them they can’t come at a cost to delivering features. If they do, they will inevitably be neglected.

Achieving this is a cultural challenge as well as a technological one. At Lonely Planet we managed to accomplish this by making the Style Guide an integral part of our development workflow.

This didn’t happen easily though, before we found success with our latest attempt we had tried and failed with two earlier approaches and unearthed problems that helped us mould our final solution.

The problem with current Style Guide Solutions

A Static HTML Style Guide

Style Guides built with static HTML are standalone representations of your UI components with no direct link to your codebase. Once you change or refactor your HTML or CSS you need to update the Style Guide if you want it to reflect the latest version.

The main difficulty with keeping this up to date with your application is having to update both versions of the same template. It requires diligence on the part of all developers to manually keep it up to date.

I built a static html Style Guide a couple of years ago to try to decipher the UI we had inherited. It gave me some clarity on our UI but didn’t fit into our workflow and ultimately didn’t make our work any easier. It quickly became a burden to maintain and fell behind and out of importance.

It’s worth mentioning that as a design tool, or as a deliverable to a client who is going to carry on the development, static Style Guides are a fantastic starting point.

A Living Style Guide

Living Style Guides should be the answer to these problems. They autogenerate Style Guides when changes are made to the codebase so in theory they shouldn’t be able to fall behind. There are a whole host to choose from and many can be set up with fairly minimal effort.

Back in 2012 we implemented KSS a fairly popular tool for generating living Style Guides developed by Kyle Neath and used at Github. Unfortunately, it only lasted 2-3 months before it was clear it had diverged from the components within our application.

So, given it’s “living”, why did it fall behind?

The majority of living Style Guide generators work by analysing the CSS: parsing comments within the files to create the documentation and to know which components to render. It makes sense that they would take this approach because CSS is easily analysed and consistent across projects. For a generic library to work across multiple applications it requires a constant to work from but it’s this key design decision which ultimately makes them hard to maintain.

There are a couple of significant ways in which we believe this type of Style Guide is unmaintainable:

1. Duplication of templates

The majority of living Style Guide solutions follow a pattern something like this:

  /* Style Guide [Buttons]
    <button class="btn-primary">Button</button>
    <button class="btn-secondary">Button</button>
  */

  .btn-primary {
    color: blue;
  }

  .btn-secondary {
    color: red;
  }

Here we have a couple of buttons referenced in the CSS which are rendered in the Style Guide as both elements and markup.

The problem here is that the template we render in the Style Guide isn’t the template we use in our applications. At best it is a direct copy; more likely it is a slimmed down, and perhaps out of date, copy.

As soon as you introduce template duplication like this you have twice as much to maintain. Inevitably, for a project spanning even just a short time, one of them is going to falling behind.

Now this is easy to overlook when you’re talking about single element components like buttons where the effort is fairly minimal to maintain but in reality a lot of components are more complex: requiring multiple elements, classes and often Javascript. We should be striving for a solution which sticks as close as possible to production.

2. Static HTML Output

There is also the problem of the output. Typically you would feature the component alongside the markup required to render it:

Markup commented within the CSS
(taken from the excellent Mailchimp Style Guide)

The idea here is that a developer can simply copy and paste this markup into their application and very quickly and easily build up their page from component parts.

Whilst this is an excellent goal, the problem in this case is the distribution of templates. Even if we presume that the rendered markup is absolutely up to date, once they copy that code they are essentially cutting a version which needs to be maintained indefinitely. When they copied the markup for a working component it had an implicit link to a snapshot of the CSS at that point. If you then update the template or refactor the CSS, you need to update all versions of the template scattered around your site.

This posed a huge problem for us because authors of components had no idea of where they were being used. They may not even have heard of the application that is now using it. That increases the risk of releasing a breaking which makes it more likely that future developers will avoid updating and reusing the component at all.

This is a huge cause for Technical Debt build up at Lonely Planet. As the entire infrastructure is too large to completely hold inside your head, authors were being forced to build defensively. As there was no mechanism for encouraging risk-free reuse of components, they simply weren’t being reused and we instead ended up with duplicated components and bloated code.

I don’t believe this is an issue scoped only to Lonely Planet or even limited to just large websites. Reducing the distribution of templates promotes easier, risk-free refactoring regardless of the size of complexity of a website.

How should Style Guides work?

They should focus on the templates. Crucially, if you’re rendering templates to a Style Guide and you want it to be maintainable then they can’t just be identical to your application templates, they need to be the exact same templates. This is easier said than done.

Templates within an application can be written in many different languages and are generally coupled to a data layer, embedded deep into an application and hard to get to. This makes it very hard for a single Open Source tool to parse your templates. It would have to work across a multitude of technologies and disparate application architectures.

This doesn’t mean it’s impossible to achieve. It does require your application to be built in a modular, component driven way though. Isolating parts of your UI into small components allows you to reuse them around the site as well as compose them to create greater functionality.

Within this type of architecture the Style Guide is able to reach the same components without understanding your entire application. To achieve this can involve a decent chunk of work although the process of restructuring your application into a component based architecture can be the mechanism to simplify and normalise the UI: bringing benefits far beyond the Style Guide itself.

This is the process we have taken at Lonely Planet, creating a component layer which both our user-facing applications and our Style Guide can work from.

Building a Component API

Slides from "Reducing Complexity with a Component API"

I go into more detail on the reasoning behind this process in my Front End Ops talk. The process of decoupling the User Interface from the application, and splitting them into components, had a lot of positive effects on our workflow and codebase.

The goals and benefits of a Style Guide were exactly what we wanted but, not knowing how to achieve them, we started by extracting as much of our UI into components and moving them outside of the applications. This also gave us the opportunity to normalise and condense our UI. Once done, we created a very simple API in which to fetch them from the Component Layer. Having the api for us was crucial because we wanted to maintain the mapping between the latest version of the the component and the application, and not have developers copy and paste component code.

Having a single version of the component, accessible via an API, worked perfectly with unit testing too so we could ensure that the contract between the API parameters and the returned template was solid. We could modify and extend the component based on the data we passed it and assert on the returned result. This also allowed us to add accessibility helpers and microformat attributes as standard and ensure that they weren’t forgotten when used in new applications.

A typical API call:


  // Input
  = ui_component("forms/search", {label: "Search"})

  // Output
  <form class="search--primary" action="//www.lonelyplanet.com/search">
    <label class="accessibility" for="search-q">Search</label>
    <input class="search__input" id="search-q" name="q" tabindex="1" type="search" value="" />
    <button class="search__button" id="search-q-submit" name="search-q-submit" type="submit">Search</button>
  </form>

The developer can modify and extend the component by manipulating the input data. For example, if we wanted to add autocomplete functionality to this search form we would usually do so by adding classes and maybe initialise a JS component somewhere. Within the scope of the Component API we can simply pass in a new boolean and it will add what is necessary:


  // Input
  = ui_component("forms/search", {
    label: "Search",
    autocomplete: true
  })

  // Output
  <form class="search--primary js-autocomplete" action="//www.lonelyplanet.com/search">
    <label class="accessibility" for="search-q">Search</label>
    <input class="js-autocomplete-input search__input" id="search-q" name="q" tabindex="1" type="search" value="" />
    <button class="search__button" id="search-q-submit" name="search-q-submit" type="submit">Search</button>
    <div class="js-autocomplete-container"></div>
  </form>

Style Guide Driven Development

Once the API is being used to fetch components, all that we really have inside any application are data representations of the components. It’s therefore pretty simple to scaffold a quick application that requests every component, multiple times, with differing data. This becomes our Style Guide. Where a regular application might request a handful of components, the Style Guide requests every component, again and again.

It’s always up to date with the rest of lonelyplanet.com because it uses the exact same templates and CSS. As we’re not just performing static analysis of the CSS we are also able to showcase components that require JS too. It becomes a risk free environment where developers can build and tweak components and then allow them to propagate out to the rest of the applications.

In fact, it has become the primary arena for development. Once you have this concept of a component layer it is irrelevant to a developer where they render it for testing. What we have seen is an organic move towards Style Guide Driven Development where developers are using it to build and iterate on components long before they reach any application. This is not something we expected but is certainly a validation of the approach and a polar opposite to our previous attempts where the Style Guide was seen as a blocker to quick feature development.

An example of our Style Guide output
An example component in our Style Guide would showcase the component alongside the API call with data.

How it all works

Our Component Layer, API and Style Guide are combined into an application called Rizzo. The Style Guide is available at rizzo.lonelyplanet.com. One thing I really didn’t cover in my talk at Front End Ops Conf was the implementation side of Rizzo and I’ve had a lot of questions around it since.

We have two different categories of apps that integrate with Rizzo at LP: Rails Apps and Other Apps.

Rails Apps

Rizzo is included as a Gem within all our applications and acts as an engine, thus exposing its partials and assets to the host App. The implementation of the API here is extremely simple and is really just sugar coating around a partial call. The only part that makes this different to just calling a partial is that it lives outside of, and is shareable across, all applications. These helpers act as the API for the Style Guide and the applications.


  -# Called from an application
  def ui_component(type, properties)
    render "components/#{type}", properties
  end

  -# Called from the Style Guide
  def styleguide_component(type, properties)
    ui_component "components/#{type}", properties
    render "styleguide/description", type, properties
  end

There is a little bit more to it but that covers most of how it works. Very, very simple. It’s much more a methodology change than it is a technical challenge.

Other Apps

Non-ruby apps don’t have the luxury of including Rizzo as a Gem (though we may look into using it with other package managers). For now, we host Rizzo as a service and expose HTTP endpoints to return the templates. For example, hitting http://rizzo.lonelyplanet.com/global-body-header will return the html for part of our header.

This adds an extra layer of complexity for these applications as they then have to implement a caching layer for Rizzo components. We cache these templates when the application boots. It’s not perfect but given our primary stack is Rails it’s not something we have spent too much time on yet.

The Style Guide

Once you have a component architecture your Style Guide can simply be another application. Ours is a tiny Ruby app, but you could use absolutely any technology including a simple static site generator.

The Style Guide simply loads up some data for a particular type of component and then iterates through it: rendering the component and the component description each time. Note it’s calling styleguide_component which ultimately calls ui_component the same as any other application would.


-# Load the data
- cards = YAML.load(File.read(File.expand_path('data/styleguide/cards_stubs.yml', __FILE__)))

<h1>Cards</h1>

-# Iterate through the data collection and render the components
- cards.each do |card|
  = styleguide_component("cards/#{card[:title]}", properties: card)

With this approach we only have to modify the underlying data to add more components or modify existing ones.

Assets

A common question has been how do we handle CSS and JS related to these components. Unfortunately I don’t have a clever answer for this at the moment, it’s a mostly manual process.

We split both our CSS and JS out into common and application files. Inside the common.css|js we load the base code as well as our most often used components (stored in /components/core). This is then cached across the entire suite of applications.

To use any non-core components within an application the developer would need to import the component’s related assets using Sass and requireJS.

I think there is definitely room to improve this process using tools like Component or AssetGraph and it’s something we’ll be looking into soon. For the moment, it is reasonably trivial to handle manually.

Rizzo on GitHub

The source code behind Lonely Planet’s components is now public at https://github.com/lonelyplanet/rizzo. The implementation is very bespoke to Lonely Planet but should give some indication of how our architecture works if you are interested in taking a similar approach. Here are a few example pieces that make up Rizzo:

A component template

A component Stylesheet

API Helper

Style Guide Data

Style Guide View

Conclusion

I believe that the difference between Rizzo and our previous two Style Guides, in terms of their successfulness, is that with Rizzo we didn’t focus on the Style Guide as the deliverable. Instead we focused on reducing complexity and increasing reusability. The Style Guide was then simple to add on at the end but, had it not been, we would still have been in a better place regardless.

To achieve something like this you’re never going to be able to just run a grunt task and have it happen for you. Unfortunately it’s not something you can add on at the end, though nor should it be. It requires you to contemplate your site architecture and structure as the main focus and the benefits of that can then extend far beyond a Style Guide.

At Lonely Planet we have a long way to go to create a solid, consistent platform, but this has certainly been proven as a step in the right direction. If you are starting a new project, or you have the means to invest some time in maintainability, I would thoroughly recommend a component based architecture along these lines.

Ten reasons we switched from an icon font to SVG

We use a lot of icons on lonelyplanet.com and recently went through the task of transferring them from an icon font to SVG files. I wanted to share why we did this along with some of the drawbacks to SVG and how we got around them.

1. Separation of concerns

We use a custom font on lonelyplanet.com and we used to bundle the icons into the same file, storing the glyphs within the Private Unicode Area. This was great because it meant one less HTTP request to fetch the icons but we also felt that it limited our flexibility in how we prioritised resource loading.

We don’t consider our font to be critical to the user’s experience and only a small subset of our icons are actually deemed critical. We try to load non-critical assets after the page content and this was something we weren’t able to do previously.

Breaking the critical icons out from the font and the rest of the icons allowed us to be more granular in how we delivered them to the user.

Counter argument

“You don’t have to bundle the font and the font icons together, you could serve two separate fonts.”

We could do this instead and it’s something we probably would have done had we stuck with the font-face solution.

2. Some devices don’t honour the Private Unicode Area

I’d heard rumours about devices overriding glyphs in the private unicode area and using them to serve emoji but I hadn’t seen it happen until recently. Emoji was historically stored in the private unicode area, but at different ranges, so it would make sense that there could be conflicts.

I can’t remember which device I was testing on but I saw one of our tick icons replaced with a multi-colour printer. The page looked amateurish and broken and certainly gave us impetus to make this transition.

3. Black squares and crosses on opera mini

Font face support and detection is historically quite tricky to get right. I’m sure you’ve all seen this image of font awesome rendering on opera mini:

I won’t go over the intricacies of this problem as Opera Mini support and many other platforms have been covered very well in this article by @kaelig. I think what is really important though, beyond Opera Mini, is that this highlights a blind spot that we’re not able to control. We can’t test on every device so we should use techniques that are more likely to render consistently.

We don’t get a huge amount of traffic from Opera Mini at the moment but we’re a travel company serving people in all conditions on all bandwidths so we want to do better than that. With SVG and PNG we feel more confident that users won’t get a broken and confusing page.

4. Chrome support for font-icons has been terrible recently

Chrome Canary and Beta were hit with a fairly horrible font bug recently. If you haven’t yet noticed the bug, fonts have been unloading and reverting to a system font after the page has experienced a period of inactivity.

When a font unloads and you’re left with the text served as Georgia it can be a little annoying. The page is still very usable though. If the same font is responsible for serving the icons then suddenly the page is littered with black squares and looks broken.

This bug was introduced during our transition to SVG. It was a relief to cut over just as we were starting to get our first bug reports about it.

Counter argument

Those bugs haven’t made it to a stable build of Chrome.

5. Crisper icons in Firefox

We’ve found that our font renders at a slightly stronger weight in Firefox than in other browsers. This is ok for text (although not great) but for icons it can make the entire page look a bit unloved and clumsy. By using SVG we are able to normalise the look and feel of our icons cross browser.

6. You don’t always have to use generated content.

If you want to use font-icons in css you need to declare them using the content property in generated content. Sometimes you might find yourself having to complicate your code to make this possible i.e. because you are already using the :before and :after pseudo elements on the element or because the element doesn’t support generated content.

In that case you could choose to render it inline but you then end up with html entities scattered through your markup which can easily be lost or forgotten about within a large application.

This problem is removed with SVG as you are not limited to generated content and can render them as a background image on any element.

7. Less fiddly to position

Admittedly this may be a result of how we created and managed our icon glyphs but we always found them awkward to position exactly how we wanted (and in a consistent fashion cross browser). We resorted to line height hacks and absolute/relative positioning to get them just right and it was difficult to come up with an abstraction that worked consistently.

With SVG we’ve found the placement much more willing. We use background-size: cover and simply resize the element to ensure consistency across browsers.

8. Multi-colour icons

Font icons are well known to have a single colour limitation. SVGs, on the other hand, can support multiple colours as well as gradients and other graphical features.

We have always had to support multi-colour map icons and had previously used an additional PNG sprite alongside our icon font. As a result of the move to SVG we were able to delete this sprite which meant one less request for the user.

Counter argument

This can be accomplished using icon layering.

It is significantly more challenging to do so successfully though: if positioning one glyph correctly cross-browser is tricky, it won’t get easier with two.

9. SVGs allow us to use animation within our icons.

We haven’t yet utilised this feature but is likely something we will look in to now that we have made the jump.

10. It’s always felt like a hack.

Through a combination of all of the above, using font-face for icons has always felt like a hack to me. It is a brilliant hack, no doubt, but it’s still a different asset type masquerading and being manipulated into something greater.

What about the benefits of font-face?

Serving icons through font-face does have some benefits over SVG and we had to consider these in depth before making the transition. The most pertinent benefits for font-face are browser support and colour flexibility.

Colour variations

The huge benefit to using an icon font is its flexibility. You have no limitation to the amount of colour variations and can easily switch it depending on the current state (:hover, :focus, .is-active etc.). This is a huge luxury and very useful for quick development. It was also the reason we resisted making the leap to SVG for so long.

Our solution

There are a few solutions out there to provide this functionality although all of them have their own limitations (for now). We finally came up with a technique which we were pretty happy with and which toed the line between flexibility and resource size.

Grunticon is designed to declare each icon individually, thus avoiding having to use sprites. We followed suit with this approach but, although we had one css selector per icon, we served each icon in six different colours.

As we were just duplicating the same icon multiple times within the same file, the file compressed down to the size of just one icon (plus around 50 bytes for gzip pointers). This meant that we could have n colour variations for each icon at almost no cost. Here’s an example of how it works.

With this solution we had the flexibility back that we thought we would miss. By taking away total flexibility it also brought the added benefit of reinforcing colour palette consistency, something that had gradually been lost from our font icon implementation.

With this technique we could easily apply state-based changes to the icons by updating their background position.

It’s worth mentioning that in the future we may be able to remove the sprite altogether and use SVG Fragment Identifiers to change the colour.

Browser support

Font icons work all the way back to IE8 whereas SVG does not. For our implementation we also required support for background-size although this is fairly comparable to SVG support.

Our solution

Grunticon handles legacy support right out of the box. We ended up tweaking it in our implementation to serve just a subset of the icons (the critical ones, e.g. the logo) to unsupported browsers. This meant that older browsers received a working page with the necessary icons and newer browsers got the full range of iconography.

Was it worth it?

Both techniques are resolution independent, scalable and fairly lightweight so if you are using either it is good for the user. We felt that on balance SVGs gave us more confidence in how our application would appear to each user and that extra element of control was ultimately what it came down to.

SVGs have been live on Lonely Planet since November 2013 and development has been painless so far.