Skip to content

Instantly share code, notes, and snippets.

@rikschennink
Last active January 29, 2019 09:44
Show Gist options
  • Save rikschennink/e2d11c73443ef7cda413ee4c9e2cb28d to your computer and use it in GitHub Desktop.
Save rikschennink/e2d11c73443ef7cda413ee4c9e2cb28d to your computer and use it in GitHub Desktop.
Sass OO Mixins: OOCSS without the HTML clutter

Sass OO Mixins: OOCSS without the HTML clutter

  • Less HTML clutter (caused by all those fragmented class names).
<button class="btn btn-primary btn-large btn-outline">Buy!</button>
  • Descriptive classes (or no classes at all) in the HTML results in cleaner and easier to read HTML.
<button class="btn-call-to-action">Buy!</button>
  • Easier to determine the look of the element by reading the @include name instead of deriving the info from all the individual properties.
@mixin button-style-ghost {
  display: inline-block;
  padding: .5rem;
  border: 2px solid #333;
  color: #333;
  font-weight:bold;
  background: transparent;
}
  • Make dependencies visible by moving the patterns to separate files and only @import them when required.

  • Use composition to build complex patterns by combining simple ones.

@mixin box-float {
  @include box-rounded;
  @include box-padded;
  background: #fff;
  box-shadow: 0 .25rem .5rem rgba(0,0,0,.25);
}
  • Keep style complexity in your CSS instead of your HTML, no need to edit the HTML when changing looks.

  • Impact of duplication in generated CSS is minimized by gzip. Also Mixins vs. Extends.

  • When old style patterns are no longer referenced they automatically stop taking up space in the CSS output.

  • The use of descriptive classes in your HTML instead of OO classes can work to enforce a more concise style. Having to name each element helps in determining if there might be too many similarly looking elements being used to achieve the same UX goal (10 different call to action button styles).

// Button styles
@mixin button-style-ghost {
color: #333;
background: transparent;
border: 2px solid #333;
// etc.
}
@mixin button-style-solid {
background-color: #333;
color: #fff;
// etc.
}
// Geometry styles
@mixin box-padded {
padding: 1.5rem;
}
@mixin box-rounded {
border-radius: .25rem;
}
@mixin box-float {
@include box-rounded;
@include box-padded;
background: #fff;
box-shadow: 0 .25rem .5rem rgba(0,0,0,.25);
}
@import 'patterns/buttons';
@import 'patterns/geometry';
// Use patterns to style generic elements
button[type=button] {
@include button-style-ghost;
}
button[type=submit] {
@include button-style-solid;
}
// When the inevitable "this link should look like a button" situation arises, it's easy to
// fix by doing this (instead of stacking all the selectors, or copy-pasting the properties)
a[download] {
@include button-style-solid;
}
// HTML class names can now be more descriptive, "message-item" is easier to read than "box-rounded box-padded box-float".
.message-item {
@include box-float;
}
@NetOpWibby
Copy link

Honestly, this is how I code. All those class names for a single element drives me crazy, looks ugly as hell, and sure isn't easy to comprehend when troubleshooting.

Your method is dope.

@isaacnass
Copy link

Yup this is the right way to do things!

Don't forget that your mixins can accept parameters so you can call them like functions!

@craig-jennings
Copy link

There are positives and negatives to this approach. With pure OOCSS the goal is to have small, granular classes that can be applied across multiple elements. If you want to change the appearance of an element, you add/remove classes from it (read: edit html). With this approach, if you want to change the look of an element, you add/remove mixins from the selector (read: edit sass).

Another issue with this approach is that you have to create a new selector each time you want a slightly different style on an element and add the mixins to it, rather than simply adding the classes you need to your html. For example:

@mixin box-padded {
    padding:1.875rem;
}

@mixin box-rounded {
    border-radius:.1875rem;
}

@mixin text-red {
  color: red;
}

@mixin text-blue {
  color: blue;
}

.my-box {
  @include box-padded;
  @include box-rounded;
  @include text-red;
}

If you wanted a box that had blue text instead, using OOCSS you'd just add the text-blue class in place of the text-red class on the element, but with you're approach you'd need some version of

.my-blue-box {
  @include box-padded;
  @include box-rounded;
  @include text-blue;
}

There's the argument of file size (more classes in html vs more selectors in css) but I've yet to read of a real-world example where that was a true factor in page load times.

Your approach does have the benefit that is inherent to css in general, one change in the stylesheet propagates to all elements with that selector. This means if you wanted all the .my-box's to have a smaller padding, you'd only have to make a change in one spot and it'd propagate to all .my-box's vs. going through all the html and changing the classes applied to the boxed elements. Many articles have discussed at length the pros/cons to this behavior. Overall, this is not a bad way to go by any means, it's just not the be-all end-all that everyone is searching for in CSS.

@SeanJM
Copy link

SeanJM commented Sep 1, 2016

I work the same way.

@rikschennink
Copy link
Author

@craigjennings11 Thanks for the detailed comment!

I think while having to create a new selector for each element can be perceived as a disadvantage it can also be seen as an advantage. Composing all sorts of types of boxes in the HTML is indeed very easy to do with OOCSS but it also creates a lot of boxes (this sounds obvious, hangon ;-)). Being forced to name each on of them helps in determining if there might be too many similarly looking elements being used to achieve the same UX goal.

@rikschennink
Copy link
Author

@isaacnass somehow my earlier reply got lost.

Anyway, I left out the parameters on purpose. Using parameters, loops, if statements, etc. is all pretty cool and can really result in clean code but it also introduces the risk of the SCSS becoming very difficult to read when returning to a project after some time. So to keep things as simple as possible I decided to purely focus on using mixins as property groups.

@justusromijn
Copy link

@craigjennings11 mixins are functions which also accept parameters, so you won't need a separate mixin for subtle differences. You can parameterize a couple of things if they make sense for their usage. If you look at the text color example:

@mixin colored-text ($color) {
    color: $color;
}
.my-blue-box {
  @include box-padded;
  @include box-rounded;
  @include colored-text(blue);
}

That solves at least that problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment