Sass che combina genitore usando e commerciale (&) con selettori di tipo


100

Ho problemi con l'annidamento in Sass. Supponiamo che io abbia il seguente codice HTML:

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

Quando provo a nidificare i miei stili nel seguente, ottengo un errore di compilazione:

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

Come faccio a fare riferimento a un selettore di tipo prima del selettore principale quando fa parte dello stesso elemento?

Risposte:


156

Come sottolinea Kumar , questo è stato possibile sin dal Sass 3.3.0.rc.1 (Maptastic Maple).

La direttiva @ at-root fa sì che una o più regole vengano emesse alla radice del documento, invece di essere annidate sotto i selettori principali.

Possiamo combinare la @at-rootdirettiva con l' interpolazione#{} per arrivare al risultato desiderato.

SASS

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

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

Output CSS

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

3
Questa dovrebbe essere la soluzione a questa domanda.
Kayhadrin

Questo non funziona per me ... l'output sta arrivando .item a.itemper qualche motivo. Ho provato a farlo a#{&}anche da solo e sempre lo stesso risultato.
jaminroe

@jaminroe stai usando Libsass? Sarà risolto in 3.3 .
Blaine

1
@jaminroe sembra che stia usando libsass (node-sass) sotto il cofano. In tal caso, dovrai attendere fino al 3.3.
Blaine

1
Ho una versione leggermente più difficile da risolvere, simile, ma con più classi, che deve essere aggiunta a un tag - chiunque?
Frank Nocke

29

Il @at-rootmetodo -only non risolverà il problema se si intende estendere il selettore più vicino a monte della catena. Come esempio:

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

Compilerà per:

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

E se avessi bisogno di unire il tuo tag al .elementposto di #id?

C'è una funzione in Sass chiamata selector-unify()che risolve questo problema. Usando questo con @at-rootè possibile targetizzare .element.

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

Compilerà per:

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

1
Questo non mi ha dato il risultato previsto. In Sass 3.4.11, questo output in #id > .element #id > div.element { color: blue; }. Un altro approccio sarebbe quello di utilizzo selector_replace, #id { > .element { @at-root #{selector-replace(&,'.element', 'div.element')} { color: blue;}}}. Ecco una sintesi per una migliore leggibilità.
Blaine

@ Blaine Hai rilevato un bug lampante, grazie. Ho modificato la mia risposta con una soluzione funzionante.
Ben Fleming,

1
Detto questo, selector-replaceè anche un altro modo per farlo, ma richiede di sapere qual è il selettore. Il selector-unifymetodo ha il vantaggio di essere utilizzato nei mixin.
Ben Fleming,

Risposta fantastica.
Senthe

8

Per i principianti, (al momento della stesura di questa risposta) non esiste una sintassi sass che utilizzi il selettore & . Se avessi intenzione di fare qualcosa del genere, avresti bisogno di uno spazio tra il selettore e la e commerciale. Per esempio:

.item {
    .helper & {

    }
}

// compiles to:
.helper .item {

}

L'altro modo di usare la e commerciale è probabilmente quello che stai cercando (erroneamente):

.item {
    &.helper {

    }
}

// compiles to:
.item.helper {

}

Questo ti permette di estendere i selettori con altre classi, ID, pseudo-selettori, ecc. Sfortunatamente per il tuo caso, teoricamente si compilerebbe in qualcosa come .itema che ovviamente non funziona.

Potresti semplicemente ripensare a come stai scrivendo il tuo CSS. C'è un elemento genitore che potresti usare?

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

In questo modo, potresti facilmente scrivere il tuo SASS nel modo seguente:

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

(Nota a margine: dovresti dare un'occhiata al tuo html. Stai mescolando virgolette singole e doppie E inserendo attributi href sui tag p.)


@ Lübnah Sono d'accordo ma non sto cercando di definire le migliori pratiche per i guadagni di micro-prestazioni. Sto cercando di convincere qualcuno che sta mettendo un hreftag su un pper scrivere CSS funzionante.
imjared

Non c'è assolutamente alcun supporto per dire che & .selector è una cattiva pratica, ci sono tonnellate di casi d'uso esattamente come quello che OP stava postando.
Mike Mellor

@MikeMellor OP ha scritto .item { a& }e non esiste una sintassi sass per questo (per quanto ne so. Ho suggerito che probabilmente stava cercando qualcosa come la sintassi della e commerciale che hai descritto che è usata abbastanza regolarmente in Sass. Tuttavia, basandosi sull'esempio di OP, .item { &a }è non valido e verrebbe compilato.itema . Proprio come ho detto nella mia risposta. C'è qualcosa che mi manca?
imjared

OP voleva .item { a& { ... } }che ora può essere fatto come sottolinea @Blaine .item { @at-root a#{&} { ... } }. Il punto è che se hai una classe sull'elemento è facile farlo, .item { &.class { ... } }quindi perché non dovresti essere in grado di fare la stessa cosa con un elemento html grezzo. Solo perché non c'era modo di farlo nel momento in cui OP ha pubblicato, non significa che non fosse corretto nel volere che la funzionalità lo facesse effettivamente.
Mike Mellor

4

AFAIK Nel caso in cui desideri combinare e commerciale per classe e tag allo stesso tempo, devi usare questa sintassi:

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

compilerà in

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

Altri usi (come usare la classe prima @at-rooto usare più messaggi @at-root) porteranno a errori.

Spero che sia utile


1
Ho appena usato questo, molto utile per i mixin in cui vuoi variare il comportamento per gli elementi span o div, ad esempio
santiago arizti

wow - molto bello :-) Quindi #{&}fondamentalmente sta ingannando il compilatore - o funzionerà sempre in futuro !?
Simon_Weaver

@Simon_Weaver in sass, tutto all'interno #{}viene valutato. &Significa anche selettore corrente. Quindi #{&}viene valutato .c1.
Vahid

Ma lo stai ingannando nel senso che & da solo non funziona ;-)
Simon_Weaver

1
@Simon_Weaver vedi questo link per ulteriori esempi di&
Vahid

3

Questa funzione è arrivata nella versione più recente di Sass, 3.3.0.rc.1(Maptastic Maple)

Le due funzionalità strettamente correlate che dovrai usare sono lo script & , che puoi interpolare all'interno di stili annidati per fare riferimento a elementi genitore, e la @at-rootdirettiva, che posiziona il selettore o il blocco css immediatamente successivo alla radice (non lo farà avere genitori nel css emesso)

Vedi questo numero di GitHub per maggiori dettagli

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.