npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

bem-sass

v1.0.0

Published

a Sass library for organizing CSS objects

Downloads

48

Readme

bem-sass

Bower version npm version Build Status

bem-sass is a Sass library for organizing CSS objects. It helps you apply BEM architecture to CSS you write with no compatibility issues with both RubySass(>= 3.4) and LibSass(>=3.3).

bem-sass is heavily inspired by Immutable CSS and ITCSS as well as the original BEM methodology. It is a pure Sass implementation of those concepts.

Quick Start

  • Install with Bower: bower install bem-sass --save-dev
  • Install with npm: npm install bem-sass --save-dev

Basic Usages

Once you import bem-sass to your project, you can simply build your own css object like below:


// Menu block

@include block(menu) {
  /*...the menu block styles are here...*/

  @include element(item) {
    /*...the menu item styles are here...*/
  }
  
  @include modifier(horizontal) {
    /*...the horizontal menu styles are here...*/
  }
}

When compiled:

.menu {
  /*...the menu block styles are here...*/
}

.menu__item {
  /*...the menu item styles are here...*/
}

.menu_horizontal {
  /*...the horizontal menu styles are here...*/
}

Configurations

You can configure bem-sass options by configure-bem-sass mixin. Using this mixin is optional. If there have been no custom configurations, the default options are exactly the same as below:

@include configure-bem-sass ((
  default-prefix: "",
  block-levels: (),
  element-sep: "__",
  modifier-sep: "_"
));

default-prefix

Set the default prefix for block mixin.

@include configure-bem-sass((
  default-prefix: "b-" // Set default block prefix to "b-"
));

/* Menu block */
@include block(menu) {
  /*...styles are here...*/
  
  @include element(item) {
    /*...styles are here...*/
  }
}

When compiled:

/* Menu block */
.b-menu {
  /*...styles here...*/
}

.b-menu__item {
  /*...styles here...*/
}

block-levels

Sometimes you may need to define several block types to organize your css object structure especially when you are considering a methodology like ITCSS. You can define your own several block levels by adding level-name(string): prefix(string) to block-levels map.

@include configure-bem-sass((
  block-levels: (
    object:    "o-",  
    component: "c-"
  )
));

/* Media object */
@include block(media, "object") {
  /*...styles are here...*/
}

/* Menu component */
@include block(menu, "component") {
  /*...styles are here...*/
}

When compiled:

/* Media object */
.o-media {
  /*...styles are here...*/
}

/* Menu component */
.c-menu {
  /*...styles are here...*/
}

element-sep, modifier-sep

You can set your own separators for element and modifier respectively.

@include configure-bem-sass((
  // Set separators like Medium.com
  element-sep: "-",
  modifier-sep: "--"
));

/* Promo block */
@include block(promo) {
  /*...styles are here...*/
  
  @include element(title) {
    /*...styles are here...*/
  }
  
  @include modifier(hero) {
    /*...styles are here...*/
  }
}

When compiled:

/* Promo block */
.promo {
  /*...styles are here...*/
}
.promo-title {
  /*...styles are here...*/
}
.promo--hero {
  /*...styles are here...*/
}

Extended Details

Boolean Modifier & Key-Value Modifier

bem-sass supports key-value modifiers. When using modifier, passing a single argument generates a boolean modifier, whereas passing 2 arguments generates a key-value modifier.

// @see https://en.bem.info/method/naming-convention/#block-modifier

@include block(menu) {
  
  /* Boolean modifier */
  @include modifier(hidden) {
    /*...the hidden menu styles are here...*/
  }
  
  /* key-value modifiers */
  @include modifier(theme, morning-forest) {
    /*...the morning-forest themed menu styles are here...*/
  }
  
  @include modifier(theme, stormy-sky) {
    /*...the stormy-sky themed menu styles are here...*/
  }
}
/* Boolean modifier */
.menu_hidden {
  /*...the hidden menu styles are here...*/
}

/* key-value modifiers */
.menu_theme_morning-forest {
  /*...the morning-forest themed menu styles are here...*/
}

.menu_theme_stormy-sky {
  /*...the stormy-sky themed menu styles are here...*/
}

Element Modifier

Elements could also get modified by their own modifiers.

// @see https://en.bem.info/method/naming-convention/#element-modifier

@include block(menu) {
  @include element(item) {
    /* Boolean modifier */
    @include modifier(visible) {
      /*...the visible menu item styles are here...*/
    }
    
    /* key-value modifier */
    @include modifier(type, radio) {
      /*...the radio type menu item styles are here...*/
    }
  }
}
/* Boolean modifier */
.menu__item_visible {
  /*...the visible menu item styles are here...*/
}

/* key-value modifier */
.menu__item_type_radio {
  /*...the radio type menu item styles are here...*/
}

Using Cascades in BEM

// @see https://en.bem.info/method/solved-problems/#using-cascades-in-bem

