Hacker News new | past | comments | ask | show | jobs | submit login

In order to reduce complexity like this, you should avoid using Bootstrap classes in your HTML directly.

Instead, use semantic class names for your app and use the new &:extend() directive in LESS 1.4 or @extend in SASS (if you're using bootstrap-sass). You'll end up with much more readable HTML and CSS, and will insulate yourself from future changes in Bootstrap.

I do stuff like this in SASS

    %flash {
      @extend .container;
      @extend .alert;
      margin: 15px auto;
      border-radius: 0;
    
      .close { top: 0; }
    }
    
    .flash-success {
      @extend %flash;
      @extend .alert-success;
    
      .close {
        color: $successText;
        opacity: 1;
      }
    }

    .flash-error {
      @extend %flash;
      @extend .alert-error;
    
      .close {
        color: $errorText;
        opacity: 1;
      }
    }



I'll politely (and completely) disagree with this. I much prefer the HTML convey semantics (to the dev, not to the user) than having magic happening behind the scenes with CSS.

By having the classes in the HTML, you know at a glance what is going to happen. Whereas using extend there's an extra layer of indirection, you end up having to look at the HTML, see there's a class called something like "sidebar". Then you have to look at the SASS, find the sidebar class to see there's an extend directive, then and work out what's going on in there. That's an extra step i'd rather avoid.

People usually follow this approach to get "clean" or "semantic" markup, but there's some falsehoods in that thinking. The "markup looks ugly", or is "non-semantic" are misguided: no user agents infer semantics from classes, and the ugliness you describe is purely aesthetic, the real beauty is in the semantics the developer can infer from having clear and obvious classes in the HTML. Another classic argument is it makes the markup bloated. This may be true on the surface, but when you factor in GZIP, it is completely negated as more repetition == better compression.

A great read on the topic is Nicholas Gallagher's article "About HTML semantics and front-end architecture"[1]. Reading that article for the first time was one of those moments of clarity, where your previous perceptions are completely shattered. Hopefully you guys will feel the same :)

[1]http://nicolasgallagher.com/about-html-semantics-front-end-a...


I'm not sure I follow. You're basically arguing for including style attributes throughout your HTML. CSS classes are always a layer of indirection, regardless of whether they are semantic or functional. As such, you shouldn't be forcing style and layout directives into the structure of the document.

The main benefit of what I'm describing isn't actually semantics. It's allowing CSS to do what it does best: cascade.

Say I've got an application where I've got several pages with unique layouts and the designer has come up with a new form style that has all the labels inline instead of on top of each input and has a new dynamic tour system that needs some area on the right of each form.

If you were using Bootstrap classes directly, you'd have to go to all of your forms and add .form-inline and change the column size classes. You wouldn't want to redefine what those classes are because that may have effects on other areas of the application. This may also break some of your Javascript, as it was dependent on those class names.

If you were using semantically-named classes, you'd simply change the width and add @extend .form-inline to your main form placeholder (which is in turn @extend'ed by any specific form class). Your HTML would stay the same, meaning any Javascript dependent on those classes wouldn't break.


