SASS/Compass Add String Extension name to this mixin - sass

I am using Compass and I have the following mixin setuo that I want to produce the following:
.blog .hero {
background-image: url('/images/hero-approach-blur.jpg');
}
#media only screen and (min-width: 600px) {
.blog .hero {
background-image: url('/images/hero-approach.jpg');
}
}
Here are some basic vars/mixins I'm using.
$bp-screen-xs: 320px;
$bp-screen-sm: 600px;
$bp-screen-md: 900px;
$bp-screen-lg: 1170px;
#mixin respond-to( $media ) {
#if $media == xsmall {
#media only screen and (min-width: $bp-screen-xs) { #content; }
} #else if $media == small {
#media only screen and (min-width: $bp-screen-sm) { #content; }
} #else if $media == medium {
#media only screen and (min-width: $bp-screen-md) { #content; }
} #else if $media == large {
#media only screen and (min-width: $bp-screen-lg) { #content; }
}
}
This seems to produce an error. How can I append that extension?
#mixin responsive-hero( $image, $ext: 'jpg' ){
$blurImage: #{ $image }-#{ 'blur' }.#{ $ext };
background-image: image-url( $blurImage );
#include respond-to( small ) {
background-image: image-url( $image );
}
}

You need to add quotes:
#mixin responsive-hero( $image, $ext: 'jpg' ){
$blurImage: "#{ $image }-#{ 'blur' }.#{ $ext }";
background-image: image-url($blurImage );
#include respond-to( small ) {
background-image: image-url("#{$image}.#{$ext}");
}
}

Related

Getting Error passing Media Queries to a SASS mixin: Error: Undefined mixin

I'm getting an error while passing the mixins into my scss file, i used the same mixins to my another project and it worked fine. but when i try to use the same mixins i get an error.
here is the code:-
.carousel-wrapper {
padding: 0 0 20px;
#include screen(custom, min, 669) {
padding: 0;
}
.carousel-stage {
transition-timing-function: cubic-bezier(
0.77,
0,
0.175,
1
) !important;
padding-left: 660px;
padding-right: 660px;
width: 6944px;
transition: all 0.6s ease 0s;
}
}
The errors:-
Here is the image of the Error
Here is the Mixins I used:-
///Media Queries
$breakpoint-small: 575.98px;
$breakpoint-med-small: 767.98px;
$breakpoint-med: 991.98px;
$breakpoint-large: 1199.98px;
#mixin screen($size, $type: max, $pixels: $breakpoint-small) {
#if $size == "small" {
#media screen and ($type + -width: $breakpoint-small) {
#content;
}
} #else if $size == "med-small" {
#media screen and ($type + -width: $breakpoint-med-small) {
#content;
}
} #else if $size == "med" {
#media screen and ($type + -width: $breakpoint-med) {
#content;
}
} #else if $size == "large" {
#media screen and ($type + -width: $breakpoint-large) {
#content;
}
} #else if $size == "custom" {
#media screen and ($type + -width: $pixels + px) {
#content;
}
} #else {
#content;
}
}
You mixin seems fine, so it must be a declaration problem.
Is the mixin code inside the same file than the first code ?
If not, you should copy-paste your code in the same file, or import it with #import.

SASS mapped property doesn't enter in IF else statement

I'm just pulling my hair right know.
I have a mixing that receives a simple object. Depending on the value of one of the properties should enter inside de IF statement or the ELSE one.
However it's always evaluating as TRUE and can't figure why.
Code is compiled using node-sass (libsass v3.5.4 ) and the gist can be seen here:
https://www.sassmeister.com/gist/40eb28fd55173d7534a7162de3c1b960
Both times calculateHeight mixin is invoked evaluates the if to TRUE and creates a CSS with twice color: red, instead of color: red and color: blue
// ----
// libsass (v3.5.4)
// ----
$headerHeight: 150px;
$headerHeightM: 115px;
$headerHeightS: 100px;
#mixin calculateHeight($obj:()){
#if #{map-get($obj, value)} {
color: red;
#media (min-width: 480px) {
#{map-get($obj, property)}: $headerHeightS;
}
#media (min-width: 768px) {
#{map-get($obj, property)}: $headerHeightM;
}
#media (min-width: 1280px) {
#{map-get($obj, property)}: $headerHeight;
}
}
#else {
color: blue;
#media (min-width: 480px) {
#{map-get($obj, property)}: #{map-get($obj, value)} 233px;
}
}
}
.header{
#include calculateHeight((property: 'height', value: false));
#include calculateHeight((property: "background", value: "url('../img/red_header_wave_1.png') no-repeat center top/100% "));
}
Not sure why, but, if I assign the value of the object property to a variable it does the trick and works. Again, not sure why but it's working now:
// ----
// libsass (v3.5.4)
// ----
$headerHeight: 150px;
$headerHeightM: 115px;
$headerHeightS: 100px;
#mixin calculateHeight($obj:()){
// Assign the mapped property to a variable prior to #if
$var: #{map-get($obj, value)};
#if $var == 'false' {
color: red;
#media (min-width: 480px) {
#{map-get($obj, property)}: $headerHeightS;
}
#media (min-width: 768px) {
#{map-get($obj, property)}: $headerHeightM;
}
#media (min-width: 1280px) {
#{map-get($obj, property)}: $headerHeight;
}
}
#else {
color: blue;
#media (min-width: 480px) {
#{map-get($obj, property)}: #{map-get($obj, value)} 233px;
}
}
}
.header{
#include calculateHeight((property: 'height', value: false));
#include calculateHeight((property: "background", value: "url('../img/red_header_wave_1.png') no-repeat center top/100% "));
}
You are interpolating the value from your map into a string, so you are actually checking the string "false", which is truthy (as you already found out). Get rid of the interpolation #{...} and it should work as expected.
- #if #{map-get($obj, value)} {
+ #if map-get($obj, value) {

