Fazendo um mix Sass com argumentos opcionais

201

Estou escrevendo um mixin assim:

@mixin box-shadow($top, $left, $blur, $color, $inset:"") {
    -webkit-box-shadow: $top $left $blur $color $inset;
    -moz-box-shadow: $top $left $blur $color $inset;
    box-shadow: $top $left $blur $color $inset;
}

Quando chamado, o que realmente quero é que, se nenhum $insetvalor for passado, nada será produzido, em vez de ser compilado para algo assim:

-webkit-box-shadow: 2px 2px 5px #555555 "";
-moz-box-shadow: 2px 2px 5px #555555 "";
box-shadow: 2px 2px 5px #555555 "";

Como reescrevo o mixin para que, se não houver valor $insetpassado, nada seja produzido?

Rich Bradshaw
fonte
6
É uma pena que SASS não tem uma blankou nilvalor.
31712 Joshua Pinter
1
Btw, enquanto olhava para uma limitação diferente do SASS, me deparei com uma boa maneira de me livrar das citações nessas situações. Eu adicionei uma resposta para isso.
31712 Joshua Pinter
4
Agora, em 2015, você pode simplesmente usar nullpara pular attr / prop. ie @include box-shadow($top, $left, $blur, $color, null)
Gotas

Respostas:

257

Uma maneira mais seca de fazê-lo

E, geralmente, um truque interessante para remover as aspas.

@mixin box-shadow($top, $left, $blur, $color, $inset:"") {
  -webkit-box-shadow: $top $left $blur $color #{$inset};
  -moz-box-shadow:    $top $left $blur $color #{$inset};
  box-shadow:         $top $left $blur $color #{$inset};
}

SASS versão 3+, você pode usar unquote():

@mixin box-shadow($top, $left, $blur, $color, $inset:"") {
  -webkit-box-shadow: $top $left $blur $color unquote($inset);
  -moz-box-shadow:    $top $left $blur $color unquote($inset);
  box-shadow:         $top $left $blur $color unquote($inset);
} 

Peguei isso aqui: passe uma lista para um mixin como um único argumento com o SASS

Joshua Pinter
fonte
6
Como Bob Sammers aponta, na versão mais recente do SASS você também pode usar o método unquote () em vez de # {} para remover as aspas. Felicidades.
Joshua Pinter
4
a maneira mais simples é usar nullo valor padrão dos parâmetros opcionais em vez de ""e eles não serão renderizados na saída! @mixin box-shadow($top, $left,... , $inset:null) {}
S.Serpooshan
@ S.Serpooshan Estou curioso que esta versão foi adicionada no Este certamente não foi apoiado volta em 2012..
Joshua Pinter
79

Uma maneira DRY muito melhor

é passar $args...para o @mixin. Dessa forma, não importa quantos $argsvocê passará. Na @inputchamada, você pode passar todos os argumentos necessários. Igual a:

@mixin box-shadow($args...) {
  -webkit-box-shadow: $args;
  -moz-box-shadow: $args;
  box-shadow: $args;
}

E agora você pode reutilizar sua sombra de caixa em todas as classes que desejar, passando todos os argumentos necessários:

