Thursday, December 26

Combining the Powers of SEM and BIO for Improving CSS

 
CSS is easy, some might argue, but that “easiness” can cause messy code. This is especially true through power of preprocessors like Sass or Less where, if you aren’t careful, your CSS can become harder to deal with instead of easier. Sass? Harder? This Gist shows a great example of Sass nesting hell.

If your Sass code looks like that, you can definitely improve your code with SEM & BIO, a CSS technique I’ll introduce you to now!

In this article, I am going to use the code example below to explain how SEM and BIO works and how they can help enhance your CSS strategy.

See the Pen by thebabydino (@thebabydino) on CodePen.

Generally, SEM is concerned with high level CSS philosophy whereas BIO is an actual technique to help you write better CSS to achieve SEM. The main purpose of both SEM and BIO is to better handle the CSS specificity which is one of the most important concepts you should understand for CSS.

Credit: Nana Jeon

First of all, let’s talk about SEM.

SEM

SEM stands for:

  • Scalable
  • Extensible
  • Maintainable

Trying to achieve those three factors can definitely improve your CSS code and it helps you build your components much more solid.

Let’s talk more about each factor in detail.

Scalable

A scalable (or reusable) component means that the same looking components should be used wherever you want without making any coding changes.

Credit: Nana Jeon

From the CodePen example above, the “Search” button in the header looks exactly same as the ‘Link’ button in the sidebar. When we compare the HTML markup,

  • the “Search” button is <button> element
  • but the “Link” button is <a role="button" ...> element

…and even if the markup is different, the styles are identical by using the same classes: .c-btn and .c-btn--yellow.

The button styles are scalable and it allows you to add the same looking components anywhere you want as it won’t be polluted by its parents or siblings. This can save you from the big headache of not knowing why totally unrelated components are broken even if the changes are made on a different component from a totally different place.

Source: Cartoon Network

Extensible

An extensible component can easily provide additional features/functionalities without breaking itself or having to be written from scratch.

Let’s look at the CodePen example again.

See the Pen by iamryanyu (@iamryanyu) on CodePen.

The button in the header and in the main section look quite similar besides the 3D effect. In this case, instead of creating two different sets of buttons having totally different code bases, we could extend the plain button style by just adding the 3D effect to it.

It goes the same with the button in the footer. Even though the button has a different color and size, we could easily extend it by adding or removing new or different features.

Credit: Nana Jeon

Maintainable

Probably one of the biggest challenges for most front-enders is to understand CSS written by other people, or our past selves. We sometimes spend more time trying to understand the existing code than adding awesomely-written new code.

The issue usually comes from:

  • no comments, whatsoever
  • over-engineering
  • no single source of truth
  • no coding standard/best practice considered
  • or all of them above
Credit: Nana Jeon

With SEM and BIO, we can definitely improve the code and save others (including ourselves!) from messy, unmaintainable code.

BIO

There are many great techniques out there to improve the way we write CSS, and from my experience, I found the following three techniques that make up the BIO acronym work very well together

  • BEM
  • ITCSS
  • OOCSS
Credit: Nana Jeon

A lot of developers/engineers already know those famous techniques but I would like to go through each of them and talk about the way I use those techniques.

BEM

BEM is very popular methodology and it has been helping us significantly improve the way we think about CSS and Sass/Less.

BEM stands for:

  • Block
  • Element
  • Modifier
Credit: Nana Jeon

As the bad example above shows, we tend to overuse the power of Sass/Less and falling into nesting-hell. But with BEM, we start to have a very low CSS specificity by maintaining the styles in one (or two) levels of nesting.

If you’ve experienced any battles fighting higher CSS specificity, you will know how painful it is to come out a winner.

Going back to our example, the HTML markup looks like this:

<div class="o-grid">
  <div class="o-grid__item o-grid__header">
    ...
  </div>
  <div class="o-grid__item o-grid__main">
    ...
  </div>
  <div class="o-grid__item o-grid__sidebar">
    ...
  </div>
  <div class="o-grid__item o-grid__footer">
    ...
  </div>
</div>

The example consists of:

  • a block: .o-grid
  • elements: .o-grid__item, .o-grid__header, .o-grid__main, .o-grid__sidebar, .o-grid__footer

Because BEM provides a naming convention that stresses unique classes, we don’t have to go into deep nesting like:

.o-grid {
  .o-grid__item {
    ...
  }
}

Instead, we can define the styles it with fewer levels:

.o-grid__item {
  ...
}

This is the biggest merit of BEM; lowering the CSS specificity which improves the whole CSS coding efficiency and experience.