No I'm not arguing for style attributes, that's a maintenance nightmare waiting to happen (with very little waiting needed!). They are a layer of indirection indeed, but which of these do you think conveys more information/semantics to the developer (these aren't bootstrap specific classes, just illustrative):

<div class="sidebar"> <!-- content --> </div>

<!-- or -->

<div class="sidebar grid-one-whole grid-one-half-medium grid-one-third-large"> <!-- content --> </div>

The second one is way more verbose, but at a glance you know exactly what is happening (assuming my class names are obvious enough). The classes convey information that an amalgamated class you get from @extend simply cannot.

First let me say that a lot of what I'm talking about is optimal for building large-scale web sites with lots of page variants. Your mileage may vary for smaller sites, the principles can still be applied, but you might not need adhere to them as strictly.

There's been a movement in recent years, Object Oriented CSS (OOCSS). This ethos urges the developer to write CSS as they would other code, using the hard lessons that have been learnt in other language. We should be thinking in abstractions, utilising the single responsibility principle, favouring composition over inheritance, loose coupling, and self-documenting code. I'll go through these one at a time, because the benefits of each flow throughout one another.

Abstractions - using a single class like "sidebar" to contain all your styling for the sidebar is not thinking in abstractions. The sidebar may need specific styling (say a different BG colour) but it also has a lot in common with other parts of the page. For instance, it's nothing more than a grid column, so why bundle all styles into one class instead of using the grid abstraction to "decorate" the sidebar with this? This is equivalent to breaking a system into reusable classes. See Nicole Sullivan's article on the Media Object [1] and Harry Roberts on the open/closed principle in CSS [2]

Single-responsibility principle - Do one thing and do it well. A class should have a single-responsibility so that it can be composed into larger "blocks" of styling. A class that does everything is monolithic and difficult to work with as soon as a design needs to change. Overly broad selectors in CSS can also break the single responsibility principle - suddenly your styling is relying on the coincidental placement of elements inside one another. Harry Roberts cover this [3]

Loose-coupling: Can parts of your code base change without affecting others? By @extending grid classes you're tightly coupling yourself to the implementation details of the grid system. Now you can of course override styles in your sidebar class, but overriding styles from previous classes is a code smell. If you're "undoing" what another class has done, you've applied a style too early. You suggest changing the CSS and leaving the HTML the same when a change is required. I always prefer changing the HTML because it has a far more limited scope for far reaching changes. If you change one segment of HTML you know it's not going to affect other parts of the site beyond itself (and possibly it's children), but if you change some tightly-coupled CSS its effects could ripple throughout the whole site. The previously mentioned article on the open/closed principle [2] touches on tight coupling in classes.

Favour composition over inheritance - In OO languages we've learnt that we should favour composition of granular, single-purpose classes over deep inheritance hierarchies. Why? Inheritance is a fundamental tenet of OO, just as the cascade is in CSS, but we still frequently eschew it. The reason for this is because we can compose infinitely more flexible pieces of functionality from granular building blocks than we can from inheriting traits from "super classes". And now that we're thinking in abstractions (as outlined above) using the single-responsibility principle, we can put multiple classes on an HTML element to compose them as you wish into large blocks. Harry Roberts (CSS Wizardry) covers this nicely [4] and also when talking about grid systems [5]

Self-documenting code - From the HTML I ideally want to know exactly where each bit of style is coming from. With one monolithic class all I know is that it's a sidebar, which doesn't really tell me much that I can't work out visually. Multiple classes tell me exactly how it will behave at a glance. This means your classes should be as descriptive as possible. Classes should not describe the content of the markup they are applied to (sidebar is definitely content-centric) but rather their intent. And small, abstract, single-responsibility classes convey more information than a monolith can, and they ease understanding of the system. Someone familiar with bootstrap could quickly get to grips a site using the plain bootstrap classes, whereas @extending all over the place necessitates digging into the CSS to gain an understanding of the system. This is covered in great depth in the original article I linked to.

Finally, you should never use as a JS hook a class whose purpose is visual styling, then the whole mess you outlined is avoidable. Either use data-* attributes (as most bootstrap widgets do) or a class which conveys intent and a single responsibility e.g. "js-date-picker".

Now my incoherent ramblings are probably lacking in a number of points, I had to leave out a lot so this didn't balloon even further (e.g. I didn't talk about specificity or BEM methodology). I urge you to read all the articles I've linked to, as hopefully you've already read the original one. You might also want to read this article which kinda covers everything in one post: http://engineering.appfolio.com/2012/11/16/css-architecture/ Most of the principles I've outlined here are actually used in bootstrap.

PS. if you want to continue the conversation, hit me up on twitter (@WickyNilliams) or something, I always forget to check back on HN comments for replies.

[1] http://www.stubbornella.org/content/2010/06/25/the-media-obj... [2] http://csswizardry.com/2012/06/the-open-closed-principle-app... [3] http://csswizardry.com/2012/04/the-single-responsibility-pri... [4] http://csswizardry.com/2012/10/a-classless-class-on-using-mo... [5] http://csswizardry.com/2013/02/responsive-grid-systems-a-sol...


I can see the benefits of using @extend to clean up the HTML, but wouldn't this pull the .container, .row, .span*, etc. CSS rules into each and every rule that extend from those? Wouldn't that have a hit on performance and file size?


I'm not sure how LESS handles it, but it adds your class to the selectors for that ruleset. If you do .myclass { @extend .container; }, you end up with .container, .myclass { // container styles }. It only adds minimal overhead.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: