Is it possible to define and overwrite Sass/SCSS variables based on conditions - css

I have an I have a _overrides.scss file in which I want to provide a global variable based on conditions.
The variable should be true if my navigation with the .side-navigation class also contains the .-open class. If it contains the -closed class, the variable should have the value false.
Something like this:
$navbarOpen: false;
.side-navigation {
&.-open {
$navbarOpen: true;
}
&.-closed {
$navbarOpen: false;
}
}
I want to use the variable within another SCSS module in React, like:
#import 'overrides';
#if $navbarOpen == true {
footer {
background: red;
}
}
The variable is recognized, but the value is always false since it doesn't seem to be overridden by the condition set in _overrides.scss.

I think that the problem is that Sass variables can't be changed in the runtime, it'll be compiled to plain CSS and all vars will be replaced. Although as I see your condition depends on runtime events.
Check this for references: Dynamic Sass Variables

Related

A scss variable doesn't return the css variable value

I have two css variables and two scss variables , the problem is the last scss variable doesn't return a value at all.
note that the values of the two sass variables comes from the css variables.
the first scss variable takes its value normally from the css variable.
:root {
--intro-img-url: url("../images/pexels-los-muertos-crew-7487374.jpg");
--dl-mode: black;
}
// the intro-img scss variable takes its value normally from the
// css variable and there's no problem with it.
$intro-img: var(--intro-img-url);
// but the dl-mode scss variable doesn't take the css variable val
// and just return nothing
$dl-mode: var(--dl-mode);
#if $dl-mode == black {
:root {
--dominant1-wmode-color: #030712;
--dominant1-bmode-color: #ffffff;
}
} #else {
:root {
--dominant1-wmode-color: green;
--dominant1-bmode-color: #030712;
}
}
Even though --dl-mode is set to black in the context of :root, the value of $dl-mode is set to var(--dl-mode). This is what your SCSS compiler will be seeing when it runs the check #if $dl-mode == black, so that check will always be false.
SCSS cannot look inside the values of CSS variables, because it needs to know those values at compile time but those values may depend on context within the HTML itself. For example, consider the following:
:root {
--my-var: black;
}
.class {
--my-var: white;
}
$my-var: var(--my-var);
#if $my-var == black {
// How can you know the value within --my-var if you don't know if you're in a .class element or not?
}

How to check in SCSS if a variable exists and ha a value?

I am new in SCSS so bear with me :)
I have a use case where a SCSS variable --my-variable can exist and can have a value depending on some settings from the backend. So, if --my-variable exists and has a value I should override some styling. If not I shouldn't override anything.
Example:
In file1 I have:
.my-div {
color: red;
}
In file2 I should have something like this:
.my-div {
#include customize(color, --my-variable);
}
#mixin customize($property, $variable) {
#if $variable and (var($variable)) {
#{$property}: var($variable);
}
}
The problem is that the if condition inside the mixin customize() is always true even if my document has no CSS variable called --my-variable. What am I doing wrong?
Thank you
Sass has a function that check if the variable exists.
variable-exists()
$colorVariable: crimson;
#if variable-exists($colorVariable) {
// Do some styling if the variable exists
}

HIghlighting row during runtime

