web-dev-qa-db-fra.com

Extension des sélecteurs à partir de requêtes multimédia avec Sass

J'ai une classe d'objets et une classe "modificatrice" compacte:

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

C'est bon. Cependant, j'aimerais ajouter une requête @media qui oblige la classe .item à être compacte lorsque l'écran est suffisamment petit.

À première vue, voici ce que j'ai essayé de faire:

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

Mais cela génère l'erreur suivante:

Vous ne pouvez pas @ ajouter un sélecteur externe à partir de @media. Vous pouvez seulement @extend des sélecteurs dans la même directive.

Comment pourrais-je accomplir cela en utilisant SASS sans avoir à recourir à des styles de copier/coller?

55
mindeavor

La réponse simple est: vous ne pouvez pas parce que Sass ne peut pas (ou ne veut pas) composer le sélecteur pour cela. Vous ne pouvez pas être à l'intérieur d'une requête multimédia et étendre quelque chose qui est en dehors d'une requête multimédia. Ce serait certainement bien si on en prenait simplement une copie au lieu d'essayer de composer les sélecteurs. Mais ce n'est pas si vous ne pouvez pas.

Utiliser un mixin

Si vous envisagez de réutiliser un bloc de code à l'intérieur et à l'extérieur de requêtes multimédia et souhaitez tout de même pouvoir l'étendre, écrivez à la fois un mixin et une classe d'extension:

@mixin foo {
    // do stuff
}

%foo {
    @include foo;
}

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

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

Étendre le sélecteur dans une requête multimédia de l'extérieur

Cela n’aidera pas vraiment votre cas d’utilisation, mais c’est une autre option:

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

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

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

.bar {
  @extend %bar;
}

Attendez que Sass lève cette restriction (ou corrigez vous-même)

Il existe un certain nombre de discussions en cours sur ce problème (veuillez ne pas contribuer à ces discussions, sauf si vous avez quelque chose de significatif à ajouter. Les responsables de la maintenance savent déjà que les utilisateurs souhaitent cette fonctionnalité. la syntaxe devrait être).

68
cimmanon

Pour mémoire, voici comment j'ai fini par résoudre le problème en ne dupliquant qu'une seule fois les styles générés:

// 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

Je crois que SASS/SCSS ne prend pas en charge la directive @extend dans une requête multimédia. http://designshack.net/articles/css/sass-and-media-queries-what-you-can-and-cant-do/

Vous devrez peut-être utiliser un mixin à la place, même si le code doit être évalué en fonction de votre objectif. 

2
JHogue

C'est la solution partielle la plus propre que j'ai trouvée. Il tire parti de @extend dans la mesure du possible et fait appel à mixins lors de requêtes multimédia.

Directives Cross-Media Query @extend dans Sass

Reportez-vous à l'article pour plus de détails, mais Gist signifie que vous appelez un paramètre fictif 'mixin' qui décide ensuite de générer @extend ou un @include.

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

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

En fin de compte, ce n’est peut-être pas mieux que d’utiliser des mixins, ce qui est actuellement la réponse acceptée.

1
Tom Genoni

J'utilise des points d'arrêt, mais c'est la même idée:

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

Comment l'utiliser:

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

Il y a un texte à propos de mixins où vous pouvez en savoir plus sur cette option.

0
Nesha Zoric