In order to keep my mobile web app lean and efficient, I'm trying to limit the number of elements on the DOM at any given time. One way in which I intend to limit the use of DOM elements, is by using the pseudo :before
and :after
elements to generate content where possible.
For example, rather than representing a list-item with metadata like this:
<dd class="item"> <div class="name">Name</div> <div class="desc">Description</div> <div class="location">Location</div> <div class="genre">Genre</div> </dd>
I could represent it like this (& use the content:
property to display the metadata):
<dd class="child" data-name="Name" data-desc="Description" data-location="Location" data-genre="Genre"> </dd>
So, one DOM element with data attributes as opposed to 5 separate elements and arguably cleaner markup.
Demo here: http://jsfiddle.net/quc8b/2/
Will this technique actually improve performance? My thought is that with fewer DOM elements javascript should parse faster and I should be able to add/remove the list-item nodes faster. But will rendering (i.e. painting, layout, & reflows) occur faster? In other words, is CSS generated content rendered/parsed faster or more efficiently than traditional elements and text nodes?
How browsers internally handle CSS generated content in the render tree and document tree is an unknown to me (shadow DOM maybe?). Are there any articles that discuss this?
A CSS pseudo-element is used to style specified parts of an element. For example, it can be used to: Style the first letter, or line, of an element. Insert content before, or after, the content of an element.
A CSS pseudo-element is a keyword added to a selector that lets you style a specific part of the selected element(s). For example, ::first-line can be used to change the font of the first line of a paragraph. /* The first line of every <p> element. */ p::first-line { color: blue; text-transform: uppercase; }
The content CSS property replaces an element with a generated value. Objects inserted using the content property are anonymous replaced elements.
The ::before selector inserts something before the content of each selected element(s). Use the content property to specify the content to insert. Use the ::after selector to insert something after the content.
I was also interested in figuring this out. So I did a simple litte test case.
I created two html pages for comparison:
A. Pseudo-selectors:
HTML: 50.000 of these: <p>paragraph</p>
CSS: p:before { display: inline-block; width: 10px; height: 10px; margin-right: 5px; background-color: red; content: ""; }
B. Many DOM-elements:
HTML: 50.000 of these: <p><span class="icon"></span> paragraph</p>
CSS: .icon { display: inline-block; width: 10px; height: 10px; margin-right: 5px; background-color: red; }
I used the Chrome Devtools Performance monitor running on a 2015 Macbook Pro.
Option B was the loser by ~400ms. It took 2452ms to parse while the "pseudo" variant took 2033ms. I ran this test three times with similar results.
To measure re-layout I started a separate recording where I resized the browser window 3 times by changing from full-screen to half-screen (using shortcut keys in a window manager)
"Many DOM-elements" was the winner, clocking in at 1136ms of rendering time, while "pseudo-elements" took 1463ms.
I tried to cause reflows by measuring the page height using this piece of Javascript: document.body.offsetHeight;
But that never took more than 4ms to execute... not enough time to reliably measure performance.
Apparently 50.000 elements isn't enough to cause any significant slowdown in that area.
PS: The test selection wasn't all that scientific, they just happened to be the first ones I thought of
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With