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-scss

v0.0.5

Published

BEM helpers for scss

Downloads

19

Readme

BEM-scss Bower version npm version Build Status

SCSS 사용 시, BEM 컨벤션을 좀 더 편리하게 적용하기 위해 만들었다. 프로젝트에 부작용 없이 BEM block type을 추가할 수 있도록 하고, Ruby Sass(>=3.4), LibSass(>=3.3) 양측에서 모두 문제 없이 컴파일링 되도록 하는 것을 목적으로 했다.

Quick Start

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

BEM-scss를 프로젝트 SCSS에 불러온 후, 최 상단에 configure-BEM을 설정한다.

@import "dist/BEM-scss";
@include configure-BEM;

Basic Usages

BEM-scss가 지원하는 기본들을 활용해 아래와 같은 SCSS code를 작성할 수 있다.

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

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

이것은 아래와 같은 css로 컴파일 된다.

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

.menu__item {
  /*...the menu block element 'item' styles here...*/
}

.menu_horiz {
  /*...the menu block modifier 'horiz' styles here...*/
}

Configurations

프로젝트에 원하는 방식으로 BEM setting을 변경할 수 있다. 이것은 선택적이며, 변경을 원할 경우 configure-BEM mixin을 통해 선언할 수 있다. 선언하지 않은 것은 결국 다음과 같은 셈이다.

@include configure-BEM ((
  block-prefix-default: "",
  block-types: (),
  element-sep: "__",
  modifier-sep: "_"
));

block-prefix-default

block에 기본적으로 사용할 접두사를 설정한다. (e.g "b-", "c-", ...) 기본값은 ""이다.

@include configure-BEM((
  default-block-prefix: "b-" // block의 기본 접두사를 "b-"로 한다
));

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

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

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

block-types

프로젝트에 사용할 block 타입들을 정의할 수 있다. 이것 여러 block type들과 그에 따른 접두사가 필요할 때, 예를 들어 ITCSS 같은 방법론을 프로젝트에 적용할 때 유용하게 활용할 수 있다. 기본값은 빈 map이다.

@include configure-BEM((
  block-types: (
    object:    "o-",  // object block의 접두사로 o-를 사용한다
    component: "c-"   // component block의 접두사로 c-를 사용한다
    utility:   "u-"   // utility block의 접두사로 u-를 사용한다
  )
));

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

  @include element(body) {
    /*...styles here...*/
  }
}

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

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

/* Clearfix utility */
@include block(clearfix, "utility") {
  /*...styles here...*/
}
/* compiled CSS */

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

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

/* Clearfix utility */
.u-clearfix {
  /*...styles here...*/
}

element-sep, modifier-sep

BEM element와 BEM modifier의 구분자를 설정한다. 기본값은 각각 "__"과 "_"이다.

@include configure-BEM((
  // separator를 medium.com 스타일로 설정한다
  element-sep: "-",
  modifier-sep: "--"
));

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

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

Extended Details

Boolean modifier & Key-value modifier

modifier를 선언하는 방식에 따라 boolean modifier와 key-value modifier를 모두 표현할 수 있다.

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

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

이것은 아래와 같이 컴파일된다.

/* Boolean modifier */
.menu_hidden {
  /*...the menu block modifier 'hidden' styles are here...*/
}

/* key-value modifiers */
.menu_theme_morning-forest {
  /*...the menu block modifier 'theme: morning-forest' styles are here...*/
}

.menu_theme_stormy-sky {
  /*...the menu block modifier 'theme: stormy-sky' styles are here...*/
}

Element modifier

element 또한 block과 같은 방식으로 modifier를 가질 수 있다.

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

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

이것은 아래와 같이 컴파일 된다

/* Boolean modifier */
.menu__item_visible {
  /*...the element item modifier 'visible' styles are here...*/
}

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

Using cascades in BEM

BEM은 CSS의 명시도(Specificity) 이슈를 피하기 위해 만들어졌지만, 제한적으로 CSS 본연의 cascading을 활용하는 경우가 있다. 예를 들어 block의 modifier(theme, state, ...)에 따라 변경되는 element를 표현할 때 cascading이 사용되는데, 이것은 아래와 방식으로 선언할 수 있다.

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

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

이것은 아래와 같이 컴파일 된다

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

.nav__item {
  /*...default nav block element 'item' styles are here...*/
}

.nav_theme_islands {
  /*...nav block modifier 'theme:islands' styles are here...*/
}

.nav_theme_islands .b-nav__item {
  /*...nav block element 'item' in 'theme:islands' styles are here...*/
}

...TODO: cascading 시의 인접 형제 선택자의 활용

Caveats

Element, Modifier의 독립적 선언 방지

element와 modifier는 독립적으로 선언될 수 없다. element는 block 안에 선언되어야 하며, modifier 또한 반드시 block 또는 유효한 element 안에 선언되어야한다.

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

// @see https://en.bem.info/method/key-concepts/#element
@include element(item) {
  /*...CSS declarations here...*/
}

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

BEM-scss는 위와 같이 block 바깥에서 element나 modifier를 선언할 경우 error를 발생시킨다.

Error: element cannot be declared ouside of a block
Error: modifier cannot be declared ouside of a block

중첩 Element 방지

중첩 element(e.g block__elem1__elem2)는 block 구조 변경, 확장의 유연성을 저해하므로 금지된다.

// @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) {
    }
  }
}

BEM-scss는 위와 같이 중첩 element를 선언할 경우 error를 발생시킨다.

Error: element cannot be declared in another element

일괄 선언의 방지

초기 버전의 BEM-scss는 컴파일될 css와 비슷한 형태로 아래와 같이 일괄 선언을 할 수 있는 방식을 지원했었다.

// WARNING! 아래 방식은 더 이상 지원하지 않는다

@include block(nav) {
  @include all(element(item), element(divider)) {
    /*...CSS declarations here...*/
  }
}

// 또는

@include block(nav) {
  @include element(item, divider) {
    /*...CSS declarations here...*/
  }
}
.b-nav__item, .b-nav__divider {
  /*...CSS declarations here...*/
}

그러나 이 방식은 코드 상에 해당 element나 modifier에 관한 선언들을 여러 곳에 분산시켜 관리 포인트를 늘리는 부작용이 있다. 해당 block, element, 또는 modifier에 관한 코드 블록은 코드 상에 한번인 것이 좋다는 판단에 더 이상 위와 같은 방식을 지원하지 않는다. 이는 SASS의 placeholder를 통해 아래와 같이 해소될 수 있다.

@include block(nav) {
  %common-styles {
    /*...CSS declarations here...*/
  }
  
  @include element(item) {
    @extend %common-styles;
  }
  
  @include element(link) {
    @extend %common-styles;
  }
}

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