Apologies if this question has been asked or if there's a much better way to achieve my objective - I'm very new on the subject.
Using .scss within my React project I have a variable which is used in a number of visual elements as a highlight, eg.:
$theme = red;
.element{
color: $theme;
}
I'd like the user to be able to customize this to suit their tastes within the app client, however it is compiled down by sass-loader/style-loader to something like:
.element{
color: red;
}
which would require me to manually maintain a list of element classes to fire style edits at after the fact.
I am hoping that someone here knows a practical way to achieve what I'm after or, if that doesn't exist, could assist me with modifying sass-loader to also spit out a list of class names where the variable is used to a file that I can load post-compile.
You can use CSS variable instead.
Declare variables:
:root {
--theme-color: red;
}
... and then use it ...
#div1 {
background-color: var(--theme-color);
}
#div2 {
background-color: var(--theme-color);
}
Note: It does not work on Internet Explorer
https://caniuse.com/#search=css%20variables
Learn more about CSS variables
https://www.w3schools.com/css/css3_variables.asp
Related
In my project, I use CSS Modules with Less, which means I get the best of both worlds.
My src folder looks something like this:
components/
[all components]
theme/
themes/
lightTheme.less
darkTheme.less
palette.less
palette.less:
#import './themes/lightTheme.less';
Then, in every component that wants to use colors from the theme, I do:
component.module.less:
#import '../../theme/palette.less';
.element {
background-color: #primary;
}
This structure lets me edit palette.less to import the theme I want to use. The thing is that I want to let the users choose their preferred theme on their own. Themes should be switchable on runtime, which means I somehow need to have both themes compiled.
I imagine the perfect solution to be something like this:
app.less
body {
#theme: #light-theme;
&.dark-theme {
#theme: #dark-theme;
}
}
And then somehow import this #theme variable in every component and read properties from it (i.e. #theme[primary]).
Unfortunately, Less variables scoping don't work like this.
I am open-minded to any solution that uses Less modules.
Thank you!
I know that you've probably looking for a solution that uses Less / CSS modules, but it's very likely that your situation can be solved solely with the use of css variables (as Morpheus commented on your question).
How it would work?
You'd have to ensure all your styling does not use hardcoded values, i.e. instead of:
.awesome-div {
background-color: #fefefe;
}
You would have:
:root {
--awesome-color: #fefefe;
}
.awesome-div {
background-color: var(--awesome-color);
}
Changing between light and dark
There are two ways of changing themes in this approach:
Use vanilla Js code within React to update the :root CSS element, check this codepen for more information;
Just load a component containing all new :root variables in its component.css file;
In React (in vanilla CSS too) you can easily have multiple components/elements declaring their own :root at their .css files.
Furthermore, any new :root will overwrite conflicting values from previous :root. For example if at file app.css we have :root { --color: red; } and, when loading another component, component A for instance, where in component_a.css we have the same variable overwritten, e.g. :root { --color: blue; } the one rendered in our browsers will be the one from component A.
Following this logic, you can have a dummy component that does and renders exactly nothing, but instead in this component.js file you import the .css of a theme, e.g.:
import './light.css'; // suppose this is the light-theme dummy component
When switching themes in your app you'd just have to remove the dummy component from scene and call the other one.
I'm not too experienced with codepen to the point of providing you an example containing imports/modules over there, but I hope the above explanation can give you an idea of what I mean. Still, here's a brief pseudo-code of what I'm intending to demonstrate:
loadTheme() {
if (this.state.theme === 'dark') return <LightTheme />;
if (this.state.theme === 'user-3232') return <UserTheme />;
return <DarkTheme />;
}
render() {
return (
<App>
{this.loadTheme()}
<OtherContent>
</App>
);
}
Check out Styled components, it can do that.
https://www.npmjs.com/package/styled-components
https://styled-components.com/docs/advanced#theming
I did it myself as a Easter Egg in an app of mine, so I know for sure it works. Unfortunately it is closed so I can't show you the code publicly.
I am trying to make a toggle between night mode and day mode only by changing colors. I have some base color variables inside my _colors.scss, and they are used all over my site. I use React to toggle a className between 'night-mode' and 'day-mode' at the first div of the project.
I have tried to wrap the variables in the mentioned class names, but the result is that no other files can access the variables. Therefore I was hoping for a solution where I can use a night-mode file and a day-time file and toggle between them.
As I see it now, the issue is that I can't wrap the $variables or the #import in a class name, which makes it difficult to know what mode is selected. I am looking for a solution that does not include jQuery (I have a variable globally stored that can be used for javascript reference if that ends up to be the best solution).
You can't toggle scss files at runtime, since they are already compiled to css.
I would go with CSS custom properties (sometimes called CSS variables) instead of pure Sass variables.
Example:
:root {
--background: lightblue;
}
.night-mode {
--background: darkblue;
}
.component {
background-color: var(--background);
}
Toggle the class .night-mode on with javascript depending on the time of day.
You may of course feed your CSS custom properties from Sass variables in your scss files:
$bg-day: lightblue;
$bg-night: darkblue;
:root {
--background: $bg-day;
}
.night-mode {
-- background: $bg-night;
}
.component {
background-color: var(--background);
}
I'm setting up a single instance single database multi-tenant application. The backend is written in Ruby on Rails, while the frontend is a separate app in AngularJS with a Rails framework.
I'm using a resolve on an abstract parent state to determine the subdomain, and subsequently the tenant. Once the tenant is determined, I want to be able to read CSS variable values from a config file on the front-end that can then be used to generate the main styles.css file that contains the classes referenced in the rest of the project.
I've heard that CSS pre-processors like Sass and Less can be used to accomplish this, but I have no experience with either and I'm stuck trying to figure out exactly how to set this up.
Some help / code examples would be appreciated - thanks!
Sass or Less won't really do what you want because they are compiled in advance of the browser loading them. In other words, the browser only loads the compiled css file.
There are however a few methods of achieving your goal. I'm not familiar with Ruby, so I'll try to keep my server language suggestions generic. These are obviously not meant as full solutions because I don't know your full situation. Instead these are just some ideas to give you some leads.
Probably the best method would be to use server logic to apply a different class to the body tag, then use that class to determine what styles are applied to the page. So for example:
/* probably a good idea to have fallback styles */
body {
color: black;
background: white;
}
body.style-one p {
color: red;
background: blue;
}
body.style-two p {
color: blue;
background: red;
}
<body class="style-one">
<p>This text will be red.</p>
You could also, of course, change the class of the body tag using javascript, and therefore the user could change the theme of the page.
Alternatively, you could use similar server logic to write out a secondary <link rel="stylesheet"...> tag to pull in one or another stylesheet. The real advantage here is that if you a large number of rules for the various themes, you can keep them nicely separate in their own files.
One last method I've used (with php) is to create the stylesheet on the fly based on GET variables, but print out the stylesheet as a css file. The downside of this method is that I think you lose some browser caching advantage. In any case, that might look something like this:
<?php
header("Content-Type: text/css");
if( $_GET['theme'] == 'one' ) {
echo 'p { color: red; }';
} else {
echo 'p { color: blue; }';
}
?>
a {
color: green;
}
<link rel="stylesheet" href="style.css.php?theme=one">
I have three big CSS files which have many classes. Same of those classes have the same name but are in different files.
Example:
CSS1:
...
.btn-primary {
background: #000;
}
...
CSS2:
...
.btn-primary {
background: #fff;
}
...
and CSS3:
...
.btn-primary {
background: #4285F4;
}
...
Let's assume that all three CSS are called in my HTML page.
Is there a way to select in my web page only the .btn-primary class from CSS3? If yes, how could I do it?
No.
If a stylesheet is loaded into a page, and it has a ruleset with selector that matches an element, then it will apply to that element.
Rules which provide conflicting information for a particular property will overwrite each other in the standard cascade order.
Not as is, but you could alter your style sheets so that it reads like this:
.btn-primary, .btn-primary.style1 { ... }
.btn-primary, .btn-primary.style2 { ... }
.btn-primary, .btn-primary.style3 { ... }
Then you could get the specific styles by using the following class:
<a class='btn-primary style2'>Stylesheet 2</a>
In short, you'll need to add some sort of additional method of narrowing down the different styles.
--
Another possibility would be to convert your css files to scss like so:
.style1 {
.btn-primary { ... }
}
You could then use the styling from specific sheets like so:
<div class='style1'>
<a class='btn-primary'>Stylesheet 1</a>
</div>
An apologetic into: the following is, in my opinion, a wrong solution. I wanted to add it as I can think of situations where you have to find this kind of hacky ways rather than change the css files.
Generally speaking, as Quentin and Bryant pointed out - there is no "namespacing" for css files and so if you load all the css files you will end up with the last overriding file's selector classes (among the name-conflicted ones) and won't be able to choose between them.
If (for some odd reason) you don't care about Chrome users - you can probably use the cssRules or rules properties of the document.styleSheets[i] object - for each loaded stylesheet file (i being the number of the file). As noted, this method does not work for Chrome. Fore some reason both cssRules and rules are null in Chrome for each of the styleSheets[i].
My hacky solution:
After loading all the css files as you need,
In javascript code, read the css file you choose as a text file. You can use AJAX for that - see this question and its answers
Search for the selector you want in the text you got and extract that string. You can parse the whole file for example and take the relevant part.
In searching how to help with this step I came across the document.styleSheets[i].cssRules object and the method that doesn't work in Chrome.
Build a style element around it and append that style element to the head element (here's an answer that shows how to create and append style elements to the head element).
This seems like a wrong way to do it from several reasons (performance, elegance, readability) - and probably means the design of the css files is not right for your project (look at Bryant's suggestions) - but I wanted this answer to be here, as there is a way to do it, albeit a hacky one, and if for some reason you can't change the css files and have to use them as is - then here you go.
I don't know what is the usage of this, I mean having three files and storing different styles and even same styles into them.
But there are some tools that will normalize and minify your CSS, for example, take a look at Nano CSS
But, as other answers says it is not possible to say what class from what file apply to this page, and they will overwrite and the last style will apply for the element.
Here is also an example to find out how overwrite works:
#test-link {
display: block;
text-decoration: none;
background: red;
color: white;
}
#test-link {
background: green;
}
#test-link {
background: orange;
}
#test-link {
background: black;
}
<a id="test-link" href="javascript:void(0);">Test link</a>
As you see, just the last style applied for the background color
We are using a framework that allow us to modify the color scheme use throughout the application. I cannot play a lot with the color and would like to reuse them in some classes. So let say that the framework define this class
.StyleFromFramework {
color:#515151;
background-color: #FFFFFF;
}
is located in a css file that I can't modify cause this file is handled by the framework (if I modified this file, all my modification will be lost when the new version of the framework is installed)
I would like to reuse the color of this classes in another class in a file containing all my updates.
.NewStyle {
color: **.StyleFromFramework:color**
Font: Verdan 11 px;
}
Is there a way to do that ?
I would try the following.
.StyleFromFramework, .NewStyle {
color:#515151;
}
.StyleFromFramework {
background-color: #FFFFFF;
}
.NewStyle {
background-color: none; /* or some other value... */
}
The first rule shares the color, and the the other two rules specify properties that are specific to the two other classes.
You should take a look at less.css which does exactly what you're looking for.
perhaps I didn't understand you correctly, but CSS is not dynamic language in which you can reuse rules and components.
I would recommend to use SASS/SCSS framework or something similar (LESS, Stylus... etc.)
In those frameworks, This is one of the most useful features, lets you share a set of CSS properties from one selector to another
read more here: http://sass-lang.com
Using a CSS preprocessor like Sass, Less or Stylus allows the use of variables which then can be reused in your project.
Foundation for instance can be completely restyled with Sass.