Skip to content

Instantly share code, notes, and snippets.

@nominalaeon
Created April 27, 2017 16:51
Show Gist options
  • Save nominalaeon/7f1b5731113c17a77f3103cba86a1671 to your computer and use it in GitHub Desktop.
Save nominalaeon/7f1b5731113c17a77f3103cba86a1671 to your computer and use it in GitHub Desktop.

Over the course of four articles, I'd like to cover my fairly rigid approach to writing CSS*. Like any other language, CSS is easier to read and introduce to new developers if it follows consistent patterns.

In Part One we'll cover general organization of basically everything that makes up a given element.

Part One: Organizing Attributes

Check out this overview for how ordering the contents of an element, and below I'll go over some reasoning for each one.

element {
    @extend .classname;         /** 1. Compiler method @extend */
    @include mixin-name();      /** 2. Compiler method @include */
                                
    background-color: $blue;
    position: relative;
    width: auto;                /** 3. Attributes */
    
    &:active { ... }
    &:hover { ... }             /** 4. Pseudo-classes */

    &::before { ... }           /** 5. Pseudo-elements */

    &.selector-class { ... }    /** 6. Self-same Classes */

    a { ... }
    h2 { ... }
    span { ... }                /** 7. Child Elements */

    .selector-class { ... }     /** 8. Child Classes */
}

Compiler methods

@extend

This is Sass's way of saying, "Copy all the attributes of this selector and paste it right here." It's like a mixin without any control over the outcome or a variable that gives you lots of CSS all at once. Most importantly, @extend is perfectly communicative. Here's a quick example:

.lipstick {
    font-style: italic;
    font-weight: 600;
    text-align: center;
}
.pig {
    @extend .lipstick;
}

/** .pig compiles as
.pig {
    font-style: italic;
    font-weight: 600;
    text-align: center;
}
*/

Keep @extend declarations at the very top so their specificity can be overpowered with attributes defined afterward.

@include

This is how we invoke a mixin. They often take arguments, but they can just as easily be used as factories to pump out blobs of attributes. Ideally they are used with arguments to return unique results for each caller's needs. If you're needing a way to hand over just a bunch of static attributes, I would argue that @extend is the more expressive way to do so.

@mixin alignment($direction) {
    float: $direction;
    text-align: $direction;
}
.pig {
    @extend .lipstick;
    @include alignment(left);
}

/** .pig compiles as
.pig {
    font-style: italic;
    font-weight: 600;
    text-align: center;
    float: left;
    text-align: left; /** value from @include will override @extend */
}
*/

Keep @include declarations second so they can overwrite any @extend declarations but still be in a position where their specificity can be overpowered.

Attributes

Alphabetize your attributes. Every modern text editor has extensions or plug-ins or even built in functionality to help if you're not already in the habit of alphabetizing. This convention should apply to pretty much anything nested below a selector, whether it's attributes or child elements. Alphabetizing is the most universally recognizable pattern for sorting pretty much anything.

In Part Two I will make the full case for alphabetization as well as explain exceptions to the rule.

Pseudo-classes

Pseudo-classes are selectors for an element's state. As long as you're defining your pseudo-classes after the extends, includes, and attributes, you're golden.

The order of these are not concrete, sometimes you'll need a :hover to be stronger than a :focus and vice versa, so it's really case by case. There aren't an overwhelming amount of pseudo-classes available so alphabetize when possible, otherwise order as needed to achieve the desired specificity.

See the full, official, curated-by-someone-else list of pseudo-classes at Mozilla Developer Network.

Pseudo-elements

You'll often be working with a max of two of these, ::before and ::after. I prefer to put ::before ahead of ::after but you'd have a hard time mucking up readability between these two. Keep their declarations after the pseudo-classes and that's good enough.

See the full, official, curated-by-someone-else list of pseudo-elements at Mozilla Developer Network.

The end

Stay tuned for Part Two where we'll go into alphabetizing. Parts Three and Four will cover naming conventions and how to nest selectors.

I want to conclude each article with this qualifier: there is value in personal and team habits. While this style guide is how I pattern CSS, nothing is more important than consistency with your team and yourself.

Thanks for reading!

* The modern workflow has virtually erased the line between CSS and Sass (...Less, Stylus, etc.), hence the abundant Sass examples in this "CSS" article.

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