whizark
12/10/2014 - 2:24 PM

Sass: Automatically placeholder-ize duplicated CSS declarations. #sass

Sass: Automatically placeholder-ize duplicated CSS declarations. #sass

<p class="test-1-1">.test-1-1</p>
<p class="test-1-2">.test-1-2</p>
<p class="test-2-1">.test-2-1</p>
<p class="test-2-2">.test-2-2</p>
<p class="test-3-1">.test-3-1</p>
<p class="test-3-2">.test-3-2</p>
<p class="test-4-1">.test-4-1</p>
<p class="test-4-2">.test-4-2</p>
.test-1-1, .test-1-2, .test-2-1, .test-2-2, .test-3-1, .test-3-2, .test-4-1, .test-4-2 {
  margin: 1em;
}
.test-1-1, .test-1-2 {
  font-size: 13px;
  color: red;
}

.test-2-1, .test-2-2 {
  font-size: 16px;
  color: red;
}

.test-3-1, .test-3-2 {
  font-size: 13px;
  color: blue;
}

.test-4-1, .test-4-2 {
  font-size: 16px;
  color: blue;
}
// ----
// Sass (v3.4.7)
// Compass (v1.0.1)
// ----

// Sass: Automatically placeholder-ize duplicated CSS declarations.
//
// Placeholder Factory(Mixin) based on the argumetns
// https://gist.github.com/whizark/1a7e587e447eb38e8a3b
//
// Other ideas
// https://github.com/whizark/xass#ideas 

// List for Placeholder names.
$-placeholders: ();

// Converts value(s) into String.
@function hash($values...) {
  $string: '';

  @each $value in $values {
    $part: inspect(unquote($value));

    // @todo Escape invalid characters for Placeholder selector
    //       such as ' ' (space), '\' (back-slash) etc.

    $string: $string + $part;
  }
  
  @return $string;
}

// Outputs CSS declarations and caches them as Placeholder.
@mixin placeholderize($id, $keys...) {
  $key : hash($id, $keys...);
  $name: '-placeholder-' + $key;

  @if index($-placeholders, $key) == null {
    @at-root %#{$name} {
      @content;
    }

    $-placeholders: append($-placeholders, $key) !global;
  }

  @extend %#{$name} !optional;
}

// Use case
@mixin component($font-size: 13px, $color: red) {
  $id: 'component';

  // Static style.
  // Placeholder-ize static style based on the ID.
  @include placeholderize($id) {
    margin: 1em;
  }

  // Dynamic style.
  // Placeholder-ize dynamic style based on the ID and arguments.
  //
  // We can easily refactor this: Extract Mixin <-> Inline Mixin
  // 1. create mixin like 'component-typography'
  // 2. move this code into the mixin
  // 3. include the mixin here
  @include placeholderize($id, $font-size, $color) {
    font-size: $font-size;
    color: $color;
  }
}

// Tests
.test-1-1 {
  @include component();
}

.test-1-2 {
  @include component();
}

.test-2-1 {
  @include component(16px);
}

.test-2-2 {
  @include component(16px);
}

.test-3-1 {
  @include component($color: blue);
}

.test-3-2 {
  @include component($color: blue);
}

.test-4-1 {
  @include component(16px, blue);
}

.test-4-2 {
  @include component(16px, blue);
}
<p class="test-1-1">.test-1-1</p>
<p class="test-1-2">.test-1-2</p>
<p class="test-2-1">.test-2-1</p>
<p class="test-2-2">.test-2-2</p>
<p class="test-3-1">.test-3-1</p>
<p class="test-3-2">.test-3-2</p>
<p class="test-4-1">.test-4-1</p>
<p class="test-4-2">.test-4-2</p>