10

In JavaScript we can create <style> element dynamically and append to <head> section in order to apply CSS rule for huge number of elements.

  1. What is advantages or disadvantages of this approach?

  2. If it is really gives performance gain comparing to javascript iteration over elements. What goes behind the scene (inside of browser)?

  3. Which one is faster or slower? Javascript iteration over elements or adding css dynamically in browser?

  4. What about processing time? processing load?

For better understanding the issue where I used this approach see following example:

Example: If I have table with 20 or more columns and 1000 rows or more as following html:

<table border="1" class='no-filter'>
    <thead>
        <tr>
            <th data-title='id'>Id</th>
            <th data-title='name'>Name</th>
            <th data-title='family_name'>Family Name</th>
            <th data-title='ssn'>SSN</th>
            //Other table data
        </tr>
    </thead>
    <tbody>
        <tr data-id='1' data-name='nick' data-famil_name='jackson' data-ssn='123456'>
            <td class="column column1">1</td>
            <td class="column column2">Nick</td>
            <td class="column column3">Jackson</td>
            <td class="column column4">123456</td>
            //Other table data
        </tr>
        //Other rows
        <tr data-id='809' data-name='helga' data-famil_name='jhonson' data-ssn='125648'>
            <td class="column column1">809</td>
            <td class="column column2">Helga</td>
            <td class="column column3">Jhonson</td>
            <td class="column column4">125648</td>
            //Other table data
        </tr>
        //Other rows
        <tr data-id='1001' data-name='nick' data-famil_name='jhonson' data-ssn='216458'>
            <td class="column column1">1001</td>
            <td class="column column2">Nick</td>
            <td class="column column3">Jhonson</td>
            <td class="column column4">216458</td>
            //Other table data
        </tr>
        //Other rows
    </tbody>
</table>

If somebody needs jsFiddle example I can create one later.

Case 1: If i want to dynamically hide only table column which contain SSN data. I can apply several approach to do this. This approach can be divided into two major category. In first category solutions I can iterate over td elements and dynamically change the style for the column. In second approach I can apply CSS by dynamically creating oneor use predefined CSS rules as given here by @Frits van Campen. (Note: @Frits van Campen is good solution for given case. But I want to discuss further more then manipulating table row showing and hiding.)

I can create dynamic CSS rule as following:

td:nth-child(3)
{
  display:none;
}

Or apply predefined CSS rule:

table.no-filter td.column3
{
   display:block;
}
table.filter3 td.column3 
{ 
   display: none; 
}

Here are jsFiddly examples:

  1. Iteration
  2. CSS on fly

Here is time comparison using console.time method which I found here. enter image description here

Left is dynamic css and right is iteration approach.

Perhaps, it is not appropriate one because it calculates appending style element vs iterating over elements. All iteration over element in dynamic CSS will be done by browsers internals. However if we think our script response time dynamic css is faster. Note: iteration approach will be faster in pure JavaScript comparing to jQuery. But how much faster i do not have results. So you can more in your answers.

Case 2: Now, I want to highlight table row <tr> which contains user with name 'Nick'. Here you can note that table row has data attributes like name, family_name, id and etc. So, here again I can iterate over elements using javascript or any other library tools or can apply some dynamic rule (I do not know whether it is possible or not apply predefined filters as in case 1.)

CSS rule:

tr[data-name ~='nick']
{
    background-color:red;
}

In this case I can do a lot of fun filtering by applying CSS rule dynamically.

Update: Example given here is for simple overview of the problem. And some optimized iterations can perform equally fast in javascript. However I consider only table which does not have dipper child elements comparatively nested ul elements where traversing in order to select element can be difficult.

Important: I only give tabel example here to make clarification with what kind of issue I faced if it is irrelevant feel free to edit the question and delete this part. Also please state your answers clearly in scope of question. Here I am not asking about 'Did I implemented in good way or not?' I am asking what is of advantages or disadvantages of dynamically creating style elements has in terms of browser internal mechanisms.

P.S. and example: Why I came with this idea? I answer recently for 'How to hide columns in very long html table' question. In this question OP asks about applying CSS rule for certain table columns in long table. I suggest to create style element with rules on fly and it works fine. I think this is because style applied by browsers internal mechanisms and gives better performance than iterating through elements and applying style to each item.

Community
  • 1
  • 1
Khamidulla
  • 2,927
  • 6
  • 35
  • 59
  • 1
    I do not understand somebody want to close the question why? Does it have some problems? – Khamidulla Jan 08 '14 at 01:48
  • SO's Q&A nature usually doesn't make it a really good fit for heavily opinion-based posts like this. Methinks it's within bounds, someone else apparently doesn't. – Niels Keurentjes Jan 08 '14 at 01:52
  • 1
    @NielsKeurentjes I think it is not opinion based question because I am clearly stating that advantages or disadvantages using on fly creation of style element in terms of technical and internal mechanisms of web browser. It is not like I like this approach and I am using kind of question. I really want to know why iterating over elments using javascript is gives less performance than creating css rule with css selector and applying it to elements? – Khamidulla Jan 08 '14 at 01:56
  • Don't tell me, I didn't vote for close and even answered :) – Niels Keurentjes Jan 08 '14 at 01:58
  • 1
    It's really hard to follow your question -- Blockquotes are meant for quoting other people, not for adding emphasis to your own post. Also, the code you're referring to should really be an SSCCE and be in this question; not just commenting on another question. – George Stocker Jan 08 '14 at 02:23
  • @GeorgeStocker Sorry I will update my question later today. – Khamidulla Jan 08 '14 at 02:34

