135

I have a couple of scss selectors where I use the same amount positive and negative, as in:

padding: 0 15px 15px;
margin: 0 -15px 20px -15px;

I'd prefer to use a variable for all the 15px amounts, but this does not work:

$pad: 15px;
padding: 0 $pad $pad;
margin: 0 -$pad 20px -$pad;

The margin amounts convert to positive numbers. Am I missing something?

Steve
  • 14,401
  • 35
  • 125
  • 230

6 Answers6

250

Try it like this

margin: 0 (-$pad) 20px (-$pad);
Zoltan Toth
  • 46,981
  • 12
  • 120
  • 134
  • 3
    Automatically tried this approach - seems not to be working when using in calc function. Edit: Seems like you don't need to use parentheses when using calc, but you do need to interpolate http://stackoverflow.com/questions/17982111/sass-variable-in-css-calc-function – Kevin Mar 20 '17 at 15:38
61

A more sane solution according to sass guidelines would be to interpolate variables like the following example:

margin: 0 -#{$pad} 20px -#{$pad};

An example: https://www.sassmeister.com/gist/c9c0208ada0eb1fdd63ae47830917293

Vangel Tzo
  • 8,885
  • 3
  • 26
  • 32
  • @Green You can always check the example link: https://www.sassmeister.com/gist/c9c0208ada0eb1fdd63ae47830917293 – Vangel Tzo Oct 21 '19 at 20:28
  • This is better than the accepted answer because it works when using a mixin inside it also :) – OZZIE Sep 15 '21 at 10:20
9

I'm adding my two-penneth after considering the two previous answers, but then reading this (emphasis mine):

You should especially avoid using interpolation like #{$number}px. This doesn’t actually create a number! It creates an unquoted string that looks like a number, but won’t work with any number operations or functions. Try to make your math unit-clean so that $number already has the unit px, or write $number * 1px.

Source

Therefore I believe the correct way would be as follows, which preserves the mathematical abilities of SASS/SCSS:

$pad: 15px;
padding: 0 $pad $pad;
margin: 0 $pad*-1 20px $pad*-1;
EvilDr
  • 8,943
  • 14
  • 73
  • 133
  • 3
    At first glance, it seems to be nit-picking (your answer), but on second glance it really is the better answer. After all, if the variable does become a negative variable the answer becomes positive! $pad: -2rem; ... margin: 0 -#{$pad}; // becomes margin: 0 --2rem; margin: 0 $pad*-1; // becomes margin: 0 2rem; – Fnordius Jun 23 '20 at 14:47
  • this is a novel solution but I disagree that it's the "correct" way - do you think it's even better than this similar solution? `margin: 0 0 - $pad 20px 0 - $pad;` – jrz Mar 09 '22 at 15:13
5

create a function

@function neg($val) {
  @return $val * -1
};

then I use it like this

$gutter: 30px;

.header {
  margin: $gutter neg($gutter);
}
Bouh
  • 1,303
  • 2
  • 10
  • 24
2

The official sass guides suggest a similar solution to the (currently) highest voted answer - instead of wrapping the minus-sign inside the parens, put it outside, e.g.

$pad: 15px;
padding: 0 $pad $pad;
margin: 0 -($pad) 20px -($pad);

source: https://sass-lang.com/documentation/operators/numeric#unary-operators

and per #comment-72915126 you would want to interpolate the sass value when it appears inside a css calc function:

margin: calc(#{-$pad} - 10px);

strangely, the parens are no longer required - perhaps the string interpolation acts in a similar way to wrapping it in parens?

(I'm using prettier@2.3 and dart-sass@1.49)

jrz
  • 4,286
  • 1
  • 29
  • 21
  • That depends on the use case. If you have `margin: 0 -($pad);` this will produce `margin: -16px;`, but you might want it to produce `margin: 0 -16px;` and then you need to have `margin: 0 (-$pad);` to achieve that. – toni_lehtimaki Dec 12 '22 at 12:37
1

The answer from @Bouh worked for me but I had to interpolate the variable to handle other variables that have calcs() in them

@function neg($val) {
  @return calc(#{$val} * -1)
};

For example:

$gutter: 30px;
$gutter-half: calc(#{$gutter} / 2);

.header {
  margin: $gutter neg($gutter-half);
}
imagica
  • 11
  • 3