May 3, 2020
Estimated Post Reading Time ~

Sass Best Practices for Adobe Experience Manager (AEM) based websites

Most of the front end developers are aware of the difficulties of having a single CSS file which is having hundred and hundred of lines, usually duplicated styles more than the required ones. In such cases, the front-end developers would be struggling to handle priority, specificity which finally ends up into a stage of maintenance hell.

Thanks to CSS preprocessors like LESS /SASS which has revolutionized vanilla CSS. Those who start learning and using them used to have a common opinion that they would never want to go back.

As with any other technology, Sass needs best practices for writing a reusable and extendable codebase which helps a front-end team to deal with CSS in a structured and professional manner. This article is all about that from my personal experience with front-end development and reading from other blogs like Sass Guidelines

Folder and File Organization
Folder structuring is the best place to start with Sass development. This is one of the key factor which help to categorize the style sheets instead of dumping all files in one place. Here is a sample folder structure which we followed to categorize our style sheets and to keep in sync with AEM component based developmentsass
|
|– core-components/
| |– _button.scss
| |– _colors.scss
| |– _globals.scss
| |– _mixins.scss
| |– _parallax.scss
| |– _typography.scss
| |– _variables.scss
| |– core.scss
| … # Etc…
|
|– components/
| |– _accordian.scss
| |– _section-type1.scss
| |– _section-type2.scss
| |– _section-type3.scss
| … # Etc…
|
|– pages/
| |– home.scss
| |– contact-us.scss
| … # Etc…
|
|– themes/
| |– _theme1.scss
| |– _theme2.scss
| |– theme-all.scss
| … # Etc…
|
|– animations/
| |– _ripples.scss
| … # Etc…

Let's go through each folder to understand the purpose of each folder.

/core-components
The core-components folder holds the styles which are common for all the pages. There is only one Sass file at the root level(ie core.scss). All the other files are prefixed with an underscore (_) to tell Sass that they are partials. Those partial will not be compiled to .css files. Here it is the core.scss file’s role to import and merge all of them into core.css.

Here is an excellent definition of partials from the Sass website itself.

“You can create partial Sass files that contain little snippets of CSS that you can include in other Sass files. This is a great way to modularize your CSS and help keep things easier to maintain.”

/components
The core-components folder holds the styles(partials) which are supposed to be imported into *pages.scss files as and when required. The components like ‘section-hero’, section-banner, ‘section-feature’ are selected to match those of the components defined by AEM

/pages
It is the *page.scss files role to import partials available in the components folder and animation folder. Ideally, pages should be just a collection of components. Any of the page-specific styles or those which need to be overridden at the page level can also be there in these files. The advantage here is that only those style(components) required for a particular page will be loaded which in-turn improves performance and reduce bandwidth usage.

/themes
This folder holds all the theme-related style sheets in the form of partials
The theme-all.scss file’s role is to import all these theme partial files.

/animations
This folder holds all the animation-related partial style sheets

Modularization
Due to its ability to import multiple .scss files and compile them into one .css file, it is super easy to bring in modularization and better maintainability in sass based projects. It also allows multiple developers to work on the same pages of a website with-out much issues/conflicts. A typical sample follows

/* Variables */
@import '../core-components/mixins';
@import '../core-components/colors';
@import '../core-components/variables';

/* components */
@import '../components/widget';
@import '../components/section-type1';
@import '../components/section-type2';

Colors
This file can be used to store all the colors which are used across the website. A typical sample follows

/* Style Guide Colors */
$green: #1F4212;
$light-white: #FBFBFB;
$cool-blue: #4D8DAB;
$dark-sky-blue: #66ACEE;
$greyish-brown: #363636;

/* shades */
$black: #000000;
$white: #FFFFFF;
$transparent: transparent;

Variables
This file is used to store a lot of information(ie those may vary) during the course of website development, UI reviews, etc. This really helped us a lot as changing a variable in one place, reflects those changes globally. The best practice is never to use a color value directly in any of the style sheets except in variable.scss.

/* Colors */
$primary-color: $white;
$secondary-color: $greyish-brown;

/* Background */
$primary-bg-color: $primary-color;
$secondary-bg-color: $light-white;

/* Buttons */
$button-color: $primary-color;
$button-background: $blue;

/* Section Hero */
$section-type1-background: $black;
$section-type1-headline-color: $primary-color;

