10up / Engineering-Best-Practices

10up Engineering Best Practices
https://10up.github.io/Engineering-Best-Practices/
MIT License
760 stars 204 forks source link

CSS / SASS architecture using ITCSS or similar approach #242

Open samikeijonen opened 6 years ago

samikeijonen commented 6 years ago

Best practises have section for file structure, including CSS / SASS.

I'd still like to open new issue for CSS / SASS architecture which tries to take deeper dive why it matters a lot.

I've personally switched using ITCSS which aims to be scalable and maintainable architecture. I have found that very true.

As a front-end developer you have probably faced the issues with CSS:

ITCSS or any other architecture tries to solve these issues.

What is ITCSS

ITCSS stands for Inverted Triangle CSS and it helps you to organize your project CSS files in such way that you can better deal with (not always easy-to-deal with) CSS specifics like global namespace, cascade and selectors specificity.

In practise the idea is to separate CSS codebase to several sections (layers). Every sections add more spesifity to CSS in the right order.

Here is one example how it might look like. I have added comments what sections means.

/**
 * Main stylesheet for the theme.
 *
 * Theme styles follow http://cssguidelin.es/ and are organized according to
 * Inverted Triangle CSS (ITCSS) principles put forth by Harry Roberts. In
 * short, each layer of CSS gets more specific as you move down this page.
 */

/*--------------------------------------------------------------
# Settings - Global variables like fonts and colors.
--------------------------------------------------------------*/
@import "settings/core";
@import "settings/fonts";
@import "settings/colors";

/*--------------------------------------------------------------
# Tools - Default mixins and functions.
--------------------------------------------------------------*/
@import "tools/mixins";
@import "tools/font-size";

/*--------------------------------------------------------------
# Generic - Ground-zero styles (resets, box-sizing, etc.).
--------------------------------------------------------------*/
@import "generic/normalize";
@import "generic/box-sizing";

/*--------------------------------------------------------------
# Elements - Unclassed HTML elements (type selectors).
--------------------------------------------------------------*/
@import "elements/page";
@import "elements/blockquote";
@import "elements/buttons";
@import "elements/forms";
@import "elements/headings";
@import "elements/hr";
@import "elements/links";
@import "elements/lists";
@import "elements/media";
@import "elements/misc";
@import "elements/pre-code";
@import "elements/tables";

/*--------------------------------------------------------------
# Objects - Undecorated design patterns.
--------------------------------------------------------------*/
@import "objects/animations";
@import "objects/icons";
@import "objects/layouts";
@import "objects/list-reset";
@import "objects/wrappers";

/*--------------------------------------------------------------
# Blocks - Editor related styles.
--------------------------------------------------------------*/
@import "blocks/blocks";
@import "blocks/color-palette";

/*--------------------------------------------------------------
# Components - specific UI components.
--------------------------------------------------------------*/
@import "components/archives";
@import "components/comments";
@import "components/footer";
@import "components/front-page";
@import "components/galleries";
@import "components/header";
@import "components/media";
@import "components/navigation";
@import "components/pagination";
@import "components/posts-and-pages";
@import "components/search";
@import "components/widgets";

/*--------------------------------------------------------------
# Utilities - Helpers and overrides.
--------------------------------------------------------------*/
@import "utilities/accessibility";
@import "utilities/alignments";
@import "utilities/font-sizes";
@import "utilities/helpers";

The first three layers are pretty straightforward and very common steps.

The next layers are more interesting.

Elements - Unclassed HTML elements (type selectors).

Elements means bare HTML elements like a or blockquote. For example:

blockquote {
    border-left: 0.25rem solid;
    font-style: italic;
    margin: 0 0 $global-spacing-unit-4;
    padding-left: $global-spacing-unit-3;

    p {
        @include font-size(1.25rem);

        &:last-of-type {
            margin-bottom: 0;
        }
    }
}

HTML elements have lower specifity than classes and that's the reason why they are kept in their own layer at the top.

However I have done one exception where classes might be good idea in this layer. If the HTML element hold one or two rules it can have utility class in the same place. For example:

h1,
.h1 {
    font-size: var(--font-size-h1);
    line-height: var(--line-height-heading);
}

Objects - Undecorated design patterns

Object can be renamed as Layouts also. It can hold base Grid styles or wrapper max width styles etc. I sometimes struggle what to put here.

Blocks - Editor related styles

This layer is optional but demonstrates how we can add new layers anywhere we like and still maintain the sanity. In this example I have put all the Gutenberg Block styles in to it's own layer. These styles are outputted in the front-end and in the editor so everything Block based can be updated in the same place.

Components - specific UI components.

Most of the work happens in the components layer. These can overwrite any styles declared before without nesting at all. Not even one level of nesting which is a good thing of BEM naming convension.

Utilities - Helpers and overrides.

Utilities or helper classes should always come last so that they can overwrite any styles declared before. That's the purpose of helper classes :) For example:

.uppercase {
    text-transform: uppercase;
}

Conclusion

This is just one approach but at least for me helps organize styles without always fighting with CSS spesifity.

The main CSS or SASS file is also a documentation on it's own and helps developers to add styles in the right layer.

Vendor or Plugins folder would be one very common layer to add. In most cases this should be before Components layer.

Yet alone ITCSS is not a silver bullet. Projects needs guidelines how to write CSS / SASS and in many cases naming convention like BEM helps organizing component level styles. I can add own issues for those if needed.

JodiWarren commented 6 years ago

I thoroughly agree with this article. If a broad consensus is reached for it, we should ensure that https://github.com/10up/theme-scaffold is updated in this style to make it easy for people to follow the correct behaviour.

I don't specifically follow ITCSS, though reading this I probably should. The things that I keep in mind with SCSS/CSS organisation:

tlovett1 commented 6 years ago

This makes a lot of sense to me. Curious to hear @timwright12's opinion as well as others.

timwright12 commented 6 years ago

This falls under the "massive can of words" category. I actually use a general version of this methodology. We've approached the topic many times on the team and there is no consensus beyond agreement on the basic directory structure we now have in the scaffolding - and it took quite a long time to agree on that.

If the directory structure is clear and consistent, that's what's most important. We don't do micro-mangey things on the FE team unless there is something that is negatively affect projects, workflows, or onboarding.

joesnellpdx commented 6 years ago

I think adding something like this into best practices would be a good idea. Best practices often are not 'rules' but pattern suggestions to follow. I think having an explanation of structure like this would be helpful - especially for new hires.

Well done @samikeijonen !

timwright12 commented 6 years ago

I agree, if we can pull out some of the really specific items and tailor it more to best practice recommendations, it would be a good fit in the docs

samikeijonen commented 6 years ago

agreement on the basic directory structure we now have in the scaffolding

It's not that much about directory structure itself, or at least how to name them and what files to put inside them.

Instead it emphasise CSS architecture, structure, and which order CSS would be outputted. In other words there would be logical reason for everything.

I'm sure current approach in theme scaffold is already doing this but as a new dev here, I just didn't picked that up by reading the code.