web-dev-qa-db-de.com

Selektoren aus Medienabfragen mit Sass erweitern

Ich habe eine Item-Klasse und eine kompakte "Modifier" -Klasse:

.item { ... }
.item.compact { /* styles to make .item smaller */ }

Das ist okay. Ich möchte jedoch eine @media-Abfrage hinzufügen, die die .item-Klasse zwingt, kompakt zu sein, wenn der Bildschirm klein genug ist.

Auf den ersten Blick habe ich folgendes versucht:

.item { ... }
.item.compact { ... }
@media (max-width: 600px) {
  .item { @extend .item.compact; }
}

Dies erzeugt jedoch den folgenden Fehler:

Sie können einen äußeren Selektor nicht innerhalb von @media erweitern. Sie dürfen nur @extend-Selektoren innerhalb derselben Anweisung.

Wie kann ich dies mit SASS erreichen, ohne auf Styles kopieren oder einfügen zu müssen?

55
mindeavor

Die einfache Antwort ist: Sie können nicht, weil Sass den Selektor nicht (oder nicht) zusammenstellen kann. Sie können sich nicht in einer Medienabfrage befinden und etwas erweitern, das sich nicht in einer Medienabfrage befindet. Es wäre sicherlich schön, wenn Sie einfach eine Kopie davon nehmen würden, anstatt zu versuchen, die Selektoren zusammenzustellen. Aber so kann es nicht sein.

Verwenden Sie ein Mixin

Wenn Sie einen Fall haben, in dem Sie einen Codeblock innerhalb und außerhalb von Medienabfragen wiederverwenden möchten und möchten, dass er diesen erweitern kann, schreiben Sie sowohl eine Mixin-Klasse als auch eine Erweiterungsklasse:

@mixin foo {
    // do stuff
}

%foo {
    @include foo;
}

// usage
.foo {
    @extend %foo;
}

@media (min-width: 30em) {
    .bar {
        @include foo;
    }
}

Erweitern Sie den Selektor innerhalb einer Medienabfrage von außen

Dies wird Ihrem Anwendungsfall nicht wirklich helfen, aber es ist eine andere Option:

%foo {
  @media (min-width: 20em) {
    color: red;
  }
}

@media (min-width: 30em) {
  %bar {
    background: yellow;
  }
}

// usage
.foo {
  @extend %foo;
}

.bar {
  @extend %bar;
}

Warten Sie, bis Sass diese Einschränkung aufhebt (oder selbst reparieren)

Es gibt eine Reihe von Diskussionen zu diesem Problem (bitte tragen Sie nicht zu diesen Threads bei, es sei denn, Sie haben etwas sinnvolles hinzuzufügen: Die Betreuer wissen bereits, dass Benutzer diese Funktionalität wünschen, es ist nur eine Frage, wie sie implementiert werden soll und welche Syntax sollte sein).

68
cimmanon

Zum Schluss habe ich das Problem gelöst, indem generierte Stile nur einmal dupliziert wurden:

// This is where the actual compact styles live
@mixin compact-mixin { /* ... */ }

// Include the compact mixin for items that are always compact
.item.compact { @include compact-mixin; }

// Here's the tricky part, due to how SASS handles extending
.item { ... }
// The following needs to be declared AFTER .item, else it'll
// be overridden by .item's NORMAL styles.
@media (max-width: 600px) {
  %compact { @include compact-mixin; }

  // Afterwards we can extend and
  // customize different item compact styles
  .item {
    @extend %compact;
    /* Other styles that override %compact */
  }
  // As shown below, we can extend the compact styles as many
  // times as we want without needing to re-extend
  // the compact mixin, thus avoiding generating duplicate css
  .item-alt {
    @extend %compact;
  }
}
11
mindeavor

Ich glaube, SASS/SCSS unterstützt die @extend-Direktive in einer Medienabfrage nicht. http://designshack.net/articles/css/sass-and-media-queries-what-you-can-and-cant-do/

Möglicherweise müssen Sie stattdessen ein Mixin verwenden, obwohl der Code-Bloat gegen Ihr Ziel abgewogen werden muss. 

2
JHogue

Dies ist die sauberste Teillösung, die ich gefunden habe. Es nutzt, wenn möglich, @extend und greift bei Medienabfragen auf Mixins zurück.

Cross-Media-Query @extend-Direktiven in Sass

Weitere Informationen finden Sie in diesem Artikel. Der Gist ist jedoch, dass Sie einen Mixin-Platzhalter aufrufen, der dann entscheidet, ob Sie @extend oder ein @include ausgeben.

@include placeholder('clear') {
   clear: both;
   overflow: hidden;
}

.a {
    @include _(clear);
}
.b {
    @include _(clear);
}
.c {
    @include breakpoint(medium) {
      @include _(clear);
   }
}

Letztendlich ist es vielleicht nicht besser als nur Mixins zu verwenden, was derzeit die akzeptierte Antwort ist.

1
Tom Genoni

Ich benutze Haltepunkte, aber es ist dieselbe Idee:

@mixin bp-small {
    @media only screen and (max-width: 30em) {
        @content;
    }

Wie man es benutzt:

.sidebar {
    width: 60%;
    float: left;
    @include bp-small {
        width: 100%;
        float: none;
    }
}

Es gibt einen Text über Mixins, wo Sie mehr über diese Option erfahren können.

0
Nesha Zoric