Skip to content

Instantly share code, notes, and snippets.

@drwpow
Last active December 4, 2015 17:33
Show Gist options
  • Save drwpow/67f611f2361a8404afca to your computer and use it in GitHub Desktop.
Save drwpow/67f611f2361a8404afca to your computer and use it in GitHub Desktop.

MVCSS stands for Modular View CSS. It’s a Sass-based CSS architecture for creating predictable and maintainable application style. Those familiar with SMACSS will find a lot of overlap.

The Basics

  1. Classes only; no IDs. Why?
  2. Try to avoid nesting selectors inside other selectors. Why?
  3. Practice single responsibility: each component is in its own file, and never affects the styling of other components. Why?
  4. Alphabetize everything (most IDEs can map this to a button).
  5. Use camelCase for compound words; no underscores or hyphens (hyphens are explained below).

Why MVCSS?

Advantages
  • Modular. Eliminates the domino effect of modifying styles with unintended side-effects. Also avoids the !important turf war altogether.
  • Scalable. Works for even the most overly-complicated applications.
  • Consistent. On a team using MVCSS, you can pick up right where someone else left off.
  • Responsive. Works great on mobile-first responsive applications.
  • Reactive. Integrates seamlessly with Ember, Angular, React, and just about any other MVC front end framework out there.
  • Agnostic. Assumes nothing about how you want to design your application, only about how you organize your CSS.
  • Tiny. With no bloat, it’s as small as it can be. Ultimately your size is up to you, but we consistently see 20–30KB total for all CSS using MVCSS + minification + gzip.
MVCSS vs Bootstrap / ZURB Foundation
  • More time up front. You have to style much more out-of-the box than other frameworks. The payoff in MVCSS is in the long-term: saving you from heavy refactoring down the line. But
  • Lots of naming. Expect to be naming lots of things, and the burden of making sure your names are future-proof is on you.
  • Defining modules can be hard. We don’t give you rules on what a module can/can’t be. This is great for flexibility, but can be difficult during build knowing what is and what is not a module. And sometimes refactoring of entire modules is not uncommon as you build or as your app evolves.
  • No JavaScript plugins. There are no JS components made for MVCSS specifically, but you’re free to use just about any library/ies you’d like (even Bootstrap).
  • No community (for now). Let’s face it—we haven’t evangelized it and documented it as much as we should, but we’re hoping that’ll change.

The Syntax

Note: the following examples are all in the bracket-less .sass format, but apply just the same to the more common .scss format.

.module

.module-submodule

.module--modifier

.has-module

.is-[something]

Module: .module

The root module. Usually contains submodules (see “Submodule” below), and also may be modified (see “Modifier” below).

Example
.footer
  background-color: darkslategrey
  color: white

Submodule: .module-submodule (one hyphen)

Use submodules when you have a complicated module that needs additional styling hooks. This is better practice than habitually nesting selectors or elements within your Sass. In your HTML, the submodules don’t always have to be nested directly under the root module, but submodules still contribute to the module as a whole and typically don’t stand on their own. In extreme scenarios you may require sub- submodules—.module-submodule-submodule—but this is rarely necessary and more often than not is an indicator you should refactor.

Example
<article class="article">
  <h1 class="article-title"></h1>
  <time class="article-date"></time>
  <div class="article-body"></div>
</article>

Modifier: .module--modifier (two hyphens)

Modifies the root module. Should never @extend the root, and shouldn’t repeat properties. This keeps your CSS minimal. Append to the root class in HTML instead: <div class="module module--modifier">.

Example
.btn
  background-color: red
  color: white

.btn--blue
  background-color: blue
<button class="btn">I am a red button!</button>
<button class="btn btn--blue">I am a blue button!</button>

Context: .has-module

Every now and then you’ll need a container for a module. Single responsibility requires modules to handle their own styles 100%, and the context class exists for this purpose. The context class is always named .has-[moduleName].

Example

