Sass combinando pai usando "e" comercial (&) com seletores de tipo

100

Estou tendo problemas com aninhamento em Sass. Digamos que eu tenha o seguinte HTML:

<p href="#" class="item">Text</p>
<p href="#" class="item">Text</p>
<a href="#" class="item">Link</a>

Quando tento aninhar meus estilos no seguinte, recebo um erro de compilação:

.item {
    color: black;
    a& {
        color:blue;
   }
}

Como faço referência a um seletor de tipo antes do seletor pai quando ele faz parte do mesmo elemento?

McShaman
fonte

Respostas:

156

Como Kumar aponta , isso é possível desde Sass 3.3.0.rc.1 (Maptastic Maple).

A diretiva @ at-root faz com que uma ou mais regras sejam emitidas na raiz do documento, em vez de serem aninhadas abaixo de seus seletores pais.

Podemos combinar a @at-rootdiretiva com a interpolação#{} para chegar ao resultado pretendido.

SASS

.item {
    color: black;
    @at-root {
        a#{&} {
            color:blue;
        }
    }
}

// Can also be written like this.
.item {
    color: black;
    @at-root a#{&} {
        color:blue;
    }
}

CSS de saída

.item {
    color: black;
}
a.item {
    color: blue;
}
Blaine
fonte
3
Esta deve ser a solução para esta questão.
Kayhadrin de
Isso não está funcionando para mim ... a saída está saindo .item a.itempor algum motivo. Eu tentei fazer a#{&}por conta própria também e ainda deu o mesmo resultado.
Jaminroe
@jaminroe, você está usando o Libsass? Ele será corrigido em 3.3 .
Blaine
1
@jaminroe parece estar usando libsass (node-sass) por baixo do capô. Se for esse o caso, você precisará esperar até 3.3.
Blaine
1
Tenho uma versão um pouco mais difícil de resolver, semelhante, mas com várias classes, que precisa ser anexada a uma tag - alguém?
Frank Nocke
29

O @at-rootmétodo -only não resolverá o problema se você pretende estender o seletor mais próximo para cima na cadeia. Como um exemplo:

#id > .element {
    @at-root div#{&} {
        color: blue;
    }
}

Compilará para:

div#id > .element {
    color: blue;
}

E se você precisar inserir sua tag em em .elementvez de #id?

Existe uma função no Sass chamada selector-unify()que resolve isso. Usando isso com @at-rooté possível direcionar .element.

#id > .element {
    @at-root #{selector-unify(&, div)} {
        color: blue;
    }
}

Compilará para:

#id > div.element {
    color: blue;
}
Ben Fleming
fonte
1
Isso não me deu o resultado pretendido. No Sass 3.4.11, isso resulta em #id > .element #id > div.element { color: blue; }. Outra abordagem seria a utilização selector_replace, #id { > .element { @at-root #{selector-replace(&,'.element', 'div.element')} { color: blue;}}}. Aqui está um resumo para melhor legibilidade.
Blaine
@Blaine: Você pegou um bug gritante, obrigado. Editei minha resposta com uma solução funcional.
Ben Fleming
1
Dito isso, selector-replacetambém é outra maneira de fazer isso, mas requer saber o que é o seletor. O selector-unifymétodo tem a vantagem de ser usado em mixins.
Ben Fleming
Resposta incrível.
Senthe
8

Para começar, (no momento em que escrevi esta resposta) não há sintaxe sass que usa o seletor & . Se você fosse fazer algo assim, precisaria de um espaço entre o seletor e o E comercial. Por exemplo:

.item {
    .helper & {

    }
}

// compiles to:
.helper .item {

}

A outra maneira de usar o E comercial é provavelmente o que você está procurando (incorretamente):

.item {
    &.helper {

    }
}

// compiles to:
.item.helper {

}

Isso permite que você estenda os seletores com outras classes, IDs, pseudo-seletores, etc. Infelizmente para o seu caso, isso teoricamente compilaria para algo como .itema que obviamente não funciona.

Você pode apenas querer repensar como está escrevendo seu CSS. Existe um elemento pai que você poderia usar?

<div class="item">
    <p>text</p>
    <p>text</p>
    <a href="#">a link</a>
</div>

Dessa forma, você poderia facilmente escrever seu SASS da seguinte maneira:

.item {
    p {
        // paragraph styles here
    }
    a {
        // anchor styles here
    }
}

(Observação: você deve dar uma olhada em seu html. Você está misturando aspas simples e duplas E colocando atributos href em tags p.)

imjared
fonte
@ Lübnah Eu concordo, mas não estou tentando definir as melhores práticas para ganhos de micro-desempenho. Estou tentando fazer com que alguém que está colocando uma hreftag em um pescreva CSS funcional.
imjared em
Não há absolutamente nenhum suporte para dizer que & .selector é uma prática ruim, há toneladas de casos de uso exatamente como o que o OP estava postando.
Mike Mellor,
@MikeMellor OP escreveu .item { a& }e não há sintaxe sass para isso (tanto quanto eu sei. Sugeri que ele provavelmente estava procurando por algo como a sintaxe do e comercial que você descreveu, que é usada regularmente no Sass. No entanto, basear-se no exemplo do OP, .item { &a }é não é válido e seria compilado.itema . Exatamente como eu disse na minha resposta. Há algo que estou perdendo?
lançado em
OP queria .item { a& { ... } }que agora pode ser feito como @Blaine aponta .item { @at-root a#{&} { ... } }. A questão é que, se você tem uma classe no elemento, é fácil de fazer, .item { &.class { ... } }então por que você não deveria ser capaz de fazer a mesma coisa com um elemento html bruto. Só porque não havia maneira de fazer isso no momento em que o OP postou, não significa que ele estava errado em querer que a funcionalidade realmente fizesse isso.
Mike Mellor,
4

AFAIK No caso de você querer combinar "e" comercial para a classe e as tags ao mesmo tempo, você precisa usar esta sintaxe:

.c1 {
  @at-root h1#{&},
    h2#{&}
    &.c2, {
    color: #aaa;
  }
}

irá compilar para

h1.c1,
h2.c1,
.c1.c2 {
  color: #aaa;
}

Outros usos (como usar a classe antes @at-rootou usar vários@at-root s) levarão a erros.

Espero que seja útil

Vahid
fonte
1
Acabei de usar isso, muito útil para mixins onde você deseja variar o comportamento de elementos span ou div, por exemplo
santiago arizti
uau - muito legal :-) Então isso #{&}está basicamente enganando o compilador - ou isso sempre funcionará no futuro !?
Simon_Weaver
@Simon_Weaver no sass, tudo dentro #{}é avaliado. Também &significa seletor de corrente. Então #{&}é avaliado para .c1.
Vahid
Mas você está enganando no sentido de que & sozinho não funciona ;-)
Simon_Weaver
1
@Simon_Weaver veja este link para mais exemplos de&
Vahid
3

Esse recurso chegou na versão mais recente do Sass, 3.3.0.rc.1(Maptastic Maple)

Os dois recursos intimamente relacionados que você precisará usar são o script &, que você pode interpolar em estilos aninhados para fazer referência a elementos pais, e o@at-root diretiva, que coloca o seletor imediatamente seguinte ou bloco de css na raiz (não tem algum pai no css gerado)

Veja este problema no Github para mais detalhes

Kumarharsh
fonte