Créer ou référencer des variables dynamiquement dans Sass


91

J'essaie d'utiliser l'interpolation de chaîne sur ma variable pour référencer une autre variable:

// Set up variable and mixin
$foo-baz: 20px;

@mixin do-this($bar) {
    width: $foo-#{$bar};
}

// Use mixin by passing 'baz' string as a param for use $foo-baz variable in the mixin
@include do-this('baz');

Mais quand je fais cela, j'obtiens l'erreur suivante:

Variable non définie: "$ foo-".

Sass prend-il en charge les variables de type PHP?

Réponses:


49

Sass n'autorise pas la création ou l'accès dynamique de variables. Cependant, vous pouvez utiliser des listes pour un comportement similaire.

scss:

$list: 20px 30px 40px;    
@mixin get-from-list($index) {
  width: nth($list, $index);
}

$item-number: 2;
#smth {
  @include get-from-list($item-number);
}

css généré:

#smth {
  width: 30px; 
}

9
@castus comment cela a-t-il résolu votre problème? Je rencontre un problème très similaire où je dois prendre une valeur de chaîne dans une liste et y ajouter un $ et l'utiliser comme variable.
cmegown le

86

Ceci est en fait possible en utilisant des cartes SASS au lieu de variables. Voici un exemple rapide:

Référencer dynamiquement:

$colors: (
  blue: #007dc6,
  blue-hover: #3da1e0
);

