@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
- 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 @media
Estender 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