Skip to content

Instantly share code, notes, and snippets.

@chriseppstein
Created May 20, 2010 07:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chriseppstein/407318 to your computer and use it in GitHub Desktop.
Save chriseppstein/407318 to your computer and use it in GitHub Desktop.
body.standard #footer,
body.standard #header,
body.standard #sidebar,
body.standard #content,
body.standard #ads {
float: left;
margin-left: 10px;
margin-right: 10px;
}
body.standard #footer,
body.standard #header,
body.standard #sidebar {
margin-left: 0;
}
body.standard #footer,
body.standard #header,
body.standard #ads {
margin-right: 0;
}
body.standard #footer,
body.standard #header {
width: 960px;
}
body.standard #sidebar {
width: 190px
}
body.standard #content {
width: 470px
}
body.standard #ads {
width: 270px
}
$gutter-width: 10px
$column-width: 40px
=column-base
float: left
margin:
left: $gutter-width
right: $gutter-width
=last-column
margin-right: 0
=first-column
margin-right: 0
=column($columns, $first: false, $last: false)
@extend column-base
@if $first
@extend first-column
@if $last
@extend last-column
width: $column-width * $columns - $gutter-width
=three-column-layout($left-cols, $middle-cols, $right-cols)
=full-width
+column($left-cols + $middle-cols + $right-cols, $first: true, $last: true)
=header
@extend full-width
=footer
@extend full-width
=left-column
+column($left-cols, $first: true)
=middle-column
+column($middle-cols)
=right-column
+column($right-cols, $last: true)
@yield
body.standard
+three-column-layout(5,12,7)
#footer
+footer
#header
+header
#sidebar
+left-column
#content
+middle-column
#ads
+right-column
@chriseppstein
Copy link
Author

So, I've never really liked interpolation but I liked what I could do with it. And I've never really liked passing selectors to mixins, it feels wrong to treat a selector like a string. In this gist, I explore how one might create reuse of patterns that coordinate styles across selectors.

New ideas in this gist:

  • Allow mixins that have no arguments to be @extend'ed
  • Allow nested mixin definitions
  • Allow nested content inside a mixin include to be placed by the mixin using @yield

@rkh
Copy link

rkh commented May 20, 2010

The @yield thing would be fancy.

@chriseppstein
Copy link
Author

I'm not sure about the word I'm using for @yield. I'm also considering @children and @content.

Also, If it's confusing that you can't extend some mixins, then I've considered @fragment or @capture for no-argument mixins...

@rkh
Copy link

rkh commented May 20, 2010

I don't like @children in that context, but both @content and @capture seem fitting to me.

@tobias
Copy link

tobias commented May 20, 2010

Out of @yield, @children, @content, @content seems the most intuitive to me, though @yield should click immediately w/rubyists.

The use of @extend on mixins doesn't make sense to me, unless I can 'open' a mixin elsewhere. like so:
=three-column-layout($left-cols, $middle-cols, $right-cols)
=full-width
+column($left-cols + $middle-cols + $right-cols, $first: true, $last: true)
=header
@extend full-width

=full-width
  padding-right: 10px

otherwise, it seems no different than +full-width.

@chriseppstein
Copy link
Author

@tobias, conceptually, the only difference between extending and including a simple mixin is what css gets generated.

What use case would be supported by reopening a mixin (btw, that would introduce a backwards incompatibility)? It's not clear to me what the purpose would be.

@tobias
Copy link

tobias commented May 20, 2010

I see no use case for reopening a mixin, I'm just trying to understand your use of @extend here. The idea of being able to reopen a mixin seems to be the conceptual equivalent of how @extend works with classes, but if that is not the case, then maybe @extend isn't the best name for this directive, as you mentioned above.

From the example, I see no difference between the css that would be generated by:
=header
@extend full-width
and
=header
+full-width

unless @extend full-width acts as a closure, and +full-width does not.

@chriseppstein
Copy link
Author

@tobias,

In this example, there's a closure around the three-column-layout mixin and it's children, so the extends are only extending the instance of full-width that exists in that context. If we were extending a class this would not be the case and might cause selector bleed to other uses of the three-column-layout. The other advantage of extending a no-argument mixin is that there's no presentational class name polluting the generated css. Take a look at the generated css, and you'll see this example is generating hand-crafted quality, semantic css, because the code is describing the concepts of building a grid and using that grid to create a three column layout.

Note that you don't have to use all of the mixins in the scoped context, so the other reason we use extend with +header and +footer is so that header and footer will share their properties if they are both used instead of copying the same contents into each.

@tobias
Copy link

tobias commented May 20, 2010

@chriseppstein:

Thanks for taking the time to explain it - that all makes sense now. I look at the generated css so rarely I had forgotten that mixin inclusion is a blind copy and does not merge the properties. With that reminder, things fell into place. Sorry to sidetrack the discussion.

@hagenburger
Copy link

I like it. The only thing I don’t like about extending mixins is the name “mixin”. Maybe “block” would be better. For the yield thing I prefer @content.

Maybe we could auto-@yield if there’s no @yield but a closure.

I think this could be possible (even this example won’t make useful code):

=columns($count)
  @for $i from 1 through $count
    .column-#{$i}
      width: $i * 10
      @yield

.table
  +columns(7)
    height: 10px

What about scopes?

=color-steps($color-start, $color-end, $steps)
  @for $step from 1 through $steps
    $color = mix-colors($color-end, $color-start, 100% / $step * $steps)
    @yield
    // or: @yield $step, $color

+color-steps(red, green, 10)
  .column-#{$step}
    background: lighten($color, 50%)
    border: 1px $color solid

@chriseppstein
Copy link
Author

Some interesting ideas and observations there, @hagenburger. Yes, if you called @yield (or whatever it is called) more than once you'd end up placing the contents more than once -- and while I can't think of a good use for that at this instant, I'm sure I will ;)

I'm not sure about auto-yielding -- at first I really liked it, but it would preclude the ability to create a mixin that performs conditional inclusion.

The idea of letting the mixin pass variables to the child block, is interesting too -- I think I prefer the explicit approach.

It had occurred to me that using mixins as a scoping/iteration mechanism like you suggest is a very interesting way of creating localized behaviors within a stylesheet. I've wanted such a capability for compass on many occasions.

@chriseppstein
Copy link
Author

Nathan and I discussed this last night... I don't think we'll see these features anytime soon.

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