One issue I still see occasionally even with BEM is poor naming. If you don’t pay enough attention, you can wind up with a really long class nam like:

/* Yikes! */
.o-grid__item-search-button-text-svg-icon {
  ...
}

When you create a class name, go with the core concept of BEM: your component is a block and all elements inside are individually attached to the block.

From our example again, I named .o-grid__form instead of .o-grid__item-form because the form itself is a separate component and doesn’t have to be tied with and be a child of o-grid__item.

Also, to more efficiently control styles, I have added another class name o-grid__header along with o-grid__item to extend the styles. Moreover, the button contains BEM-styled classes with the approach of OOCSS, which we’ll touch on next.

OOCSS

As we have already discussed, there are many great CSS methodologies and strategies helping us improve the way we write CSS. However, I see a lot of folks forcing themselves to decide on one methodology to use out of the bunch.

From my experience, combining methodologies can actually enhance their benefits by combining the best of multiple worlds. For example, I personally have found that BEM and OOCSS work very well together.

OOCSS stands for Object Oriented CSS and you can think of it working like Lego blocks:

Source: Flickr

OOCSS creates each individual part separately and then constructs them together in order to build components.

From our example, I have created buttons using the OOCSS naming convention:

  • .c-btn
  • .c-btn--yellow
  • .c-btn--blue
  • .c-btn--3d
  • .c-btn--large

To render the yellow search button in our example header, we combine these classes:

  • .c-btn
  • .c-btn--yellow

If we want to have the 3D button in the main section, we add in the 3D class, .c-btn--3d and call it a day.

And for the blue button in the footer, we can switch the yellow modifier to blue along with the large modifier. As you can see, the button is not depending on the header block giving us greater flexibility with how we use and repurpose components. And, by doing so, we can construct the buttons without impacting any other components or patterns while gaining the benefit of easily extending new presentational feature, like alternative colors and shapes.

Here example of a button collection created using OOCSS to create the variations:

See the Pen Modern Button Collection by Ryan Yu (@iamryanyu) on CodePen.

On top of BEM and OOCSS, with the help of ITCSS, we can further improve our CSS strategy. Let’s look at that method next.

ITCSS

ITCSS stands for Inverted Triangle CSS and it helps organize CSS by applying a structure that determines how specific to get with a specific component. Lubos Kmetko has written an excellent overview of ITCSS that is worth reading.

You can see how I have put ITCSS to use by splitting styles up by grouped levels of specificity in this Gist.

Based on that example, you can see how I named components by adding a namespace to the class. So, for example, a the “button” component is prefixed with a “c” (.c-button) to indicate the component status and prevent it from being mistaken for another item. By doing so, everyone working on the project knows the function of that specific class and how changing its properties might affect other areas.

Here’s a visual that illustrates all the ITCSS levels:

Let’s go through each section.

Settings

Settings are generally a collection of variables that do not generate CSS, but are applied to classes. Some examples include:

  • Base
  • Color
  • Typography
  • Animation
Tools

Tools also will not produce any CSS yet and are typically preprocessor functions that help write or extend properties on classes:

  • Functions
  • Placeholders
  • Mixins
  • Media queries
Vendors

Vendors are third-party styles that are being used on a project. Think of things like reset.css, normalize.css, or even Foundation and Bootstrap.

The reason these styles are higher up in the structure is so we can override them if needed. As you may recall, if the same class is called twice, the cascade will render the properties of the second instance, assuming the properties are exactly the same:

.btn--large {
  padding: 3em;
}

/* This one wins out */
.btn--large {
  padding: 5em;
}

Just for the side note, in Sass, you can use ~ to point to the node_modules folder so you are able to import style assets from the source rather than having to move it into your own directories.

@import '~modern-normalize/modern-normalize';
Objects

Objects (namespace: o-) are used for design patterns, such as layouts, where items are being arranged rather than decorated. Object classes are used across all pages, so if you make any changes to the object classes, you should be very careful because any changes are going to affect each and every page throughout the website.

The most common object classes I use are:

  • .o-page: the most outer container which usually contains max-width: 100vw and overflow: hidden.
  • .o-main: the outer container for the main area.
  • .o-container: the outer container for components and it usually provides a fixed width.
  • .o-content: in case if any extra configuration is needed for the actual content area.
  • .o-grid: if a grid layout with different number of columns are required.

Do you use any other object classes? If so, please share with me. ?

Elements

Elements (namespace: e-) are the HTML native elements which we would not style based on the class names. For example, we should provide default styles to <a> element rather than .link class.

