is there a way to escape # when writing Mixins in SASS? - sass

I am trying to write a mixin for animations in css3. An animation in css3 requires an #keyframe. But a mixin declaration in SASS (and other declarations) start with # too. Like #mixin, #for, etc... So what I was trying to do writing a mixin for an animation (I was trying to have all automated inside the mixin) was to put the #keyfram escaped for SASS when passed to CSS not to interpret the #keyframe's #. Is it possible to do this?
Example :
#mixin animation(
//variables :
$mykeyframe:mykeyframe,
$prop1:background,
$value1-i:white,
$value1-e:red,
$prop2:color,
$value2-i:black,
$value2-e:white,
$prop3:font-weight,
$value3-i:400,
$value3-e:bold,
$time:5s,
$iteration-count:1,
$timing-function:linear,
$delay:0s,
$direction:normal,
$play-state:running
)
{//HERE'S THE PROBLEM :
#keyframes $mykeyframe{
0%{$prop1:$value1-i; $prop2:$value2-i; $prop3:$value3-i}
100%{$prop1:$value1-e; $prop2:$value2-e; $prop3:$value3-e}
}
-webkit-animation: $mykeyframe $time $iteration-count; /* Chrome, Safari 5+ */
-moz-animation: $mykeyframe $time $iteration-count; /* Firefox 5-15 */
-o-animation: $mykeyframe $time $iteration-count; /* Opera 12.00 */
animation: $mykeyframe $time $iteration-count; /* Chrome, Firefox 16+, IE 10+, Opera 12.10+ */
/* Chrome, Firefox 16+, IE 10+, Opera 12.10+ */
animation-timing-function: $timing-function;
animation-delay: $delay;
animation-direction: $direction;
animation-play-state: $play-state;
/* Safari and Chrome: */
-webkit-animation-timing-function: $timing-function;
-webkit-animation-delay: $delay;
-webkit-animation-direction: $direction;
-webkit-animation-play-state: $play-state;
}

Even though the mixin (#mixin) and conditional (#for, #if etc.) directives in SASS start with the symbol #, you can still use it for other keywords that are not part of the SASS library like if, mixin etc.
So, you can still do:
#mixin animation($mykeyframe:mykeyframe) {
#keyframes $mykeyframe {
}
}
body {
#include animation(someframe);
}
and this will generate:
body {
#keyframes someframe {}
}

Related

sass variable not working in container query

SCSS variables don't seem to work when used in a container query. For example this code works just fine:
.parent {
container-type: inline-size;
background: yellow;
}
#container (max-width: 800px) {
.child {
background:green;
}
}
See pen: https://codepen.io/pwkip/pen/jOprKya
But when I try to use a sass-variable to define the breakpoint, it fails.
$width: 800px;
.parent {
container-type: inline-size;
background: yellow;
}
#container (max-width: $width) {
.child {
background:green;
}
}
See pen: https://codepen.io/pwkip/pen/BaPzVZW
What's the problem here? Any workaround?
I cannot find the definitive sass lang entry, but hash and curly brace is often used in #media queries.
#container (max-width: #{$width}) {
.child {
background:green;
}
}
In Brave it works in that codepen; and so do the following:
#container (max-width: ${width} ) {
As "A Boston" already pointed out the issue seems to be that you don't use the hash syntax like in his first example.
I use https://www.sassmeister.com/ quite often to check what it compiles to.
In your Codepen you forgot to add a semicolon after
$width: 800px;
^
According to: https://developer.mozilla.org/en-US/docs/Web/CSS/#container
#container queries are not supported for Firefox yet. Only Firefox Nightly supports it.
I've tested it in Chrome and it worked with the tweaks. Make sure your browser version is supported. My current Safari version did not work either (due to the version mismatch).

Dynamically displaying static images based on view port using Sass

