public
Last active

This gist demonstrates some uses of the new sass feature: Passing content blocks to mixins.

  • Download Gist
0_selector_hacks.scss
SCSS
1 2 3 4 5 6
@mixin ie6 { * html & { @content } }
 
#logo {
background-image: url("/images/logo.png");
@include ie6 { background-image: url("/images/logo.gif"); }
}
1_selector_hacks.sass
Sass
1 2 3 4 5 6 7 8
=ie6
* html &
@content
 
#logo
background-image: url("/images/logo.png")
+ie6
background-image: url("/images/logo.gif")
2_selector_hacks.css
CSS
1 2
#logo { background-image: url("/images/logo.png"); }
* html #logo { background-image: url("/images/logo.gif"); }
3_animation.scss
SCSS
1 2 3 4 5 6 7 8 9 10
@mixin keyframes {
@-moz-keyframes { @content; }
@-webkit-keyframes { @content; }
}
 
 
@include keyframes {
0% { opacity: 0; }
100% { opacity: 1; }
}
4_animation.sass
Sass
1 2 3 4 5 6 7 8 9 10 11 12
=keyframes
@-moz-keyframes
@content
 
@-webkit-keyframes
@content
 
+keyframes
0%
opacity: 0
100%
opacity: 1
5_animation.css
CSS
1 2 3 4 5 6 7 8 9
@-moz-keyframes {
0% { opacity: 0; }
100% { opacity: 1; }
}
 
@-webkit-keyframes {
0% { opacity: 0; }
100% { opacity: 1; }
}
6_media_queries.scss
SCSS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
@mixin respond-to($media) {
@if $media == handhelds {
@media only screen and (max-width: 479px) { @content; }
}
@else if $media == wide-handhelds {
@media only screen and (min-width: 480px) and (max-width: 767px) { @content; }
}
@else if $media == tablets {
@media only screen and (min-width: 768px) and (max-width: 959px) { @content; }
}
}
 
#sidebar {
float: left;
width: 300px;
@include respond-to(handhelds) { float: none; }
@include respond-to(wide-handhelds) { float: none; }
@include respond-to(tablets) { width: 240px; }
}
7_media_queries.sass
Sass
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
=respond-to($media)
@if $media == handhelds
@media only screen and (max-width: 479px)
@content
@else if $media == wide-handhelds
@media only screen and (min-width: 480px) and (max-width: 767px)
@content
@else if $media == tablets
@media only screen and (min-width: 768px) and (max-width: 959px)
@content
 
#sidebar
float: left
width: 300px
+respond-to(handhelds)
float: none
 
+respond-to(wide-handhelds)
float: none
 