Typography
It is this file that helped to controls the typography across the entire website. The best practice is that anything related to font-size, font-weight, etc has to be defined in this file so that any change later has do done only in this file and would have a global effect. Follows is a sample of this file

/* Text Styles */
.text-style {
    font-size: 2.813rem; //40px
    font-weight: normal;
    line-height: 1.01;
    text-align: center;
    color: $color-ts;
    @media #{$medium-only} {
        font-size: 2rem;
    }
    @media #{$small-and-down} {
        font-size: 1.233rem;
        line-height: 1.02;
    }
}

Mixins
They are a collection of attributes that can be imported. The best practice is that static codes should not be defined as mixins, but dynamic values passed as attributes can be used. Follows is a sample of this file

@mixin opacity($opacity) {
    opacity: $opacity;
    $opacity-ie: $opacity * 100;
    filter: alpha(opacity=$opacity-ie); //IE8
}
@mixin boxsizing($box-model) {
    -webkit-box-sizing: $box-model; // Safari <= 5
    -moz-box-sizing: $box-model; // Firefox <= 19
    box-sizing: $box-model;
}

Nesting
This is an interesting feature, but if not used judiciously can result in .css code which has too much specificity than required and hence less performance. The best practice is that
  • Avoid nesting more than 3 levels.
  • Define a class which is small and reusable.
  • Use nesting if really required, not to match HTML structure.
Media Queries
The best practice is that make use of the Sass feature to nest media queries. The following is a sample snippet.

/* Text Styles */
.text-style {
    font-size: 2.813rem; //40px
    font-weight: normal;
    line-height: 1.01;
    text-align: center;
    color: $color-ts;
    @media #{$medium-only} {
        font-size: 2rem;
    }
    @media #{$small-and-down} {
        font-size: 1.233rem;
        line-height: 1.02;
    }
}

This helps in solving many issues like
  • Re-writing the selectors somewhere else
  • The rules which are over-riding are visible there itself, which is usually not the case when they are defined at the bottom of the file or in a different file
For Adobe Experience Manager(AEM) Compatibility
Define generic style for H tags(H1, H2 through H6 ), P tags, A tags, etc so that all those pages where ever authoring is enabled, will have better flexibility for AEM based website development as the AEM development don't need to track .css class with-in the authorable sections. A sample snippet follows

/* Text content - body text*/
.text-content {
    font-size: 1.25rem; //20px
    line-height: 2;     //40px
    font-weight: $font-weight-regular;
    color: $text-content-color;
    @media #{$small-and-down} {
        font-size: 1.067rem; //16px
        line-height: 1.11; //20px
    }
    p {
        word-break: break-word;
        @media #{$small-and-down} {
            font-size: 1.067rem; //16px
            line-height: 1.63; //26px
        }
    }
    ul {
        padding-left: 1.563rem;
        box-sizing: border-box;
        @media #{$small-and-down} {
            font-size: 1.067rem; //16px
            line-height: 1.63; //26px
        }
    }
    a {
        font-size: 1.25rem; //20px
        font-weight: $font-weight-regular;
        color: $color-link;
        @media #{$small-and-down} {
            font-size: 1.067rem; //16px
            line-height: 1.63; //26px
        }
    }
}
/* H Tags */
h1 {
    font-size: 2.813rem; //45px
    line-height: 1.07; //48px
    font-weight: $font-weight-regular;
    color: $color-h1;
    &.light {
        font-weight: $font-weight-light;
    }
    @media #{$small-and-down} {
        font-size: 1.733rem; //26px
        line-height: 1.08; //28px
    }
}
h2 {
    font-size: 2.25rem; //36px
    line-height: 1.22; //44px
    font-weight: $font-weight-light;
    color: $color-h2;
    @media #{$small-and-down} {
        font-size: 1.6rem; //24px
        line-height: 1.08; //26px
    }
}

Wrap-It-Up
Sass is relatively a new technology and we all may continue learning and adopting new best practices with it. Sass does not do anything which we don’t ask it to do, so blaming that Sass results are too bloated is just that we wrote bloated code. So we all may follow the best practices so that the final CSS output is the best.

The ideal way to learn these best practices is to apply those into our projects and see what really works. Over time, we could decide what is more beneficial than others, in which case we may keep whatever works and skip what doesn’t. Let me know if you have any thoughts, advice, etc. in the comments section.


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.