I'm creating a React application that has a hero display on the landing page that displays one of three images: [hero-1.jpg, hero-2.png, hero-3.png] based on the users viewport screen size.
I have been unsuccessful trying to find resources online that show a DRY method for achieving this, for the sake of participation, I'll leave this code that I attempted that - in theory made sense to me.
N.B. I am extremely new to Sass/Scss
snippet.html
<section className="hero is-fullheight has-background-black">
<div className="hero-body">
<div className="container">
</div>
</div>
</section>
hero.scss
$i: 1;
$breakpoint-phone: 480px;
$breakpoint-tablet: 768px;
$breakpoint-desktop: 1024px;
#mixin modifier ($i:1) {
#content;
#media only screen and (max-width:$breakpoint-phone) { $i: 2; }
#media only screen and (max-width:$breakpoint-tablet) { $i: 3; }
#media only screen and (max-width:$breakpoint-desktop) { $i: 1; }
}
.hero {
background-position: center;
background-size: cover
}
#include modifier {.hero {background-image: url('../assets/hero-#{$i}.jpg');}}
Methodology:
Display content by default (which is pulled from #include).
Mixin modifier will modify the $i passed to the mixin, which is interpolated in the image path.
Expected Result:
Based on each breakpoint, $i will be set to the appropriate value and change the background image dynamically.
Actual Result:
The global $i is used, and the web page displays hero-1.jpg.
There are a few ways you can achieve this. If I was going about this, this is how I would do it.
Also, it would be very wise to practice mobile first development. Use min-width and go up instead of using max-width going down. The way you currently have it structured would mean you wouldn't have a valid URL if that $i variable wasn't set at 1 at the top of your document. Writing SASS or CSS will be much easier this way once you get used to it.
$tablet: 768px;
$desktop: 1024px;
#mixin hero-image() {
.hero {
background-position: center;
background-size: cover;
background-image: url('../assets/hero-2.jpg');
#media screen and (min-width: $tablet) {
background-image: url('../assets/hero-3.jpg');
}
#media screen and (min-width: $desktop) {
background-image: url('../assets/hero-1.jpg');
}
}
}
#include hero-image();
You're still going to have to write the background-image property 3 times. The way you were doing it was close, but you would have had to #include modifier() 3 times in your consuming scss file. At the end of the day SASS compiles to CSS. You could potentially use a SASS function or For Loop to achieve this, but mixins can get really complicated and powerful, but also incredibly difficult to read and understand. Here's what the mixin I just showed you compiles to in CSS.
.hero {
background-position: center;
background-size: cover;
background-image: url("../assets/hero-2.jpg");
}
#media screen and (min-width: 768px) {
.hero {
background-image: url("../assets/hero-3.jpg");
}
}
#media screen and (min-width: 1024px) {
.hero {
background-image: url("../assets/hero-1.jpg");
}
}
I recommend putting your SCSS/SASS into this compiler to see your results before compiling your actual project.
https://www.sassmeister.com/
Even though you are repeating background-image 3 times inside of the mixin this is very much still DRY code because you can include that one mixin everywhere your images will be shown and if you need to edit it, you can edit it in one place.

sass mixin - not all arguments used

I start using sass, at the moment I start to discover mixin and writing my own one.
I have a mixin:
#mixin column-set ($number, $width, $gap, $rule-style, $rule-width, $rule-color, $col-span) {
-webkit-column-count: $number; /* Chrome, Safari, Opera */
-moz-column-count: $number; /* Firefox */
column-count: $number;
-webkit-column-width: $width; /* Chrome, Safari, Opera */
-moz-column-width: $width; /* Firefox */
column-width: $width;
-webkit-column-gap: $gap; /* Chrome, Safari, Opera */
-moz-column-gap: $gap; /* Firefox */
column-gap: $gap;
-webkit-column-rule-style: $rule-style; /* Chrome, Safari, Opera */
-moz-column-rule-style: $rule-style; /* Firefox */
column-rule-style: $rule-style;
-webkit-column-rule-width: $rule-width; /* Chrome, Safari, Opera */
-moz-column-rule-width: $rule-width; /* Firefox */
column-rule-width: $rule-width;
-webkit-column-rule-color: $rule-color; /* Chrome, Safari, Opera */
-moz-column-rule-color: $rule-color; /* Firefox */
column-rule-color: $rule-color;
-webkit-column-span: $col-span; /* Chrome, Safari, Opera */
column-span: $col-span;
}
I would like to use it but not always with all arguments, for this reason I put them in order of how I think I will need them. But it looks like when I call this mixin I need to enter all arguments. Is there any way to avoid this?
for example:
call1
#include column-set(3, 40px);
call2
#include column-set (2, 40px, 10px, solid, 1px, blue);
I try to find there answer but with no success. Can anyone help?
You can set a default value, if don't set a value in the #include the default value is used:
#mixin column-set ($number:3, $width:200px, $gap:20px){
...
}
You can set to null also.
#mixin column-set ($number:3, $width:null, $gap:null){
...
}
In the include you can call the parameters you want to use:
.class{
#include column-set($gap:10px)
}

Configure compass browser support (Compass 1.x syntax)

