@extend

Frequentemente existem casos quando desenhas uma página quando uma classe deveria ter todos os estilos duma outra classe, bem como seus próprios estilos específicos. Por exemplo, a metodologia BEM encoraja classes de modificador que ligam-se aos mesmos elementos como classes de bloco ou elemento. Mas isto pode criar HTML atravancado, é propenso à erros de esquecer de incluir ambas classes, e pode trazer preocupações de estilo não semânticos para a tua marcação.

<%# TODO(jina): I think these code blocks should be side-by-side %>

<div class="error error--serious">
  Oh no! You've been hacked!
</div>
.error {
  border: 1px #f00;
  background-color: #fdd;
}

.error--serious {
  border-width: 3px;
}

A regra @extend da Sass soluciona isto. É escrita como @extend <selector>, e diz que a Sass que aquele seletor deve herdar os estilos dum outro:

SCSS Syntax

.error {
  border: 1px #f00;
  background-color: #fdd;

  &--serious {
    @extend .error;
    border-width: 3px;
  }
}

Sass Syntax

.error
  border: 1px #f00
  background-color: #fdd

  &--serious
    @extend .error
    border-width: 3px


CSS Output

.error, .error--serious {
  border: 1px #f00;
  background-color: #fdd;
}
.error--serious {
  border-width: 3px;
}


Quando uma classe estende uma outra, a Sass estiliza todos os elementos que correspondem ao extensor como se adicionasses a classe estendida à todos elementos na tua HTML que já tinha a classe em extensão. Tu podes apenas escrever class="error--serious", e a Sass certificar-se-á de que é estilizada como se também tivesse class="error".

Claro, os seletores não são apenas usados em suas próprias regras de estilo. A Sass sabe estender em toda parte que o seletor for usado. Isto garante que os teus elementos são estilizados exatamente como se correspondessem o seletor estendido:

SCSS Syntax

.error:hover {
  background-color: #fee;
}

.error--serious {
  @extend .error;
  border-width: 3px;
}

Sass Syntax

.error:hover
  background-color: #fee


.error--serious
  @extend .error
  border-width: 3px

CSS Output

.error:hover, .error--serious:hover {
  background-color: #fee;
}

.error--serious {
  border-width: 3px;
}

⚠️ Atenção!

As extensões são resolvidas depois do resto da tua folha de estilo for compilado. Em particular, isto acontecer depois dos seletores de pai serem resolvidos. Isto significa que se fizeres @extend .error, não surtirá efeito no seletor interno em .error { &__icon { ... } }. Isto também significa que os seletores de pai na SassScript não podem ver os resultados da extensão.

Como Isto FuncionaComo Isto Funciona permalink

Ao contrário das misturas, que copiam os estilos para a atual regra de estilo, @extend atualiza as regras de estilo que contém o seletor estendido para que também contenham o seletor estendido. Quando estendes os seletores, a Sass faz a unificação inteligente:

  • Ela nunca gera seletores como #main#footer que possivelmente não podem corresponder quaisquer elementos.

  • Ela garante que seletores complexos sejam intercalados para que funcionem não importa qual ordem os elementos da HTML são encaixados.

  • Ela corta seletores redundantes o máximo possível, embora ainda garanta que a especificidade seja maior do que ou igual à aquela do extensor.

  • Ela sabe quando um seletor corresponde tudo que um outro faz, e pode combiná-los entre si.

  • Ela manipula inteligentemente combinadores, seletores universais, e pseudo-classes que contêm seletores.

SCSS Syntax

.content nav.sidebar {
  @extend .info;
}

// Isto não será estendido, porque `p` é incompatível com `nav`.
p.info {
  background-color: #dee9fc;
}

