Performance of adding CSS class & number of children - javascript

I need to dynamically apply some styling to elements .child-1 and .child-2 by adding CSS classes.
Should I add them once to #parent or to each .child-? If I add it to #parent would existence of #large-container affect the performance?
<div id="parent">
<div class="child-1"></div>
<div class="child-2"></div>
<div id="large-container">
<!-- a bunch of content here - p tags, images... -->
</div>
</div>
(.child-1 and .child-2 are absolute positioned elements on top of #large-container)
$('#parent').addClass('myClass1 myClass2');
vs
$('.child-1, .child2').addClass('myClass1 myClass2');
Same with just CSS:
.myClass1 .child-1,
.myClass2 .child-2 {
color: red;
}
/* vs */
.myClass1.child-1,
.myClass2.child-2 {
color: blue;
}
myClass1 myClass2 only apply styles to #child-1 and 2, they don't add any styles to #large-container.
Thank you for advice!

although i think my answer is impossible to verify from a profiler (are there any css/html profiling tools out there in terms of rendering the page etc?) I'll state it based on my experience:
$('#parent').addClass('myClass1 myClass2');
is faster than
$('#child-1, #child2').addClass('myClass1 myClass2');
simply because you are traversing the dom tree once rather than twice ie
$('#child-1, #child2').addClass('myClass1 myClass2'); is the same as
$('#child-1).addClass('myClass1 myClass2');
$('#child-1).addClass('myClass1 myClass2');
to theoretically prove that last point imagine your html code looked something like this:
<div id="parent">
<div id="child-1"></div>
... lots and lots of html nodes
<div id="child-2"></div>
</div>
then looking for #child-1 is a completely separate operation than looking for #child-2.. and when it comes to css/html optimisation.. one of the most expensive operations is the DOM tree traversal.
in the case of $('#parent').addClass('myClass1 myClass2'); you are traversing the DOM tree once (ie finding where #parent is then using css cascading to apply to the elements within the narrowed down #parent DOM subtree
to address the concern that #tMagwell raised about repainting #large-container here is another optimized way of applying css:
// store the child-1 node in a variable.. ie whenever you
// refer to it in the future.. you won't have to traverse the entire DOM again
var child1element = $('#child-1');
$('#child-1).addClass('myClass1 myClass2');
// referring to child1element costs you nothing big, it's already stored in a variable
child1element.siblings().addClass('myClass1 myClass2');
this code works of course assuming that there are only child-1 and child-2.. if you got child-3, child-4.. child-n and only want to apply it to child-n.. then you can use
child1element.siblings()[n] // where n is the index of the child you want to target, since siblings() returns an array
hope this helps!
update:
to address this specific point you raised in the comments:
Does the presence of #large-container slows down something when I add classes to #parent?
the answer is yes. let me give you a scenario where it definitely does:
css:
#parent .class1 .class2
{
font-size:10pt;
}
html:
<div id="parent">
<div id="child-1"></div>
<div id="child-2"></div>
<div id="large-container">
<!-- images etc -->
<p>hello world!<p>
<!-- many more p tags that has a lot of text and stuff -->
</div>
</div>
so in this example.. the font-size:10pt placed under #parent .class1 .class2 will definitely impact the contents of #large-container.. and the operation costs something.. i have no way to quantify how expensive that is (it would depend on the browser rendering engine etc).. but suffice it to say that there is some cost x that is higher than if you didn't just add class1 and class2 to the parent div.

Related

How can I select text in an element that isn't inside another element? [duplicate]

I have the following HTML markup:
<h1>
<div class="sponsor">
<span>Hello</span>
</div>
World
</h1>
When I use the CSS selector h1 I get Hello World.
I can't unfortunately change the markup and I have to use only CSS selectors because I work with the system that aggregates RSS feeds.
Is there any CSS selector which I can take only the text node? Specifically the World in this example?
The current state of CSS can't do this, check this link: W3C
The problem here is that the content you write to the screen doesn't show up in the DOM :P.
Also ::outside doesn't seem to work yet (at least for me in Safari 6.0.3) or it simply doesn't generate the desired result yet.
Check my fiddle and then check the DOM source: JSfiddle
Finally there are attribute selectors a { content: attr(href);}, making CSS able to read DOM-node attributes. There doesn't seem to be a innerHTML equivalent of this yet. It would be great tho if that was possible, whereas you might be able to manipulate the inner markup of a tag.
Bit of a workaround:
h1 {
color: red;
}
h1 * {
color: lime;
}
<h1>
<div class="sponsor">
<span>Hello</span>
</div>
World
</h1>
This is almost the opposite of a question I asked last week: Is it possible to select the very first element within a container that's otherwise pure text without using classes or identifiers in pure CSS?
The short answer is no. "World" in this example isn't an element of its own - therefore there isn't a way to select it.
What you would have to do here is style the h1 then override that styling with div.sponsor. For instance, if you wanted "World" here to have a black background with white text you woud use something similar to:
h1 {
background:black;
color:white;
}
h1 div.sponsor {
background:white;
color:black;
}
Unfortunately, however, this wouldn't work if you were only wanting the word "World" styled and your markup had more than just that within <div>Hello</div> World Foo, for instance.
I don't believe it would be possible with pure CSS to style just "World" in this situation.
I also met same problem, where I can't touch the markup and have no control with js.
I needed to hide a text nodes in a div element, but the element to remain visible.
So here is my solution:
markup:
<div id="settings_signout_and_help">
<a id="ctl00_btnHelpDocs" class="ico icoHelp" href="http://" Help Guide</a>
Signed in as: <a id="ctl00_lUsr" href="Profile.aspx">some</a>
Home
Sign out
</div>
css:
#settings_signout_and_help {
font-size: 1px !important;
}
#settings_signout_and_help a {
font-size: 13px !important;
}
Hope this helps guys!
I had a similar problem where I had to remove the "World" text from html generated by a C# function.
I set the font-size to 0 on the 'h1' element and then applied my css to div class. Basically hiding the extra text, but keeping content in the div.
I don't know how to do it with just CSS, but...
Using JQuery, you could select all the elements inside except the stuff inside its child element
$("h1:not(h1 > div)").css()
and put whatever CSS effect you want inside there.

How to block outer CSS to modify div

Scenario
Visit this link for Codehttps://plnkr.co/edit/yjGTX0XvOZIqL17Co2MF?p=info
I do not want my innerDiv to get modified by CSS in outerDiv.
Is there some way to achieve this?
(contents(HTML) of InnerDiv are loaded via ajax call , and the resulting page already has its own CSS and both CSS files are messing up all the layouts and formats)
From a previous answer: all: initial isn't supported by Edge (Safari is finally OK)
So you can reset manually a hundred of properties if you really really really want to be sure (forget the most obscure ones you know you don't use. If you're a third party, well no luck).
You can (should) add the !important modifier (that's one of those cases where it isn't possible to do in some other way... Fine for me at least)
You can also add a whole lot of specificity to your selectors by adding an id to your component's parent and prefix each of your selectors with that id: #myComponent.my-component .my-component-descendant { color: #333 !important; }. If your existing CSS already uses id (meh), you can go even further (lower, quality wise) and use the same id multiple times in a single selector. #myComponent#myComponent#myComponent.my-component .my-component-descendant { color: #333 !important; }. What is one the crappiest thing you can imagine in a sane project is also a powerful tool when you need to add "enough" specificity.
Food for thought: the modern way of setting box-sizing by setting it on :root and then letting inheritance do its job can be helpful (or not) https://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/
Advantage: if you set another value on a descendant, descendants of the latter will inherit from it. You now have a whole part of your DOM inheriting from another value.
You can override the properties in you innerdiv; here I have overwritten the background-color property of the outerdiv
#outerMostDiv {background-color:red;}
#innerDiv {background-color:yellow;}
<div id="outerMostDiv">
<!-- SOME CSS HERE (say Outer CSS)-->
outer div
<div id="innerDiv">
<!-- some CSS HERE -->
innerdiv
</div>
</div>

Re-order Divs without access to html

I'm customising a wordpress theme and have come up against a frustrating blocker.
I would like to position the header (header.non-sticky-nav) after the fullscreen cover (.fullscreen-cover) and before the content (.content).
<header class="non-sticky-nav">
<div id="navbar"></div>
</header>
<div id="wrapper">
<div id="content">
<div class="fullscreen-cover"></div>
<div class="content"></div>
</div>
</div>
current-result_vs_desired-result
I tried repositioning the nav bar by using a "top: xpx" value but obviously that doesn't work as the .fullscreen-cover is not a fixed height.
Here is the test page I am using for the issue: http://samburrough.design/test/
The theme allows page specific or global css code injections, and as theme is regularly updated, I would like to try and stick to using this feature rather than delve into the theme files and have the changes overwritten every time I want to update.
Any help would be hugely appreciated!
Could you not create a child theme and modify the DOM that way?
At least this way the changes won't be over-written every time an update to the parent theme is released?
This would (should) actually be the preferred option.
Smashing Magazine; Create and Customise Wordpress Child Theme
Unfortunately, if the theme does not include block positioning, you need to edit the DOM. While you could probably use some wonky absolute positioning on the bar and the hero, positioning them absolutely is likely to cause you a cascade of problems - starting with the responsive nav.
There is a javascript function/method that lets nodes swap places in the dom.
you could try and look into that Node.replaceChild()
The example below is from the documentation and creates a new element but you can also select an existing node.
// create an empty element node
// without an ID, any attributes, or any content
var sp1 = document.createElement("span");
// give it an id attribute called 'newSpan'
sp1.id = "newSpan";
// create some content for the new element.
var sp1_content = document.createTextNode("new replacement span element.");
// apply that content to the new element
sp1.appendChild(sp1_content);
// build a reference to the existing node to be replaced
var sp2 = document.getElementById("childSpan");
var parentDiv = sp2.parentNode;
// replace existing node sp2 with the new span element sp1
parentDiv.replaceChild(sp1, sp2);
You could try using order with flexbox. For example:
.container {
display: flex;
flex-wrap: wrap;
}
.one,
.two {
width: 100%;
}
.one {
order: 2;
background: red;
}
.two {
order: 1;
background: blue;
}
<div class="container">
<div class="one">
1
</div>
<div class="two">
2
</div>
</div>
Might be a bit problematic, depending on what your markup looks like. And won't work on older browsers.

:target css selector not working in polymer

I'm using Polymer and I noticed that the :target css selector doesn't work.
For example
<polymer-element name="my-element" noscript>
<template>
<style>
:target {
border: 2px solid red;
}
</style>
<div id="test">This is a :target test</div>
</template>
</polymer-element>
Click me
<my-element></my-element>
DEMO
Any suggestions how I can fix this ?
I must admit: I'm not very familar with shadow DOM and absolutely not familar with Polymer but I'd like to tell you my view on this because your intention looks somewhat strange to me and this is too long for a comment.
Short
You can't use the pseudo selector :target within a shadow host.
Long
Unfortunately I was not able to find clear evidences in these resources
http://www.w3.org/TR/shadow-dom/
http://dev.w3.org/csswg/css-scoping/
but some hints...
The goal of Web Components was to give us the ability to build individual and isolated components that can be used in a document without caring of their inner function or style.
If a component could directly reach the "outside" document or if the outside document could reach any shadow hosts element directly, this would completely break the intention of Web Components.
Imagine what would happen if you insert two instances of your <my-element>. Both contain the same ID, which one should be targeted?
Of course it's possible to reach the shadow document, or the containing document from within the shadow document, but only through ::shadow or :host respectively.
To me its logical that the browser can't select elements using a mere :target selector since the target is the matter of the document (it's URL is targeted to some ID) not of any shadow DOM. It's also not possible to reach a shadow tree node with document.getElementById() from within the container document.
The CSS scoping spec which also adresses the Shadow DOM concepts states:
Why is the shadow host so weird?
The shadow host lives outside the shadow tree, and its markup is in
control of the page author, not the component author.
It would not be very good if a component used a particular class name
internally in a shadow tree, and the page author using the component
accidentally also used the the same class name and put it on the host
element. Such a situation would result in accidental styling that is
impossible for the component author to predict, and confusing for the
page author to debug.
(3.1.1. Host Elements in a Shadow Tree)
I'd say this is another evidence: the shadow host (viewed from outside) itself will keep the active (focus) state while handling the focus inside its tree.
To maintain encapsulation, the value of the Document object's focus
API property activeElement must be adjusted. To prevent loss of
information when adjusting this value, each shadow root must also have
an activeElement property to store the value of the focused element in
the shadow tree.
(6.3 Active Element)
One possible solution to your problem
If your intention was to highlight only the div, when your shadow element is :targeted this might be the correct style within your shadow document:
<polymer-element name="my-element" constructor="" attributes="">
<template>
<style>
:host(:target) #inner {
color: #0c0;
}
</style>
<content>Hello World!</content>
<div id="inner">This is a :target test</div>
...
It will highlight the <div> with green text, when your shadow element <my-element id="outer"></my-element> is targeted by #outer.
If this was not your intention and you really wanted to be able to target #inner from outside, I'd say this is not possible (see the "longer" part ;).
I don't think it's a good idea to link to elements inside shadow dom, because you may have multiple instances of the outer element in same page so you'll get multiple elements with same id.
However when you request a url with #elementId the browser will only look in light dom for the according element.
If you still need to style shadow dom elements you could simulate :target selector:
<polymer-element name="my-element" constructor="" attributes="">
<template>
<style>
#inner[target] {
border: 2px solid red;
}
</style>
<content>Hello World!</content>
<div id="inner" target?="{{innerTargetted}}">This is a :target test</div>
</template>
<script>
Polymer('my-element', {
ready: function() {
$(window).on('hashchange', function() {
this.innerTargetted = window.location.hash == '#inner';
}.bind(this));
}
});
</script>
</polymer-element>
Demo.