@mixin colorSet($colorName) {
    color: map-get($colors, $colorName);
    &:hover {
        color: map-get($colors, $colorName#{-hover});
    }
}
a {
    @include colorSet(blue);
}

Sorties comme:

a { color:#007dc6 }
a:hover { color:#3da1e0 }

Créer dynamiquement:

@function addColorSet($colorName, $colorValue, $colorHoverValue: null) {
  $colorHoverValue: if($colorHoverValue == null, darken( $colorValue, 10% ), $colorHoverValue);

  $colors: map-merge($colors, (
    $colorName: $colorValue,
    $colorName#{-hover}: $colorHoverValue
  ));

  @return $colors;
}

@each $color in blue, red {
  @if not map-has-key($colors, $color) {
    $colors: addColorSet($color, $color);
  }
  a {
    &.#{$color} { @include colorSet($color); }
  }
}

Sorties comme:

a.blue { color: #007dc6; }
a.blue:hover { color: #3da1e0; }
a.red { color: red; }
a.red:hover { color: #cc0000; }

10
Notez qu'il ne s'agit toujours pas de "variables dynamiques". C'est juste une variante de l'utilisation d'une liste de listes que nous utilisons depuis toujours.
cimmanon

13
Cela s'étend en fait aux listes, qui n'acceptent qu'un numéro d'index comme variable de spécification. Il permet aux variables d'être appelées avec un nom généré dynamiquement, créé par concaténation d'une chaîne passée, qui était la fonctionnalité demandée.
dibbledeedoo le

3
Cela devrait être la réponse acceptée. Bien que pas complètement dynamique, cela imite au mieux la fonctionnalité demandée.
thomaux

1
Bien qu'utile, cet exemple ne crée aucune variable
ithil

Vrai. Malgré le titre de la question de l'op, son texte ne décrivait pas la création de variables, donc je ne l'ai pas abordé. Cependant, vient d'ajouter une section relative à cela (bien qu'avec des cartes, pas des variables singulières).
dibbledeedoo

5

Chaque fois que j'ai besoin d'utiliser une valeur conditionnelle, je m'appuie sur les fonctions. Voici un exemple simple.

$foo: 2em;
$bar: 1.5em;

@function foo-or-bar($value) {
  @if $value == "foo" {
    @return $foo;
  }
  @else {
    @return $bar;
  }
}

@mixin do-this($thing) {
  width: foo-or-bar($thing);
}

Je pense que c'est exactement ce que je recherche. Il s'agit essentiellement de prendre la valeur transmise au mixin et de l'exécuter via la fonction. Ensuite, en fonction d'une série d'instructions if, renvoie la même valeur de chaîne qu'une variable. Serait-il possible de faire cela avec un nombre potentiellement infini de valeurs? Disons que nous avons une liste de nombreuses chaînes, pas seulement foo ou bar.
cmegown

3
C'est une pure mauvaise pratique, vous ne voulez pas vous retrouver avec une chaîne sans fin de conditions if. Utilisez des cartes SASS avec des paires de valeurs clés et tirez-en les valeurs à la place.
mystrdat

C'est principalement redondant dans cette vitrine - pourquoi ne pas appeler juste @include do-this($foo);? ... cependant cela aurait du sens, si la fonction faisait réellement quelque chose, mais elle ne faisait que passer ...
jave.web

2

Voici une autre option si vous travaillez avec des rails, et éventuellement dans d'autres circonstances.

Si vous ajoutez .erb à la fin de l'extension de fichier, Rails traitera erb sur le fichier avant de l'envoyer à l'interpréteur SASS. Cela vous donne une chance de faire ce que vous voulez dans Ruby.

Par exemple: (Fichier: foo.css.scss.erb)

// Set up variable and mixin
$foo-baz: 20px; // variable

<%
def do_this(bar)
  "width: $foo-#{bar};"
end
%>

#target {
  <%= do_this('baz') %>
}

Résultats dans le scss suivant:

// Set up variable and mixin
$foo-baz: 20px; // variable

#target {
  width: $foo-baz;
}

Ce qui, de manière grossière, aboutit au css suivant:

#target {
  width: 20px;
}

0

Je suis tombé sur le besoin de référencer une couleur de manière dynamique récemment.

J'ai un fichier _colours.scss pour chaque projet, où je définis toutes mes couleurs une fois et je les référence comme des variables partout.

Dans mon fichier _forms.scss, je voulais configurer les styles de bouton pour chaque couleur disponible. Généralement une tâche fastidieuse. Cela m'a aidé à éviter d'avoir à écrire le même code pour chaque couleur différente.

Le seul inconvénient est que vous devez lister chaque nom et valeur de couleur avant d'écrire le CSS réel.

// $red, $blue - variables defined in _colours.scss
$colours: 
  'red' $red,
  'blue' $blue;

@each $name, $colour in $colours {
  .button.has-#{$name}-background-color:hover {
    background-color: lighten($colour, 15%);
  }
}

-2

Créer une variable dynamique n'est pas possible dans SASS pour le moment, car vous allez ajouter / connecter une autre variable qui doit être analysée une fois lorsque vous exécutez la commande sass.

Dès que la commande s'exécute, elle lancera une erreur pour CSS invalide, car toutes vos variables déclarées suivront le levage.

Une fois exécuté, vous ne pouvez plus déclarer les variables à la volée

Pour savoir que j'ai compris cela, veuillez indiquer si ce qui suit est correct:

vous voulez déclarer des variables où la partie suivante (mot) est dynamique

quelque chose comme

$list: 100 200 300;

@each $n in $list {
    $font-$n: normal $n 12px/1 Arial;
}

// should result in something like

$font-100: normal 100 12px/1 Arial;
$font-200: normal 200 12px/1 Arial;
$font-300: normal 300 12px/1 Arial;

// So that we can use it as follows when needed

.span {
    font: $font-200;
    p {
       font: $font-100
    }
}

Si c'est ce que tu veux, j'ai peur pour l'instant, ce n'est pas autorisé


3
Malheureusement, cela ne fonctionne pas: erreur scss / components.scss (Ligne 71: CSS invalide après "$ font-": attendu ":", était "$ n: normal $ n 1 ...")
Krzysztof Romanowski

4
@castus, oups! désolé de ne pas être clair - je ne donne pas de solution, je vais plutôt expliquer une fois de plus la question
Om Shankar

15
ne devrait probablement pas publier une solution qui n'est pas autorisée!
Rhyso

Je largeur cela fonctionnerait mais il semble que nous ne pouvons pas créer de variables via sass?
v3nt
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.