Change all variable value based on body class - css

I am working on theme based localisation. For that I am getting class on body tag for each localisation.
I need to change all variables value based on that class
For more Understanding
$a: #000;
$b= Arial;
if body has class Australia then
$a: #ff0000;
$b: 'Roboto';
Please no js code only by scss

Using #import and !default variables
// ––––––––––––––––––––––––––––––––––––––
// _style.scss
// underscore added to prevent compilation
// ––––––––––––––––––––––––––––––––––––––
$color : red !default;
$font-family: Arial !default;
.foo { color: $color; }
.bar { font-family: $font-family; }
// ––––––––––––––––––––––––––––––––––––––
// style.scss (compile file)
// ––––––––––––––––––––––––––––––––––––––
// redefine variables
$color: blue;
$font-family: Roboto;
// add wrapper if needed (will be added to all selectors)
.australia {
#import '_style.scss';
}

The following example uses a map to define different theme values. The mixin will wrap each selector in a class (the map key) and create global variables to be used inside each selector.
$theme-map:(
'.australia': (color: blue, font-family: Roboto),
'.denmark' : (color: red, font-family: Arial)
);
#mixin theme {
#each $class, $map in $theme-map {
#{$class} & {
$color: map-get($map, color) !global;
$font-family: map-get($map, font-family) !global;
#content;
}
}
}
.foo {
#include theme {
color: $color;
font-family: $font-family;
}
}
.bar{
#include theme {
background-color: $color;
}
}
Output:
.australia .foo {
color: blue;
font-family: Roboto;
}
.denmark .foo {
color: red;
font-family: Arial;
}
.australia .bar {
background-color: blue;
}
.denmark .bar {
background-color: red;
}
PS. in the near future CSS variables will ease this type of work using variable inheritance.
.australia {
--color: red;
--font-family : Arial;
}
.denmark {
--color: blue;
--font-family : Roboto;
}
.foo {
color: var(--color);
font-family: var(--font-family);
}
.bar {
backgound-color: var(--color);
}

Related

Sass #mixin - prevent selector repetition and combine all styles under single selector

I have written this #mixin to set styles for light and dark theme in one line.
#mixin setThemeDynamicCSSRule($property, $light-theme-value, $dark-theme-value) {
#{$property}: #{$light-theme-value};
.dark-mode & {
#{$property}: #{$dark-theme-value}
}
}
body {
#include setThemeDynamicCSSRule(color, black, white);
#include setThemeDynamicCSSRule(background-color, white, black);
#include setThemeDynamicCSSRule(font-size, 16px, 32px);
}
This returns me:
body {
color: black;
background-color: white;
font-size: 16px;
}
.dark-mode body {
color: white;
}
.dark-mode body {
background-color: black;
}
.dark-mode body {
font-size: 32px;
}
it keeps repeating .dark-mode body selector for each individual setThemeDynamicCSSRule() call.
It still does the job but ideally I would like css to compile to:
body {
color: black;
background-color: white;
font-size: 16px;
}
.dark-mode body {
color: white;
background-color: black;
font-size: 32px;
}
Not exactly the way your are looking for ... but thinking forward it is the wanted result. And mayby an easier and more neat way to organize your special theme properties in one place.
Wrap your different theme property/values at to a nested map. Than use an adapted mixin.
$themes: (
color: (
'light': 'black',
'dark': 'white',
),
background-color: (
'light': 'white',
'dark': 'black',
),
font-size: (
'light': 16px,
'dark': 32px,
),
);
#mixin setThemeStyles($themes){
#each $property, $values in $themes {
#{$property}: map-get($values, 'light' );
}
.dark-mode & {
#each $property, $values in $themes{
#{$property}: map-get($values, 'dark');
}
}
}
body {
#include setThemeStyles($themes);
}
//######>> RESULT IS YOUR WANTED CSS
body {
color: "black";
background-color: "white";
font-size: 16px;
}
.dark-mode body {
color: "white";
background-color: "black";
font-size: 32px;
}

How to import a scss file inside a scss class

I want to add a different theme when i add "dark-theme" class to body. My implementation looks like this:
#import '../../../../node_modules/angular-grids/styles/material.scss';
.app-dark {
#import '../../../../node_modules/angular-grids/styles/material-dark.scss';
}
Without any luck. Any clue on how to do this?
There are two methods in order to do that. Both of them include mixins.
meta.load-css
The sass:meta feature gives the ability to do what you want.
Say you have this scss file with a theme:
//theme/_code.scss
$border-contrast: false !default;
code {
background-color: #6b717f;
color: #d2e1dd;
#if $border-contrast {
border-color: #dadbdf;
}
}
you can include that code inside another scss file like so:
// other-theme.scss
#use "sass:meta";
body.dark {
#include meta.load-css("theme/code",
$with: ("border-contrast": true));
}
This will result in the following css:
body.dark code {
background-color: #6b717f;
color: #d2e1dd;
border-color: #dadbdf;
}
You can read more about this feature here
old fashioned mixin
But you can do basically the same thing if you use mixin and include.
So, let's say you have this class you want to import into another class:
.title {
font-size: 2em;
font-weight: bold;
}
And another sass file with another theme:
.dark-theme {
.title {
font-size: 2em;
font-weight: bold;
color: white;
}
}
You can use a scss mixin and import it into both files:
mixin.scss
#mixin shared-items() {
.title {
font-size: 2em;
font-weight: bold;
}
}
then, in the theme files:
white-theme.scss
#import './mixin.scss';
/* will be included as is without a parent class */
#include shared-items;
dark-theme.scss
#import './mixin.scss';
/* will be included inside the dark-theme class */
.dark-theme {
.title {
color: white;
}
#include shared-items;
}
this will generate this css:
.title {
font-size: 2em;
font-weight: bold;
}
.dark-theme {
.title { color: white; }
.title {
font-size: 2em;
font-weight: bold;
}
}
Notice that you can also pass parameters to mixin and use them as functions.
So you can easily pass colors and use them with your theme variables.
for example:
# an example of giving a color to a placeholder mixin:
#mixin nk-placeholder($color: #C4C4CC) {
&::-webkit-input-placeholder {
color: $color;
font: inherit;
}
&::-moz-placeholder {
color: $color;
font: inherit;
}
&:-ms-input-placeholder {
color: $color;
font: inherit;
}
&:-moz-placeholder {
color: $color;
font: inherit;
}
&::placeholder {
color: $color;
font: inherit;
}
}
# same thing as above
#mixin shared-items($text-color: black) {
.title {
font-size: 2em;
font-weight: bold;
color: $text-color;
}
}
.white-theme {
#include shared-items;
}
.dark-theme {
#include shared-items(white);
}

How can I pass a tag in as a scss mixin argument?

I am creating a mixin to target a child element.
Example.
Targeting all <a> tags of the parent that has a parent of section---blue
I figure that I can pass the tag as an argument as follows
But I am not getting the desired result
SCSS
#mixin themeParent ($child) {
&--blue $child {
color: getColour("theme", "bluehighlight");
}
&--green $child {
color: getColour("theme", "greenhighlight");
}
&--purple $child {
color: getColour("theme", "purplehighlight");
}
}
.section {
#include themeParent(a);
}
I would have thought that this would compile to
.section--blue a {
color: blue;
}
Can someone please explain to me why?
#mixin themeParent ($child) {
&--blue #{$child} {
color: blue;
}
}
outputs: .section--blue a { color: blue; }
If you want more specificity, just add another &:
#mixin themeParent ($child) {
&#{&}--blue #{$child} {
color: blue;
}
}
outputs: .section.section--blue a { color: blue; }
If you want more scability, just iterate over colors you want:
#mixin themeParent ($child) {
$colors: red, blue, green;
#each $color in $colors {
&#{&}--#{$color} #{$child} {
color: $color;
}
}
}
Put $child in #{$child}.
#mixin themeParent ($child) {
#{$child} {
color: #000;
}
}
.section {
#include themeParent(a)
}
Output:
.section a {
color: #000;
}
If I put this in a simple way, there is no need to pass the tag as a parameter to the mixin function instead, u should pass the color of the element.
<div className="section--blue">
<a>section blue</a>
</div>
<div className="section-green">
<a>section green</a>
</div>
mixin and css
#mixin themeParent ($color) {
color:$color;
}
.section{
&--blue {
a{
#include themeParent(blue);
}
}
--green{
a{
#include themeParent(green);
}
}
}
Hope this is useful.

Copy styles to other class in SCSS without #extend?

I'm trying to create a helper mixin in my SCSS file for easily styling form input placeholder texts. For a while, I only needed to change the text's color, so I had this mixin:
#mixin input-placeholder($color, $opacity, $focusColor: null, $focusOpacity: null) {
&:-moz-placeholder {
color: $color;
opacity: $opacity;
}
&::-moz-placeholder {
color: $color;
opacity: $opacity;
}
&:-ms-input-placeholder {
color: $color;
opacity: $opacity;
}
&::-webkit-input-placeholder {
color: $color;
opacity: $opacity;
}
&:placeholder {
color: $color;
opacity: $opacity;
}
&:invalid {
color: $color;
}
&:focus {
#if($focusColor==null) {
$focusColor: transparent;
}
#if($focusOpacity==null) {
$focusOpacity: 0;
}
&::-webkit-input-placeholder {
color: $focusColor !important;
opacity: $focusOpacity !important;
}
&:-moz-placeholder {
color: $focusColor !important;
opacity: $focusOpacity !important;
}
&::-moz-placeholder {
color: $focusColor !important;
opacity: $focusOpacity !important;
}
&:-ms-input-placeholder {
color: $focusColor !important;
opacity: $focusOpacity !important;
}
&::-webkit-input-placeholder {
color: $focusColor !important;
opacity: $focusOpacity !important;
}
&:placeholder {
color: $focusColor !important;
opacity: $focusOpacity !important;
}
}
}
This purposely adds each selector separately and not in a comma separated list due to the fact that some browsers will ignore the entire entry if one is invalid.
I wanted to use #extend so that I could create a mixin like this:
#mixin style-input-placeholder($module) {
&:-moz-placeholder {
#extend #{$module};
}
&::-moz-placeholder {
#extend #{$module};
}
&:-ms-input-placeholder {
#extend #{$module};
}
&::-webkit-input-placeholder {
#extend #{$module};
}
&:placeholder {
#extend #{$module};
}
&:invalid {
#extend #{$module};
}
}
Where $module is the selector I pass to the mixin to extend the styles of, and I'd be able to use it like this:
.some-special-placeholder-styles {
color: purple;
opacity: 0;
text-transform: uppercase;
font-family: 'Open Sans', Arial, sans-serif;
}
input {
#include style-input-placeholder('.some-special-placeholder-styles');
}
It would allow me to modify more than just the color and opacity without having to annoyingly specify each attribute as a mixin parameter. But because of the nature of #extend, it combines all of those selectors into one comma separated list. So is there something else I can do or any workarounds that you've come across?
You can use #content directive to pass arbitrary content inside mixins (was added into sass 3.2). So your code may look like:
#mixin style-input-placeholder() {
&:-moz-placeholder {
#content;
}
&::-moz-placeholder {
#content;
}
&:-ms-input-placeholder {
#content;
}
&::-webkit-input-placeholder {
#content;
}
&:placeholder {
#content;
}
&:invalid {
#content;
}
}
input {
#include style-input-placeholder() {
color: purple;
opacity: 0;
text-transform: uppercase;
font-family: 'Open Sans', Arial, sans-serif;
}
}
Also you can try to wire your sass compilation with PostCSS and use excellent Autoprefixer plugin that will free you from defining all these vendor-specific prefixes.

Mixin for Group Pseudo Classes with SASS

Ideally I want to create a mixin to style all the placeholder pseudo classes. I'm not sure if this is even possible. Here's what I have:
#mixin placeholder($color) {
::-webkit-input-placeholder{
color: $color;
}
:-moz-placeholder {
color: $color;
}
::-moz-placeholder {
color: $color;
}
:-ms-input-placeholder {
color: $color;
}
}
Which ideally would be used like this:
input {
&#placeholder(red);
}
And would result in this CSS:
input::-webkit-input-placeholder{
color: red;
}
input:-moz-placeholder {
color: red;
}

Resources