CSS at Hootsuite

We’ve really enjoyed reading up the posts from Mark Otto, Ian Feather, Chris Coyer and others about CSS on the projects they work on. I’ve personally learned a lot from those individuals and picked up some more tricks in those posts about how CSS works on large projects.

This is a little bit about how CSS works at Hootsuite and process we have found work best for us at this point in time.

Across the company we have many different projects with different histories and systems. While we are working towards standardizing our methods and tools across all projects, the info here pertains to the main web repository which includes our dashboard, mobile web dashboard, and browser extensions.


  • The Hootsuite dashboard project has existed for over six years and while we continue to add features and revise existing ones, some has been around for a while
  • Main repository includes desktop dashboard, mobile web dashboard, browser extensions, partner dashboards and some static pages
  • ~40 engineers work on the web dashboard project writing PHP, JS, HTML and CSS
  • 4 focus primarily on HTML & CSS layer
  • We don’t throw tickets over the fence to CSS engineers but expect all engineers to write good CSS code
  • We Practice Continuous Integration and regularly release to production 10+ times a day
  • Tooling is all IDE agnostic and needs to work for any dev on any environment
  • We use Grunt and have a combination of public and custom modules
  • Our CSS preprocessor of choice is LESS

Some numbers

  • 237 LESS files (63,500 lines of code)
  • These compile into 144 CSS Files (60,000 lines of code)
  • 1100 view files (800 HTML and 280 EJS)
  • 52 different CSS bundles get sent to production


We compile each LESS file to a CSS file for the most part. It evolved this way because our architecture was built to bundle CSS files in the deployment process. As we write new sections, we are moving toward using @import on dev to maintain smaller LESS files.

  • We only use nesting, variables, mixins, imports. With many people working in the UI layer, not just UI devs, our LESS needs to be easy to understand. New features are evaluated and adopted when they provide reasonable benefit
  • We use lesshat for css3 mixins
  • We have our own mixin library (image replacement, clearfix, etc.)
  • We’ve standardized variables for the project including font stacks, brand colours, media queries and other commonly reused strings.
  • We prefer to use LESS comments that don’t compile to CSS (Even though CSS comments are stripped when we build our CSS for staging/production)

CSS Frameworks and Grids

  • Use the YUI CSS Reset
  • The desktop dashboard uses jquery.ui for some UI elements
  • The mobile dashboard uses a scaled down version of jquery.mobile
  • We do not use grid systems in the main product, but use 960.gs and rwdgrid on some static non-logged in pages


  • Use a system derived from many of the principles in BEM and SUIT CSS
  • Main differences make it easier to integrate in our old CSS system (largely around naming conventions)
  • Favours encapsulation and elements that are accessible within an application (not scoping to .analytics etc.)


Code formatting and standardization is important and we want to offload as much work to robots to let humans focus on the things that can’t be automated. We use the following as tooling for LESS/CSS:

  • CSSComb for LESS Linting and ordering: This is currently being rolled out with the end goal of having pre-commit hooks to enforce it
  • BlessCSS: IE9 and below stop parsing a CSS file when 4095 selectors have been seen. We don’t currently emulate our production bundles in our dev environments so many existing tools to monitor this don’t work so we wrote a custom grunt module that will let the engineer if they are close to, or over the limit in a way that it works in development. Additionally, builds will also break if a bundle surpasses 4095 selectors so we can actively gain insight and maintain browser compliance for IE.

Browser Support

  • Currently support IE8+, current versions of Chrome, Safari and Firefox
  • OK to degrade in stylistic things (rounded corners) but not more functional things (e.g. flexbox)
  • Browser testing in a Continuous Integration environment remains a challenge but the IE VM Project makes it easier


  • We have an internal static styleguide that dev’s update when the work on / create new UI elements
  • We wrote a grunt task to import our CSS and JS from our staging environment to make adding components easier
  • Lessons Learned: It is difficult and time consuming to reverse engineer a styleguide and many available living styleguide frameworks are highly opinionated about the CSS they need to work and difficult to retrofit into an existing project.

Dark Launching

We dark launch most of our UI features. Sometimes, for example new features, this can be done by wrapping the new DOM elements in Dark Launch Flags, but other times we need the ability to dark launch just CSS. We have found this method the best when needing to dark launch something in CSS

  • Find the parents DOM element to the element containing CSS
  • Dark launch a selector with if/else block
  • Wrap existing the old LESS in the disabled class, and write all new CSS as a descent of the new class
  • When the feature is launched, you can easily clean up by removing the small DL in the view, and removing all LESS


At Hootsuite we are constantly trying to find measurable improvements we can integrate into our systems and while we have done a good job improving some of our processes, there is still a lot of work to do. Specifically integrating tools like Live reload, properly emulating production bundles in development environment and implementing graphing and statistics around the health of CSS.

Writing CSS at scale is about significantly more than the nuts and bolts of writing good CSS. It must be scalable, maintainable and supported by tooling, documentation and build systems that maintain engineer productivity and happiness.