Criação ou referência de variáveis ​​dinamicamente no Sass

91

Estou tentando usar a interpolação de string na minha variável para fazer referência a outra variável:

// 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');

Mas quando faço isso, recebo o seguinte erro:

Variável indefinida: "$ foo-".

O Sass oferece suporte a variáveis ​​de variáveis ​​no estilo PHP?

Krzysztof Romanowski
fonte

Respostas:

49

O Sass não permite que variáveis ​​sejam criadas ou acessadas dinamicamente. No entanto, você pode usar listas para comportamentos semelhantes.

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 gerado:

#smth {
  width: 30px; 
}
lisowski.r
fonte
9
@castus como isso resolveu seu problema? Estou tendo um problema muito semelhante, em que preciso pegar um valor de string de uma lista e adicionar $ a ele e usá-lo como uma variável.
cmegown
86

Na verdade, isso é possível usando mapas SASS em vez de variáveis. Aqui está um exemplo rápido:

Referenciando dinamicamente:

$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);
}

Produz como:

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

Criando dinamicamente:

@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); }
  }
}

Produz como:

a.blue { color: #007dc6; }
a.blue:hover { color: #3da1e0; }
a.red { color: red; }
a.red:hover { color: #cc0000; }
dibbledeedoo
fonte
10
Observe que isso ainda não é "variáveis ​​dinâmicas". Esta é apenas uma variação do uso de uma lista de listas que usamos desde sempre.
cimmanon
13
Na verdade, isso se expande nas listas, que aceitam apenas um número de índice como variável de especificação. Permite que as variáveis ​​sejam chamadas com um nome gerado dinamicamente, criado pela concatenação de uma string passada, que era a funcionalidade solicitada.
dibbledeedoo
3
Esta deve ser a resposta aceita. Embora não seja completamente dinâmico, ele imita melhor a funcionalidade solicitada.
thomaux
1
Embora útil, este exemplo não está criando nenhuma variável
ithil de
Verdade. Apesar do título da pergunta da op, seu texto não descreve a criação de variáveis, então não abordei isso. No entanto, acabou de adicionar uma seção relativa a fazer isso (embora ainda com mapas, não variáveis ​​singulares).
dibbledeedoo
5

Sempre que preciso usar um valor condicional, recorro às funções. Aqui está um exemplo simples.

$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);
}
Adam Stacoviak
fonte
Acho que é exatamente isso que estou procurando. Isso é essencialmente pegar o valor passado para o mixin e executá-lo por meio da função. Então, dependendo de uma série de instruções if, retorna o mesmo valor de string que uma variável. Seria possível fazer isso com um número potencialmente infinito de valores? Digamos que temos uma lista de muitas strings, não apenas foo ou bar.
cmegown
3
Isso é pura prática ruim, você não quer acabar com uma cadeia interminável de condições se. Use mapas SASS com pares de valores-chave e extraia os valores deles.
mystrdat
É basicamente redundante neste mostruário - por que você não ligaria apenas @include do-this($foo);? ... no entanto, isso faria sentido, se a função realmente fizesse algo, mas só passa ...
jave.web
2

Aqui está outra opção se você estiver trabalhando com trilhos e, possivelmente, em outras circunstâncias.

Se você adicionar .erb ao final da extensão do arquivo, o Rails processará o erb no arquivo antes de enviá-lo para o interpretador SASS. Isso lhe dá a chance de fazer o que quiser em Ruby.

Por exemplo: (Arquivo: 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') %>
}

Resulta no seguinte scss:

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

#target {
  width: $foo-baz;
}

O que, claro, resulta no seguinte css:

#target {
  width: 20px;
}
Blake Taylor
fonte
0

Recentemente, descobri a necessidade de fazer referência a uma cor dinamicamente.

Tenho um arquivo _colours.scss para cada projeto, onde defino todas as minhas cores uma vez e faço referência a elas como variáveis ​​em todo o processo.

No meu arquivo _forms.scss, eu queria configurar estilos de botão para cada cor disponível. Normalmente uma tarefa tediosa. Isso me ajudou a evitar ter que escrever o mesmo código para cada cor diferente.

A única desvantagem é que você deve listar cada nome e valor de cor antes de escrever o css real.

// $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%);
  }
}
lukeseager
fonte
-2

Fazer uma variável dinâmica não é possível no SASS a partir de agora, uma vez que você adicionará / conectará outra var que precisa ser analisada uma vez quando você executar o comando sass.

Assim que o comando for executado, ele lançará um erro para CSS inválido, pois todas as suas variáveis ​​declaradas seguirão o içamento.

Uma vez executado, você não pode declarar variáveis ​​novamente em tempo real

Para saber que entendi isso, gentilmente declare se o seguinte está correto:

você deseja declarar variáveis ​​onde a próxima parte (palavra) é dinâmica

algo como

$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
    }
}

Se é isso que você quer, estou com medo por agora, isso não é permitido

Om Shankar
fonte
3
Infelizmente isso não está funcionando: erro scss / components.scss (Linha 71: CSS inválido depois de "$ font-": esperado ":", era "$ n: normal $ n 1 ...")
Krzysztof Romanowski
4
@castus, oops! desculpe por não ter sido claro - não estou dando uma solução, ao invés disso explicando a questão mais uma vez
Om Shankar
15
provavelmente não deveria postar uma solução que não é permitida!
Rhyso
largura isso funcionaria, mas parece que não podemos criar variáveis ​​via sass?
v3nt de