.my-box-shadow {
  @include box-shadow(2px 2px 5px #555, inset 0 0 0);
}
Fabricio
fonte
11
Isso é bom saber, mas muitas vezes é mais clara para indicar quais os argumentos a mixinestá esperando, como $top, $left, $blur, etc argumentos variáveis, como você mostrou, são grandes para a máxima flexibilidade, no entanto.
Joshua Pinter
1
Obrigado, cara isso me ajuda muito
Nilesh Sutar
48

Sass suporta @ifdeclarações. (Veja a documentação .)

Você poderia escrever sua mixin assim:

@mixin box-shadow($top, $left, $blur, $color, $inset:"") {
  @if $inset != "" {
    -webkit-box-shadow:$top $left $blur $color $inset;
    -moz-box-shadow:$top $left $blur $color $inset;
    box-shadow:$top $left $blur $color $inset;
  }
}
Andrew Vit
fonte
Isso não é útil aqui, apenas a insetparte deve ser excluída quando for nula, nem todas as propriedades de sombra de caixa
S.Serpooshan
@ S.Serpooshan Basta adicionar um elsee incluir todas as propriedades não inseridas dentro.
mbomb007
@ mbomb007 eu sei, acabei de relatar um problema com esta solução. E outras respostas fornecidas acima são absolutamente melhores.
S.Serpooshan
26

Você pode colocar a propriedade null como valor padrão e, se não passar o parâmetro, ele não será interpretado.

@mixin box-shadow($top, $left, $blur, $color, $inset:null) {
  -webkit-box-shadow: $top $left $blur $color $inset;
  -moz-box-shadow:    $top $left $blur $color $inset;
  box-shadow:         $top $left $blur $color $inset;
}

Isso significa que você pode escrever a instrução include como esta.

@include box-shadow($top, $left, $blur, $color);

Em vez de escrever assim.

@include box-shadow($top, $left, $blur, $color, null);

Como mostrado na resposta aqui

user1551211
fonte
1
Esta resposta oferece nada de novo sobre as respostas existentes (ver: stackoverflow.com/a/23565388/1652962 )
cimmanon
9
@ cimmanon Pelo contrário, isso fornece utilidade extra, pois você pode escrever a importação como em @include box-shadow($top, $left, $blur, $color);vez de @include box-shadow($top, $left, $blur, $color, null);. Portanto, essa resposta é muito mais benéfica.
Dan
1
@ Dan Na verdade, você perde a legibilidade fazendo dessa maneira, então, sem dúvida, é menos benéfico do que a resposta da qual derivou.
TylerH
@TylerH Isso é verdade
Dan
14

Eu sei que é uma pergunta antiga, mas acho que isso ainda é relevante. Indiscutivelmente, uma maneira mais clara de fazer isso é usar a função unquote () (que o SASS possui desde a versão 3.0.0):

@mixin box-shadow($top, $left, $blur, $color, $inset:"") {
  -webkit-box-shadow: $top $left $blur $color unquote($inset);
  -moz-box-shadow: $top $left $blur $color unquote($inset);
  box-shadow: $top $left $blur $color unquote($inset);
}

Isso é aproximadamente equivalente à resposta de Josh, mas acho que a função denominada explicitamente é menos ofuscada do que a sintaxe de interpolação de strings.

Bob Sammers
fonte
12

Eu sei que não é exatamente a resposta que você estava procurando, mas você pode passar "null"como último argumento ao @include box-shadowmisturar, assim: @include box-shadow(12px, 14px, 2px, green, null);Agora, se esse argumento for apenas um nessa propriedade, essa propriedade (e seu valor (padrão)) não será compilado . Se houver dois ou mais argumentos nessa "linha", apenas aqueles que você anulou não serão compilados (seu caso).

A saída CSS é exatamente como você queria, mas você precisa escrever seus null:)

  @include box-shadow(12px, 14px, 2px, green, null);

  // compiles to ...

  -webkit-box-shadow: 12px 14px 2px green;  
  -moz-box-shadow: 12px 14px 2px green;  
  box-shadow: 12px 14px 2px green;
Gotas
fonte
1
Definitivamente, minha maneira favorita de fazer isso mantém tudo simples de ler e entender quando você precisa voltar a um script. thnx Drops.
Plentybinary
7

Aqui está a solução que eu uso, com as notas abaixo:

@mixin transition($trans...) {
  @if length($trans) < 1 {
    $trans: all .15s ease-out;
  }
  -moz-transition: $trans;
  -ms-transition: $trans;
  -webkit-transition: $trans;
  transition: $trans;
}

.use-this {
  @include transition;
}

.use-this-2 {
  @include transition(all 1s ease-out, color 2s ease-in);
}
  • prefere passar valores de propriedade como css nativo para ficar perto da "língua"
  • permite passar número variável de argumentos
  • definir um valor padrão para preguiça
