sass css: classe de parent cible de l'enfant

j'utilise sass et j'ai trouvé un problème. Ceci est un exemple de ce que je suis en train de faire:

.message-error {
    background-color: red;

    p& {
        background-color: yellow
     }
  }

Prévue css:

.message-error {
    background-color: red;
}
p.message-error {
    background-color: yellow ;
}

L'idée: tous les éléments .message d'erreur s'affichera en rouge, sauf si elle est p.message d'erreur. Ce n'est pas une situation réelle, juste pour montrer un exemple.

SASS n'est pas capable de compiler ceci, j'ai même essayé la concaténation des chaînes. Y a-t-il un plugin qui fera exactement la même chose?

NOTE: Je sais que je peux mettre un autre css définition de la forme

p.message-error{....}

sous, mais je voudrais éviter cela et utiliser un endroit pour tous .message-définitions d'erreur.

Merci.

31
demandé sur Bernoulli IT 2012-02-15 16:59:23

10 réponses

à partir de sass 3.4, ceci est maintenant pris en charge. La syntaxe ressemble à ceci:

.message-error {
    background-color: red;

    @at-root p#{&} {
        background-color: yellow
    }
}

Notez le @at-root la directive et la syntaxe d'interpolation sur l'ampli. Le défaut d'inclure les @at-root la directive entraînera un sélecteur .message-error p.message-error plutôt que p.message-error.

22
répondu cimmanon 2014-12-02 19:32:45

Natalie Weizenbaum (le lead designer et développeur de Sass) dit qu'il ne sera jamais pris en charge:

Actuellement & est syntaxiquement identique à un sélecteur d'éléments, donc il ne peut pas apparaître aux côtés de l'un. Je pense que cela aide à clarifier où il peut être utilisé; par exemple, foo&bar ne serait jamais un valide sélecteur (ou serait peut-être équivalent à foo& bar ou foo &bar). je ne pense pas que cette utilisation l'affaire est suffisamment solide pour justifier un changement que.

Source:#282 – Élément.sélecteur parent

à ma connaissance, il n'y a pas de solution possible.

19
répondu piouPiouM 2017-11-27 10:30:39