+respond-to(tablets)
width: 240px
8_media_queries.css
CSS
1 2 3 4
#sidebar { float: left; width: 300px; }
@media only screen and (max-width: 479px) { #sidebar { float: none; } }
@media only screen and (min-width: 480px) and (max-width: 767px) { #sidebar { float: none; } }
@media only screen and (min-width: 768px) and (max-width: 959px) { #sidebar { width: 240px; } }

Great feature! Especially the media query example demonstrates its power to improve stylesheet maintainability.

I cannot find it in the Sass changelog, though. Is it already released?

Examples 4, 5, 6 are wrong as you need a name for your @-webkit-/-moz-keyframes section. The mixin should look like this:

@mixin keyframes($name) {
  @-moz-keyframes    $name { @content; }
  @-webkit-keyframes $name { @content; }
}

Yet I get an error when parsing this:

Syntax error: Invalid CSS after "...z-keyframes ": expected "}", was "$name { @conten..."
on line 4 of /style.scss

It would be really cool if you could make variables you create in your mixin available to the stuff inside the @content block. So for example, I could make a mixin that would loop over a list:

$GLOBAL_LIST: apple peach pear banana;

/*
  Mixin
*/
@mixin list-fruit() {
  @each $fruit in $GLOBAL_LIST {
    @content;
  }
}

/*
  Usage
*/
@include list-fruit() {
  .thumbnail-#{$fruit} {
    background-image: image-url('icon-#{$fruit}.png');
  }
}

/*
  Expected output:
*/
.thumbnail-apple {
  background-image: url(images/icon-apple.png);
}

.thumbnail-peach {
  background-image: url(images/icon-peach.png);
}

.thumbnail-pear {
  background-image: url(images/icon-pear.png);
}

.thumbnail-banana {
  background-image: url(images/icon-banana.png);
}

@brianmcallister I had this thought while spec'ing the feature, but decided to keep it simple for the initial release. If the use cases are compelling enough, we will consider this for a future release. The syntax would need to allow passing arguments from the mixin to the content block because the scope of the block is the caller, not the mixin. E.g.

@mixin fruit-thumbnail($fruit) {
  .thumbnail-#{$fruit} {
    background-image: image-url('icon-#{$fruit}.png');
  }
}
@mixin list-fruit() {
  @each $fruit in $GLOBAL_LIST {
    @content $fruit;
  }
}
@include list-fruit() with fruit-thumbnail;

Hi,

Still find some lack of implementation for basic scenarios (or maybe i'm missing something here). It would be very cool to be able to assign variables depending on media queries, like so, inside media queries:

$break-smart: 480px;
$break-tablet: 768px;
$break-wide: 1000px;

@media screen and (max-width: $break-smart) { 
    $grid-columns: 10;
    $grid-gutter-width: 10px;
    $grid-total-width: 310px; 
    $grid-col-width: ( ($grid-total-width - $grid-gutter-width) / $grid-columns) - $grid-gutter-width;
 }
@media screen and (min-width: $break-smart + 1) and (max-width: $break-tablet) { 
    $grid-columns: 10;
    $grid-gutter-width: 10px;
    $grid-total-width: 460px; 
    $grid-col-width: ( ($grid-total-width - $grid-gutter-width) / $grid-columns) - $grid-gutter-width;
 }
@media screen and (min-width: $break-tablet + 1) and (max-width: $break-wide) { 
    $grid-columns: 12;
    $grid-gutter-width: 10px;
    $grid-total-width: 740px; 
    $grid-col-width: ( ($grid-total-width - $grid-gutter-width) / $grid-columns) - $grid-gutter-width;
 }
@media screen and (min-width: $break-wide + 1) { 
    $grid-columns: 12;
    $grid-gutter-width: 20px;
    $grid-total-width: 980px; 
    $grid-col-width: ( ($grid-total-width - $grid-gutter-width) / $grid-columns) - $grid-gutter-width;
 }

It would be cool because it would save us from having to define further "target" resolutions. Previous code throws a Syntax error because variables used later in scss are not set. Alternative code (ie your respond-to mixins) is much more cumbersome:

$break-smart: 480px;
$break-tablet: 768px;
$break-wide: 1000px;

@mixin respond-to($media) {
  @if $media == smart {
    $grid-columns: 10;
    $grid-gutter-width: 10px;
    $grid-total-width: 310px; 
    $grid-col-width: ( ($grid-total-width - $grid-gutter-width) / $grid-columns) - $grid-gutter-width;
    @media screen and (max-width: $break-smart) { @content; }
  }
  @else if $media == tablet {
    $grid-columns: 10;
    $grid-gutter-width: 10px;
    $grid-total-width: 460px; 
    $grid-col-width: ( ($grid-total-width - $grid-gutter-width) / $grid-columns) - $grid-gutter-width;
    @media screen and (min-width: $break-smart + 1) and (max-width: $break-tablet) { @content; }
  }
  @else if $media == tablet-wide {
    $grid-columns: 12;
    $grid-gutter-width: 10px;
    $grid-total-width: 740px; 
    $grid-col-width: ( ($grid-total-width - $grid-gutter-width) / $grid-columns) - $grid-gutter-width;
    @media screen and (min-width: $break-tablet + 1) and (max-width: $break-wide) { @content; }
  }
  @else if $media == desktop {
    $grid-columns: 12;
    $grid-gutter-width: 20px;
    $grid-total-width: 980px; 
    $grid-col-width: ( ($grid-total-width - $grid-gutter-width) / $grid-columns) - $grid-gutter-width;
    @media screen and (min-width: $break-wide + 1) { @content; }
  }
}

…later in scss:

.main {  
            @include respond-to(smart)     { @include grid($grid-total-width); }
            @include respond-to(tablet)    { @include grid($grid-total-width);  }
            @include respond-to(tablet-wide) { @include grid($grid-total-width);  }
            @include respond-to(desktop)   { @include grid($grid-total-width);  }
}

Summarizing, a simple total width has to be defined in respond-to mixin but then called the same way for all targets! Surely I'm missing something.

It's getting better though
Thanx

Note: there's now a keyframe animation module in compass 0.13: http://beta.compass-style.org/reference/compass/css3/animation/

@zigotica OH MY GOSH ,YES! I was just playing with mixins and @content and tried doing that because it made so much more sense! I even tweeted at Chris and Nathan about it, then googled it and got here! It's been 4 months and we still don't have it… :(

The respond-to mixin makes for much better organisation of my layout styles. One (current) drawback is the duplication of media queries though - for other visitors to this gist, there's plenty of discussion on potential fixes over at the Sass GitHub page you might like to read.

All the best, Karl

As an IE 7 & 8 media queries workaround, I'm playing with the idea below.

Does anybody see any drawbacks to this? or maybe there's a better way?

@mixin respond-to($media) {
  @if $media == handhelds {
    @media only screen and (max-width: 479px) { @content; }
  }
  @else if $media == wide-handhelds {
    @media only screen and (min-width: 480px) and (max-width: 767px) { @content; }
  }
  @else if $media == tablets {
    @media only screen and (min-width: 768px) and (max-width: 959px) { @content; }
    .lt-ie9 & { @content; }
  }
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.