Skip to content

Instantly share code, notes, and snippets.

@bobbygrace
Last active September 27, 2025 06:29
Show Gist options
  • Save bobbygrace/9e961e8982f42eb91b80 to your computer and use it in GitHub Desktop.
Save bobbygrace/9e961e8982f42eb91b80 to your computer and use it in GitHub Desktop.

Revisions

  1. bobbygrace revised this gist Jan 25, 2016. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,7 @@
    Hello, visitors! If you want an updated version of this styleguide _in repo form with tons of real-life examples_… check out Trellisheets! https://github.com/trello/trellisheets

    -----

    # Trello CSS Guide

    “I perfectly understand our CSS. I never have any issues with cascading rules. I never have to use `!important` or inline styles. Even though somebody else wrote this bit of CSS, I know exactly how it works and how to extend it. Fixes are easy! I have a hard time breaking our CSS. I know exactly where to put new CSS. We use all of our CSS and it’s pretty small overall. When I delete a template, I know the exact corresponding CSS file and I can delete it all at once. Nothing gets left behind.”
  2. bobbygrace revised this gist Feb 17, 2015. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -477,7 +477,8 @@ You might get the impression from this guide that our CSS is in great shape. Tha

    Some additional things to keep in mind:

    - Comments rarely hurt. If you find an answer on Stack Overflow or in a blog post, add the link to a comment so future people know what’s up.
    - Comments rarely hurt. If you find an answer on Stack Overflow or in a blog post, add the link to a comment so future people know what’s up. It’s good to explain the purpose of the file in a comment at the top.
    - In your markup, order classes like so `<div class="component mod util state js"></div>`.
    - You can embed common images and files under 10kb using datauris. In the Trello web client, you can use `embed(/path/to/file)` to do this. This saves a request, but adds to the CSS size, so only use it on extremely common things like the logo.
    - Avoid body classes. There is rarely a need for them. Stick to modifiers within your component.
    - Explicitly write out class names in selectors. Don’t concatenate strings or use preprocessor trickery to build a class name. We want to be able to search for class names and that makes it impossible. This goes for `.js-` classes in JavaScript, too.
  3. bobbygrace revised this gist Feb 17, 2015. 1 changed file with 10 additions and 12 deletions.
    22 changes: 10 additions & 12 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -368,28 +368,26 @@ Be sure to **use a descriptive class name**. The intent of `.js-open-content-men

    ## 4. Mixins

    > Prefix mixins with `.m-` and only use them for browser polyfills.
    > Prefix mixins with `.m-` and only use them sparingly for shared styles.
    Mixins can get complicated fast. Simple-looking rules can get way out of hand when they’re including tons of nested rules. That’s why we only use mixins in for browser polyfills. Some CSS features still require a lot of browser-specific declarations in order to work, like gradients and box-shadow. Writing those over and over is error-prone. Use an `.m-` prefixed mixin to handle them. For example:
    Mixins are shared styles that are used in more than one component. Mixins should not be standalone classes or used in markup. They should be single level and contain no nesting. Mixins make things complicated fast, so **use sparingly**.

    Previously, we used mixins for browser prefixed features, but we use [autoprefixer](https://www.npmjs.com/package/autoprefixer) for that now.

    When using a mixin, it should include the parenthesis to make it more obvious that it’s a mixin. Example usage:

    ``` LESS
    // mixins.less

    .m-vertical-gradient (@topcolor: #999, @bottomcolor: #aaa) {
    background: @topcolor;
    background: -webkit-linear-gradient(top, @topcolor 0%, @bottomcolor 100%);
    background: linear-gradient(to bottom, @topcolor 0%, @bottomcolor 100%);
    .m-list-divider () {
    border-bottom: 1px solid @light-gray-300;
    }

    // component.less
    .component-descendant {
    .m-vertical-gradient(#fff, #f0f0f0);
    padding: 20px;
    .component-descendent {
    .m-list-divider();
    }
    ```

    Be sure to check [caniuse.com](http://caniuse.com/) and our [supported browsers](https://trello.com/platforms) to see which prefixes you actually need for your polyfill.


    ## 5. Utilities

  4. bobbygrace revised this gist Feb 12, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -303,7 +303,7 @@ Here’s an example:
    margin: 0;
    }

    .member-list-item-option {
    .member-list-item-action {
    float: right;
    }
    ```
  5. bobbygrace revised this gist Feb 12, 2015. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -391,7 +391,7 @@ Mixins can get complicated fast. Simple-looking rules can get way out of hand wh
    Be sure to check [caniuse.com](http://caniuse.com/) and our [supported browsers](https://trello.com/platforms) to see which prefixes you actually need for your polyfill.


    ## 6. Utilities
    ## 5. Utilities

    > Prefix utility classes with `.u-`.
    @@ -410,7 +410,7 @@ All the utils should be in a single file. There shouldn’t be any need to overw
    You should really only need a few utilities. We don’t need something like `.u-float-left { float: left; }` where including `float: left;` in the component is just as easy and more visible.


    ## 7. File Structure
    ## 6. File Structure

    The file will look something like this:

    @@ -444,7 +444,7 @@ Then include the components. Each component should have its own file and include
    This should output a single `app.css` file (or something similarly named).


    ## 8. Style
    ## 7. Style

    Even following the above guidelines, it’s still possible to write CSS in a ton of different ways. Writing our CSS in a consistent way makes it more readable for everyone. Take this bit of CSS:

    @@ -473,7 +473,7 @@ It sticks to these style rules:
    - Prefer hsl(a) over hex and rgb(a). Working with colors in code is easier with hsl, especially when making things lighter or darker, since you only have one variable to adjust.


    ## 9. Miscellany
    ## 8. Miscellany

    You might get the impression from this guide that our CSS is in great shape. That is not the case. While we’ve always stuck to .js classes and often use namespaced-component-looking classes, there is a mishmash of styles and patterns throughout. That’s okay. Going forward, you should rewrite sections according to these rules. Leave the place nicer than you found it.

  6. bobbygrace revised this gist Feb 11, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -313,10 +313,10 @@ A _bad_ thing to do would be this:
    ``` HTML
    <!-- HTML -->

    <div class="member-list>
    <div class="member-list">
    <div class="member-list-item">
    <p class="member-list-item-name">Pat</p>
    <a href="#" class="member-list-item-button button>Add</a>
    <a href="#" class="member-list-item-button button">Add</a>
    </div>
    </div>
    ```
  7. bobbygrace revised this gist Feb 11, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -264,7 +264,7 @@ Here’s an example:
    ``` HTML
    <!-- HTML -->

    <div class="member-list>
    <div class="member-list">
    <div class="member-list-item">
    <p class="member-list-item-name">Gumby</p>
    <div class="member-list-item-action">
  8. bobbygrace revised this gist Feb 11, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -267,8 +267,8 @@ Here’s an example:
    <div class="member-list”>
    <div class="member-list-item">
    <p class="member-list-item-name">Gumby</p>
    <div class="member-list-item-action>
    <a href="#" class="button mod-small>Add</a>
    <div class="member-list-item-action">
    <a href="#" class="button mod-small">Add</a>
    </div>
    </div>
    </div>
  9. bobbygrace revised this gist Feb 11, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -422,7 +422,7 @@ The file will look something like this:
    // Variables
    @import "media-queries.less"
    @import "colors.less"
    @import other-variables-like-fonts.less"
    @import "other-variables-like-fonts.less"
    // Mixins
    @import "mixins.less"
  10. bobbygrace revised this gist Feb 11, 2015. 1 changed file with 22 additions and 15 deletions.
    37 changes: 22 additions & 15 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -42,7 +42,7 @@ Components help encapsulate your CSS and prevent run-away cascading styles and k

    Here’s an example with descendant selectors:

    ```
    ``` LESS
    .global-header {
    background: hsl(202, 70%, 90%);
    color: hsl(202, 0%, 100%);
    @@ -79,7 +79,7 @@ Here’s an example with descendant selectors:

    And here’s the same example with namespacing:

    ```
    ``` LESS
    .global-header {
    background: hsl(202, 70%, 90%);
    color: hsl(202, 0%, 100%);
    @@ -130,13 +130,15 @@ Let’s say you want to use a component, but style it in a special way. We run i

    For example, we want to specially style our sign up button among the header buttons. We’ll add `.global-header-nav-item.mod-sign-up`, which looks like this:

    ```
    ``` HTML
    <!-- HTML -->

    <a class="global-header-nav-item mod-sign-up">
    Sign Up
    </a>
    ```

    ``` LESS
    // global-header.less

    .global-header-nav-item {
    @@ -160,7 +162,7 @@ We inherit all the `global-header-nav-item` styles and modify it with `.mod-sign

    You’ll often want to overwrite a descendant of the modified selector. Do that like so:

    ```
    ``` LESS
    .global-header-nav-item.mod-sign-up {
    background: hsl(120, 70%, 40%);
    color: #fff;
    @@ -187,7 +189,7 @@ Example: Let’s say that when you click the logo, it goes back to your home pag

    You’ll use a `.global-header-logo-image.is-loading` rule. That looks like this:

    ```
    ``` LESS
    .global-header-logo-image {
    background: url("logo.png");
    height: 40px;
    @@ -214,7 +216,7 @@ It might be tempting to add something like a `mobile.less` file that contains al

    Rather than writing out the media queries every time, we’ll use a media-queries.less file with media query variables. It should look something like this:

    ```
    ``` LESS
    @highdensity: ~"only screen and (-webkit-min-device-pixel-ratio: 1.5)",
    ~"only screen and (min--moz-device-pixel-ratio: 1.5)",
    ~"only screen and (-o-min-device-pixel-ratio: 3/2)",
    @@ -230,7 +232,7 @@ Rather than writing out the media queries every time, we’ll use a media-querie

    To use a media query:

    ```
    ``` LESS
    // Input
    @media @large {
    .component-nav { … }
    @@ -259,7 +261,7 @@ This is tricky. Components shouldn’t know anything about each other. If the sm

    Here’s an example:

    ```
    ``` HTML
    <!-- HTML -->

    <div class="member-list”>
    @@ -270,8 +272,9 @@ Here’s an example:
    </div>
    </div>
    </div>
    ```
    ``` LESS
    // button.less
    .button {
    @@ -307,7 +310,7 @@ Here’s an example:
    A _bad_ thing to do would be this:
    ```
    ``` HTML
    <!-- HTML -->
    <div class="member-list”>
    @@ -316,7 +319,9 @@ A _bad_ thing to do would be this:
    <a href="#" class="member-list-item-button button”>Add</a>
    </div>
    </div>
    ```
    ``` LESS
    // member-list.less
    .member-list-item-button {
    @@ -336,15 +341,17 @@ You should end up with a lot of components. Always be asking yourself if everyth
    For example:
    ```
    ``` HTML
    <!-- HTML -->
    <div class="content-nav">
    <a href="#" class="content-nav-button js-open-content-menu">
    Menu
    </a>
    </div>
    ```
    ``` JavaScript
    // JavaScript (with jQuery)
    $(".js-open-content-menu").on("click", function(e){
    @@ -365,7 +372,7 @@ Be sure to **use a descriptive class name**. The intent of `.js-open-content-men
    Mixins can get complicated fast. Simple-looking rules can get way out of hand when they’re including tons of nested rules. That’s why we only use mixins in for browser polyfills. Some CSS features still require a lot of browser-specific declarations in order to work, like gradients and box-shadow. Writing those over and over is error-prone. Use an `.m-` prefixed mixin to handle them. For example:
    ```
    ``` LESS
    // mixins.less
    .m-vertical-gradient (@topcolor: #999, @bottomcolor: #aaa) {
    @@ -390,7 +397,7 @@ Be sure to check [caniuse.com](http://caniuse.com/) and our [supported browsers]
    Sometimes we need a universal class that can be used in any component. Things like clear fixes, vertical alignment, and text truncation. Denote these classes by prefixing them with `.u-`. For example:
    ```
    ``` LESS
    .u-truncate-text {
    overflow: hidden;
    text-overflow: ellipsis;
    @@ -407,7 +414,7 @@ You should really only need a few utilities. We don’t need something like `.u-
    The file will look something like this:
    ```
    ``` LESS
    @charset "UTF-8"
    @import "normalize.css"
    @@ -441,7 +448,7 @@ This should output a single `app.css` file (or something similarly named).

    Even following the above guidelines, it’s still possible to write CSS in a ton of different ways. Writing our CSS in a consistent way makes it more readable for everyone. Take this bit of CSS:

    ```
    ``` LESS
    .global-header-nav-item {
    background: hsl(0, 0%, 90%);
    border-radius: 3px;
  11. bobbygrace revised this gist Feb 4, 2015. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,10 @@
    # Trello CSS Guide

    “I perfectly understand our CSS. I never have any issues with cascading rules. Even though somebody else wrote this bit of CSS, I know exactly how it works and how to extend it. I know where to put new CSS. We use all of our CSS and it’s pretty small overall. I have a hard time breaking our CSS, even though I’m new. When I delete a template, I know the exact corresponding CSS file and I can delete it all at once. Nothing gets left behind.”
    “I perfectly understand our CSS. I never have any issues with cascading rules. I never have to use `!important` or inline styles. Even though somebody else wrote this bit of CSS, I know exactly how it works and how to extend it. Fixes are easy! I have a hard time breaking our CSS. I know exactly where to put new CSS. We use all of our CSS and it’s pretty small overall. When I delete a template, I know the exact corresponding CSS file and I can delete it all at once. Nothing gets left behind.”

    You often hear updog saying stuff like this. Who’s updog? Not much, who is up with you?

    Having fun with this guide so far? I hope so. Unfortunately, this is where the fun ends. Now it’s time to get serious and talk about _rules_.
    This is where any fun you might have been having ends. Now it’s time to get serious and talk about rules.

    Writing CSS is hard. Even if you know all the intricacies of position and float and overflow and z-index, it’s easy to end up with spaghetti code where you need inline styles, !important rules, unused cruft, and general confusion. This guide provides some architecture for writing CSS so it stays clean and maintainable for generations to come.

    @@ -179,7 +179,7 @@ Put modifiers at the bottom of the component file, after the original components

    ### State

    > Use the `.component-descendant.is-state` pattern for state.
    > Use the `.component-descendant.is-state` pattern for state. Manipulate `.is-` classes in JavaScript (but not presentation classes).
    State classes show that something is enabled, expanded, hidden, or what have you. For these classes, we’ll use a new `.component-descendant.is-state` pattern.

  12. bobbygrace revised this gist Jan 23, 2015. 1 changed file with 60 additions and 51 deletions.
    111 changes: 60 additions & 51 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -8,20 +8,20 @@ Having fun with this guide so far? I hope so. Unfortunately, this is where the f

    Writing CSS is hard. Even if you know all the intricacies of position and float and overflow and z-index, it’s easy to end up with spaghetti code where you need inline styles, !important rules, unused cruft, and general confusion. This guide provides some architecture for writing CSS so it stays clean and maintainable for generations to come.

    There are nine _fascinating_ parts.
    There are eight _fascinating_ parts.

    1. [Tools](#1-tools)
    2. [Components](#2-components)
    - [Modifiers](#modifiers)
    - [State](#state)
    - [Media Queries](#media-queries)
    - [Keeping It Encapsulated](#keeping-it-encapsulated)
    3. [JavaScript](#3-javascript)
    4. [Mixins](#4-mixins)
    5. [Media Queries](#5-media-queries)
    6. [Utilities](#6-utilities)
    7. [File Structure](#8-file-structure)
    8. [Style](#8-style)
    9. [Miscellany](#9-miscellany)
    5. [Utilities](#5-utilities)
    6. [File Structure](#6-file-structure)
    7. [Style](#7-style)
    8. [Miscellany](#8-miscellany)
    - [Performance](#performance)


    @@ -117,7 +117,7 @@ And here’s the same example with namespacing:

    Namespacing keeps specificity low, which leads to fewer inline styles, !important declarations, and makes things more maintainable over time.

    Make sure **every selector is a class**. There should be no reason to use id or element selectors. Everything in the class should be lowercase.
    Make sure **every selector is a class**. There should be no reason to use id or element selectors. No underscores or camelCase. Everything should be lowercase.

    Components make it easy to see relationships between classes. You just need to look at the name. You should still **indent descendant classes** so their relationship is even more obvious and it’s easier to scan the file. Stateful things like `:hover` should be on the same level.

    @@ -174,7 +174,7 @@ You’ll often want to overwrite a descendant of the modified selector. Do that

    Generally, we try and avoid nesting because it results in runaway rules that are impossible to read. This is an exception.

    Put modifiers at the bottom of the component file, after the original components. If you notice that you’re starting to have a lot of modifiers, it might be a sign that you should break it out into its own component.
    Put modifiers at the bottom of the component file, after the original components.


    ### State
    @@ -206,6 +206,51 @@ Like modifiers, it’s possible that the same state class will be used on differ
    We also don’t indent state classes. Again, that’s only for descendants. State classes should appear at the bottom of the file, after the original components and modifiers.


    ### Media Queries

    > Use media query variables in your component.
    It might be tempting to add something like a `mobile.less` file that contains all your mobile-specific rules. We want to avoid global media queries and instead include them inside our components. This way when we update or delete a component, we’ll be less likely to forget about the media rules.

    Rather than writing out the media queries every time, we’ll use a media-queries.less file with media query variables. It should look something like this:

    ```
    @highdensity: ~"only screen and (-webkit-min-device-pixel-ratio: 1.5)",
    ~"only screen and (min--moz-device-pixel-ratio: 1.5)",
    ~"only screen and (-o-min-device-pixel-ratio: 3/2)",
    ~"only screen and (min-device-pixel-ratio: 1.5)";
    @small: ~"only screen and (max-width: 750px)";
    @medium: ~"only screen and (min-width: 751px) and (max-width: 900px)";
    @large: ~"only screen and (min-width: 901px) and (max-width: 1280px)";
    @extra-large: ~"only screen and (min-width: 1281px)";
    @print: ~"print";
    ```

    To use a media query:

    ```
    // Input
    @media @large {
    .component-nav { … }
    }
    /* Output */
    @media only screen and (min-width: 901px) and (max-width: 1280px) {
    .component-nav { … }
    }
    ```

    You can use commas to include multiple variables, like `@media @small, @medium { … }`.

    This means we’re using the same breakpoints throughout and you don’t have to write the same media query over and over. Repeated phrases like media queries are easily compressed so you don’t need to worry about CSS size getting too big. This practice was taken from [this CodePen from Eric Rasch](http://codepen.io/ericrasch/pen/HzoEx).

    Note that print is a media attribute, too. Keep your print rules inside components. We don’t want to forget about them either.

    Put media rules at the bottom of the component file.


    ## Keeping It Encapsulated

    Components can control a large part of the layout or just a button. In your templates, you’ll likely end up with parts of one component inside another component, like a `.button` inside a `.member-list`. We need to change the button’s size and positioning to fit the list.
    @@ -280,7 +325,9 @@ A _bad_ thing to do would be this:
    }
    ```

    In the _bad_ example, `.member-list-item-button` overrides styles specific to the button component. It assumes things about button that it shouldn’t have to know anything about. It also prevents us from reusing the small button style and makes it hard to clean up later if needed.
    In the _bad_ example, `.member-list-item-button` overrides styles specific to the button component. It assumes things about button that it shouldn’t have to know anything about. It also prevents us from reusing the small button style and makes it hard to clean or change up later if needed.

    You should end up with a lot of components. Always be asking yourself if everything inside a component is absolutely related and can’t be broken down into more components. If you start to have a lot of modifiers and descendants, it might be time to break it up.


    ## 3. JavaScript
    @@ -337,45 +384,6 @@ Mixins can get complicated fast. Simple-looking rules can get way out of hand wh
    Be sure to check [caniuse.com](http://caniuse.com/) and our [supported browsers](https://trello.com/platforms) to see which prefixes you actually need for your polyfill.


    ### 5. Media Queries

    It might be tempting to add something like a `mobile.less` file that contains all your mobile-specific media queried rules. We want to avoid global media queries so that we can keep our components encapsulated. We want all media queries (and modifiers and states) to be in one component file so that when we delete a component down the line, we don’t have to look in multiple files to make sure we got everything related to it.

    We use LESS variables for media queries and include them in our components. Use a media-queries.less file like this:

    ```
    @highdensity: ~"only screen and (-webkit-min-device-pixel-ratio: 1.5)",
    ~"only screen and (min--moz-device-pixel-ratio: 1.5)",
    ~"only screen and (-o-min-device-pixel-ratio: 3/2)",
    ~"only screen and (min-device-pixel-ratio: 1.5)";
    @small: ~"only screen and (max-width: 750px)";
    @medium: ~"only screen and (min-width: 751px) and (max-width: 900px)";
    @large: ~"only screen and (min-width: 901px) and (max-width: 1280px)";
    @extra-large: ~"only screen and (min-width: 1281px)";
    @print: ~"print";
    ```

    To use a media query:

    ```
    // Input
    @media @large {
    .component-nav { … }
    }
    // Output
    @media only screen and (min-width: 901px) and (max-width: 1280px) {
    .component-nav { … }
    }
    ```

    This means we’re using the same breakpoints throughout. You don’t need to worry about CSS size. Repeated phrases like media queries are easily compressed. This practice was taken from [this CodePen from Eric Rasch](http://codepen.io/ericrasch/pen/HzoEx).

    Note that print is a media attribute, too. Keep your print rules inside components. We don’t want to forget about them when we change a component later.


    ## 6. Utilities

    > Prefix utility classes with `.u-`.
    @@ -392,7 +400,7 @@ Sometimes we need a universal class that can be used in any component. Things li

    All the utils should be in a single file. There shouldn’t be any need to overwrite them in components or mixins.

    You should really only need a few utilities. We don’t need something like `.u-float-left { float: left; }`. Just include `float: left;` in the component.
    You should really only need a few utilities. We don’t need something like `.u-float-left { float: left; }` where including `float: left;` in the component is just as easy and more visible.


    ## 7. File Structure
    @@ -406,8 +414,8 @@ The file will look something like this:
    // Variables
    @import "media-queries.less"
    @import "variables-like-fonts.less"
    @import "other-variables-like-colors.less"
    @import "colors.less"
    @import other-variables-like-fonts.less"
    // Mixins
    @import "mixins.less"
    @@ -428,6 +436,7 @@ Then include the components. Each component should have its own file and include

    This should output a single `app.css` file (or something similarly named).


    ## 8. Style

    Even following the above guidelines, it’s still possible to write CSS in a ton of different ways. Writing our CSS in a consistent way makes it more readable for everyone. Take this bit of CSS:
  13. bobbygrace revised this gist Jan 23, 2015. 1 changed file with 15 additions and 13 deletions.
    28 changes: 15 additions & 13 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -341,37 +341,39 @@ Be sure to check [caniuse.com](http://caniuse.com/) and our [supported browsers]

    It might be tempting to add something like a `mobile.less` file that contains all your mobile-specific media queried rules. We want to avoid global media queries so that we can keep our components encapsulated. We want all media queries (and modifiers and states) to be in one component file so that when we delete a component down the line, we don’t have to look in multiple files to make sure we got everything related to it.

    We use LESS variables for media queries our media queries and include them in our components. Use a media-queries.less file like this:
    We use LESS variables for media queries and include them in our components. Use a media-queries.less file like this:

    ```
    @highdensity: ~"only screen and (-webkit-min-device-pixel-ratio: 1.5)",
    ~"only screen and (min--moz-device-pixel-ratio: 1.5)",
    ~"only screen and (-o-min-device-pixel-ratio: 3/2)",
    ~"only screen and (min-device-pixel-ratio: 1.5)";
    @mobile: ~"only screen and (max-width: 529px)";
    @tablet: ~"only screen and (min-width: 530px) and (max-width: 949px)";
    @desktop: ~"only screen and (min-width: 950px) and (max-width: 1128px)";
    @desktop-xl: ~"only screen and (min-width: 1129px)";
    @print: ~"print”;
    @highdensity: ~"only screen and (-webkit-min-device-pixel-ratio: 1.5)",
    ~"only screen and (min--moz-device-pixel-ratio: 1.5)",
    ~"only screen and (-o-min-device-pixel-ratio: 3/2)",
    ~"only screen and (min-device-pixel-ratio: 1.5)";
    @small: ~"only screen and (max-width: 750px)";
    @medium: ~"only screen and (min-width: 751px) and (max-width: 900px)";
    @large: ~"only screen and (min-width: 901px) and (max-width: 1280px)";
    @extra-large: ~"only screen and (min-width: 1281px)";
    @print: ~"print";
    ```

    To use a media query:

    ```
    // Input
    @media @tablet {
    @media @large {
    .component-nav { … }
    }
    // Output
    @media only screen and (min-width: 530px) and (max-width: 949px {
    @media only screen and (min-width: 901px) and (max-width: 1280px) {
    .component-nav { … }
    }
    ```

    This means we’re using the same breakpoints throughout. You don’t need to worry about CSS size. Repeated phrases like media queries are easily compressed. This practice was taken from [this CodePen from Eric Rasch](http://codepen.io/ericrasch/pen/HzoEx).

    Note that print is a media attribute, too. Keep your print rules inside components, too. We don’t want to forget about them.
    Note that print is a media attribute, too. Keep your print rules inside components. We don’t want to forget about them when we change a component later.


    ## 6. Utilities
  14. bobbygrace revised this gist Jan 23, 2015. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -457,7 +457,7 @@ It sticks to these style rules:

    ## 9. Miscellany

    If you look at our CSS today, it looks nothing like this. We’ve always stuck to .js classes and often use namespaced-component-looking classes, but there is a mishmash of styles and patterns throughout. That’s okay. Going forward, you should rewrite section of the app according to these rules. Leave the world a better place.
    You might get the impression from this guide that our CSS is in great shape. That is not the case. While we’ve always stuck to .js classes and often use namespaced-component-looking classes, there is a mishmash of styles and patterns throughout. That’s okay. Going forward, you should rewrite sections according to these rules. Leave the place nicer than you found it.

    Some additional things to keep in mind:

    @@ -471,7 +471,7 @@ Some additional reading on CSS architecture around the web:

    - [Medium’s CSS guidelines.](https://gist.github.com/fat/a47b882eb5f84293c4ed) I ~~stole~~ learned a lot from this.
    - [“CSS At…” from CSS Tricks](http://css-tricks.com/css/). This is a big list of CSS practices at various companies.
    - The BEM, or “block, element, and modifier”, methodology is similar to our components. It is well explained in [this CSS Wizardry article](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/) and some good context.
    - The BEM, or “block, element, modifier”, methodology is similar to our components. It is well explained in [this CSS Wizardry article](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/).


    ### Performance
    @@ -484,4 +484,4 @@ Selector performance seems to matters less and less these days, but can be a pro

    You shouldn’t have to worry about selector performance if you use components correctly. It will keep specificity about as low as it gets.

    Layouts and paints can cause lots of performance damage. Be cautious with CSS3 features like text-shadow, box-shadow, border-radius, and animations, [especially when used together](http://www.html5rocks.com/en/tutorials/speed/css-paint-times/). We wrote a big blog post about performance from the borderlands era [back in January 2014](http://blog.fogcreek.com/we-spent-a-week-making-trello-boards-load-extremely-fast-heres-how-we-did-it/). Much of this was due to layout thrashing caused by JavaScript, but we cut out some heavy styles like borders, gradients, and shadows, which helped a lot.
    Layouts and paints can cause lots of performance damage. Be cautious with CSS3 features like text-shadow, box-shadow, border-radius, and animations, [especially when used together](http://www.html5rocks.com/en/tutorials/speed/css-paint-times/). We wrote a big blog post about performance [back in January 2014](http://blog.fogcreek.com/we-spent-a-week-making-trello-boards-load-extremely-fast-heres-how-we-did-it/). Much of this was due to layout thrashing caused by JavaScript, but we cut out some heavy styles like borders, gradients, and shadows, which helped a lot.
  15. bobbygrace revised this gist Jan 22, 2015. 1 changed file with 33 additions and 19 deletions.
    52 changes: 33 additions & 19 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -156,7 +156,7 @@ For example, we want to specially style our sign up button among the header butt

    We inherit all the `global-header-nav-item` styles and modify it with `.mod-sign-up`. This breaks our namespace convention and increases the specificity, but that’s exactly what we want. This means we don’t have to worry about the order in the file. For the sake of clarity, put it after the part of the component it modifies. Put modifiers on the same indention level as the selector it’s modifying.

    **You should never write a bare `.mod-` class**. It should always be tied to a part of a component. `.header-button.mod-sign-up { background: green; }` is good, but `.mod-sign-up { background: green; }` is bad. We could be using `.mod-sign-up` in another component and we wouldn’t want to override it. You shouldn’t have any global mods.
    **You should never write a bare `.mod-` class**. It should always be tied to a part of a component. `.header-button.mod-sign-up { background: green; }` is good, but `.mod-sign-up { background: green; }` is bad. We could be using `.mod-sign-up` in another component and we wouldn’t want to override it.

    You’ll often want to overwrite a descendant of the modified selector. Do that like so:

    @@ -174,6 +174,8 @@ You’ll often want to overwrite a descendant of the modified selector. Do that

    Generally, we try and avoid nesting because it results in runaway rules that are impossible to read. This is an exception.

    Put modifiers at the bottom of the component file, after the original components. If you notice that you’re starting to have a lot of modifiers, it might be a sign that you should break it out into its own component.


    ### State

    @@ -197,16 +199,16 @@ You’ll use a `.global-header-logo-image.is-loading` rule. That looks like this
    }
    ```

    JavaScript defines the state of the application, so we’ll use JavaScript to toggle the state classes. The `.component.is-state` pattern decouples state and presentation concerns so we can add state classes without needing to know about the presentation class. A developer can just say to the designer, “This element has an .is-loading class. You can style it however you want.”. If the state class were something like `global-header-logo-image--is-loading`, the developer would have to know a lot about the presentation.
    JavaScript defines the state of the application, so we’ll use JavaScript to toggle the state classes. The `.component.is-state` pattern decouples state and presentation concerns so we can add state classes without needing to know about the presentation class. A developer can just say to the designer, “This element has an .is-loading class. You can style it however you want.”. If the state class were something like `global-header-logo-image--is-loading`, the developer would have to know a lot about the presentation and it would be harder to update in the future.

    Like modifiers, it’s possible that the same state class will be used on different components. You don’t want to override or inherit styles, so it’s important that **every component define its own styles for the state**. They should never be defined on their own. Meaning you should see `.global-header.is-hidden { display: none; }`, but never `.is-hidden { display: none; }` (as tempting as that may be).
    Like modifiers, it’s possible that the same state class will be used on different components. You don’t want to override or inherit styles, so it’s important that **every component define its own styles for the state**. They should never be defined on their own. Meaning you should see `.global-header.is-hidden { display: none; }`, but never `.is-hidden { display: none; }` (as tempting as that may be). `.is-hidden` could conceivably mean different things in different components.

    We also don’t indent state classes. Again, that’s only for descendants.
    We also don’t indent state classes. Again, that’s only for descendants. State classes should appear at the bottom of the file, after the original components and modifiers.


    ## Keeping It Encapsulated

    Components can be big or small: a whole header layout or just a button. In your templates, you’ll likely end up with parts of one component inside another component, like a `.button` inside a `.member-list`. We need to change the button’s size and positioning to fit the list.
    Components can control a large part of the layout or just a button. In your templates, you’ll likely end up with parts of one component inside another component, like a `.button` inside a `.member-list`. We need to change the button’s size and positioning to fit the list.

    This is tricky. Components shouldn’t know anything about each other. If the smaller button can be reused in multiple places, add a modifier in the button component (like, `.button.mod-small`) and use it in member-list. Do the positioning with a member list component with a descendant, since that’s specific to the member list and not the button.

    @@ -233,9 +235,9 @@ Here’s an example:
    padding: 8px 12px;
    }
    .button.mod-small {
    padding: 6px 10px;
    }
    .button.mod-small {
    padding: 6px 10px;
    }
    // member-list.less
    @@ -314,24 +316,25 @@ Be sure to **use a descriptive class name**. The intent of `.js-open-content-men

    > Prefix mixins with `.m-` and only use them for browser polyfills.
    Mixins can get complicated fast. Simple-looking rules can get way out of hand when they’re including tons of nested rules. That’s why we only use mixins in for browser polyfills. Some CSS features still require a lot of browser-specific prefixes work, like gradients and box-shadow. Writing those over and over is error-prone. Use an `.m-` prefixed mixin to handle them. For example:
    Mixins can get complicated fast. Simple-looking rules can get way out of hand when they’re including tons of nested rules. That’s why we only use mixins in for browser polyfills. Some CSS features still require a lot of browser-specific declarations in order to work, like gradients and box-shadow. Writing those over and over is error-prone. Use an `.m-` prefixed mixin to handle them. For example:

    ```
    // LESS
    // mixins.less
    .m-vertical-gradient (@topcolor: #999, @bottomcolor: #aaa) {
    background: @topcolor;
    background: -webkit-linear-gradient(top, @topcolor 0%, @bottomcolor 100%);
    background: linear-gradient(to bottom, @topcolor 0%, @bottomcolor 100%);
    }
    // component.less
    .component-descendant {
    .m-vertical-gradient(#fff, #f0f0f0);
    padding: 20px;
    }
    ```

    Be sure to check [caniuse.com](http://caniuse.com/) to see which prefixes you actually need for your polyfill.
    Be sure to check [caniuse.com](http://caniuse.com/) and our [supported browsers](https://trello.com/platforms) to see which prefixes you actually need for your polyfill.


    ### 5. Media Queries
    @@ -375,7 +378,7 @@ Note that print is a media attribute, too. Keep your print rules inside componen

    > Prefix utility classes with `.u-`.
    Sometimes we need a universal class that can be used in any component. Things like floats, clear fixes, text decoration, vertical alignment, and text truncation. Denote these classes by prefixing them with `.u-`. For example:
    Sometimes we need a universal class that can be used in any component. Things like clear fixes, vertical alignment, and text truncation. Denote these classes by prefixing them with `.u-`. For example:

    ```
    .u-truncate-text {
    @@ -385,30 +388,43 @@ Sometimes we need a universal class that can be used in any component. Things li
    }
    ```

    All the utils should be in a single file and never appear in components or mixins. There really shouldn’t be a huge need for utilities. Use them sparingly.
    All the utils should be in a single file. There shouldn’t be any need to overwrite them in components or mixins.

    You should really only need a few utilities. We don’t need something like `.u-float-left { float: left; }`. Just include `float: left;` in the component.

    ## 7. File Structure

    Include normalize.css at the top of the file. Then include variables, mixins, and utils (respectively). Each component should have its own file and include all the necessary modifiers, states, and media queries.
    ## 7. File Structure

    The file will look something like this:

    ```
    @charset "UTF-8"
    @import "normalize.css"
    // Variables
    @import "media-queries.less"
    @import "variables-like-fonts.less"
    @import "other-variables-like-maybe-colors.less"
    @import "other-variables-like-colors.less"
    // Mixins
    @import "mixins.less"
    // Utils
    @import "utils.less"
    // Components
    @import "component-1.less"
    @import "component-2.less"
    @import "component-3.less"
    @import "component-4.less" // and so forth
    ```

    This should output a single `app.css` file (or something similarly named). If we write components correctly, the order of the components should not matter.
    Include [normalize.css](http://necolas.github.io/normalize.css/) at the top of the file. It standardizes CSS defaults across browsers. You should use it in all projects. Then include variables, mixins, and utils (respectively).

    Then include the components. Each component should have its own file and include all the necessary modifiers, states, and media queries. If we write components correctly, the order should not matter.

    This should output a single `app.css` file (or something similarly named).

    ## 8. Style

    @@ -446,9 +462,7 @@ If you look at our CSS today, it looks nothing like this. We’ve always stuck t
    Some additional things to keep in mind:

    - Comments rarely hurt. If you find an answer on Stack Overflow or in a blog post, add the link to a comment so future people know what’s up.
    - [normalize.css](http://necolas.github.io/normalize.css/) is a file that standardizes CSS defaults across browsers. We don’t currently use it in the Trello app (we should), but you should use it on new projects.
    - You can embed common images and files under 10kb using datauris. In the Trello web client, you can use `embed(/path/to/file)` to do this. This saves a request, but adds to the CSS size, so only use it on extremely common things like the logo.
    - Keep in mind our [supported browsers](https://trello.com/platforms) and check [caniuse.com](http://caniuse.com) to see if we support a new feature and whether you need a browser prefix or not.
    - Avoid body classes. There is rarely a need for them. Stick to modifiers within your component.
    - Explicitly write out class names in selectors. Don’t concatenate strings or use preprocessor trickery to build a class name. We want to be able to search for class names and that makes it impossible. This goes for `.js-` classes in JavaScript, too.
    - If you are worried about long selector names making our CSS huge, don’t be. Compression makes this a moot point.
  16. bobbygrace revised this gist Jan 19, 2015. 1 changed file with 1 addition and 3 deletions.
    4 changes: 1 addition & 3 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -154,12 +154,10 @@ For example, we want to specially style our sign up button among the header butt
    }
    ```

    We inherit all the `global-header-nav-item` styles and modify it with `.mod-sign-up`. This breaks our namespace convention and increases the specificity, but that’s exactly what we want. This means we don’t have to worry about the order in the file. For the sake of clarity, put it after the part of the component it modifies.
    We inherit all the `global-header-nav-item` styles and modify it with `.mod-sign-up`. This breaks our namespace convention and increases the specificity, but that’s exactly what we want. This means we don’t have to worry about the order in the file. For the sake of clarity, put it after the part of the component it modifies. Put modifiers on the same indention level as the selector it’s modifying.

    **You should never write a bare `.mod-` class**. It should always be tied to a part of a component. `.header-button.mod-sign-up { background: green; }` is good, but `.mod-sign-up { background: green; }` is bad. We could be using `.mod-sign-up` in another component and we wouldn’t want to override it. You shouldn’t have any global mods.

    Put modifiers on the same indention level as the selector it’s modifying.

    You’ll often want to overwrite a descendant of the modified selector. Do that like so:

    ```
  17. bobbygrace revised this gist Jan 19, 2015. 1 changed file with 24 additions and 8 deletions.
    32 changes: 24 additions & 8 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -29,7 +29,7 @@ There are nine _fascinating_ parts.

    > Use only imports, variables, and mixins (and only for vender-prefixed features) from CSS preprocessors.
    To keep our CSS readable, we try and keep our CSS very vanilla. We use LESS, but only use imports, data-uri, variables, and some mixins (only for vender-prefixed stuff). We use imports so that variables and mixins are available everywhere and it all outputs to a single file. We occasionally use nesting, but only for very shallow things like `&:hover`. Don’t use more complex functions like guards and loops.
    To keep our CSS readable, we try and keep our CSS very vanilla. We use LESS, but only use imports, data-uri, variables, and some mixins (only for vender-prefixed stuff). We use imports so that variables and mixins are available everywhere and it all outputs to a single file. We occasionally use nesting, but only for very shallow things like `&:hover`. We don’t use more complex functions like guards and loops.

    If you follow the rest of the guide, you shouldn’t need the complex functions in preprocessors. Have I piqued your interest? Read on…

    @@ -154,11 +154,27 @@ For example, we want to specially style our sign up button among the header butt
    }
    ```

    We inherit all the `global-header-nav-item` styles and modify it with `.mod-sign-up`. This breaks our namespace convention and increases the specificity, but that’s exactly what we want. This means we don’t have to worry about the order in the file. Although for the sake of clarity, put it after the part of the component it modifies.
    We inherit all the `global-header-nav-item` styles and modify it with `.mod-sign-up`. This breaks our namespace convention and increases the specificity, but that’s exactly what we want. This means we don’t have to worry about the order in the file. For the sake of clarity, put it after the part of the component it modifies.

    **You should never write a bare `.mod-` class**. It should always be tied to a part of a component. `.header-button.mod-sign-up { background: green; }` is good, but `.mod-sign-up { background: green; }` is bad. We could be using `.mod-sign-up` in another component and we wouldn’t want to override it. You shouldn’t have any global mods.

    Again, these have the same indention levels because they are on the same hierarchical level, not descendants.
    Put modifiers on the same indention level as the selector it’s modifying.

    You’ll often want to overwrite a descendant of the modified selector. Do that like so:

    ```
    .global-header-nav-item.mod-sign-up {
    background: hsl(120, 70%, 40%);
    color: #fff;
    .global-header-nav-item-text {
    font-weight: bold;
    }
    }
    ```

    Generally, we try and avoid nesting because it results in runaway rules that are impossible to read. This is an exception.


    ### State
    @@ -185,7 +201,7 @@ You’ll use a `.global-header-logo-image.is-loading` rule. That looks like this

    JavaScript defines the state of the application, so we’ll use JavaScript to toggle the state classes. The `.component.is-state` pattern decouples state and presentation concerns so we can add state classes without needing to know about the presentation class. A developer can just say to the designer, “This element has an .is-loading class. You can style it however you want.”. If the state class were something like `global-header-logo-image--is-loading`, the developer would have to know a lot about the presentation.

    Like modifiers, it’s possible that the same state class will be used on different components. You don’t want to override or inherit styles, so it’s important that **every component define its own styles for the state**. They should never be defined on their own. Meaning you should see `.global-header.is-hidden { display: none; }`, but never `.is-hidden { display: none; }`.
    Like modifiers, it’s possible that the same state class will be used on different components. You don’t want to override or inherit styles, so it’s important that **every component define its own styles for the state**. They should never be defined on their own. Meaning you should see `.global-header.is-hidden { display: none; }`, but never `.is-hidden { display: none; }` (as tempting as that may be).

    We also don’t indent state classes. Again, that’s only for descendants.

    @@ -194,7 +210,7 @@ We also don’t indent state classes. Again, that’s only for descendants.

    Components can be big or small: a whole header layout or just a button. In your templates, you’ll likely end up with parts of one component inside another component, like a `.button` inside a `.member-list`. We need to change the button’s size and positioning to fit the list.

    This is tricky. Components shouldn’t know anything about each other. If the smaller button can be reused in multiple places, add a modifier in the button component (like, `.button--small`) and use it in member-list. Do the positioning with a member list component with a descendant, since that’s specific to the member list and not the button.
    This is tricky. Components shouldn’t know anything about each other. If the smaller button can be reused in multiple places, add a modifier in the button component (like, `.button.mod-small`) and use it in member-list. Do the positioning with a member list component with a descendant, since that’s specific to the member list and not the button.

    Here’s an example:

    @@ -205,7 +221,7 @@ Here’s an example:
    <div class="member-list-item">
    <p class="member-list-item-name">Gumby</p>
    <div class="member-list-item-action”>
    <a href="#" class="button button--small”>Add</a>
    <a href="#" class="button mod-small”>Add</a>
    </div>
    </div>
    </div>
    @@ -219,7 +235,7 @@ Here’s an example:
    padding: 8px 12px;
    }
    .button--small {
    .button.mod-small {
    padding: 6px 10px;
    }
    @@ -264,7 +280,7 @@ A _bad_ thing to do would be this:
    }
    ```

    In the _bad_ example, `.member-list-item-button` overrides styles specific to the .button component. It assumes things about .button that it shouldn’t have to know anything about. It also prevents us from reusing the small button style and makes it hard to clean up later if needed.
    In the _bad_ example, `.member-list-item-button` overrides styles specific to the button component. It assumes things about button that it shouldn’t have to know anything about. It also prevents us from reusing the small button style and makes it hard to clean up later if needed.


    ## 3. JavaScript
  18. bobbygrace revised this gist Jan 19, 2015. 1 changed file with 2 additions and 4 deletions.
    6 changes: 2 additions & 4 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -183,11 +183,9 @@ You’ll use a `.global-header-logo-image.is-loading` rule. That looks like this
    }
    ```

    “Wait, isn’t state kinda like a modifier? Why not something like `.global-header-logo-image--is-loading`?“
    JavaScript defines the state of the application, so we’ll use JavaScript to toggle the state classes. The `.component.is-state` pattern decouples state and presentation concerns so we can add state classes without needing to know about the presentation class. A developer can just say to the designer, “This element has an .is-loading class. You can style it however you want.”. If the state class were something like `global-header-logo-image--is-loading`, the developer would have to know a lot about the presentation.

    JavaScript defines the state of the application, so we’ll use JavaScript to toggle the state classes. The `.component.is-state` pattern decouples state and presentation concerns so we can add state classes without needing to know about the presentation class. A developer can just say to the designer, “This element has an .is-loading class. You can style it however you want.”. If the state class were `global-header-logo-image--is-loading`, the developer would have to know a lot about the presentation.

    It’s likely the same state class will be used on different components. You don’t want to override or inherit styles, so it’s important that **every component define its own styles for the state**. They should never be defined on their own. Meaning you should see `.global-header.is-hidden { display: none; }`, but never `.is-hidden { display: none; }`.
    Like modifiers, it’s possible that the same state class will be used on different components. You don’t want to override or inherit styles, so it’s important that **every component define its own styles for the state**. They should never be defined on their own. Meaning you should see `.global-header.is-hidden { display: none; }`, but never `.is-hidden { display: none; }`.

    We also don’t indent state classes. Again, that’s only for descendants.

  19. bobbygrace revised this gist Jan 19, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -156,7 +156,7 @@ For example, we want to specially style our sign up button among the header butt

    We inherit all the `global-header-nav-item` styles and modify it with `.mod-sign-up`. This breaks our namespace convention and increases the specificity, but that’s exactly what we want. This means we don’t have to worry about the order in the file. Although for the sake of clarity, put it after the part of the component it modifies.

    **You should never write a bare `.mod-` class**. It should always be tied to a part of a component. `.header-button.mod-sign-up { background: green; }` is good, but `.mod-sign-up { background: green; }` is bad. We could be using `.mod-sign-up` in another component and we don’t want to could override it. You shouldn’t have any global mods.
    **You should never write a bare `.mod-` class**. It should always be tied to a part of a component. `.header-button.mod-sign-up { background: green; }` is good, but `.mod-sign-up { background: green; }` is bad. We could be using `.mod-sign-up` in another component and we wouldn’t want to override it. You shouldn’t have any global mods.

    Again, these have the same indention levels because they are on the same hierarchical level, not descendants.

  20. bobbygrace revised this gist Jan 19, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -156,7 +156,7 @@ For example, we want to specially style our sign up button among the header butt

    We inherit all the `global-header-nav-item` styles and modify it with `.mod-sign-up`. This breaks our namespace convention and increases the specificity, but that’s exactly what we want. This means we don’t have to worry about the order in the file. Although for the sake of clarity, put it after the part of the component it modifies.

    **You should never write a bare `.mod-` class**. It should always be tied to a part of a component. `.header-button.mod-sign-up { background: green; }` is good, but `mod-sign-up { background: green; }` is bad. We could be using `.mod-sign-up` in another component and we don’t want to could override it. You shouldn’t have any global mods.
    **You should never write a bare `.mod-` class**. It should always be tied to a part of a component. `.header-button.mod-sign-up { background: green; }` is good, but `.mod-sign-up { background: green; }` is bad. We could be using `.mod-sign-up` in another component and we don’t want to could override it. You shouldn’t have any global mods.

    Again, these have the same indention levels because they are on the same hierarchical level, not descendants.

  21. bobbygrace revised this gist Jan 19, 2015. 1 changed file with 31 additions and 28 deletions.
    59 changes: 31 additions & 28 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -1,28 +1,28 @@
    # CSS Guide
    # Trello CSS Guide

    “I perfectly understand our CSS. I never have any issues with cascading rules. Even though somebody else wrote this bit of CSS, I know exactly how it works and how to extend it. I know where to put new CSS. We use all of our CSS and it’s pretty small overall. I have a hard time breaking our CSS, even though I’m new. When I delete a template, I know the exact corresponding CSS file and I can delete it all at once. Nothing gets left behind.”

    You often hear updog saying stuff like this. Who’s updog? Not much, who is up with you?

    Having fun with this guide so far? I hope so. Unfortunately, this is where the fun ends. Now it’s time to get serious and talk about _rules_.

    Writing CSS is hard. Even if you know all the intricacies of position and float and overflow and z-index, it’s easy to end up with spaghetti code where you need inline styles, !important rules, unused cruft, and general confusion. “It works!” is not enough. This guide is here to provide some architecture for writing CSS so it stays clean and maintainable.
    Writing CSS is hard. Even if you know all the intricacies of position and float and overflow and z-index, it’s easy to end up with spaghetti code where you need inline styles, !important rules, unused cruft, and general confusion. This guide provides some architecture for writing CSS so it stays clean and maintainable for generations to come.

    There are nine _fascinating_ parts.

    1. Tools
    2. Components
    - Modifiers
    - State
    - Keeping It Encapsulated
    3. JavaScript
    4. Mixins
    5. Media Queries
    6. Utilities
    7. File Structure
    8. Style
    9. Miscellany
    - Performance
    1. [Tools](#1-tools)
    2. [Components](#2-components)
    - [Modifiers](#modifiers)
    - [State](#state)
    - [Keeping It Encapsulated](#keeping-it-encapsulated)
    3. [JavaScript](#3-javascript)
    4. [Mixins](#4-mixins)
    5. [Media Queries](#5-media-queries)
    6. [Utilities](#6-utilities)
    7. [File Structure](#8-file-structure)
    8. [Style](#8-style)
    9. [Miscellany](#9-miscellany)
    - [Performance](#performance)


    ## 1. Tools
    @@ -124,18 +124,16 @@ Components make it easy to see relationships between classes. You just need to l

    ### Modifiers

    > Use the `.component-descendant--modifier` pattern for modifier classes.
    > Use the `.component-descendant.mod-modifier` pattern for modifier classes.
    Let’s say you want to use a component, but style it in a special way. We run into a problem with namespacing because the class needs to be a sibling, not a child. Naming the selector `.component-descendant-modifier` means the modifier could be easily confused for a descendant. So instead of using a single hyphen, like `-descendant`, we’ll add two hyphens, like `--modifier`.
    Let’s say you want to use a component, but style it in a special way. We run into a problem with namespacing because the class needs to be a sibling, not a child. Naming the selector `.component-descendant-modifier` means the modifier could be easily confused for a descendant. To denote that a class is a modifier, use a `.mod-modifier` class.

    For example, we want to specially style our sign up button among the header buttons. We’ll add `--sign-up` to the end of `.global-header-nav-item`, making it `.global-header-nav-item--sign-up`.

    Which looks like this:
    For example, we want to specially style our sign up button among the header buttons. We’ll add `.global-header-nav-item.mod-sign-up`, which looks like this:

    ```
    <!-- HTML -->
    <a class="global-header-nav-item global-header-nav-item--sign-up">
    <a class="global-header-nav-item mod-sign-up">
    Sign Up
    </a>
    @@ -150,15 +148,17 @@ Which looks like this:
    transition: background 100ms;
    }
    .global-header-nav-item--sign-up {
    .global-header-nav-item.mod-sign-up {
    background: hsl(120, 70%, 40%);
    color: #fff;
    }
    ```

    We inherit all the `global-header-nav-item` styles and modify it with `.global-header-nav-item--sign-up`.
    We inherit all the `global-header-nav-item` styles and modify it with `.mod-sign-up`. This breaks our namespace convention and increases the specificity, but that’s exactly what we want. This means we don’t have to worry about the order in the file. Although for the sake of clarity, put it after the part of the component it modifies.

    **You should never write a bare `.mod-` class**. It should always be tied to a part of a component. `.header-button.mod-sign-up { background: green; }` is good, but `mod-sign-up { background: green; }` is bad. We could be using `.mod-sign-up` in another component and we don’t want to could override it. You shouldn’t have any global mods.

    Again, these have the same indention levels because they are on the same hierarchical level, not descendants. Modifier classes should appear after the general component part.
    Again, these have the same indention levels because they are on the same hierarchical level, not descendants.


    ### State
    @@ -366,12 +366,14 @@ Note that print is a media attribute, too. Keep your print rules inside componen
    Sometimes we need a universal class that can be used in any component. Things like floats, clear fixes, text decoration, vertical alignment, and text truncation. Denote these classes by prefixing them with `.u-`. For example:

    ```
    .u-float-left {
    float: left;
    .u-truncate-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    }
    ```

    All the utils should be in a single file and never appear with components or mixins.
    All the utils should be in a single file and never appear in components or mixins. There really shouldn’t be a huge need for utilities. Use them sparingly.


    ## 7. File Structure
    @@ -393,7 +395,7 @@ The file will look something like this:
    @import "component-4.less" // and so forth
    ```

    This should output a single `app.css` file (or something similarly named).
    This should output a single `app.css` file (or something similarly named). If we write components correctly, the order of the components should not matter.


    ## 8. Style
    @@ -436,6 +438,7 @@ Some additional things to keep in mind:
    - You can embed common images and files under 10kb using datauris. In the Trello web client, you can use `embed(/path/to/file)` to do this. This saves a request, but adds to the CSS size, so only use it on extremely common things like the logo.
    - Keep in mind our [supported browsers](https://trello.com/platforms) and check [caniuse.com](http://caniuse.com) to see if we support a new feature and whether you need a browser prefix or not.
    - Avoid body classes. There is rarely a need for them. Stick to modifiers within your component.
    - Explicitly write out class names in selectors. Don’t concatenate strings or use preprocessor trickery to build a class name. We want to be able to search for class names and that makes it impossible. This goes for `.js-` classes in JavaScript, too.
    - If you are worried about long selector names making our CSS huge, don’t be. Compression makes this a moot point.

    Some additional reading on CSS architecture around the web:
  22. bobbygrace created this gist Jan 19, 2015.
    458 changes: 458 additions & 0 deletions trello-css-guide.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,458 @@
    # CSS Guide

    “I perfectly understand our CSS. I never have any issues with cascading rules. Even though somebody else wrote this bit of CSS, I know exactly how it works and how to extend it. I know where to put new CSS. We use all of our CSS and it’s pretty small overall. I have a hard time breaking our CSS, even though I’m new. When I delete a template, I know the exact corresponding CSS file and I can delete it all at once. Nothing gets left behind.”

    You often hear updog saying stuff like this. Who’s updog? Not much, who is up with you?

    Having fun with this guide so far? I hope so. Unfortunately, this is where the fun ends. Now it’s time to get serious and talk about _rules_.

    Writing CSS is hard. Even if you know all the intricacies of position and float and overflow and z-index, it’s easy to end up with spaghetti code where you need inline styles, !important rules, unused cruft, and general confusion. “It works!” is not enough. This guide is here to provide some architecture for writing CSS so it stays clean and maintainable.

    There are nine _fascinating_ parts.

    1. Tools
    2. Components
    - Modifiers
    - State
    - Keeping It Encapsulated
    3. JavaScript
    4. Mixins
    5. Media Queries
    6. Utilities
    7. File Structure
    8. Style
    9. Miscellany
    - Performance


    ## 1. Tools

    > Use only imports, variables, and mixins (and only for vender-prefixed features) from CSS preprocessors.
    To keep our CSS readable, we try and keep our CSS very vanilla. We use LESS, but only use imports, data-uri, variables, and some mixins (only for vender-prefixed stuff). We use imports so that variables and mixins are available everywhere and it all outputs to a single file. We occasionally use nesting, but only for very shallow things like `&:hover`. Don’t use more complex functions like guards and loops.

    If you follow the rest of the guide, you shouldn’t need the complex functions in preprocessors. Have I piqued your interest? Read on…


    ## 2. Components

    > Use the `.component-descendant-descendant` pattern for components.
    Components help encapsulate your CSS and prevent run-away cascading styles and keep things readable and maintainable. Central to componentizing CSS is namespacing. Instead of using descendant selectors, like `.header img { … }`, you’ll create a new hyphen-separated class for the descendant element, like `.header-image { … }`.

    Here’s an example with descendant selectors:

    ```
    .global-header {
    background: hsl(202, 70%, 90%);
    color: hsl(202, 0%, 100%);
    height: 40px;
    padding: 10px;
    }
    .global-header .logo {
    float: left;
    }
    .global-header .logo img {
    height: 40px;
    width: 200px;
    }
    .global-header .nav {
    float: right;
    }
    .global-header .nav .item {
    background: hsl(0, 0%, 90%);
    border-radius: 3px;
    display: block;
    float: left;
    -webkit-transition: background 100ms;
    transition: background 100ms;
    }
    .global-header .nav .item:hover {
    background: hsl(0, 0%, 80%);
    }
    ```

    And here’s the same example with namespacing:

    ```
    .global-header {
    background: hsl(202, 70%, 90%);
    color: hsl(202, 0%, 100%);
    height: 40px;
    padding: 10px;
    }
    .global-header-logo {
    float: left;
    }
    .global-header-logo-image {
    background: url("logo.png");
    height: 40px;
    width: 200px;
    }
    .global-header-nav {
    float: right;
    }
    .global-header-nav-item {
    background: hsl(0, 0%, 90%);
    border-radius: 3px;
    display: block;
    float: left;
    -webkit-transition: background 100ms;
    transition: background 100ms;
    }
    .global-header-nav-item:hover {
    background: hsl(0, 0%, 80%);
    }
    ```

    Namespacing keeps specificity low, which leads to fewer inline styles, !important declarations, and makes things more maintainable over time.

    Make sure **every selector is a class**. There should be no reason to use id or element selectors. Everything in the class should be lowercase.

    Components make it easy to see relationships between classes. You just need to look at the name. You should still **indent descendant classes** so their relationship is even more obvious and it’s easier to scan the file. Stateful things like `:hover` should be on the same level.


    ### Modifiers

    > Use the `.component-descendant--modifier` pattern for modifier classes.
    Let’s say you want to use a component, but style it in a special way. We run into a problem with namespacing because the class needs to be a sibling, not a child. Naming the selector `.component-descendant-modifier` means the modifier could be easily confused for a descendant. So instead of using a single hyphen, like `-descendant`, we’ll add two hyphens, like `--modifier`.

    For example, we want to specially style our sign up button among the header buttons. We’ll add `--sign-up` to the end of `.global-header-nav-item`, making it `.global-header-nav-item--sign-up`.

    Which looks like this:

    ```
    <!-- HTML -->
    <a class="global-header-nav-item global-header-nav-item--sign-up">
    Sign Up
    </a>
    // global-header.less
    .global-header-nav-item {
    background: hsl(0, 0%, 90%);
    border-radius: 3px;
    display: block;
    float: left;
    -webkit-transition: background 100ms;
    transition: background 100ms;
    }
    .global-header-nav-item--sign-up {
    background: hsl(120, 70%, 40%);
    color: #fff;
    }
    ```

    We inherit all the `global-header-nav-item` styles and modify it with `.global-header-nav-item--sign-up`.

    Again, these have the same indention levels because they are on the same hierarchical level, not descendants. Modifier classes should appear after the general component part.


    ### State

    > Use the `.component-descendant.is-state` pattern for state.
    State classes show that something is enabled, expanded, hidden, or what have you. For these classes, we’ll use a new `.component-descendant.is-state` pattern.

    Example: Let’s say that when you click the logo, it goes back to your home page. But because it’s a single page app, it needs to load things. You want your logo to do a loading animation. This should sound familiar to Trello users.

    You’ll use a `.global-header-logo-image.is-loading` rule. That looks like this:

    ```
    .global-header-logo-image {
    background: url("logo.png");
    height: 40px;
    width: 200px;
    }
    .global-header-logo-image.is-loading {
    background: url("logo-loading.gif");
    }
    ```

    “Wait, isn’t state kinda like a modifier? Why not something like `.global-header-logo-image--is-loading`?“

    JavaScript defines the state of the application, so we’ll use JavaScript to toggle the state classes. The `.component.is-state` pattern decouples state and presentation concerns so we can add state classes without needing to know about the presentation class. A developer can just say to the designer, “This element has an .is-loading class. You can style it however you want.”. If the state class were `global-header-logo-image--is-loading`, the developer would have to know a lot about the presentation.

    It’s likely the same state class will be used on different components. You don’t want to override or inherit styles, so it’s important that **every component define its own styles for the state**. They should never be defined on their own. Meaning you should see `.global-header.is-hidden { display: none; }`, but never `.is-hidden { display: none; }`.

    We also don’t indent state classes. Again, that’s only for descendants.


    ## Keeping It Encapsulated

    Components can be big or small: a whole header layout or just a button. In your templates, you’ll likely end up with parts of one component inside another component, like a `.button` inside a `.member-list`. We need to change the button’s size and positioning to fit the list.

    This is tricky. Components shouldn’t know anything about each other. If the smaller button can be reused in multiple places, add a modifier in the button component (like, `.button--small`) and use it in member-list. Do the positioning with a member list component with a descendant, since that’s specific to the member list and not the button.

    Here’s an example:

    ```
    <!-- HTML -->
    <div class="member-list”>
    <div class="member-list-item">
    <p class="member-list-item-name">Gumby</p>
    <div class="member-list-item-action”>
    <a href="#" class="button button--small”>Add</a>
    </div>
    </div>
    </div>
    // button.less
    .button {
    background: #fff;
    border: 1ps solid #999;
    padding: 8px 12px;
    }
    .button--small {
    padding: 6px 10px;
    }
    // member-list.less
    .member-list {
    padding: 20px;
    }
    .member-list-item {
    margin: 10px 0;
    }
    .member-list-item-name {
    font-weight: bold;
    margin: 0;
    }
    .member-list-item-option {
    float: right;
    }
    ```

    A _bad_ thing to do would be this:

    ```
    <!-- HTML -->
    <div class="member-list”>
    <div class="member-list-item">
    <p class="member-list-item-name">Pat</p>
    <a href="#" class="member-list-item-button button”>Add</a>
    </div>
    </div>
    // member-list.less
    .member-list-item-button {
    float: right;
    padding: 6px 10px;
    }
    ```

    In the _bad_ example, `.member-list-item-button` overrides styles specific to the .button component. It assumes things about .button that it shouldn’t have to know anything about. It also prevents us from reusing the small button style and makes it hard to clean up later if needed.


    ## 3. JavaScript

    > Separate style and behavior concerns by using `.js-` prefixed classes for behavior.
    For example:

    ```
    <!-- HTML -->
    <div class="content-nav">
    <a href="#" class="content-nav-button js-open-content-menu">
    Menu
    </a>
    </div>
    // JavaScript (with jQuery)
    $(".js-open-content-menu").on("click", function(e){
    openMenu();
    });
    ```

    Why do we want to do this? The `.js-` class makes it clear to the next person changing this template that it is being used for some JavaScript event and should be approached with caution.

    Be sure to **use a descriptive class name**. The intent of `.js-open-content-menu` is more clear than `.js-menu`. A more descriptive class is less likely to conflict with other classes and it’s lots easier to search for. The class should almost always include a verb since it’s tied to an action.

    **`.js-` classes should never appear in your stylesheets**. They are for JavaScript only. Inversely, there is never a reason to see presentation classes like `.header-nav-button` in JavaScript. You will see state classes like `.is-state` in your JavaScript and your stylesheets as `.component.is-state`.


    ## 4. Mixins

    > Prefix mixins with `.m-` and only use them for browser polyfills.
    Mixins can get complicated fast. Simple-looking rules can get way out of hand when they’re including tons of nested rules. That’s why we only use mixins in for browser polyfills. Some CSS features still require a lot of browser-specific prefixes work, like gradients and box-shadow. Writing those over and over is error-prone. Use an `.m-` prefixed mixin to handle them. For example:

    ```
    // LESS
    .m-vertical-gradient (@topcolor: #999, @bottomcolor: #aaa) {
    background: @topcolor;
    background: -webkit-linear-gradient(top, @topcolor 0%, @bottomcolor 100%);
    background: linear-gradient(to bottom, @topcolor 0%, @bottomcolor 100%);
    }
    .component-descendant {
    .m-vertical-gradient(#fff, #f0f0f0);
    padding: 20px;
    }
    ```

    Be sure to check [caniuse.com](http://caniuse.com/) to see which prefixes you actually need for your polyfill.


    ### 5. Media Queries

    It might be tempting to add something like a `mobile.less` file that contains all your mobile-specific media queried rules. We want to avoid global media queries so that we can keep our components encapsulated. We want all media queries (and modifiers and states) to be in one component file so that when we delete a component down the line, we don’t have to look in multiple files to make sure we got everything related to it.

    We use LESS variables for media queries our media queries and include them in our components. Use a media-queries.less file like this:

    ```
    @highdensity: ~"only screen and (-webkit-min-device-pixel-ratio: 1.5)",
    ~"only screen and (min--moz-device-pixel-ratio: 1.5)",
    ~"only screen and (-o-min-device-pixel-ratio: 3/2)",
    ~"only screen and (min-device-pixel-ratio: 1.5)";
    @mobile: ~"only screen and (max-width: 529px)";
    @tablet: ~"only screen and (min-width: 530px) and (max-width: 949px)";
    @desktop: ~"only screen and (min-width: 950px) and (max-width: 1128px)";
    @desktop-xl: ~"only screen and (min-width: 1129px)";
    @print: ~"print”;
    ```

    To use a media query:

    ```
    // Input
    @media @tablet {
    .component-nav { … }
    }
    // Output
    @media only screen and (min-width: 530px) and (max-width: 949px {
    .component-nav { … }
    }
    ```

    This means we’re using the same breakpoints throughout. You don’t need to worry about CSS size. Repeated phrases like media queries are easily compressed. This practice was taken from [this CodePen from Eric Rasch](http://codepen.io/ericrasch/pen/HzoEx).

    Note that print is a media attribute, too. Keep your print rules inside components, too. We don’t want to forget about them.


    ## 6. Utilities

    > Prefix utility classes with `.u-`.
    Sometimes we need a universal class that can be used in any component. Things like floats, clear fixes, text decoration, vertical alignment, and text truncation. Denote these classes by prefixing them with `.u-`. For example:

    ```
    .u-float-left {
    float: left;
    }
    ```

    All the utils should be in a single file and never appear with components or mixins.


    ## 7. File Structure

    Include normalize.css at the top of the file. Then include variables, mixins, and utils (respectively). Each component should have its own file and include all the necessary modifiers, states, and media queries.

    The file will look something like this:

    ```
    @import "normalize.css"
    @import "media-queries.less"
    @import "variables-like-fonts.less"
    @import "other-variables-like-maybe-colors.less"
    @import "mixins.less"
    @import "utils.less"
    @import "component-1.less"
    @import "component-2.less"
    @import "component-3.less"
    @import "component-4.less" // and so forth
    ```

    This should output a single `app.css` file (or something similarly named).


    ## 8. Style

    Even following the above guidelines, it’s still possible to write CSS in a ton of different ways. Writing our CSS in a consistent way makes it more readable for everyone. Take this bit of CSS:

    ```
    .global-header-nav-item {
    background: hsl(0, 0%, 90%);
    border-radius: 3px;
    display: block;
    float: left;
    padding: 8px 12px;
    -webkit-transition: background 100ms;
    transition: background 100ms;
    }
    ```

    It sticks to these style rules:

    - Use a new line for every selector and every declaration.
    - Use two new lines between rules.
    - Add a single space between the property and value, for example `prop: value;` and not `prop:value;`.
    - Alphabetize declarations.
    - Use 2 spaces to indent, not 4 spaces and not tabs.
    - No underscores or camelCase for selectors.
    - Use shorthand when appropriate, like `padding: 15px 0;` and not `padding: 15px 0px 15px 0px;`.
    - When using vendor prefixed features, put the standard declaration last. For example: `-webkit-transition: all 100ms; transition: all 100ms;`. (Note: Browsers will optimize the standard declaration, but continue to keep the old one around for compatibility. Putting the standard declaration after the vendor one means it will get used and you get the most optimized version.)
    - Prefer hsl(a) over hex and rgb(a). Working with colors in code is easier with hsl, especially when making things lighter or darker, since you only have one variable to adjust.


    ## 9. Miscellany

    If you look at our CSS today, it looks nothing like this. We’ve always stuck to .js classes and often use namespaced-component-looking classes, but there is a mishmash of styles and patterns throughout. That’s okay. Going forward, you should rewrite section of the app according to these rules. Leave the world a better place.

    Some additional things to keep in mind:

    - Comments rarely hurt. If you find an answer on Stack Overflow or in a blog post, add the link to a comment so future people know what’s up.
    - [normalize.css](http://necolas.github.io/normalize.css/) is a file that standardizes CSS defaults across browsers. We don’t currently use it in the Trello app (we should), but you should use it on new projects.
    - You can embed common images and files under 10kb using datauris. In the Trello web client, you can use `embed(/path/to/file)` to do this. This saves a request, but adds to the CSS size, so only use it on extremely common things like the logo.
    - Keep in mind our [supported browsers](https://trello.com/platforms) and check [caniuse.com](http://caniuse.com) to see if we support a new feature and whether you need a browser prefix or not.
    - Avoid body classes. There is rarely a need for them. Stick to modifiers within your component.
    - If you are worried about long selector names making our CSS huge, don’t be. Compression makes this a moot point.

    Some additional reading on CSS architecture around the web:

    - [Medium’s CSS guidelines.](https://gist.github.com/fat/a47b882eb5f84293c4ed) I ~~stole~~ learned a lot from this.
    - [“CSS At…” from CSS Tricks](http://css-tricks.com/css/). This is a big list of CSS practices at various companies.
    - The BEM, or “block, element, and modifier”, methodology is similar to our components. It is well explained in [this CSS Wizardry article](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/) and some good context.


    ### Performance

    Performance probably deserves it’s own guide, but I’ll talk about two big concepts: selector performance and layouts/paints.

    Selector performance seems to matters less and less these days, but can be a problem in a complex, single-page app with thousands of DOM elements (like Trello). [The CSS Tricks article about selector performance](http://css-tricks.com/efficiently-rendering-css/) should help explain the important concept of the key selector. Seemingly specific rules like `.component-descendant-descendant div` are actual quite expensive in complex apps because rules are read _from right to left_. It needs to look up all the divs first (which could be thousands) then go up the DOM from there.

    [Juriy Zaytsev’s post on CSS profiling](http://perfectionkills.com/profiling-css-for-fun-and-profit-optimization-notes/) profiles browsers on selector matching, layouts, paints, and parsing times of a complex app. It confirms the theory that highly specific selectors are bad for big apps. Harry Roberts of CSS Wizardry also wrote about [CSS selector performance](http://csswizardry.com/2011/09/writing-efficient-css-selectors/).

    You shouldn’t have to worry about selector performance if you use components correctly. It will keep specificity about as low as it gets.

    Layouts and paints can cause lots of performance damage. Be cautious with CSS3 features like text-shadow, box-shadow, border-radius, and animations, [especially when used together](http://www.html5rocks.com/en/tutorials/speed/css-paint-times/). We wrote a big blog post about performance from the borderlands era [back in January 2014](http://blog.fogcreek.com/we-spent-a-week-making-trello-boards-load-extremely-fast-heres-how-we-did-it/). Much of this was due to layout thrashing caused by JavaScript, but we cut out some heavy styles like borders, gradients, and shadows, which helped a lot.