Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript: Advantages and disadvantages of dynamically (on fly) creating style element

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.

like image 665
Khamidulla Avatar asked Jan 08 '14 01:01

Khamidulla


People also ask

What are the advantages of CSS-in-JS?

CSS-in-JS makes it so you don't have to name things so carefully. You can still use names if you want, but because of the component-level scope, you can name things willy-nilly without fear of style collisions. It's possible to use names like “button” or “heading” in multiple files and nothing will break on the page.

Which of the following is a disadvantage of using JavaScript?

Q 5 - Which of the following is a disadvantage of using JavaScript? A - Client-side JavaScript does not allow the reading or writing of files.


2 Answers

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.

like image 130
Niels Keurentjes Avatar answered Oct 03 '22 08:10

Niels Keurentjes


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.

like image 35
Halcyon Avatar answered Oct 01 '22 08:10

Halcyon