J'utilise Sass et j'ai trouvé un problème. Voici un exemple de ce que j'essaie de faire:
.message-error {
background-color: red;
p& {
background-color: yellow
}
}
Css attendu:
.message-error {
background-color: red;
}
p.message-error {
background-color: yellow ;
}
L'idée: tous les éléments avec .message-error seront rouges, sauf s'il s'agit de p.message-error. Ce n'est pas une situation réelle, juste pour montrer un exemple.
SASS n'est pas capable de compiler cela, j'ai même essayé la concaténation de chaînes. Y at-il un plugin qui fera exactement la même chose?
NOTE: Je sais que je peux mettre une autre définition CSS comme
p.message-error{....}
sous, mais je voudrais éviter cela et utiliser un seul endroit pour toutes les définitions .message-error.
Merci.
A partir de Sass 3.4, cela est maintenant supporté. La syntaxe ressemble à ceci:
.message-error {
background-color: red;
@at-root p#{&} {
background-color: yellow
}
}
Notez la directive @at-root
et la syntaxe d'interpolation sur l'esperluette. Si la directive @at-root
n'est pas incluse, un sélecteur du type .message-error p.message-error
plutôt que p.message-error
sera créé.
Natalie Weizenbaum (la concepteur en chef et développeur de Sass) dit que cela ne sera jamais supporté:
À l’heure actuelle,
&
est syntaxiquement identique à un sélecteur d’éléments. ne peut pas apparaître à côté d'un. Je pense que cela aide à clarifier où il peut être utilisé; Par exemple,foo&bar
ne serait jamais un sélecteur valide (ou pourrait être équivalent àfoo& bar
oufoo &bar
). Je ne pense pas que cette utilisation le cas est assez fort pour justifier de changer cela.
Source: # 282 - Sélecteur d'élément.parent
À ma connaissance, il n'y a pas de solution de contournement possible.
La meilleure chose à faire serait probablement la suivante (en supposant que votre classe .message-error comporte un peu plus que la couleur de fond.
.message-error {
background-color: red;
}
p.message-error {
@extend .message-error;
background-color: yellow
}
Cette approche n'offre pas ce regroupement proche, mais vous pouvez simplement les garder proches les uns des autres.
Je pense que si vous voulez les garder groupés par sélecteur de parents, vous devrez peut-être ajouter un parent commun:
body {
& .message-error {background-color: red;}
& p.message-error {background-color: yellow}
}
Bien entendu, body
peut être remplacé par un autre parent commun, tel que #Content
ou un autre nom div
qui contiendra tous les messages d'erreur.
UPDATE (une autre idée)
Si vous exploitez les listes @for et alors il semble que cela devrait fonctionner (ce que je ne sais pas, c'est si la liste permettra le .
(point).
@for $i from 1 to 3 {
nth(. p. ul., #{$i})message-error {
background-color: nth(red yellow cyan, #{$i}));
}
}
Devrait compiler quelque chose comme:
.message-error {
background-color: red;}
p.message-error {
background-color: yellow;}
ul.message-error {
background-color: cyan;}
@Zeljko Il n'est pas possible de faire ce que vous voulez via SASS.
Voir le commentaire Nex3: 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
}
}
J'ai fait un mixin qui résout ce problème.
Github: https://github.com/imkremen/sass-parent-append
Exemple: 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;
}
J'ai eu le même problème alors j'ai fait un mixin pour ça.
@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 que cela fonctionne, vous aurez également besoin d'une fonction de remplacement de chaîne ( 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;
}
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 les sélecteurs imbriqués mais pas avec les composés.
Je l'ai déjà rencontré auparavant. Bootstrap 3 gère cela en utilisant un hack de sélecteur de 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 erreurs sass. Le code ci-dessus vous permet de le gérer en un seul bloc et de le réduire dans votre éditeur. L'imbrication de la variable la rend également locale afin que vous puissiez réutiliser $ class pour toutes les instances où vous devez appliquer ce hack. Voir ci-dessous pour un échantillon de travail ...