/* Nav block */
@include block(nav) {
  /*...the default nav styles are here...*/
  
  @include element(item) {
    /*...the default nav item styles are here...*/
  }
  
  @include modifier(theme, islands) {
    /*...the islands themed nav styles are here...*/
   
    @include element(item) {
      /*...the islands themed nav item styles are here...*/
    }
  }
}

When compiled:

/* Nav block */
.nav {
  /*...the default nav styles are here...*/
}

.nav__item {
  /*...the default nav item styles are here...*/
}

.nav_theme_islands {
  /*...the islands themed nav styles are here...*/
}

.nav_theme_islands > .b-nav__item {
  /*...the islands themed nav item styles are here...*/
}

Adjacent Sibling Elements in a Modifier

Given that you want to add a top line to each item of a modified nav block except the first item. With & provided by the original Sass, you cannot achieve this requirement. In that kind of circumstance, you can use adjacent-siblings mixin.

@include block(nav) {

  @include modifier(secondary) {

    @include element(item) {

      // Using & + & produces `.nav_secondary .nav__item + .nav_secondary .nav__item` which we do not expect.
      // Use `adjacent-siblings` here.

      @include adjacent-siblings {
        border-top: 1px solid rgb(0, 0, 0);
      }
    }
  }
}

When compiled:

.nav_secondary > .nav__item + .nav__item {
  border-top: 1px solid rgb(0, 0, 0);
}

Shared CSS Rules Between Elements

Given that nav__item and nav__link have common CSS rules. Since bem-sass enforces immutability on every BEM entity, it seems that the only way to avoid an inevitable code duplication is using Sass placeholder and @extend.

@include block(nav) { 

  %shared-rules { // <--- BAD: A placeholder inside block generates unwanted nested selectors
    display: inline-block;
    height: 100%;
  }

  @include element(item) {
    @extend %shared-rules; 
  }

  @include element(link) {
    @extend %shared-rules;
  }
}

But when compiled, this produces unexpected nested selectors like below:

.nav .nav__item,
.nav .nav__link {
  display: inline-block;
  height: 100%;
}

To avoid this, bem-sass provides def-shared-rules and shared-rules.

@include block(nav) {

  @include def-shared-rules("items") {
    display: inline-block;
    height: 100%;
  }

  @include element(item) {
    @include shared-rules("items");
  }

  @include element(link) {
    @include shared-rules("items");
  }
}
.nav__item,
.nav__link {
  display: inline-block;
  height: 100%;
}

Note that def-shared-rules and shared-rules should be inside of a block.

Caveats

Element and Modifier Cannot be used Stand-Alone

An element(or a modifier) is a part of a block. It has no standalone meaning without it's parent block.

// @see https://en.bem.info/method/key-concepts/#element
@include element(item) { // <-- BAD: element without it's block
  /*...CSS declarations here...*/
}

// @see https://en.bem.info/faq/#how-do-i-make-global-modifiers-for-blocks
@include modifier(theme, islands) { // <- BAD: modifier without it's block
  /*...CSS declarations here...*/
}

When compiled:

Error: element should be inside of a block
Error: modifier should be inside of a block

Avoid Elements Within Elements

The existence of elements of elements is an antipattern because it hinders the ability to change the internal structure of the block. bem-sass prevents you from creating those kind of invalid elements.

// @see https://en.bem.info/faq/#why-does-bem-not-recommend-using-elements-within-elements-block__elem1__elem2
@include block(nav) {
  @include element(item) {
    @include element(link) { // <--- BAD: Attempt to make an element within another element
    }
  }
}
Error: element should not be within another element

Keep BEM Entities Immutable

bem-sass ensures that every BEM entity you create is immutable. It prevents you from reassigning css classes which in turn produces side effects.

// Nav block
@include block(nav) {
  /*...CSS declarations here...*/ 

  @include element(item) {
    /*...CSS declarations here...*/ 
  }

  @include element(item) { //   <--- BAD: Attempt to reassign the nav item styles
    /*...CSS declarations here...*/ 
  }
}

@include block(nav) { // <--- BAD: Attempt to reassign the nav block styles
  /*...CSS declarations here...*/ 
}
Error: in `element': Attempt to reassign `.nav__item` 
Error: in `block': Attempt to reassign `.nav`

The Order of Block Levels Matters

Note that the order of your block levels is important. For example, the following will cause an error:

/* Menu component */  
@include block(menu, "component") { //  <--- BAD: `component` is ahead of `object`
  /*...styles are here...*/
}

/* Media object */
@include block(media, "object") {
  /*...styles are here...*/
}
Error: the `object` level block `media` should not be behind of any `components` level blocks. Your block levels are: object, component

See Also

  • https://en.bem.info/
  • https://css-tricks.com/snippets/sass/bem-mixins/
  • http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/
  • https://speakerdeck.com/dafed/managing-css-projects-with-itcss