SASS: Get value of variables after returning a string from list

Is there a way I can get the value of nth($list , 1)
$xs: 600px;
$sm: 960px;
$md: 1280px;
$lg: 1920px;
$list: xs, sm, md, lg;
#mixin respond($media) {
#for $i from 1 through length($list) {
#if $media==nth($list, 1) {
#media only screen and (max-width: nth($list, 1) - 1px) {
#content;
}
}
}
}
I'm getting this now
#media only screen and (max-width: xs-1px) {}
I want the value of the variable $xs = 600px;
#media only screen and (max-width: 600px - 1px) {}
I tried:
$nth($scree-size , 1)
$#{nth($scree-size , 1)}
The short answer is: no, as what you are looking for are dynamic variable names and they are not well supported. However, I suggest to use a map instead to have a somewhat cleaner code without the need to repeat the variable names and to simplify your mixin in general:
$breakpoints: (
xs: 600px,
sm: 960px,
md: 1280px,
lg: 1920px
);
#mixin respond($media) {
#if map-has-key($breakpoints, $media) {
#media only screen and (max-width: map-get($breakpoints, $media) - 1px) {
#content;
}
}
}
#include respond("md") {
.class {
color: red;
}
}
outputs:
#media only screen and (max-width: 1279px) {
.class {
color: red;
}
}

Conditionally negating a media query in Sass

I have the following mixin (source):
#mixin media($queries) {
#if length($queries) == 0 {
#content;
} #else {
$first-key: nth(map-keys($queries), 1);
#media ($first-key: map-get($queries, $first-key)) {
$queries: map-remove($queries, $first-key);
#include media($queries) {
#content;
}
}
}
}
I would like to use a condition to be able to negate the media query, like so:
#media not screen and ($first-key: map-get($queries, $first-key)) {
What is the correct syntax to add it dynamically? I tried the following without success:
$invert: true;
$foo: if($invert, 'not screen and', null);
#media #{$foo} ($first-key: map-get($queries, $first-key)) {
Error:
Invalid CSS after "...#media #{$foo} ": expected "{", was "($first-key: ma..."
The iterated queries could look like this:
tablet: (
respond-to: (min-width: 421px, max-width: 992px)
)
Which would result in the following css when used:
#media (min-width: 421px) and (max-width: 992px) { }
I don't have an explanation as to why what you have doesn't work (this issue claims that interpolation is done before the media query is parsed).
It looks like you'll need to move the and outside of the variable and into the media query itself:
#mixin media($queries, $invert: false) {
#if length($queries) == 0 {
#content;
} #else {
$first-key: nth(map-keys($queries), 1);
$foo: if($invert, 'not', '') screen;
#media #{$foo} and ($first-key: map-get($queries, $first-key)) {
$queries: map-remove($queries, $first-key);
#include media($queries, $invert) {
#content;
}
}
}
}
Output:
#media not screen and (min-width: 30em) and (max-width: 50em) {
.foo {
color: red;
}
}
#media (min-width: 30em) {
.foo {
color: green;
}
}
And yes, you need to apply the not each time you nest it otherwise Sass won't merge the media query (you can't merge a not screen with a (min-width: 30em) because they're exclusive from each other).

Undefined operation: "500px gte medium-screens"

I'm trying to combine Jake Archibald's mobile-friendly IE sass mixins... http://jakearchibald.github.io/sass-ie ...with the responsive mixins illustrated by Dan Cederholm in his book 'Sass for Web Designers'. I'm using CodeKit to compile the files (detailed below).
all.scss compiles successfully, but all-old-ie.scss fails. CodeKit says:
Error: Undefined operation: "500px gte medium-screens".
on line 8 of /Applications/MAMP/htdocs/sass-ie-test/sass/_utils.scss, in `responsive'
from line 4 of /Applications/MAMP/htdocs/sass-ie-test/sass/_layout.scss
from line 2 of /Applications/MAMP/htdocs/sass-ie-test/sass/all.scss
from line 3 of /Applications/MAMP/htdocs/sass-ie-test/sass/all-old-ie.scss
Use --trace for backtrace.
Not sure what's going on here. My files are:
_utils.scss
$medium: 600px;
$large: 950px;
$fix-mqs: false !default;
#mixin responsive($width) {
#if $fix-mqs {
#if $fix-mqs >= $width {
#content;
}
}
#else if $width == medium-screens {
#media only screen and (min-width: $medium) {
#content;
}
}
#else if $width == large-screens {
#media only screen and (min-width: $large) {
#content;
}
}
}
$old-ie: false !default;
#mixin old-ie {
#if $old-ie {
#content;
}
}
_layout.scss
article {
padding: 30px;
#include responsive(medium-screens) {
padding: 50px;
}
#include responsive(large-screens) {
padding: 70px;
}
#include old-ie {
//stuff for ie
}
}
all.scss
#import 'utils';
#import 'layout';
all-old-ie.scss
$old-ie: true;
$fix-mqs: 500px;
#import 'all';
The error is quite clear here. It explicitly states that it cannot possibly determine whether or not the number 500px is greater than or equal (gte) to the string medium-screens.
You're trying to overcomplicate things for no reason: just use variables.
$medium: 600px;
$large: 950px;
#mixin responsive($width) {
#if $fix-mqs {
#if $fix-mqs >= $width {
#content;
}
} #else {
#media only screen and (min-width: $width) {
#content;
}
}
}
article {
padding: 30px;
#include responsive($medium) {
padding: 50px;
}
#include responsive($large) {
padding: 70px;
}
#include old-ie {
//stuff for ie
}
}

Resources