Display: Block/None html elements with css..not releasing from memory

I can't wrap my head around this. I have several Divs within a HTML page. Each Div represents a different section and thus contains different images for that section. All the images are referenced from css and displayed/removed using javascript (document.getElementById('DIV').style.display='none/block';).
For the purpose of this example lets say I have 2 divs. Each section Div(Div1 & Div2) would be the parent divs and any Div within those parents will be its child. (DIV1a, DIV2a)
I have found that if Div1 is set using display: block and uses the css Background-image:.... and Div2 is display='none' when I hide Div1 using style.display = 'none'; that it does remove it from the screen and allows me to show Div2..however the background-image is still present in the browser memory.
The interesting thing and which I can't wrap my head around is if I place the background-img into a child div(div1a) within DIV1 when I use style.display = 'none' for the the Parent DIV1 the child div1a image does get removed from the browser memory when I use style.display = 'none' on the parent DIV1. However I have found this also to be inconsistent....it seems to work on some parent divs and not on others.
As you can probably tell by this point I am heavily confused and really don't know how to approach this.
Thank you all for your time and thoughts.
Code Example:
When using this method
<div id="Div1">
content....
</div>
<div id="Div2" style="display: none">
...content
</div>
div#Div1{
background-image: url(images/mybg.png);
background-repeat: no-repeat;
width: 480px;
height: 360px;
}
document.getElementById("Div1").style.display='none';
document.getElementById("Div2").style.display='block';
The image is still present in the resources tab when I execute the above javascript
When using this method:
<div id="Div1">
<div id="Div1a">
content....
</div>
</div>
<div id="Div2" style="display: none">
content....
</div>
div#Div1a{
background-image: url(images/mybg.png);
background-repeat: no-repeat;
width: 480px;
height: 360px;
}
document.getElementById("Div1").style.display='none';
document.getElementById("Div2").style.display='block';
The image gets removed from the resources tab when I execute the above javascript...but this effect is inconsistent and doesn't always work :s
Setting something to display: none does not remove anything from memory in any browser. The entire DOM element is still in the DOM occupying the same amount of memory, it is just marked hidden from view and layout.
If you want to actually remove an element from memory, then you need to physically remove it from the DOM, usually using parent.removeChild(child) AND make sure that there are no references to the DOM element anywhere in your javascript which would keep it from getting garbage collected.
Also, I don't know how you are assessing memory usage in your browser, but most methods will not accurately detect whether a browser has freed a given image or not because the memory may have been freed from an internal pool of memory (available for reuse), but not returned to the OS. Just releasing an image will not necessarily show a reduction in memory usage by the browser. What does show would be highly browser specific and even OS specific and would certainly depend upon exactly what tools you were using to examine memory usage.

Categories