Is it possible in Javascript to set different element's styles at once, in such way that only one reflow is triggered? For example, is it possible to set at once the color style for different elements as in the below code snippet, in a way that just one reflow is triggered instead of three reflows?
document.getElementById("elem1").style.color = '#000';
document.getElementById("elem2").style.color = '#fff';
document.getElementById("elem3").style.color = '#abc';
I am familiar with techniques (as explained here) that minimize reflows/repaints such as using document fragments or using css classes instead of manipulating css styles through javascript, but I don't see how they can be applied on this case.
EDIT: the three elements on the example are siblings but there might exist, or not, other sibling elements between them, meaning that we cannot assume that they are defined necessarily by that order in the html structure. For example, its possible that we have a structure like this:
<div id="parent">
<div id="elem1">elem1</div>
<div id="elem2">elem2</div>
<div id="elem4">elem4</div>
<div id="elem3">elem3</div>
</div>
Much appreciated for any help!
Cheers
As far as I am aware the is no way to set the class of multiple elements at once. However, the browser may actually batch these changes for you anyway. Providing you don't read styles as well as writing them I believe this should hold true.
This article provides some insight into how reflow and repaint are triggered http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/
You can prepare class like this :
.color1{
color : #000;
}
.color2{
color : #abc;
}
And set to your elements like this :
document.getElementById("elem1").className = document.getElementById("elem1").className + " color1";
document.getElementById("elem2").className = document.getElementById("elem2").className + " color2";
Depending on your element structure. For example assuming those elements are sibling DIVs, you can define CSS as:
div.myclass {
color:#000
}
div.myclass + div {
color:#fff
}
div.myclass + div + div {
color:#abc
}
Then a single JS command:
document.getElementById("elem1").className = "myclass";
Would set color for all 3: http://jsfiddle.net/PjZ77/1/
If it makes sense in your case, use css classes and swap the container class.
HTML structure could be :
<div id="container1">
<div id="elem1" class="clsA">A</div>
<div id="elem2" class="clsB">B</div>
<div id="elem3" class="clsC">C</div>
</div>
and in CSS:
#container1 .clsA { color: #000; }
#container1 .clsB { color: #111; }
#container1 .clsC { color: #222; }
#container1.mystate .clsA { color: #DDD; }
#container1.mystate .clsB { color: #EEE; }
#container1.mystate .clsC { color: #FFF; }
You can set document.getElementById("container1").className with mystate class (or empty class, or any class name that makes sense you defined in the css.
Class change occurs for only one element (the container), so the elem(n) child items will be refreshed at the same moment.
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>
i would like to find all classes and ids inside a certain div ! and these css attributes!
Example :
<div class="demo">
<div class="new_class">
<p id="para">This is Demo Paragraph</p>
<a style="background:#ccc">HyperLink</a>
</div>
</div>
<style>
.demo{
height:100px; width:100px; background:#FF0;
}
.new_class{height:40px; width:40px; background:#999;}
#para{color:#E1E1E1;}
</style>
Now The question is that: i would like to find all classes and ids which are used inside demo class ! and Their css values too(which style applying now. ).
I would like to find result as below :
<style>
.demo{
height:100px; width:100px; background:#FF0;
}
.new_class{height:40px; width:40px; background:#999;}
#para{color:#E1E1E1;}
a{background:#ccc;}
</style>
OP, not sure what your purpose is, but in general, this can be useful. I had a project where I needed to embed a fancy template from one site onto a page on a different site with a very different, and conflicting stylesheet. I used some code similar to the following to grab every applied style from the original content, via document.styleSheets, then reapplied them all as inline styles, so I could put it onto the "parent" site without the stylesheets conflicting.
Fiddle
JS
var selector,rule;
var result=[];
var sheets = document.styleSheets;
for (var i in sheets) {
//rules or cssRules, depending on the browser
var rules = sheets[i].rules || sheets[i].cssRules;
//iterate over every css rule in the document
for (var r in rules)
{
selector=rules[r].selectorText;
rule=rules[r].cssText;
//select demo itself, as well as all of its children
$('.demo, .demo *').each(function () {
//console.log($(this),selector);
//for each element, see if it matches the current rule. add if it does
if ($(this).is(selector))
{
result.push(rule);
}
});
}
}
console.log(result);
//result[0] .demo { height: 100px; width: 100px; background: none repeat scroll 0% 0% rgb(255, 255, 0); }
//result[1] .new_class { height: 40px; width: 40px; background: none repeat scroll 0% 0% rgb(153, 153, 153); }
//result[2] #para { color: rgb(225, 225, 225); }
Granted, you will have to tweak this on your own to do things like, removing duplicate styles that would occur if you were to apply this to a larger block of HTML, and for dealing with inline styles (which this does not attempt to do, but you can get them from the style attribute and work from there...), and possibly the computed style, which you can get with getComputedStyle, as indicated by the #Derek's answer. but this should get you started.
To find all existing id, try:
var ids = [];
$(".demo *").each(function(){ this.id && ids.push(this.id); });
console.log(ids);
Do the same thing for class or anything else.
However, to get your expected output, you must first acquire the defined CSS style for each element. Which one should be included? p by default gets margins and paddings. Do you include those too? You will also need to dig into all the CSS declarations just to find the style that are applied, which is almost impossible to do.
For example,
<div class="yellow"></div>
<style>
div.yellow:not(.blue){
background: yellow;
}
</style>
How do you get the background of the <div> tag? .style.background? Nah, it returns "". Well now you will have to reach into the CSS declaration with document.styleSheets to see which one applied. How do you even check if the rule div.yellow:not(.blue) matches your element? Good luck doing that. (There might be libraries that does this kind of thing, or maybe you can even utilize jQuery's internal selector engine with .is, though it will not be the same as in CSS) Another thing you can do is try getComputedStyle. It gives you every single computed styles that aren't even in your declaration. So what you are trying to do is not possible to do. (I don't even know what you are doing something like this.)
I have to modify an existing HTML5 app that has two different types of themes.
For example, I have something like this:
<body class="theme1 theme2">
<div id="div1">I'm happy with both themes</div>
<div id="div2">I just want theme 2</div>
</body>
This example is overly simplified. I know that I could just apply theme2 to div2. But the point is that those themes classes are in the body and I cannot "easily" change that.
I naively thought that I could just do something like this in JS:
getElementById('div2').classList.remove('theme1');
But this does not seem to work. I think that this only work on classes directly applied to the element. I would prefer a "pure CSS" solution anyway.
The info that I find seems related to preventing inheritance of specific properties. In my case, I want to prevent inheritance of any property under the theme1 class for div2 and all its children.
Properties are inherited, classes are not.
The only way to stop a property being inherited is to assign a value to that property for the given element.
The code doesn't work because 'theme1' is not a class of div 'div2'.
I don't know of a way to selectively remove the inheritance as you asked. The closest solution I can think of is to use nesting to create a more specific selector and override the undesired styles. Simple example:
.theme2 {
font-style: italic;
}
.theme2 #div2 {
font-style: normal;
}
This would "remove" the italic style from div2. You would have to redefine all the undesired styles. From a maintenance standpoint this may or may not be an acceptable solution. But it does solve the problem.
No, that's not how CSS works. If properties are getting applied to a descendent because of a class on an ancestor, and you cannot change that class or the properties, then you have to override the properties (via a more specific selector) that you don't want inherited.
e.g.
body.theme2 div { background: #000; }
#div2 { background: transparent; }
Let's start with some common.js:
//<![CDATA[
var doc = document, bod = doc.body, IE = parseFloat(navigator.appVersion.split('MSIE')[1]);
bod.className = 'js';
function gteIE(version, className){
if(IE >= version)bod.className = className;
}
function E(e){
return doc.getElementById(e);
}
function removeParentClassName(childId, removeClassName){
var cn = new RegExp('(\s+)?'+removeClassName, 'i'), pn = E(childId).parentNode;
pn.className = pn.className.replace(cn, '');
}
//]]>
Now on your current page:
removeParentClassName('div2', 'theme1');
One way you could do this with pure CSS would be to set up you CSS rules like so
.theme1 .div1,
.theme2 .div1,
.theme1 .div2,
.theme2 .div2 {font-style:normal;} /* apply theme1 and theme2 styles here */
.theme1.theme2 .div2 {font-style:italic;} /* apply theme2 only rules here */
I want to add another class to a element, but some of those elements already have an existing class, however the class I am adding I want it to be the first class added in the class field and don't want to append it; because from what I know, in general, rules in the last listed class will overwrite rules in the former classes, correct!?
I know of a jquery method as below..
$("p").addClass("myClass");
However from what I understand this just appends the class and you can't choose where to put it.
Is there any way to do this easily or will I have to start removing classes and re-adding them?
Not sure if there is any need to do something like this, I personally like advice of #bwoebi just change specifity.
But still if you need it, this might help
HTML
<div class="second">Lorem text</div>
jQuery
var $div = $('div'),
classes = $div.attr('class');
$div.attr('class', 'first' + ' ' + classes);
You can put your variable which contains class's name in place of 'first'
Demo
You add multiple classes to an element by simply separating the classes using a space. For example:
<p class="key_paragraph dark no_border">Your text here</p>
<p class="key_paragraph dark">Your text here</p>
The order in which the classes are listed in the html attribute does not matter. What matters is the stylesheet.
In your stylesheet (css file), if you want any of the classes to override another you could change the order of the rules in the stylesheet. For example, if the class 'dark' has a border and the class 'no_border' does not, you must place 'no_border' after 'dark' in your stylesheet to ensure 'no_border' overrides 'dark' for the first paragraph. Like so:
.dark {
border: 2px solid red;
}
.no_border {
border: none;
}
Secondly, you could add specificity regardless of the order of the css rules. For example, combining classes to say 'if an element has the classes dark and red' is more specific than either of the two above rules. See here for more info on specificity. Thus, the following rule would ensure there is no border on elements with the classes 'dark' and 'no_border' regardless of the order in which they appear on the stlesheet:
.dark.no_border {
border: none;
}
.dark {
border: 2px solid red;
}
A third option is to use the css :not selector to target all elements with the class 'dark' that do not also have the class 'no_border'. Again, the order of rules in the stylesheet will not matter here. This is done as follows:
.no_border {
border: none;
}
.dark:not(.no_border) {
border: 2px solid red;
}
There are other ways to do this, but hopefully I have explained three easy ways in a manner you can understand. There is a more jquery-specific demo here (see the third example). Let me know if you have any questions.
Just for fun in case you wanted to add the new class at a specific index inside the current classes:
http://jsfiddle.net/ckzVk/
function addClassAtIndex(elementId,classNameToAdd,index){
var element = document.getElementById(elementId);
var elementClasses = element.className.split(" ");
elementClasses.splice(index,0,classNameToAdd);
var newClasses = elementClasses.join(" ");
element.className = newClasses;
}
To add class "man" to div:
<div id="stuff" class="cool bro sweet">The div.</div>
JS:
addClassAtIndex("stuff","man",1");
Result:
<div id="stuff" class="cool man bro sweet">The div.</div>
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!