Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

CSS

Sass extending components (best practices)

So I am working through or rather re-working through some of Guil Hernandez' Sass works particularly in BEM. Currently I have some Sass that makes a button '.btn' and nested in that is some Sass that makes a '.btn--primary' for example. In my html I am having to call both classes to give the button its shape and color

<a href="#" class="btn btn--primary">

Is it better practice to have the '.btn' class as an extend and then have my '.btn--primary' extend from my '.btn' class? My Html looks cleaner.

<a href="#" class="btn--primary">

but whats the pitfall of doing this?

1 Answer

Colin Marshall
Colin Marshall
32,861 Points

If you were to follow BEM rules strictly, I think this is technically one example of how your HTML would look for a button:

<div class="btn">
  <a href="#" class="btn__link btn__link--primary btn__link--large">This is a button</a>
</div>

The div with the btn class is the block in BEM, and acts as a container. The anchor tag (a) with the class btn__link is the element in BEM. In BEM, the element will always be a child element of the block, so it must go inside it. The btn__link--primary and the btn__link--large classes are the modifiers in BEM which would contain button color rules and button size rules, respectively.

For elements like buttons, strictly following BEM rules will create extra div (or other container/block elements) in your HTML. IMO, for things like buttons, you should make exceptions to not follow BEM strictly. I would personally just ignore the block part of BEM with buttons, as you have done, so you don't have to wrap it in a div. I think the most important thing is that you stay consistent, and make sure others can easily understand your code if they pick it up.

As for how you have your code, there is one potential issue I see with it. If you have a set of btn rules that you extend to every modifier class, you will end up with duplicate code in your CSS.

For example, let's pretend this is your btn extend:

%btn {
  padding: 15px 30px;
  border: 0;
  border-radius : 4px;
  color: white;
  text-transform: uppercase;
  font-size : em(14px);
  font-weight: $font-weight--medium;
  transition: opacity $trns-duration;
  display: block;
}

Then you would have this code for your modifiers:

.btn {

  @include m(primary) {
    @extend %btn;
    color: green;
    background-color: pink;
  }

  @include m(secondary) {
    @extend %btn;
    color: blue;
    background-color: orange;
  }

  @include m(warning) {
    @extend %btn;
    color: white;
    background-color: red;
  }

}

You are going to end up with this as your CSS:

.btn--primary {
  padding: 15px 30px;
  border: 0;
  border-radius : 4px;
  color: white;
  text-transform: uppercase;
  font-size : em(14px);
  font-weight: 400;
  display: block;
  color: green;
  background-color: pink;
}

.btn--secondary {
  padding: 15px 30px;
  border: 0;
  border-radius : 4px;
  color: white;
  text-transform: uppercase;
  font-size : em(14px);
  font-weight: 400;
  display: block;
  color: blue;
  background-color: orange;
}

.btn--warning {
  padding: 15px 30px;
  border: 0;
  border-radius : 4px;
  color: white;
  text-transform: uppercase;
  font-size : em(14px);
  font-weight: 400;
  display: block;
  color: white;
  background-color: red;
}

See all those repetitive lines of code? Your HTML will look cleaner the way you proposed, but your CSS will end up with lots of lines repeated.

Yeah I get that it muddies the CSS a bit and I try to stay DRY. Guil Hernandez mentioned in this course http://teamtreehouse.com/library/css-to-sass something along the lines of "Do not Repeate Yourself, so put it in a mixin and the CSS output might repeat but you only did it once so you didn't repeat Yourself". Which is where I cam trying ot figure out what the best way to go about this is. I want to be efficient.

Colin Marshall
Colin Marshall
32,861 Points

For me personally, I would do buttons how you originally had them:

<a href="#" class="btn btn--primary">

The CSS would be more DRY that way, as you mentioned. The CSS output from my example would then change to:

.btn {
  padding: 15px 30px;
  border: 0;
  border-radius : 4px;
  color: white;
  text-transform: uppercase;
  font-size : em(14px);
  font-weight: 400;
  display: block;
}

.btn--primary { 
  color: green;
  background-color: pink;
}

.btn--secondary {
  color: blue;
  background-color: orange;
}

.btn--warning {
  color: white;
  background-color: red;
}

Although you would end up with the extra class (btn) in the HTML, it would save you some file size in your CSS. The difference in file size is negligible though, so go with what you like better personally.