If your root module was .alert that had to stick to the top of the <body> element:

.alert
  left: 0
  position: absolute
  right: 0
  top: 0

.has-alert
  position: relative
<body class="has-alert">
  <div class="alert"></div>

This allows you to style the alert without polluting the global styling of your body tag.

States: .is-[something]

State classes are useful for user interactions. States can represent which navigation element is current (.is-current), which carousel item is visible (.is-visible), or even which element is animating (is-animating). State classes can be named anything, but always start with .is- and end in a one-word description of what that element is doing. States are always attached to a modifier class so 1) your states are always scoped to your module and never bleed into others (single-responsibility), and 2) so states always take priority.

Example
.notification
  background-color: red
  display: none

.notification.is-visible
  display: block

File Setup

We recommend keeping your files organized in a particular order: base > submodules > modifiers > context > states. This way you can stick to single-class specificity and still have the styles cascade properly.

Here is an example structures/_cal.sass (CSS attributes removed for clarity):

// *************************************
//
//   Calendar
//   -> User-selectable date picker
//
// *************************************

// -------------------------------------
//   Base
// -------------------------------------

.cal

// -------------------------------------
//   Submodules
// -------------------------------------

// ----- Day ----- //

.cal-day

// ----- Month ----- //

.cal-month

// ----- Year ----- //

.cal-year

// -------------------------------------
//   Modifiers
// -------------------------------------

// ----- Large ----- //

.cal--l

// ----- Small ----- //

.cal--s

// -------------------------------------
//   Context
// -------------------------------------

.has-cal

// -------------------------------------
//   States
// -------------------------------------

// ----- Disabled ----- //

.cal.is-disabled

// ----- Showing ----- //

.cal.is-showing

Note that everything is alphabetized within each section. Make sure to do the same with CSS attributes. As for comment style, feel free to experiment, but this is a very readable style.

Folder setup

The application.sass file—a convention from Rails—is the main manifest where everything is loaded in the correct order with @import, and will eventually be compressed and served as a single file. The folder structure is as follows:

application.sass
foundation/
components/
structures/

And opening each folder you’ll find:

application.sass

foundation/
  └ reset
  └ helpers
  └ config
  └ base
  └ tools

components/
  └ [your components]

structures/
  └ [your structures]

Foundation

The MVCSS foundation in application.sass is loaded in a specific order:

  1. @import "foundation/reset"
  2. @import "foundation/helpers"
  3. @import "foundation/config"
  4. @import "foundation/base"

And, lastly, "@import "foundation/tools" is loaded at the end of application.sass—after the components and structures. This way, the tools can do what they’re meant to do: override styles for one-off situations.

Reset — This is simply normalize.css.

Helpers — Sass functions to use throughout the app.

Config — Colors, typography, responsive settings, grid configuration, and anything else that could benefit from a Sass variable within the app.

Base — Base styles for class-less DOM elements.

Tools — Reusable, single-attribute utility classes useful when making a module would be overkill (we use things like .ttu for text-transform: uppercase).

Components

Generic CSS modules that are the scaffolding of the website (examples include .grid for responsive grids, .modal for modals, and .card for card-like components). Ideally serve a multitude of purposes across an app.

Structures

Very styled CSS modules that cater to very specific parts of the app (such as .product for styling an ecommerce product listing or .article for styling a blog article). Generally serve one and only one purpose within an app.

Adding new Modules

Adding new modules is as simple as making a new .sass file and placing it in the components/ or structures/ directory based on what it is. Some projects’ application.sass uses the following:

@import "structures/*"

In this scenario, the file is added as soon as it’s placed in a folder. In this scenario, take care to delete unused styles so that the stylesheet doesn’t become bloated.

In other scenarios, you may see this instead:

@import "structures/bucket"
@import "structures/button"
@import "structures/cal"

In this scenario, you’ll need to add your file to either the components/ or structures/ folder and manually include it in application.sass.

Read More

You can read the full documentation on MVCSS here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment