changing a variable in SCSS not working in angular - css

// this variable is default or dark
$mode: default;
.dark-mode {
$mode: dark !important;
}
.light-mode {
$mode: default !important;
}
when I change the $mode to default or dark, it's working but when I use class .dark-mode or .light-mode not work
my code is below not working but when I change the $mode in Scss manual working
where is my problem ?
<div class="dark-mode">
<router-outlet></router-outlet>
</div>

Related

map.get doesn't work in include mixin scss - Angular project

Github project
Hello every one ! I'm on an angular project and i'm stuck with my scss.
I have a mixin (in its own file mixins.scss :
BUTTON MIXINS
===================== */
#mixin btn($color:false,$bgColor:false,$size:false,$hoverBgColor:false){
button {
#if $color {
color: $color;
}
#if $bgColor {
background-color: $bgColor;
}
#if $size {
font-size: $size;
}
#if $hoverBgColor {
&:hover {
background-color: $hoverBgColor;
}
}
}
}
Also i have a global scss file with my variables :
$colors: (
primary-black: #000000,
primary-white: #FFFFFF,
medium-grey: #7A746E,
light-cream: #FFF7F0,
);
/* =====================
BUTTON VARIABLE
===================== */
$btnColor:(
btnHeaderFooterColor: map-get($colors, "primary-black"),
btnBody: map-get($colors, "light-red"),
);
When i want use my mixin for my button-component nothing happen, this is an example of my code.
button-component.scss :
#use "sass:map";
#import './../../../../styles/base/mixins';
#import './../../../../styles/base/global';
button {
.btn {
padding: 0.5rem 1.7rem;
border-radius: 1.8rem;
border-color: transparent;
&__headerFooter {
#include btn(map.get($btnColor, btnHeaderFooterColor));
}
}
}
I already tried #usebut i have the same result, my code doesn't appears in the browser inspector, i applied the class in my HTML, but if you want check the project the link is available just on top of this post.
I really appreciate your help because for me it's a mystery this situation !
Thanks you for reading me. :)

Change body background with data-theme attribute on click with React

I'm trying to change the theme in an app using the data attribute and then changing the CSS variables according to the different data-theme values.
In the App component, I check if the user has a default theme set, and use that to set new theme on click
import "./styles.css";
import useLocalStorage from "use-local-storage";
export default function App() {
// Check user set theme mode...
const defaultDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
// Create theme mode state...
const [theme, setTheme] = useLocalStorage(
"theme",
defaultDark ? "dark" : "light"
);
// Handle on click from the theme switcher...
const clickHandler = () => {
const newTheme = theme === "light" ? "dark" : "light";
setTheme(newTheme);
};
return (
<div className="App" data-theme={theme}>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={() => clickHandler()}>Dark Mode</button>
</div>
);
}
In the styles.css I set the different variables to define the theme
/* Set the dark mode variables... */
[data-theme="dark"] {
--background: black;
--title-text: white;
--desc-text: grey;
}
/* Set the light mode variables... */
[data-theme="light"] {
--background: white;
--title-text: black;
--desc-text: grey;
}
/* Page Styles... */
body {
padding: 0;
margin: 0;
background: var(--background);
}
/*The rest of the CSS...*/
The rest of the elements work fine as they are wrapped in an element that has the data-theme attribute. However, the body is not wrapped with the data-theme attribute, so there is no change in the body background. In this example, I used .App but I would like to change the body instead. Is there a way to wrap the body in the data-theme attribute in React?
Here is the link to the full code in CodeSandbox
Full code on CodeSandbox
How about wrap App with div.body them pass data-theme into .body instead and make div.body cover body
<div className='body' data-theme={theme}>
<div className='App'></div>
</div>

Is there an `and` operator (&&) in Scss?

I have this HTML element:
<button class="Button Button--is-primary Button--is-disabled Button--is-dark-theme">
And I need to defined in Scss a set of deep selectors like this:
.Button {
// Apply this for all Buttons that are dark theme
&--is-dark-theme {
// Apply this for all Buttons that are Dark AND are Primary
&--is-primary {
//...
}
}
}
But, my problem is that rule is going to create this:
.Button--is-dark-theme--is-primary
When I actually need:
.Button--is-dark-theme.Button--is-primary
I just found this:
.Button {
$self: &;
// Apply this for all Buttons that are dark theme
&--is-dark-theme {
// Apply this for all Buttons that are Dark AND are Primary
&#{$self}--is-primary {
color: red;
}
}
}
Which generates:
.Button--is-dark-theme.Button--is-primary {
color: red;
}
Any better option?

How to define a sass map for specific CSS selector