La meilleure chose à faire serait probablement ceci (en supposant que vous avez un peu plus dans votre .message d'erreur classe que juste la couleur d'arrière-plan.

.message-error {
  background-color: red;
}

p.message-error {
  @extend .message-error;
  background-color: yellow
}

cette approche n'offre pas ce regroupement étroit, mais vous pouvez simplement les garder proches les uns des autres.

9
répondu Norris 2014-02-28 08:55:03

je pense que si vous voulez les garder regroupés par parent sélecteur, vous pouvez avoir besoin d'ajouter un parent commun:

body {
    & .message-error {background-color: red;}
    & p.message-error {background-color: yellow}
}

bien sûr, body peut être remplacé par un autre parent commun, tels que #Content ou un autre div qui contiendra tous les messages d'erreur.

mise à JOUR (une Autre Idée)

Si vous utilisez @ et listes alors il semble que cela devrait fonctionner (ce que je ne sais pas est si la liste permettra à l' . (période).

@for $i from 1 to 3 {
  nth(. p. ul., #{$i})message-error {
    background-color: nth(red yellow cyan, #{$i}));
  }
}

devrait se compiler à quelque chose comme:

.message-error {
   background-color: red;}
p.message-error {
   background-color: yellow;}
ul.message-error {
   background-color: cyan;}
2
répondu ScottS 2012-02-23 20:47:38
https://github.com/nex3/sass/issues/286#issuecomment-7496412

La clé est l'espace avant le '&':

.message-error {
    background-color: red;

    p & {
        background-color: yellow
     }
  }

au lieu de:

.message-error {
    background-color: red;

    p& {
        background-color: yellow
     }
  }
2
répondu Tian 2013-03-05 18:39:42

j'ai couru dans cette avant que. Bootstrap 3 gère cela en utilisant un hack de sélecteur parent. Je l'ai légèrement modifié pour mes propres besoins...

@mixin message-error() {
  $class: '.message-error';
  #{$class} {
    background-color: red;
  }
  p#{$class} {
    background-color: yellow;
  }
}
@include message-error();

wheresrhys utilise une approche similaire ci-dessus, mais avec quelques sass erreurs. Le code ci-dessus vous permet de le gérer comme un bloc et le réduire dans votre éditeur. L'imbrication de la variable le rend également local de sorte que vous pouvez réutiliser $class pour toutes les instances où vous devez appliquer ce hack. Voir ci-dessous pour un travail échantillon...

http://sassmeister.com/gist/318dce458a9eb3991b13

0
répondu Adam Youngers 2014-12-02 19:21:12

j'ai fait un mixin qui résout ce problème.

https://github.com/imkremen/sass-parent-append

https://codepen.io/imkremen/pen/RMVBvq


Utilisation (scss):

.ancestor {
  display: inline-flex;

  .grandparent {
    padding: 32px;
    background-color: lightgreen;

    .parent {
      padding: 32px;
      background-color: blue;

      .elem {
        padding: 16px;
        background-color: white;

        @include parent-append(":focus", 3) {
          box-shadow: inset 0 0 0 8px aqua;
        }

        @include parent-append(":hover") {
          background-color: fuchsia;
        }

        @include parent-append("p", 0, true) {
          background-color: green;
        }
      }
    }
  }
}

Résultat (css):

.ancestor {
  display: inline-flex;
}
.ancestor .grandparent {
  padding: 32px;
  background-color: lightgreen;
}
.ancestor .grandparent .parent {
  padding: 32px;
  background-color: blue;
}
.ancestor .grandparent .parent .elem {
  padding: 16px;
  background-color: white;
}
.ancestor:focus .grandparent .parent .elem {
  box-shadow: inset 0 0 0 8px aqua;
}
.ancestor .grandparent .parent:hover .elem {
  background-color: fuchsia;
}
.ancestor .grandparent .parent p.elem {
  background-color: green;
}
0
répondu imkremen 2018-03-22 12:37:34

j'ai eu le même problème j'ai donc fait un mixin.

@mixin tag($tag) {
  $ampersand: & + '';
  $selectors: simple-selectors(str-replace($ampersand, ' ', ''));

  $main-selector: nth($selectors, -1);
  $previous-selectors: str-replace($ampersand, $main-selector, '');

  @at-root {
     #{$previous-selectors}#{$tag}#{$main-selector} {
      @content;
    }
  }
}

Pour le faire fonctionner, vous aurez besoin d'un fonction de remplacement de chaîne (à partir de Hugo Giraudel):

@function str-replace($string, $search, $replace: '') {
  $index: str-index($string, $search);
  @if $index {
    @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
  }
  @return $string;
}

Comment cela fonctionne:

SCSS

.foo {
  color: blue;

  @include tag(p) {
    color: red;
  }
}

Sortie

.foo {
  color: blue;
}

p.foo {
  color: red;
}

cas D'utilisation

Cette méthode fonctionne avec imbriqué sélecteurs mais pas composé de pentecôte .

0
répondu Quentin Veron 2018-09-20 22:45:17

cette tricherie pourrait marcher

 {
     $and: .message-error;
     #{$and} {
        background-color: red;
     }

     p#{$and} {
        background-color: yellow
     }
  }

Vous pouvez même être en mesure d'utiliser $& comme votre nom de variable mais je ne suis pas sûr à 100% qu'il ne lancera pas une erreur.

et SASS a intégré la détermination de la portée, ce qui élimine la nécessité de se soucier de la valeur de $and fuite pour le reste de votre feuille de style

les Variables ne sont disponibles qu'au niveau des sélecteurs imbriqués où elles sont définies. Si ils sont définis en dehors de toutes les sélecteurs, ils sont disponible partout.

-1
répondu wheresrhys 2012-02-23 10:35:28

dans la version actuelle: Selective Steve (3.4.14) c'est maintenant possible, il suffit de mettre à jour un peu votre code:

.message-error {
    background-color: red;
    p &{
        background-color: yellow
     }
 }

cela ne fonctionne que si vous êtes d'un niveau imbriqués, par exemple, il ne fonctionne pas si vous avez quelque chose comme ceci:

.messages{
    .message-error {
        background-color: red;
        p &{
            background-color: yellow
         }
     }
 }
-1
répondu Felipe Salazar 2015-06-10 00:45:19