Persistent css rule changes for dynamically created elements - javascript

I want to permanently modify a css rule (such that new elements will take on this css rule). It appears that all jquery modifications using css do not persist (Say modifying a background color for future elements does not persist when they are created):
$(".red").css("background-color", "blue");
See my fiddle here:
https://jsfiddle.net/Lvm0c7m6/
I would like all future elements to now have the new rule created by css, is there a way to do this (with good cross browser support).

You order javascript at execution time to add an inline style to all elements with class 'red', coloring them blue. After that you add new elements to the DOM. They have no knowledge of the earlier command an therefore are not influenced by them.
This solves your problem, as this adds a style rule to the document. This influences all elements and is 'persistent':
$( "<style>.red { background: blue; }</style>" ).appendTo( "body" );
See: https://jsfiddle.net/aLghL2ke/
Note that if you want to run this command multiple times, it would be nice to remove the old style block from your code. This can be done with jQuery too using this command:
$( "body style" ).remove();
See: https://jsfiddle.net/4duxsz0a/

Related

What are the conditions under which a browser will re-assess and reapply CSS selectors and styles?

Talking strictly about CSS 3, html 5, and styles defined on stylesheets or in a top level tag:
This is what I have observed:
Using JavaScript:
If I move an element under another element, or out from under its parent, it and all elements under it will be reviewed for restyling.
If I add or remove a class, an element and all elements under it will be reviewed for restyling.
If I add or remove an attribute, an element and all elements under it will be reviewed for restyling.
I assume this is also true of the sibling (~) relationship as well? I mean moving elements relative to their siblings?
Is there anything else that would trigger this? And is there a document someplace (like mozilla) that specifies this as a standard?
That really depends on what you call "restyling".
Here it seems you are only talking about recalculating all the styles applied by all the stylesheets in the document, which is also known as "reflow" or "layout".
Any change to the DOM will mark the CSSOM as dirty, and before the time of rendering, the browser will perform such a reflow if the CSSOM is dirty.
Note that some operations, (most being referenced in this gist by Paul Irish), will force a synchronous reflow, because they do require that an up-to-date boxing model is calculated to return the correct values, or to act correctly. So one must be careful when doing DOM changes in a loop to not also force such a synchronous reflow and let the browser do it at the best time, (generally just before the next paint, but in some browsers it's also done at idle).
However this reflow may not cost much, browser may very well have enough optimizations to know what could have changed and go only through these. Moreover, these don't include the repaint operation, which will only happen at the next screen refresh.
But this is not the only time the browser needs to recalculate the boxes layout, for instance every time the page is resized, or even if an in-flow element's size changes as part of an animation etc. but here, the full stylesheets are not recomputed.
There is not really a place in the specs where it is defined what should trigger these operations, nor even when they should occur. The HTML specification only asks that the browser performs the "rendering steps" of the event-loop, which does end with a quite underspecified "update the rendering or user interface of that Document". The ResizeObserver API does extend the rendering step to include styles recalc and layout update but they don't go as far as defining these steps. Note that there is an open issue on the HTML specs to define it more clearly, but for the time being we don't even have browser interoperability.
CSS3 is a series of separate specifications covering individual topics but includes CSS2 within the official definition of CSS.
CSS2 definitions define rendered content as (the emphasis mine)
The content of an element after the rendering that applies to it according to the relevant style sheets has been applied. How a replaced element's content is rendered is not defined by this specification. Rendered content may also be alternate text for an element (e.g., the value of the XHTML "alt" attribute), and may include items inserted implicitly or explicitly by the style sheet, such as bullets, numbering, etc.
I take this to mean that when a document or part thereof is rendered, the browser is responsible for ensuring that CSS rules are correctly applied according to the content rendered, with DOM content and CSS rules specifiying the logical requirements of the rendering and the browser ensuring it produces page layout in conformance with the logical model.
My experience is that browsers will update the DOM when vanilla JavaScript1 code adds, moves or removes elements in the DOM, and also when changes to style sheet content or element style attributes are updated in script. Changes in the DOM appear to take place synchronously when modifying element placement or styling rules: getting the bounding rectangles of elements in the DOM whose styling or location in the DOM has been modified does not require browses to render the content first.
Hence you're basic assumptions about what you can rely on are essentially correct apart from the wording
reviewed for restyling
There is no active "review" taking place - excepting that modifying some properties can trigger a automatic and synchronous reflow operation in order for the calling script to have synchronous access to DOM property values that would need a reflow to calculate.
If you change the position of an element in the DOM, it's position has been changed upon return from the method used to change it's position.
If you add, delete or modify an attribute of an element (in the DOM), changes to the attribute and any side effects produced will have been put into effect upon return from the method used to make the change.
If you add, delete or modify style sheet rules, changes are effective in results returned from DOM inspection after the method used to change the style sheet returns.
There is a hint of this in the MDN article on `Window.getCommputedStyle. Overall I don't think it's mentioned anywhere specifically because it's inherent in the behavior of the DOM. You only get to know about it when a) you need to use the results of changes synchronously and b) are curious as to why it works as you hoped it would! :)
Examples showing synchronous results:
Changing element location in the DOM, style attribute changes:
setTimeout( ()=> {
const [div1, div2] = Array.from(document.querySelectorAll('div'));
div2.appendChild(div1);
div1.style.backgroundColor = "yellow";
div1.style.textAlign = "center";
const rect = div1.getBoundingClientRect();
const style = getComputedStyle(div1);
console.log("Synchronous results for div1: ",
{top: rect.top, backgroundColor: style.backgroundColor});
}, 3000);
<div>Division 1</div>
<div>Division 2</div>
... please wait 3 seconds
Changing CSS rules in the CSSOM
"use strict";
let div = document.querySelector('div');
let sheet = Array.from(document.styleSheets)
.find(sheet=> sheet.ownerNode.id == "absDiv");
console.log("div offsetWidth ", div.offsetWidth); // before
sheet.insertRule("div{ width: 200px;}");
console.log("after width set in CSS: ", div.offsetWidth);
<style id="absDiv">
div { background-color: yellow; }
</style>
<div>Div element</div>
1 Vanilla Javascript implicitly excludes cases of shadow DOMs and components. Refer to Kaido's answer for broader treatment.

How to make an element's CSS NOT inherit from others?

I want the element to use only css that are in the "A" section and ignore the "B" section.
Is it possible?If javascript can do this, How?
Thanks you.
You can not do that with the example you've provided. The C in CSS stands for Cascading, the styling rules cascade down the DOM tree.
You have to reset the styling of the element to what you want with a more specific selector, e.g. #Examplewrapper input{}. By using a more specific selector, it'll overwrite/suplement the previous styling, without the need for !important.
Alternatively, you can set the most upper selector more specific, e.g. #content input{}. This way, when you place a form in the #footer, it will not have the styling, as #content doesn't have a #footer in it (it cant cascade).
I do recommend to define a general input as you have. This way, all forms have the same font, size and styling throughout your website. If you want another color border, you only have to change that one settings. This is the way many (profesional) sites work, because it is the most efficient.
This is how the inheritance works. You can only overwrite styles if others are set globally (i.e. for all input elements).
You can always limit the global styles of input with some classname, like input.myStyle so the raw input will have no styles set.

Moving an element into a new div - doesn't take on its new css properties

So, I have an element that has some "pre-existing" behavior attached to it. So, I found that just moving it (as required by some new requirements) retains the existing behaviors = good. But the issue is, when I move the element I need to give it "new styles".
So, if I have something like this:
<div id="existingStructure">
<div id="legacyElement"></div>
</div>
Now, that has pre-existing styles attached to both. I can rearrange these styles etc.. but I can't change them. The styles are attached to the "id's" rather than a class definition. I believe I can change that if needed.
Now, I need to move "legacyElement" when certain things happen to a "new div".
I just
jQuery('#newStructure').append('#legacyElement');
<div id="newStructure">
<div id="legacyElement"></div>
</div>
Unfortunetly, the styles I have on newStructure don't seem to be applying to *legacyElement" when it gets moved here dynamically.
I was thinking of moving all the styles to a class rather than associated to the ids, and when I move it.. I just jQuery().addClass / jQuery().removeClass etc...
Is there a better/easier more robust way that I can just have the legacyElement loose its styles when it sits under existingStructure and then get new ones when moved to "newStructure" etc.. and vice versa. That element "legacyElement" will be pinging back and forth.. so, I need it to have the styles under each parent div as it goes there.
so when an action happens on page, I move it back:
jQuery('#existingStructure').append('#legacyElement');
If I am not succinct enough, please let me know.
The EXISTING styles are in an external CSS file and are like so..
#existingStructure {
// bunch of css
}
#existingStructure .item1 input[type="text"] {
// bunch of css
}
#legacyElement{
// bunch of css
}
and new styles are sorta the same except 'additional styles' might be applied.
#newStructure {
// bunch of css
}
#newStructure .item1 input[type="text"] {
// bunch of css
}
You can certainly target your div styles by their parents:
#existingStructure #legacyElement {some styles}
#newStructure #legacyElement {some other styles}
To explain futher, this arrangement should result in greater specificity, overriding styles that are simply applied to either #existingStructure or #legacyElement. I'm hoping no one did anything foolish like using !important on them.
Short answer: It should.
Here's an example I quickly made in jsFiddle: http://jsfiddle.net/CCm4J/1/
So then why isn't yours? Most likely you have css rules that are embedded that apply only when in the existingStructure id/class perhaps? Without see more of your css I'm not sure how specific I can get. I would just verify that your css rules are allowed to apply outside of existingStructure (and even that existingStructure might have rules for its parent too!)

How to apply function to all elements having border-radius property

The idea is making some border-radius effect in IE 7/8, so I've decided to use jquery.corner.js library. To make it more generic I want to write some script which applies corner() function to all elements within a page having border-radius property.
For example, for this element
.someElement
{
border-radius:10px;
}
function must do the following
$(".someElement").corner("10px");
The problem is that I want to apply rounded corners to all elements, including dynamically added elements and elements which are inheriting border-radius property among some action(hover, click, etc.). Is this possible?
You need to declare a function that applies you css on every change.
To detect css style changes, see here:
Event detect when css property changed using Jquery
Then you need call that function on style change and on dom tree change (every time you append something into the page)....
I would advise you use a specific class to apply border radius css. This way you can select the rounded elements via jQuery class selectors.
You should have a generic css class that is used on all elements that have rounded borders and then use that class in your selector.
You will have to do this in a document ready handler. This will of course only apply rounded borders to elements that currently exists. If you want to cover elements loaded with ajax you can do the following:
$(document).ajaxSuccess(function(e, xhr, settings)
{
$(xhr.responseText).find(".class-that-applies-rounded-borders").corner("10px");
});

Which is faster? - modifying css property or adding class in jquery

I have about 100 elements in like and am trying to create an animation with jquery.
<div class="box" id="a1"></div>
I need to add special styles to each of the elements based on a function.
which of them is rendered faster in browser:
adding css property
$(this).css({'background-color':'#000'})
or adding class
$(this).addClass("style1")
Updated
Few more things i wish to add:
Right now it has 100 elements and am adding them by jquery.
To create randomness i need to create about 25 styles - am doing it by javascript
should i also add size of stylesheet to the same to get exact benchmarks.
which of them is rendered faster in browser:
Depends on the browser. you should do some tests if it's interesting you.
Anyway it's not important and very unlikely to be the bottle-neck of your website.
Avoid micro-optimization, "premature optimization is the root of all evil", you're wasting your time.
According to jsPerf, addClass is noticeably faster by about 50%.
Here's the jsPerf data for Chrome but in my tests it was about the same using Firefox:
$('#a1').css({ 'background-color': '#000' }) 82,043 ±0.21% 48%
slower
$('#a1').addClass("style1") 158,876 ±0.83% fastest
Adding a class to the parent of all these 100 elements will be faster and defining that class in the css file or page.
.style1 .box{
//define style here
}
This way you just have to manipulate the class of only one element and it is definitely faster than modifying each of the 100 element's style using css method.
How fast? It all depends on the number of lines of code executed in each of the operations which is again dependent on browser to browser.
If you go with my approach it will definitely be faster.
You can even consider using a style tag.
It could turn to be very fast.
For example if you have a lot of elements to modify, let's say 100 elements, as you write your css only once, the DOM will be changed only once.
HTML:
<style type="text/css" id="specialStyle"></style>
<div class="oneHundredElements" id="box1"/>
<div class="oneHundredElements" id="box2"/>
...
<div class="oneHundredElements" id="box100"/>
SCRIPT:
<script>
var css = '.oneHundredElements {background-color:#000;}';
$('#specialStyle').html(css);
</script>
http://jsperf.com/foox/4

Categories