Dynamiczne tworzenie lub odwoływanie się do zmiennych w Sassie

94

Próbuję użyć interpolacji ciągów w mojej zmiennej, aby odwołać się do innej zmiennej:

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

Ale kiedy to robię, pojawia się następujący błąd:

Niezdefiniowana zmienna: „$ foo-”.

Czy Sass obsługuje zmienne w stylu PHP?

Krzysztof Romanowski
źródło

Odpowiedzi:

50

Sass nie zezwala na dynamiczne tworzenie lub dostęp do zmiennych. Możesz jednak używać list do podobnego zachowania.

scss:

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

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

wygenerowano css:

#smth {
  width: 30px; 
}
lisowski.r
źródło
9
@castus, jak to rozwiązało twój problem? Mam do czynienia z bardzo podobnym problemem, w którym muszę pobrać wartość ciągu z listy, dodać do niej $ i użyć go jako zmiennej.
cmegown
88

W rzeczywistości jest to możliwe przy użyciu map SASS zamiast zmiennych. Oto krótki przykład:

Dynamiczne tworzenie odniesień:

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

Wyniki jako:

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

Tworzymy dynamicznie:

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

Wyniki jako:

a.blue { color: #007dc6; }
a.blue:hover { color: #3da1e0; }
a.red { color: red; }
a.red:hover { color: #cc0000; }
dibbledeedoo
źródło
10
Zauważ, że nadal nie są to „zmienne dynamiczne”. To tylko odmiana korzystania z listy list, których używamy od zawsze.
cimmanon
13
To faktycznie rozszerza listy, które akceptują tylko numer indeksu jako zmienną określającą. Pozwala na wywołanie zmiennych z dynamicznie generowaną nazwą, utworzoną przez konkatenację przekazanego ciągu, który był żądaną funkcjonalnością.
dibbledeedoo
3
To powinna być akceptowana odpowiedź. Chociaż nie jest to całkowicie dynamiczne, najlepiej naśladuje żądaną funkcjonalność.
thomaux
1
Chociaż jest użyteczny, ten przykład w ogóle nie tworzy żadnych zmiennych
ithil
Prawdziwe. Pomimo tytułu pytania op, jego tekst nie opisywał tworzenia zmiennych, więc nie odniosłem się do tego. Jednak właśnie dodałem sekcję dotyczącą robienia tego (choć nadal z mapami, a nie pojedynczymi zmiennymi).
dibbledeedoo
5

Zawsze, gdy potrzebuję wartości warunkowej, opieram się na funkcjach. Oto prosty przykład.

$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
źródło
Myślę, że właśnie tego szukam. Jest to zasadniczo pobieranie wartości przekazanej do miksera i przepuszczanie jej przez funkcję. Następnie, w zależności od serii instrukcji if, zwraca tę samą wartość ciągu jako zmienną. Czy byłoby możliwe to zrobić z potencjalnie nieskończoną liczbą wartości? Powiedzmy, że mamy listę wielu ciągów znaków, a nie tylko foo czy bar.
cmegown
3
To czysta zła praktyka, nie chcesz skończyć z niekończącym się łańcuchem warunków warunkowych. Użyj map SASS z parami klucz-wartość i zamiast tego wyciągnij z nich wartości.
mystrdat
Jest to głównie zbędne w tej prezentacji - dlaczego nie zadzwonisz po prostu @include do-this($foo);? ... jednak miałoby to sens, gdyby funkcja faktycznie coś zrobiła, ale tylko przechodzi ...
jave.web
2

Oto inna opcja, jeśli pracujesz z szynami i prawdopodobnie w innych okolicznościach.

Jeśli dodasz .erb na końcu rozszerzenia pliku, Railsy przetworzą plik erb przed wysłaniem go do interpretera SASS. Daje ci to szansę robienia tego, co chcesz w Rubim.

Na przykład: (File: 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') %>
}

Wyniki w następującym scss:

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

#target {
  width: $foo-baz;
}

Co, ogólnie rzecz biorąc, daje następujący CSS:

#target {
  width: 20px;
}
Blake Taylor
źródło
0

Ostatnio natrafiłem na potrzebę dynamicznego odwoływania się do koloru.

Mam plik _colours.scss dla każdego projektu, w którym raz definiuję wszystkie kolory i odnoszę się do nich jako zmiennych w całym tekście.

W moim pliku _forms.scss chciałem ustawić style przycisków dla każdego dostępnego koloru. Zwykle żmudne zadanie. Pomogło mi to uniknąć konieczności pisania tego samego kodu dla każdego koloru.

Jedynym minusem jest to, że przed zapisaniem właściwego css musisz podać każdą nazwę koloru i wartość.

// $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
źródło
-2

Utworzenie zmiennej dynamicznej nie jest obecnie możliwe w SASS, ponieważ będziesz dodawać / podłączać inny var, który musi zostać przeanalizowany raz po uruchomieniu polecenia sass.

Jak tylko polecenie zostanie uruchomione, zgłosi błąd dotyczący Nieprawidłowego CSS, ponieważ wszystkie zadeklarowane zmienne będą podążać za podnoszeniem.

Po uruchomieniu nie można ponownie deklarować zmiennych w locie

Aby wiedzieć, że to zrozumiałem, powiedz, czy poniższe stwierdzenia są poprawne:

chcesz zadeklarować zmienne, w których następna część (słowo) jest dynamiczna

coś jak

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

Jeśli tego chcesz, obawiam się, że na razie nie jest to dozwolone

Om Shankar
źródło
3
Niestety to nie działa: błąd scss / components.scss (Linia 71: Nieprawidłowy CSS po "$ font-": oczekiwano ":", było "$ n: normal $ n 1 ...")
Krzysztof Romanowski
4
@castus, ups! przepraszam, że nie jest to jasne - nie daję rozwiązania, raczej wyjaśniam pytanie jeszcze raz
Om Shankar
16
prawdopodobnie nie powinien publikować rozwiązania, które jest niedozwolone!
Rhyso
Rozumiem, że to zadziała, ale wydaje się, że nie możemy tworzyć zmiennych przez sass?
v3nt