3 Answers3

4

Apart from some scoping issues (there might be more tables on the page...) there is nothing inherently wrong with this approach - the style elements are there in the DOM to be edited as you see fit, the browsers are following standards by respecting it. In your test case, there's not really a valid other approach since indeed colgroup has extremely messy support - there are 78 duplicate bugs on the subject in Bugzilla, and Mozilla has been refusing to implement it properly since the first related bug report in 1998.

The reason it's faster is simply one of overhead - once the complete DOM is assembled a relatively minor stylesheet can be applied in native C++ much faster than a Javascript interpreter can ever loop over all rows and cells. This is because historically CSS rules are applied in reverse, and the browser keeps a dictionary inside quickly allowing it to find all td elements. Native C++ will always beat more complex interpreter-based code.

In the future, the scoping issue can also be resolved with scoped styles (currently only in FF, rather typical), you'd be coding like this:

<table>
  <style id="myTableStyle" scoped>
    td:nth-child(1) { display:none }
  </style>
  <tbody>
     ...
  </tbody>
</table>

The scoped attribute makes the contained styles only valid for its containing element, the table in this case, and of course all its contained elements. And since you can access it by ID the contents are easily replaced/reconstructed.

While this would be preferable to your approach, as long as there's no universal browser support for this creating style elements in the head is the best workaround.

Niels Keurentjes
  • 41,402
  • 9
  • 98
  • 136
  • Thank you for your answering. Can you give some more information about internals of browser if you know about this? – Khamidulla Jan 08 '14 at 02:02
  • See second paragraph. – Niels Keurentjes Jan 08 '14 at 02:03
  • Thank you for your answer. However I need more information about browser internals and with some reference information or documentation if it is possible. Sorry If I does not clearly state my question in first attempt. :( +1 for 2nd paragraph. – Khamidulla Jan 08 '14 at 02:19
4

Dynamically generating CSS is bad. Don't do it.

A solution that works by generating dynamic CSS can converted to a solution that doesn't require dynamic CSS.

If you need an example, see my answer here: jQuery to update actual CSS


To respond directly about the case you linked:

This seems like a very strange use-case to me. A page that has a table with 1000 rows is already a bad starting position. You can't reasonably fit 1000 rows on your screen and expect any kind of useful interaction. CSS is not the problem here. If the table were smaller the performance concerns disappear.

There are possibly other approaches than the on OP suggests. You don't need to (dynamically) add a class to each cell, you can put the class there on generation time, like:

<table class="no-filter">
...
  <td class="filter1 filter2"></td>
...
</table>

Then have something like:

table.filter1 td.filter2 { display: none; }
table.filter2 td.filter1 { display: none; }

You only change the class on the table to say which filter applies.

CSS is more than just a hammer, it's a whole tool-set of very refined and very powerful tools. Make sure you use the right ones.


The advantages of having static CSS should be self-apparent:

  • Much easier to understand, test, debug and maintain.
  • The CSS is actually in CSS (not in JavaScript).
  • You can do templating, maybe add some visual regression tests.

There are also some performance concerns. I can see browser vendors optimizing AGAINST dynamic CSS. By this I mean if there is an optimization for static CSS that reduces performance of dynamic CSS you just might make this tradeoff.

Community
  • 1
  • 1
Halcyon
  • 57,230
  • 10
  • 89
  • 128
  • To @FirtsVanCampen how about google excel kind of application. In this web app you can create long list or elements. How they approach with things, with such huge number of elements? Does they create static rules for dynamic behavior of people? – Khamidulla Jan 08 '14 at 02:28
  • 1
    If you have a clear-cut use case I can respond to it. If you only have some vauge idea of something that might not work then at best I can give you a vague answer. – Halcyon Jan 08 '14 at 02:31
  • An Excel like app (don't have Google Apps myself) will most likely just keep one full-window table open and populate the contents from JSON-returning Ajax calls. That's how I would build it, and actually how I built all my dynamically filtering/sortable/paged/etc tables to date. I agree with @FritsvanCampen that sending too much HTML to begin with is never a good idea, but for simple pages I understand why you would still do it. – Niels Keurentjes Jan 08 '14 at 02:43
  • @FritsvanCampen can you clarify more on this part 'I can see browser vendors optimizing AGAINST dynamic CSS.'? – Khamidulla Jan 08 '14 at 05:45
  • 1
    The only issue is that if you have more than a few filters you quickly hit the point where you are generating a *lot* of CSS. Even if you change your example to be hiding and showing entire `tr`s, when you have 12 filters you have `12 * 11` selectors for a grand total of 131 selectors ... and that's assuming that you cannot apply multiple filters to the table. If any combination of the 12 is possible, it's a whopping 4,095 selectors to generate to target all the potential combinations of `table.filter1.filter3.filterN` (and that's assuming you also hide everything by default or use `:not`). – Sean Vieira Jan 08 '14 at 06:29
  • That's quite an extreme and pessimistic viewpoint. Essentially what you're doing here is building an index. If you have experience with relational database you'll know their performance characteristics. You're trading CPU for memory. You could make an argument for generating this index in CSS from a sparser definition; but it's important to see that this can be done beforehand. You don't need to generate it in JavaScript (of the fly); which supports my argument that you don't need dynamically generated CSS. – Halcyon Jan 08 '14 at 13:36
-1

There's a library called less.js which lets you manipulate css with variables in in your.css file.It's a very good library and you might want to take a look into that. http://www.lesscss.org/

Swaraj Chhatre
  • 627
  • 1
  • 10
  • 22