18

I am working on a Rails project that is just starting. We want to use twitter bootstrap as a base for our styles, at the beginning we would simply use bootstrap's class names directly on the HTML code, just like is shown in bootstrap's documentation, but after reading the following posts:

Lessons learned in maintainable css

Please stop embedding Bootstrap classes in your HTML

it became clear why that's not the proper why to use bootstrap, so after some more readings:

Decouple Your CSS From HTML

smacss

among other, it seemed that using sass @extend was the proper way to avoid using bootstrap's class names, so instead of doing this:

<button type="submit" class="btn">Search</button>

we would do this:

<button type="submit" class="button">Search</button>

and our sass code would look like this:

.button {
   @extend ".btn";
}

The problem with that approach, besides the bunch of extra selectors that will be added each time we extend a bootstrap class just to use a different name, is that in cases where bootstrap uses selectors like this:

.form-search .input-append .btn, .form-search .form-input-append .btn {
  border-radius: 0 14px 14px 0;
} 

the button won't get the right style because sass will not apply that same rule to our custom class name, I mean, sass is not doing this:

.form-search .input-append .btn, .form-search .input-append .button, 
.form-search .form-input-append .btn, .form-search .form-input-append .button {
  border-radius: 0 14px 14px 0;
} 

So I wonder, is this the right way to avoid embedding bootstrap's class names into HTML, if so, how should I handle this problem (it happens frequently)? if not, what would be a better way to use custom class names but still get the styles from bootstrap.

I really appreciate your thoughts on this. Please keep in mind that I am just learning about overall web design (css, sass, less, html, js, etc.).

Community
  • 1
  • 1
