Anyone know of a way to use the SASS if function (not the #if directive) without a false (aka else) clause?
Use Case: I have a SASS library that's normally used on its own and includes a full CSS reset. Someone wants to take an individual file from the library and add it to a project that includes Zurb Foundation, which, of course, totally destroys the CSS reset. I'd like to accommodate that use case with something like:
$css-reset: false !default;
.form__input {
border-radius: 4px if(not $css-reset, !important);
}
That's a SASS compile error, though, since the compiler requires a third parameter to the if() function.
Thanks in advance
Not super elegant, but this works:
border-radius: 4px if(not $css-reset, !important, unquote("");
Related
I'm migrating a Stylus library to SCSS since Angular 12 has deprecated Stylus and I'm in that impacted 0.3%. I've run into something we were doing that I'm not sure how to convert to SCSS—maybe it's impossible.
Let me lay this out simply: I work on several projects that all use loads of the same styles, so we put those styles together into one style sheet in its own NPM package. We can then just grab #import '#company/design/styles'; and suddenly we've got all of our regular styles and variables and mixins available in the project, or we can import #import '#company/package/styles/common'; for just the variables and mixins.
The thing is, our projects might need to configure the library before we import it. Suppose the library contains this bit:
// #company/package/styles/_forms.scss
input:invalid {
background: url('/assets/input-error.svg') no-repeat center right;
}
Not every project will have /assets/input-error.svg at that exact location. Maybe one of my projects has to use /subfolder/static/input-error.svg.
I could include this then overwrite input:invalid { background-image: url(...) } to supply it with the correct location, but there may be many references to this particular file and many other assets on top of that to correct. So we instead, in our Stylus library, we introduced an $asset-input-error variable that points to /assets/input-error.svg by default and did something like this:
// #company/package/styles/_forms.scss
input:invalid {
background: url($asset-input-error) no-repeat center right;
}
// the local project
$asset-input-error: '/subfolder/static/input-error.svg';
#import '#company/package/styles';
The above is heavily simplified and isn't actually legitimate SCSS, but I hope it conveys what we're trying to do: we want to set up what are effectively environment variables in our SCSS, include the common style sheet, and have it use those variables.
The thing is, I'm not sure what the legitimate or idiomatic approach is to do this in SCSS. Unlike Stylus, which has a global scope for its variables, SCSS would have me #use '../config'; and reference config.$asset-input-error, and from outside the library there's no way I see to change the configuration to point that asset to a different location. I'm sure SCSS has a way for me to do this, but I'm not sure what it is. Do I convert the entire library into a giant mixin to which I pass optional configuration? Do I do something with global variables? Something else?
How can I provide variables to my SCSS style sheet to configure it as part of including it in a project?
Ultimately the end goal here is just to be able to say to the library things like: “the assets to reference are here” (very important) or “the error color is this in this particuilar project” (less important).
Using #import
You can use global variables declared before the #import as you stated.
SCSS Documentation for this method
#company/package/styles/_forms.scss
$asset-input-error: '/subfolder/static/input-error.svg' !default;
input:invalid {
background: url($asset-input-error) no-repeat center right;
}
#company/package/styles/styles.scss
#import 'forms';
local.scss
$asset-input-error: '/different/path/input-error.svg';
#import '#company/package/styles';
CodeSandbox Demo
Using #use [...] with
You can also hop aboard the #use train if you prefer to future-proof your library.
SCSS Documentation for this method
SCSS Documentation for using mixins
SCSS Documentation for configuring forwards
#company/package/styles/_forms.scss
$asset-input-error: '/subfolder/static/input-error.svg' !default;
input:invalid {
background: url($asset-input-error) no-repeat center right;
}
#company/package/styles/styles.scss
#forward 'forms';
local.scss
#use 'styles' with (
$asset-input-error: '/different/path/input-error.svg'
);
Sadly CodeSandbox and StackBlitz don't support dart-sass, so I don't have a live demo for this but I tested it on the latest version of sass from npm.
In Sass, I could find I can use '#extend' with '#mixin'.
But from the code, I got curious what's the advantage of using extend.
If we know which 'classes' exactly what do we have to use, we can just use two classes, not extend and make another class.
In my opinion, if we just use two classes, not making multiple extends, code would be shorter and we can save memory. What can I think of the advantage is it's just more easy to see on 'CSS output', but usually people just check SCSS file, not CSS code output.
Isn't it just better to use two separate classes instead of using multiple extends? What is the main advantage of using '#mixin'?
It helps you write DRY code quickly. #extend can be very useful when used properly.
It allows a selector to extend the styles of another selector, essentially providing a form of sub-classing. #extend works by combining selectors into a single comma-separated selector.
I.e. -
.A {
font-size: 1rem;
color:red;
}
.a{
#extend .A;
line-height: normal;
}
Which outputs:
.A,.a {
font-size: 1rem;
color:red;
}
.a{
line-height: normal;
}
There are a couple of important issues with extends to keep in mind:
they change the order of your CSS rules and re-group them often awkwardly which can have unintentional issues down the road
they are less performant than Mixins when your Sass is minified and gzipped.
Great article detailing these issues by Harry Roberts: "Mixins for Better Performance"
Using SASS/SUSY,
I am trying to create RTL rules that only apply when [dir="rtl"] is set (dynamically) but my layout is taking on the RTL flow rules by default. How do I do this with SUSY?
I have a Demo here
$default-dir: (
math: fluid,
columns: 12,
gutter-position: split,
gutters: 0,
flow: ltr
);
.boxes{
width: 100%;
display: block;
margin: 0 auto;
max-width: 1280px;
#include clearfix;
#include layout($default-dir);
[dir="rtl"] &{
#include layout(rtl);//I EXPECT THIS LINE TO ONLY APPLY TO RTL [dir="rtl]
background-color: orange;
}
...
}
This is a common confusion between how CSS works, and how Sass works. CSS is DOM-aware, because it is compiled by browsers along with HTML. Sass is working at a different layer, unaware of the DOM structures implied by your CSS.
The layout mixin is a Sass abstraction, changing a few global Sass variables that Susy can refer back to — it has no actual CSS output of its own. The layout mixin changes the output of other functions and mixins that come after it in the Sass. You can also use with-layout() { <content> } to wrap entire blocks of mixins and functions — but in both cases, the variables only exist in Sass.
In order to change the layout based on a selector, you have to provide both layouts in full — not just one layout, and a scoped variable change. That means something more like this:
.box-item {
#include span(1 of 2);
[dir='rtl'] & {
#include span(1 of 2 rtl)
}
}
There are some workarounds to make that less repetitive, but none are as simple and clean as what you hoped for. They basically involve finding ways to compile the same code block twice, with different variables and an extra selector.
I'm using Compass to compile a Sass Zen theme. I got this warning:
Compass has changed how browser support is configured. The following configuration variables are no longer supported: $legacy-support-for-ie6, $legacy-support-for-ie7, $legacy-support-for-ie8
I installed older versions of
compass (0.12.7)
sass (3.2.19)
breakpoint (1.3)
I'm no longer getting the warning, however, I'm losing semicolons in the compiled code. Example:
/* Address paddings set differently in IE 6/7. */
menu,
ol,
ul {
padding: 0 0 0 $indent-amount; /* LTR */
}
#if $legacy-support-for-ie7 {
/* Correct list images handled incorrectly in IE 7. */
nav ul,
nav ol {
list-style: none;
list-style-image: none;
}
Compiles to
menu,
ol,
ul {
padding: 0 0 0 30px
/* LTR */
}
Notice the missing semicolon. It seems like everywhere there's an #if $legacy-support-for-ie compass then strips the preceding semicolon.
There are 51 declarations of #if $legacy-support-for-ie in my files, I'd rather just leave them if possible.
The $legacy-support-for-ie has nothing to do with the very last semicolon being dropped. That's a particular of Compass.
Sass does not care how your code is formatted as long as it is valid. When the CSS is generated, it follows the style rules dictated by the chosen output style for things like whitespace, indentation, punctuation, etc. You can only specify a different output style, not change the particulars of any given style.
Note that omitting the final semicolon is completely valid according to CSS.
I've had issues with using the latest version of compass when a site was setup to use the pre 1.0 release of compass. Try using Compass 0.12.7 and then rebuilding your dependencies from there. https://rubygems.org/gems/compass/versions/0.12.7
How to define a SCSS variable in Config.rb for SCSS file[ COMPASS project ]
My Use-case
In Config.rb file something like
a = true
In style.scss i like to use the variable like
#if a == true{
background: #fff;
}
#else {
background: #000;
}
One of the solution
http://worldhousefinder.com/?p=124141
But its not worked for me.
You can't/shouldn't do this. You will precompile your assets so there is no way of dynamically adapting to changing variables. This might work for your config.rb variable, but it is a bad pattern to use and you'd have to recompile your assets every time you change the variable, this defeats the purpose of doing if else checks in your sass.
A much easier approach is to either add a class .active .inactive on your elements (body). Or output inline css in your head for things like custom colors etc depending on users that are signed in.
What are you trying to do? It sounds like something you'd do to check whether you are in production or development? In which case you could do something like:
<body class='<%= "development" if Rails.env == 'development' %>'>
or even
<body <%= "style='background-color: red;'" if Rails.env == 'development' %>
You should never need to use ruby in your css and javascript, if you find yourself doing it you are probably approaching it in the wrong way. At least that is what I have found after many attempts to do this nicely.
p.s. data-attributes are a very effective way of passing variables, etc to javascript
First of all, have you looked at variables and mixins?
If you're REALLY trying to pass outside variables to SASS, you must understand that it's not aware of your config file when it's compiling CSS. According to Nathan Weizenbaum (one of the main developers of Haml), the best way to do it is by creating custom user-defined functions.
If you go that route (again, quoting Nathan):
You'll want to make sure that your stylesheets
get regenerated whenever the data changes. You can do so by calling
Sass::Plugin.force_update_stylesheets.