Re: Thinking about mixins as a new type of selector

I asked David for some more details about how his proposal worked in
some corner cases.  With that information, it's clear that this
proposal is exactly equivalent to SASS's @extend, just with a more
explicit (and I think less convenient) syntax.

Here's a few examples to illustrate this, taken from SASS's own reference files.

Example 1
=========
SASS:
.error {
  border: 1px #f00;
  background-color: #fdd;
}
.error.intrusion {
  background-image: url("/image/hacked.png");
}
.seriousError {
  @extend .error;
  border-width: 3px;
}

CSS:
@matches $error .error;
$error {
  border: 1px #f00;
  background-color: #fdd;
}
$error.intrusion {
  background-image: url("/image/hacked.png");
}
@matches $error .seriousError;
.seriousError {
  border-width: 3px;
}


Example 2
=========
SASS:
.error {
  border: 1px #f00;
  background-color: #fdd;
}
.attention {
  font-size: 3em;
  background-color: #ff0;
}
.seriousError {
  @extend .error;
  @extend .attention;
  border-width: 3px;
}

CSS:
@matches $error .error;
$error {
  border: 1px #f00;
  background-color: #fdd;
}
@matches $attention .attention;
$attention {
  font-size: 3em;
  background-color: #ff0;
}
@matches $error .seriousError;
@matches $attention .seriousError;
.seriousError {
  border-width: 3px;
}


Example 3
=========
SASS:
.error {
  border: 1px #f00;
  background-color: #fdd;
}
.seriousError {
  @extend .error;
  border-width: 3px;
}
.criticalError {
  @extend .seriousError;
  position: fixed;
  top: 10%;
  bottom: 10%;
  left: 10%;
  right: 10%;
}

CSS:
@matches $error .error;
$error {
  border: 1px #f00;
  background-color: #fdd;
}
@matches $error $seriousError;
@matches $seriousError .seriousError;
$seriousError {
  border-width: 3px;
}
@matches $seriousError .criticalError;
.criticalError {
  position: fixed;
  top: 10%;
  bottom: 10%;
  left: 10%;
  right: 10%;
}


Example 4
=========
SASS:
#admin .tabbar a {font-weight: bold}
#demo .overview .fakelink {@extend a}

CSS:
@matches $link a;
#admin .tabbar $link {font-weight: bold}
@matches $link #demo .overview .fakelink;

Equivalent Vanilla:
#admin .tabbar a,
:matches(#admin .tabbar .fakelink):matches(#demo .overview .fakelink) {
  font-weight: bold;
}


(Technically, David's proposal is more powerful. SASS "cheats" in
example 4 and actually doesn't quite generate the same thing, to avoid
having to generate a combinatorial explosion of selectors.  Similarly,
SASS avoids extending things across @media boundaries, so that it
doesn't have to duplicate a lot of style, which isn't a problem for a
native system.  These are both just implementation difficulties
because SASS isn't native; they're not fundamental weaknesses of
SASS's @extend.)

Overall, I find David's syntax somewhat less convenient than SASS's
@extend.  At least in these small examples, it seems like David's
syntax moves important information around in a slightly confusing way.
 It *may* be better in larger examples, I'm not sure.  It also means
that you have to change potentially a lot of code if you later decide
you want to extend a particular selector (to change all the instances
of the "normal" selector you're using to a variable).

I might like a variant of SASS's extend that doesn't nest inside of a
declaration block, though, like:

.error { ... }
.seriousError { ... }
@extend .error .seriousError;

The first argument would be a compound selector, the second would be a
complex selector defined to be equivalent.  I'm not sure if this is
easier or harder to read.


Anyway, good times.  I approve of motion in this direction.

As a final note, this is *not* a replacement for my @mixin suggestion.
 This can be used to replace @mixin without any arguments, but Mixins
with arguments are powerful and very useful, as SASS demonstrates.

~TJ

Received on Thursday, 16 August 2012 00:15:50 UTC