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?


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


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

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

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


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.


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;

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

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 sass@3.4.9:

// 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


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

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

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.


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

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

Como isso adiciona algo sobre as respostas existentes?
Cimmanon
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.