see this codepen
it is super basic
$span1Width: 10;
$marginWidth: 5;
#mixin span-width($spannr) {
width: $span1Width * $spannr *1%;
*width: $marginWidth* $spannr -1 *1%;
}
div{
#use span-width(10);
}
resulting in "empty rule" when doing a analyse css with codepen.
If you check the example on sass documentation on how to use mixins you can see:
$color: white;
#mixin colors($color: blue) {
background-color: $color;
#content;
border-color: $color;
}
.colors {
#include colors { color: $color; }
}
So you should use #include and { } instead. Like (using default 5 in this example):
$span1Width: 10;
$marginWidth: 5;
#mixin span-width($spannr: 5) {
width: $span1Width * $spannr *1%;
*width: $marginWidth* $spannr -1 *1%;
}
div{
#include span-width{ spannr: 10};
}
That should give you the correct result
Related
I'm trying to create a mixin that allows me to write code blocks flexibly depending on whether body has a certain class.
#mixin when($class) {
body.#{$class} & {
#content;
}
}
Use Cases
#hero {
#include when('theme--dark') {
span {
content: 'Good Evening';
}
}
}
#hero {
#include when('page-landing') {
button.cta {
padding: 3rem 5rem;
font-size: 3rem;
background-color: $green;
}
}
}
even better if the following can be achieved
#mixin when($parent, $class) {
#{$parent}.#{$class} & {
#content;
}
}
#hero {
#include when('body','page-landing') {
button.cta {
padding: 3rem 5rem;
font-size: 3rem;
background-color: $green;
}
}
}
non of the previous codes work, not even certain of the syntax but wondering if something similar can be produced, any help is appreciated thanks!
Though your approach is absolutely fine, here is a slightly cleaner implementation, that grants a little more flexibilty when it comes to the number of selectors you want to check for.
#mixin when($selectors...) {
$n: "";
#each $selector in $selectors {
$n: str-insert($n, "#{$selector}", str-length($n) + 1);
}
#{$n} {
#content;
}
}
#hero {
#include when('body', '[dark-mode=true]', '.primary') {
color: #fff;
}
}
I'm trying to use a var defined for one mixin in another mixin.
In my case, I definee the $gutter variable in the container() mixin.
I don't want to define it again for the col() mixin, so I was trying to get it into the col() mixin.
Here is what I've done so far:
#mixin container($gutter, $placeholder:"cols") {
margin: 0 -#{$gutter / 2};
%#{$placeholder} {
margin-left: #{$gutter / 2};
margin-right: #{$gutter / 2};
}
}
#mixin cols($cols, $placeholder:"cols") {
#extend %#{$placeholder};
width: #{(100% / $cols) - $gutter};
}
.wrap {
#include container(2%);
> .half {
#include cols(2);
}
> .third {
#include cols(3);
}
> .fourth {
#include cols(4);
}
}
The css result I need is the following:
.wrap {
margin: 0 -1%;
}
.wrap > .half, .wrap > .third, .wrap > .fourth {
margin-left: 1%;
margin-right: 1%;
}
.wrap > .half {
width: 48%;
}
.wrap > .third {
width: 31.33333%;
}
.wrap > .fourth {
width: 23%;
}
Is there a way to do this? It fails in line 11 because $gutter is undefined. A global variable isn't the solution i need, because I have to use this mixin in different breakpoints with different gutters. So for each breakpoint will define container() and cols() for the elements again.
You are creating a variable inside a mixin. Variables inside mixins are local they are not global. If you want to create a global variable from a mixin then you have to use the !global flag
you can rewrite the container mixin like this
#mixin container($gutter, $placeholder:"cols") {
$gutter: $gutter !global;
margin: 0 -#{$gutter / 2};
%#{$placeholder} {
margin-left: #{$gutter / 2};
margin-right: #{$gutter / 2};
}
}
I'm trying to do a mixin that have optional arguments. This is a simplified version:
#mixin marginCalculator($size, $size2:"") {
margin: $size * 1px unquote($size2 * 1px);
}
I'm just passing in numbers as arguments. But i only want the first one to be mandatory. No problem if it only would output the number but i need to add a unit to it.
As can be seen in the snippet above i'm trying to multiplicate 1px with "" which ouputs an error message. As it should! But i was hoping for the empty quote to be returned. Is there another way to achieve this?
You have 2 options:
Check the type of the value being passed in
#mixin marginCalculator($size, $size2: "") {
margin: ($size * 1px) (if(type-of($size2) == number, $size2 * 1px, null));
}
Loop over a list
This is a much better solution since it will allow you to gracefully handle 3-value margins as well.
#mixin marginCalculator($size...) {
$xs: ();
#each $s in $size {
$xs: append($xs, $s * 1px);
}
margin: $xs;
}
.foo {
#include marginCalculator(1);
#include marginCalculator(1, 2);
#include marginCalculator(1, 2, 3);
}
Alternately:
#mixin marginCalculator($sizes) {
$xs: ();
#each $s in $size {
$xs: append($xs, $s * 1px);
}
margin: $xs;
}
.foo {
#include marginCalculator(1);
#include marginCalculator(1 2);
#include marginCalculator(1 2 3);
}
Output:
.foo .foo {
margin: 1px;
margin: 1px 2px;
margin: 1px 2px 3px;
}
You can use an if() function to check if it has no value:
#mixin marginCalculator($size, $size2:"") {
margin: ($size * 1px) if($size2!="", $size2 * 1px, null);
}
Here, i check it against the default, an empty string, and return the calculation if it isn't that, and null if it is. If we return an empty string, it'll cause a CSS error.
I'm trying to style placeholders for input fields (for different browsers) in Sass 3.3.1, and want to change the opacity when the field is focused. I'm having a hard time combining the pseudo-class and pseudo-elements with the ampersand. The following gives a compilation error:
::-webkit-input-placeholder,
:-moz-placeholder,
::-moz-placeholder,
:-ms-input-placeholder{
... some default styling
:focus#{&}{
opacity: 0;
}
}
Can this be done?
Edit
This is the output I am looking for:
::-webkit-input-placeholder {
opacity: 1;
}
:-moz-placeholder{
opacity: 1;
}
::-moz-placeholder{
opacity: 1;
}
:-ms-input-placeholder{
opacity: 1;
}
:focus::-webkit-input-placeholder {
opacity: 0;
}
:focus:-moz-placeholder{
opacity: 0;
}
:focus::-moz-placeholder{
opacity: 0;
}
:focus:-ms-input-placeholder{
opacity: 0;
}
// Cross-browsers opacity: #include opacity(0.5);
#mixin opacity($opacity) {
opacity: $opacity;
$opacity-ie: $opacity * 100;
filter: alpha(opacity=$opacity-ie); //IE8
}
// Transitions for all: #include transition($transition);
$transition: all .3s ease;
#mixin transition($value) {
-webkit-transition: $value;
-moz-transition: $value;
-ms-transition: $value;
-o-transition: $value;
transition: $value;
}
// Input placeholder animation: #include placeholder { color: #000 }
#mixin placeholder {
&::-webkit-input-placeholder {
#content;
}
&:-moz-placeholder {
#content;
}
&::-moz-placeholder {
#content;
}
&:-ms-input-placeholder {
#content;
}
}
// How to use:
input {
text-overflow: ellipsis;
color: mediumseagreen;
#include placeholder {
color: cornflowerblue;
transition: $transition;
#include opacity(1);
}
&:focus {
#include placeholder {
#include opacity(0);
transition: $transition;
}
}
}
This is going to be the other way around, actually:
element:focus{
&::-webkit-input-placeholder,
&:-moz-placeholder,
&::-moz-placeholder,
&:-ms-input-placeholder{
opacity: 0;
}
}
Edit
I seem to have a problem combining them in my testing, but the following should work:
::-webkit-input-placeholder{
color: red;
&:focus{
color: blue;
}
}
On thing to note, though, is that this only works if they are separated out. You cannot combine multiple pseudo-selectors to one definition (like ::-webkit-input-placeholder, :-moz-input-placeholder{ /* this does not work in my testing */ }).
Update 2
Heres a quick SASS function I mocked up that will simplify the process:
#mixin input-placeholder($all:default){
#if $all == default {
$all : ("::-webkit-input-placeholder", ":-moz-placeholder","::-moz-placeholder",":-ms-input-placeholder");
}
#each $placeholder in $all {
#{unquote($placeholder)}{
#content;
}
}
}
You can use it by doing the following:
#include input-placeholder{
color: red;
&:focus {
color: blue;
}
}
This means you only have to write your code once. It will output all of them on individual lines and apply the same rules to them.
Solution from SASS Compass:
// Style the html5 input placeholder in browsers that support it.
//
// The styles for the input placeholder are passed as mixin content
// and the selector comes from the mixin's context.
//
// For example:
//
// #{elements-of-type(text-input)} {
// #include input-placeholder {
// color: #bfbfbf;
// font-style: italic;
// }
// }
//
// if you want to apply the placeholder styles to all elements supporting
// the `input-placeholder` pseudo class (beware of performance impacts):
//
// * {
// #include input-placeholder {
// color: #bfbfbf;
// font-style: italic;
// }
// }
#mixin input-placeholder {
#include with-each-prefix(css-placeholder, $input-placeholder-support-threshold) {
#if $current-prefix == -webkit {
&::-webkit-input-placeholder { #content; }
}
#elseif $current-prefix == -moz {
// for Firefox 19 and below
#if support-legacy-browser("firefox", "4", "19", $threshold: $input-placeholder-support-threshold) {
&:-moz-placeholder { #content; }
}
// for Firefox 20 and above
&::-moz-placeholder { #content; }
}
#elseif $current-prefix == -ms {
&:-ms-input-placeholder { #content; }
}
}
// This is not standardized yet so no official selector is generated.
}
I'm trying to loop through a list of values in Sass and use interpolation of the current key to dynamically output class names that utilize #include and #extend, respectively.
Here is a pen showing the problem, simplified. http://codepen.io/ghepting/pen/vBmLy
As you can see in the markup, I have tried including the "_" inside of the interpolated string as well as outside of it. Is there something I'm missing to work around this limitation of how Sass supports interpolation?
(Note: the OP's pen has disappeared. This is not the original code found in the pen, but a rough approximation of the problem)
$error-light: red;
$error-dark: darken(red, 10%);
$success-light: green;
$success-dark: darken(green, 10%);
$dialogs: error, success;
#each $d in $dialogs {
.#{$d} {
background: $#{$d}-light;
}
}
Interpolation doesn't work on mixins or variables at this point in time. You'll have to come up with a different way to achieve your goal.
As of Sass 3.3, you can use mappings for this purpose for variables:
$dialogs:
( error:
( light: red
, dark: darken(red, 10%)
)
, success:
( light: green
, dark: darken(green, 10%)
)
);
#each $name, $colors in $dialogs {
.#{$name} {
color: map-get($colors, dark);
}
}
And for functions:
#function green() {
#return lighten(green, 10%);
}
#function red() {
#return lighten(red, 10%);
}
#mixin my-bg($function-name) {
background: call($function-name);
}
.foo {
#include my-bg('red');
}
Alternative workaround (for a particular use case):
https://sass-lang.com/documentation/at-rules/mixin#passing-arbitrary-arguments
💡 Fun fact:
Because an argument list keeps track of both positional and keyword arguments, you use it to pass both at once to another mixin. That makes it super easy to define an alias for a mixin!
If you are interested in mixin interpolation because you have a group of mixins, like this:
//_mixins.scss
#mixin text-style-1($args...){ //sass here }
#mixin text-style-2($args...){ //sass here }
#mixin text-style-3($args...){ //sass here }
//_text.scss
.text-style-1 {
#include text-style-1;
}
.text-style-1-contrast {
#include text-style-1($contrast: true);
}
.text-style-2 {
#include text-style-2;
}
.text-style-2-contrast {
#include text-style-2($contrast: true);
}
We can take advantage of passing arbitrary arguments and use an alias for the group:
//_mixins.scss
#mixin text-style-1($args...){ //sass here }
#mixin text-style-2($args...){ //sass here }
#mixin text-style-3($args...){ //sass here }
#mixin text($mixin, $args...) {
#if $mixin == 'style-1' { #include text-style-1($args...); }
#else if $mixin == 'style-2' { #include text-style-2($args...); }
#else if $mixin == 'style-3' { #include text-style-3($args...); }
}
//_text.scss
$text-styles: 'style-1', 'style-2', 'style-3';
#each $style in $text-styles {
.text-#{$style} {
#include text($style);
}
.text-#{$style}-contrast {
#include text($style, $contrast: true);
}
}
Ran into this issue of trying to include an interpolated variable inside a mixin and was able to resolve it with placeholders:
%color-scheme-dark-bg-1 { background-color: #4e5163; }
%color-scheme-dark-color-1 { color: #4e5163 !important; }
%color-scheme-light-bg-1 { background-color: #c7c8ce; }
%color-scheme-dark-bg-2 { background-color: #fd6839; }
%color-scheme-dark-color-2 { color: #fd6839 !important; }
%color-scheme-light-bg-2 { background-color: #fecfc1; }
.card_color {
#mixin CardColorScheme($arg: 1) {
.borderPercent {
#extend %color-scheme-dark-bg-#{$arg};
}
.border {
#extend %color-scheme-light-bg-#{$arg};
}
ul li:before {
#extend %color-scheme-dark-color-#{$arg};
}
.percent {
#extend %color-scheme-dark-color-#{$arg};
}
.heading {
#extend %color-scheme-dark-color-#{$arg};
}
}
&--scheme {
&-1 {
#include CardColorScheme(1);
}
&-2 {
#include CardColorScheme(2);
}
}
}
Hat tip to: https://krasimirtsonev.com/blog/article/SASS-interpolation-in-a-name-of-variable-nest-variables-within-variables