I am implementing a dark mode on my site, and trying to do it in the cleanest way possible (no boiler plate code).
So I want to make .darkmode class in CSS, define styles with it, and when the user enables darkmode, javascript simply adds the darkmode class to the <body>.
How could I do something like this with CSS?
.darkmode {
.content{
background-color: black;
}
input{
background-color: black;
}
}
So my questions is, how can I make CSS change different elements on the page when adding this class to the <body>?
The code that you posted would be valid SCSS/LESS. But in plain css you can simply do that by using
.darkmode .content { /* CSS */ }
.darkmode input { /* CSS */ }
So yes, you always have to specify the .darkmode in front of every selector.
Let's suppose you have a selector, like
.mydiv .myanchor
You can override/add attributes using
body.darkmode .mydiv .myanchor
is much more specific and therefore the rules will override the default rules.
To achieve that in normal CSS you would have to use the CSS child selector;
body.darkmode .content {
/* Put styles here */
}
body.darkmode input {
/* Put styles here */
}
Basically the logic there says: "get the body element with the class darkmode and find it's child .content/input"
With CSS selectors, having two element selectors seporated by a space finds all of the second elements inside the first elements; div p would find all of the <p> tags inside all <div> tags.
Related
Let's say I have following situation which I have to switch the style for several elements and switch them back when a specific condition is met.
let div = document.querySelectorAll('div')
document.querySelector('button').addEventListener('click', function() {
div[0].classList.toggle("div1")
div[1].classList.toggle("div2")
div[2].classList.toggle("div3")
div[0].classList.toggle("new1")
div[1].classList.toggle("new2")
div[2].classList.toggle("new3")
})
.div1 {
color: red;
}
.div2 {
color: green;
}
.div3 {
color: grey;
}
.new1 {
color: yellow;
background: grey
}
.new2 {
color: pink;
background: green
}
.new3 {
color: orange;
background: red
}
<div class='div1'>1</div>
<div class='div2'>2</div>
<div class='div3'>3</div>
<button>Click</button>
I am now creating several class and use classList.toggle() to switch between them, it absolutely work but the code looks so massy and I want to make my code more readably, what will a better solution for this kinds of situation.
I have thought of switching between with/without a specific css stylesheet, but I don't think it will work for my situation and I need to consider overwriting problem? (Correct me if I am wrong).
Could anyone suggest me an alternative and better solution of solving this situation like this where you have to assign lots of styles to multiple elements or is there an easy way?
*I know this is a stupid example and in this example, a possible solution is to use a forEach loop and use template literal for the className, but this is just a minimal example I created because of Stack overflow rule, so please don't blame me on this rough example. My actual code contains more different html tags and css styles I have to deal with. By storing them in a variable and keeping switching class between them is too messy and annoying.
My code looks something like this:
So here's what I recommend: You can use conditional styling to change everything in one place. Example:
.a {
/* one set of styles */
}
.b .a {
/* set a different set of styles */
}
This way, you can conditionally set class b on a higher level element (like document.body) and change all your styles automatically.
You can change the classes of the elements in a loop (assuming you have your css pre-formated). For example;
/**
* When the BUTTON with the id named 'clickMe' is click
* Select all the DIV elements
* Foreach DIV selected, if the DIV contains the 'old-class-name'; remove it.
* Add the new class name to the class-list of the selected DIV
*/
document.body.querySelector('#clickMe').addEventListener('click',()=>{
document.body.querySelectorAll('DIV').forEach((D,I)=>{
if(D.classList.contains('old-class-name')) D.classList.remove('old-class-name');
D.classList.add(`new-class-name-${I}`);
});
});
// List of CSS class names.
.new-class-name-0{
color: orange;
}
.new-class-name-1{
color: green;
}
.new-class-name-2{
color: blue;
}
<div class="old-class-name">Div 1</div>
<div class="old-class-name">Div 2</div>
<div class="old-class-name">Div 3</div>
<button id="clickMe">Click</button>
Is it possible to add a classname to a CSS variable or is there some other way to set it up so that I don't have to manipulate each individual variable directly via javascript? I'd like to keep all my styles in CSS and simply turn on relevant classes with JS. For example, If something like this was possible in CSS:
:root.white{ --bgcol:#FFF; --col:#000; }
:root.black{ --bgcol:#000; --col:#FFF; }
Then I could then just toggle the .black or .white class from javascript to trigger all vars to change. What's the best approach for this type of setup?
That's frankly the best (as in most idiomatic) approach — the use of class names, if not altogether separate stylesheets (as has been tradition for many, many years), to theme entire layouts via custom properties. It's the most "fundamentally CSS" approach with JavaScript merely being the glue that makes the theme switching work. You really can't do much better than that.
For those unaware what :root means and wondering where exactly the class names are being applied, it's the html element (the parent of body). So there is nothing special going on here — you're simply switching class names on the html element. It just happens that global custom properties are conventionally defined for the document root element since it's at the top level of the inheritance chain.
If you have any theme-agnostic custom properties, as well as style properties (i.e. not custom properties) that apply to the root element, keep them in their own unqualified :root rule, separate from your themed custom properties, so they won't be affected by theme switching. Here's an example:
const root = document.documentElement;
// Default theme - should assign declaratively in markup, not JS
// For a classless default theme, move its custom properties to unqualified :root
// Again, keep it separate from the other :root rule that contains non-theme props
// Remember, the cascade is your friend, not the enemy
root.classList.add('white');
document.querySelector('button').addEventListener('click', function() {
root.classList.toggle('white');
root.classList.toggle('black');
});
:root {
--spacing: 1rem;
color: var(--col);
background-color: var(--bgcol);
}
:root.white {
--bgcol: #FFF;
--col: #000;
}
:root.black {
--bgcol: #000;
--col: #FFF;
}
p {
margin: var(--spacing);
border: thin dashed;
padding: var(--spacing);
}
<button>Switch themes</button>
<p>Hello world!
Using :root selector is identical to using html, except its specifity is higher, thus there is no issues in using this approach.
For example:
:root {
--bg: red;
}
:root.blue {
--bg: blue;
}
// ...
div {
background: var(--bg);
}
Later, you should just change html's class and variables will change.
You can see an example in this fiddle.
I got a problem with TinyMCE when it comes to parent site CSS selectors.
My TinyMCE opens an iframe. I add the parent css to the tinyMCE via content_css property, no problem from there.
Now imagine that i got a css style like this:
.mysite.default .content h1 {
...
}
.mysite.default .info h4 {
}
The problem comes when i want to access to .content h1 or .info h4.
As by default, by adding to the body the class .mysite.default, if you got an h1 or h4, those won't be applied of course due to the selector .content and .info in the middle.
So inside the iframe's body i would be able to set styles only for
.mysite.default h1 { ... }
.mysite.default h4 { ... }
Is there a good strategy to have this kind of flexibility?
Problem is that I don't have only one h1 or h4 or span styling, I may got many of them, that's why I need a flexible selector strategy for this...
I can't just copy all the styles of the parent dynamically at runtime, because what if one of the parent selectors has a border, margins, padding (because it might be a parent div wrapper container with some unique styling) ?
So it's not that easy as saying, "hey add every parent style and that's all", because the child will have extra borders, extra margins when starting to edit that div.
If I understand you correctly, you should be able to use
.mysite.default * h1 { ... }
to select all h1s inside other tags: the * wildcard covers any wrapping tag/class/id.
Hope that is helpful...!
I'd like to apply a CSS to some linkbuttons on page load but one of them <a id="lb1">logoff</a> must keep its style, no hover nor other event must change its style.
The linkbuttons have no class and the css applied to all of them is done to tags, this way:
a
{
//style
}
a:hover
{
// style
}
Is it possible?
No, you can't.
You can use more specific selectors (or even inline CSS with the style attribute) so that they are less likely to be overridden accidentally.
You can use the (eugh) sledgehammer of !important so they will only be overridden by another !important rule.
There is no way to prevent them being overridden though.
Please please please please please avoid using !important whenever possible. You will run into SO many annoying problems and issues from using this. I consider it a very lazy hack.
What you want to do is append a class to the link that you don't want overwritten. Classes are given a higher priority than general selectors (such a, p, b). So if you append this class to the link, the CSS will override the default CSS you have set for a.
CSS:
a {
color: red;
}
a:hover {
color: blue;
}
.derp:hover { /*you can add everything you want to preserve here, essentially make it the same as the link css. you can also change it to #lbl:hover, although there's no good reason to be using an ID as a CSS selector*/
color: red;
}
HTML:
this will turn blue on hover
<a class="derp" href="#">this will stay red on hover</a>
Here's a fiddle to show you. The second link has a class appended that preserves the original style: http://jsfiddle.net/p6QWq/
Why not add a class to all the link buttons you want to change, and not add it to the one you don't want to change.
Then you can call:
$(".myClass").css("backgound-color", "blue");
This would change the background color for every element with a class of myClass to a blue background.
Or you could add a whole new class to the link buttons that have a class of myClass:
$(".myClass").addClass("myExtraClass");
This would then make the class attribute of your link button class="myclass myExtraClass"
Seeing your code posted makes it a little more clear on what you want to do. Try this:
a {
text-decoration: none;
color: orange;
}
a:hover {
text-decoration: underline;
color: blue;
}
This would apply a default style to all <a> elements. Now you could overwrite this default style by providing a specific style for the anchor with the id you gave above:
#lb1 {
color: black;
text-decoration: none;
}
#lb1:hover {
color: black;
text-decoration: none;
}
I mocked this up in a quick and dirty jsFiddle. See if this gives you the desired result. IDs take precedence over classes and default element styling. So if you have one that you want to keep the same, apply and ID and style the particular element accordingly. This would also help you by preventing you from having to apply a class to several elements. It's less coding to apply one ID than to apply twelve classes. (Just an exaggerated example. I don't know how many links you have.)
Hope this helps.
css is cascading by definition, so any style you apply to a tags will apply to this specific one, except if you overwrite it.
You'll have to either assign a class to all the other buttons or overwrite all the default properties for this specific button.
Also, do not forget the pseudo-classes :visited and :active.
You should use !important in your css like :
a {
/* style */
background: #FFF !important;
}
a:hover {
/* style */
background: #FFF !important;
}
You could always overwrite your css by simply creating another stylesheet and place it at the END of your stylesheet links in the head of your html.
<head>
<link rel="stylesheet" href="location/location/first_stylesheet.css">
<link rel="stylesheet" href="location/location/revised_stylesheet.css">
</head>
This is not the most productive method of overwriting your css however; one would be well advised to eliminate the necessity for this separate stylesheet by simply appending elements with a class attribute. The class attr will allow you to modify basic html elements, tags and overlay a final layer to "rule them all". Enjoy!
Is there any way to stop the conflict between same class or id of multiple css files. As I am explaining below for better understanding:
There is a master web page which has several <div> but there is a <div class"dynamic"> which always reload the contents including css files. Let's suppose if any class of master page has the same name to reloaded elements' class while properties are different. Then how should I handle this to stop the conflict.
master.html
<html>
<head> //attached master.css file here </head>
<body>
<div class="myClass"> </div>
<div class="dynamic"> /* often reload elements by ajax */ </div>
</body>
</html>
master.css
.myClass { height: 100px; width: 150px; background : red;}
.dynamic { height: 200p; width: 200px; }
now i am showing the reloaded html elements & css files into dynamic div of master page
reloaded tag line by ajax : <div class"myClass"> </div>
reload.css
.myClass{height: 30px; width: 25px; background: yellow; }
Now as you can see there are two classes with same name but different properties. Then how should I stop the confliction?
#Edit Thanks everyone for your support & time but my problem is different here.
the dynamic reloaded contents & css files are streaming from the client/user machine while master html page & it's css streaing directly from server.
so whatever the contents loads in dynamic div, it's coming from client side (e.g. tag lines & css, js). in that case i am not able to handle the css file which is just reloaded by ajax() so i think it can be sort out using js/jQuery fn().
You could apply the cascading rules of the CSS:
In your case, div.myClass inside div.dynamic should override div.myClass belongs to the body.
you adjust the reload.css rules to
.dynamic .myClass{height: 30px; width: 25px; background: yellow; }
The cascading rules which are applied when determine which rules should apply to html div could be referenced here
Updated 11.23
As the OP only have control over master.css, the above solution won't work. Thus, I suggest use child selector to limit the CSS rules to only the outer div.myClass. Modify the rule in your master.css to:
body > .myClass {...}
This rule will only apply to the .myClass which is the child of body. It leaves the spaces of styling for inner .myClass div.
Option 1: A more specific selector
.dynamic .myClass { }
This selector selects the .myClass element that is a descendent of .dynamic.
.dynamic > .myClass { }
This selector selects the .myClass element that is a direct child of .dynamic.
Option 2: Inline CSS
<div class="dynamic">
<div class="myClass" style="background-color: yellow;"></div>
</div>
Option 3: Use a different class.
UPDATE
If you want to avoid the previous defined property to be overwritten by a later defined value, you can use the !important syntax.
.myClass { background-color: red !important; } /* Sets the property to red */
.myClass { background-color: yellow; } /* Property is NOT overwritten */
If I understand your question correctly, this should sort it.
So you should add !important to the properties that seem to be overwritten.
div.myclass { ble ble }
div.main div.myclass { ble ble }
<body>
<div class="myclass"></div>
<div class="main><div class="myclass"></div></div>
</body>
Whichever css class of the same name is loaded last will overwrite anything set by the earlier class. However, if you use an inline style attribute this will always take precedence over anything set by the css file (so using an inline style is one option).
You could also use different style names or clarify your style with tag names div.myClass or id's #myDiv.myClass.