Estendendo seletores de consultas de mídia com Sass

86

Eu tenho uma classe de item e uma classe "modificadora" compacta:

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

Isto é bom. No entanto, gostaria de adicionar uma @mediaconsulta que force a .itemclasse a ser compacta quando a tela é pequena o suficiente.

À primeira vista, foi isso que tentei fazer:

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

Mas isso gera o seguinte erro:

Você não pode @estender um seletor externo de dentro de @media. Você só pode @extend seletores dentro da mesma diretiva.

Como eu faria isso usando SASS sem ter que recorrer a estilos de copiar / colar?

soundly_typed
fonte
Fyi, aqui está um problema que faria o exemplo que você deu funcionar corretamente: github.com/sass/sass/issues/1050
Ajedi32

Respostas:

112

A resposta simples é: você não pode porque Sass não pode (ou não quer) compor o seletor para isso. Você não pode estar dentro de uma consulta de mídia e estender algo que está fora de uma consulta de mídia. Certamente seria bom se ele simplesmente pegasse uma cópia ao invés de tentar compor os seletores. Mas não, então você não pode.

Use um mixin

Se você tiver um caso em que irá reutilizar um bloco de código dentro e fora das consultas de mídia e ainda quiser que ele seja capaz de estendê-lo, escreva uma classe mixin e uma classe extend:

@mixin foo {
    // do stuff
}

%foo {
    @include foo;
}

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

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

Estenda o seletor em uma consulta de mídia de fora

Isso realmente não ajudará em seu caso de uso, mas é outra opção:

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

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

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

.bar {
  @extend %bar;
}

Espere até que Sass tire essa restrição (ou remende você mesmo)

Há uma série de discussões em andamento sobre este problema (por favor, não contribua com esses tópicos, a menos que você tenha algo significativo a acrescentar: os mantenedores já estão cientes de que os usuários desejam esta funcionalidade, é apenas uma questão de como implementá-la e qual o sintaxe deve ser).

Cimmanon
fonte
@mindeavor Isso funcionou para você? Você conseguiu usar a classe estendida em uma consulta de mídia? No Sass 3.2?
Yahreen de
1
%fooé desnecessário, .foopode diretamente @include foo.
phil294
No meu caso, acabei de usar% placeholder com consultas estendidas de mídia externa. Então, dentro da consulta de mídia, para o meu seletor acabou de adicionar extend% placeholder. Vou ver se as discussões trazem algo útil. Obrigado Cimmanon.
keypaul
11

Para registro, aqui está como acabei resolvendo o problema com a duplicação de estilos gerados apenas uma vez:

// 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;
  }
}
soundly_typed
fonte
2

Eu acredito que SASS / SCSS não suporta a @extenddiretiva dentro de uma consulta de mídia. http://designshack.net/articles/css/sass-and-media-queries-what-you-can-and-cant-do/

Você pode precisar usar um mixin em vez disso, embora o inchaço do código precise ser pesado contra seu objetivo.

JHogue
fonte
Um link para uma solução é bem-vindo, mas certifique-se de que sua resposta seja útil sem ele: adicione contexto ao link para que seus outros usuários tenham uma ideia do que ele é e por que está lá, depois cite a parte mais relevante da página que você ' novo link para caso a página de destino não esteja disponível. Respostas que são pouco mais do que um link podem ser excluídas.
dippas
1

Esta é a solução parcial mais limpa que encontrei. Ele tira vantagem do @extend onde possível e recorre aos mixins quando está dentro de consultas de mídia.

Cross-Media Query @extend Directives no Sass

Veja o artigo para detalhes completos, mas a essência é que você chama um mixin de 'placeholder' que então decide se deve produzir @extend ou @include.

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

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

Em última análise, pode não ser melhor do que apenas usar mixins, que atualmente é a resposta aceita.

Tom Genoni
fonte
0

Eu uso pontos de interrupção, mas é a mesma ideia:

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

Como usá-lo:

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

Existe um texto sobre mixins onde você pode descobrir mais sobre esta opção.

Nesha Zoric
fonte
-2

Você poderia reestruturar?

.compact { //compact-styles }
.item {}
.item.compact { @extend .compact } 

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

Se eu entendi a documentação corretamente, isso deve funcionar. Acho que o motivo pelo qual você está tentando não funcionar é que ele não vê .item.compact ao analisar @extend, mas essa é uma suposição desinformada, então pegue isso com um caminhão carregado de sal! :)

Jason M. Batchelor
fonte
Como você está compilando seu SASS? Externamente, com JS ou com algum tipo de componente do lado do servidor?
Jason M. Batchelor
Ele está sendo compilado por meio da rails-sassgema padrão , usando SASS
v3.2.4
1
Parece que a capacidade de estender as consultas @media foi descontinuada e deve ser eliminada em 3.3: chriseppstein.github.com/blog/2012/08/23/sass-3-2-is-released (leia a área que diz "Limitações @extendnas diretivas CSS")
Jason M. Batchelor
Se entendi as informações corretamente, isso pode ser a causa do problema. Eu estaria interessado em saber o que você descobriu!
Jason M. Batchelor