With 0.12.x version of Compass, I was defining support for oldies that way:
#import "compass/support"
$legacy-support-for-ie6: false;
$legacy-support-for-ie7: true;
$legacy-support-for-ie8: true;
$legacy-support-for-mozilla: false;
#if ($legacy-support-for-ie7) {
// specific declaration if ie7 is supported
}
I'm wonder how I should define browser support following Compass 1.x system.
Maybe something like that:
// Add support for a specific browser
$browser-minimum-versions: (
'ie': "7",
'ie': "8"
);
// Reject browsers
$supported-browsers: reject(browser-versions("ie"), "6", "7", "8");
But it returns that error (running on Compass 1.0.1):
(Line 206 of /Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.1/stylesheets/compass/_support.scss: 5.5 is not known browser.)
Excluding browsers is done by modifying the $graceful-usage-threshold variable. If Browser X only has 4.99% of the market share, you want to set it to 5.
$debug-browser-support: true;
$browser-minimum-versions: (
"ie": "9"
);
$graceful-usage-threshold: 4.46163;
#import "compass";
.foo {
#include opacity(.5);
#include border-radius(10px);
}
Output:
.foo {
/* Content for ie 8 omitted.
Minimum support is 9. */
opacity: 0.5;
/* Capability border-radius is not prefixed with -moz because 0.25036% of users are affected which is less than the threshold of 4.46163. */
/* Capability border-radius is not prefixed with -ms because 0% of users are affected which is less than the threshold of 4.46163. */
/* Capability border-radius is not prefixed with -o because 0% of users are affected which is less than the threshold of 4.46163. */
/* Capability border-radius is not prefixed with -webkit because 0.1583% of users are affected which is less than the threshold of 4.46163. */
border-radius: 10px;
}
Note that this causes other minority browsers to be excluded that you may want to support. That's when the $browser-minimum-versions comes into play.
$browser-minimum-versions: (
"ie": "9",
"safari": "4"
);
Output:
.foo {
/* Content for ie 8 omitted.
Minimum support is 9. */
opacity: 0.5;
/* Capability border-radius is not prefixed with -moz because 0.25036% of users are affected which is less than the threshold of 4.46163. */
/* Capability border-radius is not prefixed with -ms because 0% of users are affected which is less than the threshold of 4.46163. */
/* Capability border-radius is not prefixed with -o because 0% of users are affected which is less than the threshold of 4.46163. */
/* Capability border-radius is prefixed with -webkit because safari "4" is required. */
/* Creating new -webkit context. */
-webkit-border-radius: 10px;
border-radius: 10px;
}
There are changes in the works to make it easier to exclude old browsers. You can follow them here: https://github.com/Compass/compass/issues/1762
If you want to make rules for a specific browser, then the $critical-usage-threshold variable comes into play:
$debug-browser-support: true;
$browser-minimum-versions: (
"ie": "9"
);
$critical-usage-threshold: 4.46163;
$graceful-usage-threshold: 4.46163;
#import "compass";
.foo {
#include for-legacy-browser('ie', '8') {
color: green;
// this is based on $critical-usage-threshold by default
// if $critical-usage-threshold is lower than the version's usage
// then this content will be generated
}
#if support-legacy-browser('ie', '8') {
color: red;
}
}

Why the css2sass and sass-convert converter trips off with CSS multiline comment?

The CSS to convert to SASS:
body {
background: transparent !important; color: #444 !important; text-shadow: none;
}
/* Don't show links for images */
pre, blockquote {
border: 1px solid #999; page-break-inside: avoid;
}
img {
page-break-inside: avoid;
}
/* Grade-A Mobile Browsers */
html {
-webkit-text-size-adjust:none; -ms-text-size-adjust:none;
}
Converted SASS:
body
background: transparent !important
color: #444 !important
text-shadow: none
/* Don't show links for images
pre, blockquote
border: 1px solid #999
page-break-inside: avoid
img
page-break-inside: avoid
/* Grade-A Mobile Browsers
html
-webkit-text-size-adjust: none
-ms-text-size-adjust: none
Watch out the /* Don't show links for images and /* Grade-A Mobile Browsers.
That makes the whole block after it commented.
It should have been /* Don't show links for images */ instead?
Actually Sass can go both ways. You have to understand that for Sass, /* is just the starting point of a block comment that will go like this :
/* This is the beginning of a commment
* This line is indented under it, so it's part of the comment
html
// This selector is not indented so it's not part of the comment
Sass doesn't need */ to end comments the same way it doesn't need } to end selectors : the indentation takes care of it for you.
I recommand you check the Sass comments syntax in more detail in the reference page.
sass-convert --from css --to scss actual.css>newlyCreated.scss
sass-convert --from css --to sass actual.css>newlyCreated.sass

Resources