Jose
  • 601
  • 5
  • 15
  • 4
    Other than "don't use Bootstrap" or "rewrite Bootstrap to be not retarded", I'm not sure that there is a solution. In your button example, the class name shouldn't be quoted (plus, I'd argue that the "button" class on a button element is superfluous). Your second example won't work because it is a compound selector, and `@extend` only works on simple selectors. – cimmanon Apr 17 '13 at 14:49
  • 2
    Bootstrap is opinionated software. It uses lots and lots of classes. If don't want to use lots and lots of classes, I agree with @cimmanon that "don't use Bootstrap" is a good solution. – bookcasey Apr 17 '13 at 17:25
  • 2
    Bootstrap is originally written in LESS, but there are a couple of ports to SASS: - https://github.com/thomas-mcdonald/bootstrap-sass - https://github.com/jlong/sass-twitter-bootstrap Try them, at least one of them should have the classes you need. – Andrey Mikhaylov - lolmaus Apr 17 '13 at 16:38
  • 2
    I disagree that the "button" class on a button element is superfluous. There may be a situation where you don't want styles applied to a button. "button" may not be the most appropriate class name to use for this, but I believe there certainly should be one used. – Matthew G Aug 09 '13 at 00:22
  • @MatthewG how is `button.button` (Not to mention `table.table` and `label.label`) not superfluous? – steveax Oct 10 '13 at 06:43
  • 1
    I don't think it really matters if it's button.button or button.btn, table.table or table.tbl, label.label or label.lbl, the point is applying global styles to a tag could make it annoying to track down misplaced styles later. – Matthew G Oct 10 '13 at 23:26
  • @MatthewG It's anyways not a good practice to do shit like `button.button`. It has lower performance due to two stages of selections. – Aniket Nov 09 '13 at 04:49
  • @MatthewG is correct; the "button" class is not superfluous. And now, since Jose is attempting to modularize and decouple his CSS, he'll be able to choose any name he wants and under-the-hood still use the Bootstrap ".btn" class, essentially creating a simple, domain-specific CSS. – tjklemz Nov 26 '13 at 00:39
  • I think the simple solution is to just namespace your custom selectors to avoid collisions with bootstrap, so .awesome-button, .awesome-btn, .awesome-whatever. – Matt Lambert Dec 11 '13 at 06:23
  • Bootstrap 3 now makes this really easy [via LESS mixins](http://getbootstrap.com/css/#grid-less). – Tim Nov 23 '13 at 22:02

5 Answers5

2

When you rename .btn to .button, you also should rename .form-search to .form-searchnew etc? In that case your sass code in the example above should be something like:

.form-searchnew .input-appendnew .button {
  extend(.form-search .input-append .btn);
}

Which make sense (i don't know sass) and results in the css you expect.

I think bootstrap is not about css only. Bootstrap is about css, html(structure) and javascript. Even when you separate css from html i would not easy to migrate to an other framework. Beside the css you will have to change the html structure and javascript call too.

Example migrate from Twitter's Bootstrap 2 to 3 (see: Updating Bootstrap to version 3 - what do I have to do?). I also wondered if you could migrate by extending the old classes to the new css (see: http://bassjobsen.weblogs.fm/migrate-your-templates-from-twitter-bootstrap-2-x-to-twitter-bootstrap-3/). After reading the migration guide, i think you couldn't.

Other solutions. Angular JS decouples Twitter's Bootstrap from javascript. Also in this case migrations does not seem to be painless see: Angular Dialog directives with Bootstrap 3

Maybe also read this post: http://www.jasonwong.org/post/45849350459/migrating-from-zurb-foundation-twitter-bootstrap-to. It refers to Bourdon and Neat.

Example from their website:

<!-- HTML markup for the section right below this code block -->
<section>
  <aside>What is it about?</aside>
  <article>Neat is an open source semantic grid framework built on top of Sass and Bourbon…</article>
</section>

// Enter Neat
section {
  @include outer-container;
  aside { @include span-columns(3); }
  article { @include span-columns(9); }
}
// And the result is...

As they say: "it relies entirely on Sass mixins and does not pollute your HTML" which seems the way you're looking for.

Community
  • 1
  • 1
Bass Jobsen
  • 48,736
  • 16
  • 143
  • 224
2

I recommend you have a look at sass placeholder classes http://sass-lang.com/documentation/file.SASS_REFERENCE.html#placeholders in order not to bloath your css. Most likely you won't be using every single element included in bootstrap and placeholders only get written to your stylesheet if they are actually extended in your code.

Also, I think people tend to get confused about how css frameworks work and how decoupling css and html actually works. For very large websites (or ones that you expect eventually to grow very large), where performance and css file size is crucial, some kind of OOCSS approach is your best bet. And this means inevitably that you have formatting code directly in your HTML.

If you can allow yourself to be a little less efficient and want your HTML clean, make sure to use semantic classes (examples for buttons: call-to-action, call-to-action-secondary, submit, btn-primary, btn-corporate-color, etc...)

Also remember to decouple your JS from CSS! use special classes for attaching behaviour (example js-submit, js-call-to-action, etc....)

Last but not least: don't plan for updating your css framework. These frameworks are meant to give you a headstart, not to be your overall design solution. Extend them, adapt them, make them your own, invest in design and create your own look in order to make your app unique. If what makes you think of updating is a worry to keep up with standard changes, better use compass mixins.

emik
  • 903
  • 12
  • 11
  • 1
    I wanted to +10 but I can only +1 ! I am trying to rewrite boostrapp's sass and converting everything to placeholders, but it's tedious.. Do you know if someone has already gone though this task and shared it ? – redben Jun 08 '14 at 16:21
1

Use @extend, but don't quote selectors:

.button { @extend .btn; }

Then you'll see that Sass extends related selectors too, like you want (.form-search .input-append .btn etc.).

… besides the bunch of extra selectors that will be added each time we extend a bootstrap class just to use a different name …

@extend works by copying selectors. If you don't want that, you can "extend" in HTML instead -- i.e. add Bootstrap's class names. :)

sam
  • 40,318
  • 2
  • 41
  • 37
1

For being new to most of this, you're on the right track; the resources you've been reading are excellent. But, I think the concerns you have might not be justified:

...the button won't get the right style because sass will not apply that same rule to our custom class name...

In fact, I think you must be mistaken. According to the Sass documentation:

@extend works by inserting the extending selector (e.g. .seriousError) anywhere in the stylesheet that the extended selector (.e.g .error) appears.

See http://sass-lang.com/documentation/file.SASS_REFERENCE.html#how_it_works for the full code example.

Your original solution was actually correct. Use extends, but without the quotes:

.button {
  @extend .btn; //no quotes
}

I tested this using your example, and it works correctly. Sass copies all the selectors with ".btn" and on those newly created selectors, it replaces ".btn" with ".button".

Also, if Sass produces too much duplication for your liking, don't worry about it (so long as you are following best practices as pointed out by the links you posted). Duplicate code is easily compressed if the server uses gzip or the equivalent; the client shouldn't notice any slower loading times, although it might take slightly longer to "unzip" the CSS. As for CSS selector speed, don't worry about that either; the only case where speed matters for selectors is on the JavaScript side, particularly with jQuery. For your Sass code, simply follow best practices for maintainability (notably, modularization as you are trying to do, i.e. SMACSS) and you'll be good to go.

tjklemz
  • 1,170
  • 12
  • 19
0

The answers given by sam and tjklemz will help you resolve your immediate technical challenge, but it's possible to decouple your CSS and HTML even more. I'll give an example below, but keep in mind that this is just a quick example to demonstrate the power of mixins/extending CSS classes.

I'd also strongly recommend checking out the ZURB Foundation framework, as it is natively SASS, and designed with this style of development in mind.

For example:

<body>
    <div id="my-header">
        <h1><a href="#">My Company</a></h1>
        <h2>My Tagline</h2>
    </div>
    <div id="my-main">
        <div class="my-widget">
            <h1>Widget Title</h1>
            <a>Widget Option 1</a>
            <a>Widget Option 2</a> 
        </div>    
    </div>
</body>

With the accompanying SCSS:

//these examples wouldn't really work
//because bootstrap needs more markup
#my-header {
    @extend .navbar;
}
#my-header h1 {
    @extend .branding;
}
#my-main {
    @extend .container;
}

//good example
.my-widget {
    @extend .well;
    @extend .hero-unit;
}
.my-widget a {
    @extend .btn;
}