// Do this for the default link style
a {
  text-decoration: none;

  &:hover {
    background-color: blue;
    color: white;
  }
}

// Don’t provide the default link style to a class
.link {
  text-decoration: none;

  &:hover {
    background-color: blue;
    color: white;
  }
}

It is because, especially in a CMS like WordPress, you wouldn’t want to add a class every single time you want to use a link in content. Hence, we provide a default style to the <a> element so without any class, the link will still have good-looking styles.

Components

A component (namespace: c-) is a small feature that makes up a part of the website. Think buttons, accordions, sliders, modal dialogs, etc. Each component is fully functional by itself and does not rely on any other components. This fact should be considered when you name the component.

For example, the button in the main section from the example above shouldn’t be called .c-main-button because main scopes it inside the main section and limits the use of it in other places, like a sidebar. Something like .c-btn is much nicer because the button is no longer tied to any other specific sections of the page.

If you need any extra features, you can always extend properties with a BEM modifier (combining powers!) or use Scope, which is coming up in a bit.

Patterns

A lot of developers/engineers use the terms component and pattern synonymously and that’s totally fine if you are more comfortable with that. It is just my preference to separate those two terms.

For a general rule of thumb, I think of a pattern (namespace: p-) as a combination of components but in a way that is not scaleable.

For example, I would consider the accordion as a component. It is scaleable and reusable on its own, meaning that it can be used in other parts of the website without making any changes even if the accordion would contain other components such as buttons.

On the other hand, the header, for example, would be a pattern because it is not scaleable (the header cannot be used in the content or sidebar area) and also contains other components such as buttons, accordions, menus, logos, search form etc.

Scope

Be warned; I only use the scope if it’s absolutely necessary. The purpose of the scope (namespace: s-) is to give us the highest specificity so we can overwrite any styles for a specific purpose.

Remember, If you find yourself using the scope class many times, you might be writing styles that are too specific and you should consider refactor your CSS structure.

Here is a simple example of the use of the scope class, .s-home.

.c-accordion {
  .s-home & {
    // Changing the background color specically on the homepage
    background-color: tomato;
  }
}

As a side note, the above example could actually be refactored by providing a modifier to the accordion (e.g., .c-accordion--bg-tomato) instead of using the scope class. That would be a much more extensible way of writing and make the component more modular.

Extra Namespace

On top of the namespaces we discussed above, there are two more I often use:

  • is-: this indicates the state of the block or element. Most commonly used class is .is-active, like the active link in navigation.
  • js-: this indicates that the specific element is bound to JavaScript events. For example, js-menu-click indicates that the element is bound to the click event.

Linting

Finally making rules with .stylelint and .eslint can significantly improve the code quality.

In the frontend workflow, I don’t make it as a recommendation; I make it mandatory so that failing of the rules won’t get approved.

In this way, we can ensure that the coding quality stays at its best and provide better code to other developers, including your future self.

In Action

In this section, I’d like to discuss how we could use SEM and BIO. I have made a simple, practical example to get us started:

See the Pen by iamryanyu (@iamryanyu) on CodePen.

The main practice with the example is to build an accordion that can be used as:

  • a normal accordion but with different color themes in the main section
  • a menu in the sidebar
  • a block displaying social media icons in the footer

What we’re achieving is a component that is:

  • Scalable: as it can be added in any part of the page without any coding changes
  • Extensible: as it can serve different functionalities with the core functions unchanged
  • Maintainable: as it is organized in a way that makes sense

To achieve SEM, BIO has been used including:

  • BEM: .c-accordion as a block and its children as elements, also used modifiers, e.g., .c-accordion--light and .c-accordion--dark
  • ITCSS: The ordering/sorting of SASS files handles the CSS specificity quite well. For example, the accordion button in the sidebar contains class="c-accordion__trigger p-sidebar-menu__button" which the pattern (p-) overwrites the component (c-) with no issues.
  • OOCSS: the accordion is constructed with several classes, for example, class="c-accordion c-accordion--dark c-accordion--single" which creates a dark theme with opening a single panel only each time.

Final thoughts

I have used this approach for almost all of my projects including universities, government departments, commercial retailers, and many other websites. In each case, I have successfully delivered all of the projects to the clients (almost no issues during the client approval stage and delivered on time); this approach has worked for me very well so far and I think it could for you as well.

That being said, technologies always change (especially on the front end) and I am more than happy to hear and discuss any of your ideas/approaches/strategies that worked for you. Let me know in the comments!

Source: css-tricks.com

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x