106 votes

Extension des sélecteurs à partir de media queries avec Sass

J'ai une classe d'article et une classe compacte de "modificateur" :

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

C'est bien. Cependant, j'aimerais ajouter un @media qui force le .item pour être compact lorsque l'écran est suffisamment petit.

A première vue, c'est 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 @extendre un sélecteur externe à partir d'un @media. Vous pouvez uniquement @extension de sélecteurs au sein d'une même directive.

Comment puis-je y parvenir en utilisant SASS sans avoir recours au copier/coller de styles ?

141voto

cimmanon Points 25378

La réponse est simple : vous ne pouvez pas le faire parce que Sass ne peut pas (ou ne veut pas) composer le sélecteur correspondant. Vous ne pouvez pas être à l'intérieur d'une requête média et étendre quelque chose qui est à l'extérieur d'une requête média. Ce serait certainement bien s'il pouvait simplement en prendre une copie au lieu d'essayer de composer les sélecteurs. Mais ce n'est pas le cas, donc vous ne pouvez pas le faire.

Utiliser une mixine

Si vous avez l'intention de réutiliser un bloc de code à l'intérieur et à l'extérieur des requêtes média et que vous voulez quand même pouvoir l'étendre, écrivez à la fois un mixin et une classe extend :

@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 média depuis l'extérieur

Cela ne vous aidera pas vraiment dans votre cas, 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-la vous-même).

Un certain nombre de discussions sont en cours à ce sujet (veuillez ne pas contribuer à ces fils de discussion à moins d'avoir quelque chose de significatif à ajouter : les mainteneurs sont déjà conscients que les utilisateurs souhaitent cette fonctionnalité, il s'agit juste de savoir comment l'implémenter et quelle doit être la syntaxe).

13voto

mindeavor Points 2154

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;
  }
}

2voto

JHogue Points 206

Je crois que SASS/SCSS ne supporte pas l'option @extend à l'intérieur d'une requête média. http://designshack.net/articles/css/sass-and-media-queries-what-you-can-and-cant-do/

Vous pourriez avoir besoin d'utiliser un mixin à la place, bien que le gonflement du code doive être évalué par rapport à votre objectif.

1voto

Tom Genoni Points 66

C'est la solution la plus propre et partielle que j'ai trouvée. Elle tire parti de @extend lorsque cela est possible et se rabat sur les mixins lorsqu'elle se trouve dans les media queries.

Directives @extend de requête cross-média dans Sass

Consultez l'article pour plus de détails, mais l'essentiel est que vous appelez un mixin 'placeholder' qui décide ensuite de produire un @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 simplement des mixins, ce qui est actuellement la réponse acceptée.

0voto

Nebojsa Zoric Points 41

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 des mixins où vous pouvez trouver plus d'informations sur cette option.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X