duggi
fonte
Como isso adiciona algo sobre as respostas existentes (a saber: stackoverflow.com/a/28072864/1652962 )?
Cimmanon
Ele explicou como saber se mais de um argumento é passado para a função e, se sim, alterar a saída. A outra resposta não.
TetraDev 10/11/2015
Às vezes, você deseja definir um comportamento global. por exemplo, transições de animação em que você geralmente deseja ter uma experiência muito uniforme e não quer arriscar a "discrição do desenvolvedor criativo" quando se trata de decidir o que fazer. isso define um padrão que pode ser substituído, mas geralmente não será devido à sintaxe mais compacta ao não passar argumentos. você também pode alterar o comportamento global em um único local dessa maneira.
duggi
3

Com [email protected]:

// declare
@mixin button( $bgcolor:blue ){
    background:$bgcolor;
}

e usar sem valor, o botão ficará azul

//use
.my_button{
    @include button();
}

e com valor, o botão ficará vermelho

//use
.my_button{
    @include button( red );
}

trabalha com hexa também

gael
fonte
Como isso adiciona algo sobre as respostas existentes?
Cimmanon
3

Ainda mais seca!

@mixin box-shadow($args...) {
  @each $pre in -webkit-, -moz-, -ms-, -o- {
    #{$pre + box-shadow}: $args;
  } 
  #{box-shadow}: #{$args};
}

E agora você pode reutilizar sua sombra de caixa ainda mais inteligente:

.myShadow {
  @include box-shadow(2px 2px 5px #555, inset 0 0 0);
}
Ben Kalsky
fonte
Apenas uma observação - por mais legível que seja e reconheço que é aqui que se deve traçar a linha entre o código DRY e a legibilidade / manutenção .
Leo Napoleon
Concordo que, para aumentar a legibilidade / manutenção, eu criaria uma "lista de navegadores" para reutilizar em outros mixins. Isso também pode ser facilmente montado em outras propriedades do css, que podem ser executadas com um conjunto de mixins secos. Este artigo de 2014 ainda é um ótimo exemplo.
Ben Kalsky
1
@mixin box-shadow($left: 0, $top: 0, $blur: 6px, $color: hsla(0,0%,0%,0.25), $inset: false) {
    @if $inset {
        -webkit-box-shadow: inset $left $top $blur $color;
        -moz-box-shadow: inset $left $top $blur $color;
        box-shadow: inset $left $top $blur $color;
    } @else {
        -webkit-box-shadow: $left $top $blur $color;
        -moz-box-shadow: $left $top $blur $color;
        box-shadow: $left $top $blur $color;
    }
}
Adam C
fonte
Isso é sem dúvida pior do que todas as outras respostas, devido à sua verbosidade. Além disso, é próximo o suficiente de uma das outras respostas para contar como duplicado.
Cimmanon
1

Maneira super simples

Basta adicionar um valor padrão de none$ inset - para

@mixin box-shadow($top, $left, $blur, $color, $inset: none) { ....

Agora, quando nenhum $ inset for passado, nada será exibido.

fidev
fonte
1

Você sempre pode atribuir nulo aos seus argumentos opcionais. Aqui está uma correção simples

@mixin box-shadow($top, $left, $blur, $color, $inset:null) { //assigning null to inset value makes it optional
    -webkit-box-shadow: $top $left $blur $color $inset;
    -moz-box-shadow: $top $left $blur $color $inset;
    box-shadow: $top $left $blur $color $inset;
}
Benjamin
fonte
0

Eu sou novo nos compiladores css, espero que ajude,

        @mixin positionStyle($params...){

            $temp:nth($params,1);
            @if $temp != null{
            position:$temp;
            }

             $temp:nth($params,2);
            @if $temp != null{
            top:$temp;
            }

             $temp:nth($params,3);
            @if $temp != null{
            right:$temp;
            }

             $temp:nth($params,4);
            @if $temp != null{
            bottom:$temp;
            }

            $temp:nth($params,5);
            @if $temp != null{
            left:$temp;
            }

    .someClass{
    @include positionStyle(absolute,30px,5px,null,null);
    }

//output

.someClass{
position:absolute;
 top: 30px;
 right: 5px;
}
rastreador de microfone
fonte
Como isso adiciona algo sobre as respostas existentes?
Cimmanon