I am trying to customize scss in my project so that I can use css variables according to css selector applied on outermost element.
The basic Idea I have is to define color variables and then use those color variables to define semantic color variables in two different css selectors.
$primary: orange;
$primary-dark: redorange;
$warn: red;
$accent: grey;
$dark-grey: #757678;
$light-grey: #f7f7f7;
$error-text: $warn;
.light {
$background: $light-grey;
$button-bg: $primary;
}
.dark {
$background: $dark-grey;
$button-bg: $primary-dark;
}
This is one solution I tried, but in scss we cannot change scope of variables according to selectors.
So I tried using functions.
$white: #fff;
$light-grey: #eaeaea
$primry-dark: redorange;
$primary: orange;
$black: #000;
$semantic-colors: (
background: (
screen: $white,
tile: $light-grey,
),
buttons: (
primary: $primary
link: $white
icons: $primary-dark;
)
);
#function semantic-color($semantic-color:'background', $tone: "base") {
// #return red;
#return map-get(map-get($semantic-colors, $semantic-color), $tone);
}
.side-nav-link {
background-color: semantic-color(background, tile);
}
The above code works fine. but I want to have a color map based on a theme. for eg:
dark has its own semantic color map and light has its own and I can access based on scope.
.light {
$semantic-colors: (
background: (
base: $white,
tile: $light-grey,
),
buttons: (
primary: $primary,
link: $white,
icons: $primary-dark;
)
);
}
.dark {
$semantic-colors: (
background: (
base: $black,
tile: $dark-grey,
),
buttons: (
primary: $primary-dark,
link: $black,
icons: $primary;
)
);
}
I can create two different maps within semantic-color map:
$semantic-colors: (
light:(
background: (
base: $white,
tile: $light-grey,
),
buttons: (
primary: $primary
link: $white
icons: $primary-dark;
)
),
dark:(
background: (
base: $black,
tile: $dark-grey,
),
buttons: (
primary: $primary-dark,
link: $black,
icons: $primary;
)
)
);
and then modify my function to get color within a specific map based on $theme variable.
For eg:
$theme: dark;
#function semantic-color($semantic-color:'background', $tone: "base") {
// #return red;
#return map-get(map-get(map-get($semantic-colors, $theme), $semantic-color), $tone);
}
but I don't know a way to define $theme according to .light and .dark selectors.
If I try doing something like this:
.light {
$theme: light;
}
.dark {
$theme: dark;
}
and then use the $theme variable in the semantic-color function then I get the error $theme is not defined.
so my question is
"Is there a way I can define $theme or semantic-color function or $sematic-color map according to a CSS selector (.light or .dark in my case)?"
I have read sass documentation but could not find any solution to suit my situation.
Articles I referred to:
Theming in SASS
Creating a Color Language in Web Interfaces (with Sass Maps)
educba SASS Map
I am not quits sure if I did it completly right ... but as I see your idea and code in general works well.
The only thing seems to be: there had been some errors in your code seeting up $semantic-colors !?
This (correctedt version = only corrections in $semantic-colors) works here:
//########### SASS: demo file
//### VARS
$primary: orange;
$primary-dark: redorange;
$warn: red;
$accent: grey;
$dark-grey: #757678;
$light-grey: #f7f7f7;
$white: #ffffff;
$black: #000000;
$error-text: $warn;
$semantic-colors: (
light: (
background: (
base: $white,
tile: $light-grey,
),
buttons: (
primary: $primary,
link: $white,
icons: $primary-dark,
),
),
dark: (
background: (
base: $black,
tile: $dark-grey,
),
buttons: (
primary: $primary-dark,
link: $black,
icons: $primary,
),
),
);
//### METHODS
$theme: dark;
#function semantic-color($semantic-color: "background", $tone: "base") {
// #return red;
#return map-get(
map-get(map-get($semantic-colors, $theme), $semantic-color),
$tone
);
}
//### STYLES
.light {
$theme: light;
background: semantic-color('background', 'base');
}
//###########################
//###### CSS: compiled file
.light {
background: #ffffff; // if $theme changes to dark this becomes #000000
}
Because of your comment I believe to understand your question better now. So, according to your last comment I add an additional answer as it is more an explanation about the general howto than a concrete answer to your code.
First: I believe your code (SASS-map/-function) works the right way
To me it seems more a question about understanding how the theme technique works.
So let's start from the base:
1. What you need to do for theming in html:
// set a theme anchor with classes
// --> class to body
<body class="theme_light">
... code ...
... all elements within body will be styled by theme-light-classes
// or ALTERNATIVE do it with a marker where your app starts in html
// --> class to app-root-element
<div class="app_root theme_light">
... code ...
... all elements within app-div will by styled by theme-light-classes
</div>
</body>
2. Based on HTML what you nee in CSS:
Write the styling for your elements for both(!) themes based on the used marker technique (body or app) ...
// write styling classes for both themes (dark + light)
// as child selector based on the html theme-anchor-classes
/* stylings light theme */
.theme_light .content {
background: #theme-light-background-color;
color: #theme-light-font-color;
}
.theme_light .button {
background: #theme-light-button-background-color;
color: #theme-light-button-font-color;
}
/* stylings dark theme */
.theme_dark .content {
background: #theme-dark-background-color;
color: #theme-dark-font-color;
}
.theme_dark .button {
background: #theme-dark-button-background-color;
color: #theme-dark-button-font-color;
}
// if you anchor with app class your css-selectors would have to be
/* light theme */
.app_root.theme_light .content { ... }
.app_root.theme_light .content { ... }
/* dark theme */
.app_root.theme_dark .content { ... }
.app_root.theme_dark .content { ... }
3. Use your SASS-function/-map to achieve this in SASS
In this step we use your (still working) function and map from your question. Writing the CSS in SASS is as easy with nesting the element classes ...
// write themes dark & white nested to the anchor classes
// use function & map from question
.theme_light {
// set sass theme varible
// to get from function values for theme light
$theme: light;
// write stylings
// function will automatic return values for light theme
body {
background: semantic-color('background', 'base');
color: semantic-color('text-color', 'base');
}
button {
background: semantic-color('buttons', 'primary');
color: semantic-color('buttons-text', 'primary');
}
}
.theme_dark {
// set sass theme varible
// to get from function values for theme dark
$theme: dark;
// write stylings
// function will automatic NOW return values for light theme
body {
background: semantic-color('background', 'base');
color: semantic-color('text-color', 'base');
}
button {
background: semantic-color('buttons', 'primary');
color: semantic-color('buttons-text', 'primary');
}
}
//###
//### --> that will compile the needed css!!!
//###
//### NOTE:
//--> if you use app-anchor-class
//--> your nesting would be as follow
.app_root.theme_light { ... same code as above ... }
.app_root.theme_dark { ... same code as above ... }
HINTS:
As you see your function is a powerful tool: as shown in the example it leads to write identical code twice. If you write a SASS mixin (use directive #content to pass individual theme styles to it) you can reduce it so you are able to write all themes at once.
As you see the SASS variable $theme is used IN SASS as switch which changes your function semantic-color() to get the right color (light or dark).
There are many approches to realize theme stylings in SASS. This is one of the traditional methods and having a good organized map a very intuitive one.

Angular Material Snackbar Change Color

I'm using Angular 7 with Material Snackbar. I want to changes the color of Snackbar to green.
In app.component.ts, I have:
this.snackBarRef = this.snackBar.open(result.localized_message, 'X', {
duration: 4000,
verticalPosition: 'top',
panelClass: 'notif-success'
});
this.snackBarRef.onAction().subscribe(() => {
this.snackBarRef.dismiss();
});
In app.component.scss, I have:
.notif-success {
color: #155724 !important; // green
background-color: #d4edda !important;
border-color: #c3e6cb !important;
.mat-simple-snackbar-action {
color: #155724 !important;
}
}
But the Snackbar is still shown in its default colors.
I can see that the notif-success class has been applied to the snackbar
<snack-bar-container class="mat-snack-bar-container ng-tns-c18-84 ng-trigger ng-trigger-state notif-success mat-snack-bar-center mat-snack-bar-top ng-star-inserted" role="status" style="transform: scale(1); opacity: 1;">
Why is the custom css not working?
You should write that .notif-success CSS class on your main styles.scss, instead of the app.component.scss.
If you are wondering, it is the one which is on the same directory level as your index.html, package.json, etc.
MatSnackBar colors can be customized by adding this CSS rule to the styles.css file. Tested for Angular Material 15.
.mat-mdc-snack-bar-container {
--mat-mdc-snack-bar-button-color: red;
--mdc-snackbar-container-color: black;
--mdc-snackbar-supporting-text-color: yellow;
}
In Angular 15, the answer by Egemen Çiftci is the only one that works for me. I extended it to support different background colors for success and error notifications:
this.snackBar.open('Success', 'Close', {
panelClass: 'app-notification-success',
};
this.snackBar.open('Error', 'Close', {
panelClass: 'app-notification-error',
};
In the global styles.scss:
.mat-mdc-snack-bar-container {
--mat-mdc-snack-bar-button-color: #ffffff;
--mdc-snackbar-supporting-text-color: #ffffff;
&.app-notification-error {
--mdc-snackbar-container-color: #f23a2f;
}
&.app-notification-success {
--mdc-snackbar-container-color: #43a446;
}
}
"panelClass" styles is not being applied to Snack Bar in v15, It's because in v15 the background color is on a different element.
In .css file
.style-error {
color: white;
--mdc-snackbar-container-color: #FF005D !important;
}
In .ts file
openSnackBar(message: string, type:string) {
this._snackBar.open(message,'Ok', {
duration: 2000,
panelClass: ["style-error"]
});
}
Above code will work for Angular v15.
::ng-deep is deprecated as stated by #Akber Iqbal. Put the following code in the global css or scss
snack-bar-container.mat-snack-bar-container {
color: #155724 !important;
background-color: #d4edda !important;
border-color: #c3e6cb !important;
}
div.mat-simple-snackbar-action {
color: red !important;
}
This styling code worked on #angular/material#11.2.2 with #angular/core#11.2.3
Note: It doesn't work in the component css or scss
This is what you're looking for:
::ng-deep .mat-snack-bar-container{
color: #155724 !important;
background-color: #d4edda !important;
border-color: #c3e6cb !important;
}
::ng-deep .mat-simple-snackbar-action {
color: red;
}
complete working demo here
Instead of:
panelClass: 'notif-success'
Try:
extraClasses: ['notif-success']
I had the same issue and stumbled across this Stackblitz that had a working example.
Just realized extraClasses is deprecated, the accepted answer is probably better here.

Resources