// Não existe maneira de saber se `<div class="guide">` estará dentro ou
// fora do `<div class="content">`, assim a Sass gera ambos por segurança.
.guide .info {
  border: 1px solid rgba(#000, 0.8);
  border-radius: 2px;
}

// A Sass sabe que todo elemento correspondendo "main.content" também corresponde `.content`
// e evita gerar seletores intercalados desnecessários.
main.content .info {
  font-size: 0.8em;
}

Sass Syntax

.content nav.sidebar
  @extend .info


// Isto não será estendido, porque `p` é incompatível com `nav`.
p.info
  background-color: #dee9fc


// Não existe maneira de saber se `<div class="guide">` estará dentro ou
// fora do `<div class="content">`, assim a Sass gera ambos por segurança.
.guide .info
  border: 1px solid rgba(#000, 0.8)
  border-radius: 2px


// A Sass sabe que todo elemento correspondendo "main.content" também corresponde `.content`
// e evita gerar seletores intercalados desnecessários.
main.content .info
  font-size: 0.8em

CSS Output

p.info {
  background-color: #dee9fc;
}

.guide .info, .guide .content nav.sidebar, .content .guide nav.sidebar {
  border: 1px solid rgba(0, 0, 0, 0.8);
  border-radius: 2px;
}

main.content .info, main.content nav.sidebar {
  font-size: 0.8em;
}









💡 Fato Divertido:

Tu podes acessar diretamente a unificação inteligente da Sass usando funções de seletor! A função selector.unify() retorna um seletor que corresponde a interseção de dois seletores, enquanto a função seletor.extend() funciona tal como @extend, mas sobre um único seletor.

⚠️ Atenção!

Uma vez que @extend atualiza as regras de estilo que contém o seletor estendido, suas regras têm precedência na cascata baseado em onde as regras de estilo do seletor estendido aparecem, não baseados em onde a @extend aparece. Isto pode ser confuso, mas apenas lembre: isto é a mesma precedência que estas regras teriam se adicionasses a classe estendida ao teu HTML!

Seletores de Espaço ReservadoSeletores de Espaço Reservado permalink

Algumas vezes queres escrever uma regra de estilo que está apenas destinada a ser estendida. Neste caso, podes usar os seletores de espaço reservado, que se parecerem com seletores de classe que começam com % ao invés de .. Quaisquer seletores que incluem espaços reservados não são incluídos na saída de CSS, mas os seletores que as estendem são:

SCSS Syntax

.alert:hover, %strong-alert {
  font-weight: bold;
}

%strong-alert:hover {
  color: red;
}

Sass Syntax

.alert:hover, %strong-alert
  font-weight: bold


%strong-alert:hover
  color: red

CSS Output

.alert:hover {
  font-weight: bold;
}




Espaços Reservados PrivadosEspaços Reservados Privados permalink

Tal como os membros do módulo, um seletor de espaço reservado pode ser marcado como privado ao iniciar o seu nome ou com - ou _. Um seletor de espaço reservado privado apenas pode ser estendido dentro da folha de estilo que o define. Para quaisquer outras folhas de estilo, parecerá como se este seletor não existisse.

Âmbito de ExtensãoÂmbito de Extensão permalink

Quando uma folha de estilo estende um seletor, esta extensão apenas afetará as regras de estilo escritas módulos ascendentes — isto é, os módulos que são carregados por esta folha de estilo usando a regra @use ou a regra @forward, módulos carregados por estes módulos, e assim por diante. Isto ajuda a tornar as regras de @extend mais previsíveis, garantindo que afetam apenas os estilos que estavam cientes de quando as escrevestes-

⚠️ Atenção!

As extensões não são limitadas ao todo se estiveres a usar a regra @import. Não apenas afetarão todas as folhas de estilo que importas, afetarão todas as folhas de estilo que importam a tua folha de estilo, todo o resto que estas folhas de estilo importam, e assim por diante. Sem @use, as extensões são globais.

Extensões Obrigatórias e OpcionaisExtensões Obrigatórias e Opcionais permalink

Normalmente, se uma @extend não corresponder quaisquer seletores na folha de estilo, Sass produzirá um erro. Isto ajuda proteger de erros de digitação ou de renomear um seletor sem renomear os seletores que herdam deste. Extensões que exigem que o seletor estendido exista são obrigatória.

Isto pode não ser sempre o que queres. Se quiseres que a @extend não faça nada se o seletor estendido não existir, apenas adicione !optional no final.

Extensões ou Misturas?Extensões ou Misturas? permalink

As extensões e misturas são ambas maneiras de encapsular e reutilizar estilos na Sass, o que naturalmente levanta a questão de quando usar uma ou outra. As misturas são obviamente necessárias quando precisas de configurar os estilos usando argumentos, mas e se forem apenas um pedaço de estilos?

Como regra de ouro, extensões são a melhor opção quando estás a expressar uma relação entre classes semânticas (ou outros seletores semânticos). Uma vez que um elemento com a classe .error--serious é um erro, faz sentido para ele estender .error. Mas para coleções não semânticas de estilos, escrever uma mistura pode evitar dores de cabeças de cascata e torna mais fácil configurar.

💡 Fato Divertido:

A maioria dos servidores da Web compactam a CSS que servem usando um algoritmo que é muito bom em lidar com pedaços repetidos de texto idêntico. Isto significa que, embora as misturas possam produzir mais CSS do que as extensões, provavelmente não acrescentará substancialmente a quantidade que os teus utilizadores precisam descarregar. Então escolha a funcionalidade que faz mais sentido para o teu caso de uso, não aquele que gera menos CSS!

LimitaçõesLimitações permalink

Seletores DesautorizadosSeletores Desautorizados permalink

Compatibilidade (No Compound Extensions):
Sass de Dart
LibSass
Sass de Ruby

A LibSass e Sass de Ruby atualmente permite que seletores compostos como .message.info sejam estendidos. No entanto, este comportamento não corresponde a definição de @extend: ao invés de estilizar elementos que correspondem o seletor estendendo como se tivesse class="message info", o que seria afetado pelas regras de estilo que incluíam ou .message ou .info, este apenas os estilizou com regras que incluíam ambas .message e .info.

Para manter a definição de @extend clara e compreensível, e manter a implementação clara e eficiente, este comportamento agora está depreciada e será removida das versões futuras.

Consulte a página de mudança de rutura por mais detalhes.

Apenas seletores simples — seletores de individuais como .info ou a — podem ser estendidos. Se .message.info poderia ser estendido, a definição de @extend diz que os elementos correspondendo o extensor seriam estilizados como se correspondesse .message.info. Isto apenas é o mesmo que corresponder ambas .message e .info, assim não existiriam qualquer beneficio em escrever esta no lugar de @extend .message, .info.

De maneira semelhante, se .main .info pudessem ser estendidos, faria (quase) a mesma coisa como estender .info por si mesmo. As diferenças subtis não são dignas da confusão de parecer que está a fazer algo substancialmente diferente, assim isto não é permitido:

SCSS Syntax

.alert {
  @extend .message.info;
  //      ^^^^^^^^^^^^^
  // Error: Write @extend .message, .info instead.

  @extend .main .info;
  //      ^^^^^^^^^^^
  // Error: write @extend .info instead.
}

Sass Syntax

.alert
  @extend .message.info
  //      ^^^^^^^^^^^^^
  // Error: Write @extend .message, .info instead.

  @extend .main .info
  //      ^^^^^^^^^^^
  // Error: write @extend .info instead.

Heurísticas da HTMLHeurísticas da HTML permalink

Quando a @extend seletores complexos intercalados, não gera todas as combinações possíveis de seletores ancestrais. Muitos dos seletores que poderia gerar são pouco prováveis que na realidade correspondam a HTML real, gerá-los tornaria as folhas de estilo muito grande para um valor real muito pequeno. Ao invés disto, usa uma heurística: supõe que cada ancestral do seletor será autosuficiente, sem ser intercalado com quaisquer outros ancestrais do seletor:

SCSS Syntax

header .warning li {
  font-weight: bold;
}

aside .notice dd {
  // Sass doesn't generate CSS to match the <dd> in
  //
  // <header>
  //   <aside>
  //     <div class="warning">
  //       <div class="notice">
  //         <dd>...</dd>
  //       </div>
  //     </div>
  //   </aside>
  // </header>
  //
  // because matching all elements like that would require us to generate nine
  // new selectors instead of just two.
  @extend li;
}

Sass Syntax

header .warning li
  font-weight: bold


aside .notice dd
  // Sass doesn't generate CSS to match the <dd> in
  //
  // <header>
  //   <aside>
  //     <div class="warning">
  //       <div class="notice">
  //         <dd>...</dd>
  //       </div>
  //     </div>
  //   </aside>
  // </header>
  //
  // because matching all elements like that would require us to generate nine
  // new selectors instead of just two.
  @extend li

CSS Output

header .warning li, header .warning aside .notice dd, aside .notice header .warning dd {
  font-weight: bold;
}


















Estender em @mediaEstender em @media permalink

Embora @extend seja permitido dentro da @media e outras regras de arroba da CSS, não é permitido estender seletores que aparecem fora da sua regra de arroba. Isto porque estender seletor apenas aplicasse dentro do contexto duma dada media, e não existe maneira de garantir que a restrição está preservada no seletor gerado sem duplicar a regra de estilo inteira:

SCSS Syntax

@media screen and (max-width: 600px) {
  .error--serious {
    @extend .error;
    //      ^^^^^^
    // Error: ".error" was extended in @media, but used outside it.
  }
}

.error {
  border: 1px #f00;
  background-color: #fdd;
}

Sass Syntax

@media screen and (max-width: 600px)
  .error--serious
    @extend .error
    //      ^^^^^^
    // Error: ".error" was extended in @media, but used outside it.



.error
  border: 1px #f00
  background-color: #fdd