< More articles

How Does One Inherit BEM styles?

October 26, 2016

At work, we follow the BEM methodology in naming our HTML elements and CSS styles. But we’ve been struggling with the best way to inherit styles from similar blocks. As with many things in programming, there’s great documentation to get you started, but the next level is up to you.

From my research, there seems to be three primary behaviors for inheriting styles:

Option 1: Extend all the options

This method expects you to create bite-sized components you will extend in classes:

.button--submit {
  @extend %button;
  @extend %button--large;
  @extend %button--blue;
}

Option 2: Extend the parent

This method inherits the parent on every option:

%icon {
  content: '';
  display: block;

  &--pins {
    @extend %icon;
    background-image: url('../img/pins.svg');
  }
}

Option 3: Extend is evil

It seems there’s a group of developers that thinks @extend is a bad thing. They suggest mixing in components.

@mixin center($max-width) {
  max-width: $max-width;
  width: 100%;
  margin: 0 auto;
}

.container {
  @include center(1200px);
}

What about the next level?

These three methods have different merits that I can appreciate, but it seems to me things get much harder when you have blocks that are similar and should inherit styles from other blocks.

Would it be better to inherit from each component, or mix it all in?

In our most recent project, we’re attempting extending each class within a block, similar to below:

The base element:

// _listed-item.scss
%listed-item {
  background-color: $grey-light;
  margin: 2em 0;
  width: 100%;

  &__image-link {
    display: block;
    text-align: center;
  }

  &__image {
    background-position: center center;
    background-repeat: no-repeat;
    background-size: cover;
    height: 100%;
    width: 100%;
  }
}

One use:

// _paginated-story.scss
.paginated-story {
  @extend %listed-item;
  padding: 1em;

  &__image-link {
    @extend %listed-item__image-link;

    // Specific to .paginated-story
    color: $story-color;         
  }

  &__image {
    @extend %listed-item__image;
  }
}

Another use:

// _event-listing.scss
.event-listing {
  @extend %listed-item;

  &__image-link {
    @extend %listed-item__image-link;

    // Specific to .event-listing
    color: $event-color;
  }

  &__image {
    @extend %listed-item__image;
  }

What I like about this approach is that it’s easier to see what gets pulled in (and is different) from the base class. It was more challenging than I anticipated to create the base class out of an already existing class, but it might get easier with practice. On top of that, I think the result might be more friendly to a developer who would be less familiar with the code.

But I wonder if it might be better to leverage the @mixin directive. It’ll be easier to see what is different from the inherited class and it would have less “boilerplate”, but it would require opening up another sass file to understand what’s going on.

.paginated-story {
  @mixin listed-item($link-color: $story-color);
  padding: 1em;
}
.event-listing {
  @mixin listed-item($link-color: $event-color);
}

How about you?

As I said, we’re trying to figure this out. What do you do? What are your pain points? Is there another option you’d recommend? Please, let me know.

< Check out other articles