Динамическое создание или обращение к переменным в Sass

94

Я пытаюсь использовать строковую интерполяцию в моей переменной для ссылки на другую переменную:

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

Но когда я это сделаю, я получаю следующую ошибку:

Неопределенная переменная: "$ foo-".

Поддерживает ли Sass переменные переменных в стиле PHP?

Кшиштоф Романовски
источник

Ответы:

50

Sass не позволяет создавать переменные или получать к ним доступ динамически. Однако вы можете использовать списки для аналогичного поведения.

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 сгенерирован:

#smth {
  width: 30px; 
}
lisowski.r
источник
9
@castus, как это решило вашу проблему? У меня очень похожая проблема, когда мне нужно взять строковое значение из списка, добавить к нему $ и использовать его как переменную.
cmegown
88

На самом деле это можно сделать, используя карты SASS вместо переменных. Вот краткий пример:

Динамическая ссылка:

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

Выводится как:

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

Создание динамически:

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

Выводится как:

a.blue { color: #007dc6; }
a.blue:hover { color: #3da1e0; }
a.red { color: red; }
a.red:hover { color: #cc0000; }
болтать
источник
10
Обратите внимание, что это еще не «динамические переменные». Это всего лишь вариант использования списка списков, который мы используем всегда.
cimmanon
13
Это фактически расширяет списки, которые принимают только номер индекса в качестве определяющей переменной. Он позволяет вызывать переменные с динамически сгенерированным именем, созданным путем конкатенации переданной строки, которая была запрошенной функцией.
dibbledeedoo
3
Это должен быть принятый ответ. Хотя это не полностью динамично, это лучше всего имитирует запрошенную функциональность.
thomaux
1
Хотя этот пример полезен, он вообще не создает никаких переменных
ithil 03
Правда. Несмотря на название вопроса op, в его тексте не описывается создание переменных, поэтому я не стал обращать на это внимание. Тем не менее, просто добавил раздел, связанный с этим (хотя все еще с картами, а не с отдельными переменными).
dibbledeedoo
5

Каждый раз, когда мне нужно использовать условное значение, я опираюсь на функции. Вот простой пример.

$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);
}
Адам Стаковяк
источник
Я думаю, это именно то, что я ищу. Это, по сути, берет значение, переданное в миксин, и прогоняет его через функцию. Затем, в зависимости от серии операторов if, возвращает то же строковое значение, что и переменная. Можно ли сделать это с потенциально бесконечным числом значений? Допустим, у нас есть список из множества строк, а не только foo или bar.
cmegown
3
Это чистая плохая практика, вы не хотите, чтобы закончилась бесконечная цепочка условий if. Используйте карты SASS с парами ключ-значение и вместо этого извлекайте из него значения.
mystrdat
В этой витрине это в основном избыточно - почему бы вам просто не позвонить @include do-this($foo);? ... однако это имело бы смысл, если бы функция действительно что-то делала, но только проходила ...
jave.web
2

Вот еще один вариант, если вы работаете с рельсами и, возможно, при других обстоятельствах.

Если вы добавите .erb в конец расширения файла, Rails обработает erb в файле перед отправкой его интерпретатору SASS. Это дает вам возможность делать в Ruby все, что вы хотите.

Например: (Файл: 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') %>
}

Результаты в следующем scss:

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

#target {
  width: $foo-baz;
}

Что, грубо говоря, приводит к следующему css:

#target {
  width: 20px;
}
Блейк Тейлор
источник
0

Недавно я столкнулся с необходимостью динамически ссылаться на цвет.

У меня есть файл _colours.scss для каждого проекта, где я определяю все свои цвета один раз и ссылаюсь на них как на переменные.

В моем файле _forms.scss я хотел настроить стили кнопок для каждого доступного цвета. Обычно утомительная задача. Это помогло мне избежать написания одного и того же кода для каждого цвета.

Единственным недостатком является то, что вам нужно перечислить каждое имя и значение цвета до написания фактического CSS.

// $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
источник
-2

В настоящее время создание динамической переменной в SASS невозможно, так как вы будете добавлять / подключать еще одну переменную, которую необходимо проанализировать один раз при запуске команды sass.

Как только команда запустится, она выдаст ошибку Invalid CSS, поскольку все ваши объявленные переменные будут следовать за подъемом.

После запуска вы не можете снова объявлять переменные на лету

Чтобы знать, что я понял это, просьба указать, правильно ли следующее:

вы хотите объявить переменные, где следующая часть (слово) является динамической

что-то типа

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

Если это то, что вы хотите, боюсь, на данный момент это запрещено

Ом Шанкар
источник
3
К сожалению, это не работает: ошибка scss / components.scss (Строка 71: Недействительный CSS после «$ font-»: ожидалось «:», было «$ n: нормальный $ n 1 ...»)
Кшиштоф Романовский
4
@castus, ой! извините за непонятность - я не даю решения, а просто объясняю вопрос еще раз
Ом Шанкар
16
вероятно, не следует публиковать недопустимое решение!
Rhyso
я ширину, это будет работать, но кажется, мы не можем создавать переменные через sass?
v3nt