I am trying to highlight a row based user input. I am using Angular 5, with ag-grid-angular 19.1.2. Setting the style with gridOptions.getRowStyle changes the background, but I would rather use scss classes if possible. The function setHighlight() is called in the html file through (change)=setHighlight()
setHighlight() {
const nextChronoId = this.getNextChronoDateId();
// this.highlightWithStyle(nextChronoId); // Working solution
this.highlightWithClass(nextChronoId);
const row = this.gridApi.getDisplayedRowAtIndex(nextChronoId);
this.gridApi.redrawRows({ rowNodes: [row]})
}
Function definitions:
highlightWithStyle(id: number) {
this.gridApi.gridCore.gridOptions.getRowStyle = function(params) {
if (params.data.Id === id) {
return { background: 'green' }
}
}
}
highlightWithClass(id: number) {
this.gridApi.gridCore.gridOptions.getRowClass = function(params) {
if (params.data.Id === id) {
return 'highlighted'
}
}
}
My scss class:
/deep/ .ag-theme-balham .ag-row .ag-row-no-focus .ag-row-even .ag-row-level0 .ag-row-last, .highlighted{
background-color: green;
}
My issue
Using getRowClass does not apply my highlighted class correctly to the rowNode. After reading (and trying) this, I think that my custom scss class overwritten by the ag-classes. The same problem occurs when using rowClassRules.
Question
How can I make Angular 5 and ag-grid work together in setting my custom scss class correctly?
Stepping with the debugger shows the class is picked up and appended to the native ag-grid classes.
In rowComp.js:
Addition, screen dump from dev tools:
angular's ViewEncapsulationis the culprit here.
First be aware that all shadow piercing selectors like /deep/ or ::ng-deep are or will be deprecated.
this leaves, to my knowledge, two options.
use ViewEncapsulation.None
add your highlighted class to the global stylesheet
setting ViewEncapsulation.None brings its own possible problems:
All components styles would become globally available styles.
I would advise to go with option two.
this answers sums it up pretty well.
Additionally:
.ag-theme-balham .ag-row .ag-row-no-focus .ag-row-even .ag-row-level0 .ag-row-last
this selector will never match anything, you should change it to
.ag-theme-balham .ag-row.ag-row-no-focus.ag-row-even.ag-row-level0.ag-row-last
every class after ag-theme-balham exists on the same element.
with the selector you wrote, you would denote a hierarchy.
Hope this helps

SASS: Conditional values of CSS property based on that if an element with certain value of the same property has been present already in the page

I want to have different values of a css property (I am using SASS), based on that whether a element with a certain property's value '$additionalNavHeight' is present on the page. In some pages there is no such element, in other - there is. I wrote a SASS mixin:
#mixin top-position($navHeight, $additionalNavHeight)
{
#if $additionalNavHeight == true {
.loadingAnimation {
top: $navHeight + $additionalNavHeight;
}
}
#else {
.loadingAnimation {
top: $navHeight;
}
}
}
And I included the mixin in the selector:
#include top-position($navHeight, $additionalNavHeight);
I thought this should change the value of the property 'top' of the element with the class 'loadingAnimation', based on that if in the page already is present the element with the value of its 'top' property '$additionalNavHeight'. The compiler doesn't show any error, but the code doesn't change anything. What am I doing wrong? Any help would be very appreciated.
Тhe simplest solution. You must check with JavaScript if element exists or not
and to apply the second class to element. In the second case (element existing)
you must add adittionnal height. In this case the mixin is redundant.
.loadingAnimation {
top: $navHeight;
}
.loadingAnimation.additinnalHeight {
top: $navHeight + $additionalNavHeight;
}
Here is example jsfiffle:
https://jsfiddle.net/ra9r8rk8/
In this case element will receive class newClass when the first div exists. (the element)
Edit: This is second improved solution. In fact there is no need for regular expression. We can just use classList:
https://jsfiddle.net/ra9r8rk8/1/

Append a variable's value to a selector #if it exists (using variable-exists)

I'm trying to add in a class name to SCSS if it exists.
Using a base framework which outputs 2 CSS files.
theme_1.css
theme_2.css
Each CSS file is compiled from its respective SCSS file - which either contains a variable called $body-container or not.
$body-container: .body-container;
If the variable exists then it should be appended to the body tag.
This is the SCSS that I've tried so far
body #if(variable-exists(body-container)) { $body-container } {
/* styles here */
}
I'm expecting the following:
For the SCSS file that contains the variable
body .body-container {
/* styles here */
}
and without the variable declared
body {
/* styles here */
}
But getting the following error Error: Invalid CSS after "...body-container ": expected ":", was "} {"
As mentioned in my comment, I don't think it is possible to append a variable to a selector in that way (the one used in question). The error message indicates that it expects a : after the variable name which is implying that it is expecting a value assignment to the variable within the #if loop.
Having said that, it is still possible to achieve this using the below workaround. The idea is to see if the variable is defined and if yes, set another dummy variable ($selector) as the concatenation of body and the original variable's ($body-container) value. If not, then just set it as body.
Then we can use this dummy variable ($selector) through interpolation. So, if $body-container has been defined the selector would be body .body-container. Else, it would simply be body.
$body-container: ".body-container";
#if variable-exists(body-container) {
$selector: "body " + $body-container !global;
}
#else {
$selector: "body" !global;
}
#{$selector} {
color: red;
}

Resources