Thinking in programming

Things I like to talk about programming

Archive for June 2010

Deepening at CSS selectors

leave a comment »

It is always good to ask ourselves if the code we write can be improved in some way – is it possible to improve the quality and/or its performance?. In this case, I’m going deepen a bit in the way the browsers read the CSS “code”.

Web browsers use a engine in charge of the process of rendering the DOM elements. For each element, the engine looks at which CSS styles should be applied to it (according to the CSS rules matching it.) Each rule is evaluated by parts, from right to left (yes, in reverse). Starting from the one located on the far right (called the “key”, because it indicates which elements should be chosen) and sequentially moves through each part until it reach the one located at the far left, or alternatively, until the rule is discarded for that item (if it is concluded that there is no match).

Under the previous system, the fewer rules have to evaluate the engine and the more specific are these rules, it will be better (in terms of performance).

CSS Selectors are classified accordingly to their efficiency in the following groups (in order from most to least efficient):

  1. #element_id (selector by ID) The ID are uniques by definition, so, this is the fastest rule.
  2. .main_menu (selector by class)
  3. span (selector by tag)
  4. Universal Rules – All the others rules, goes inside this category

For example:

<ul id="”ul_id”" class="”ul-class”">
  <li id="”li_id”" class="”li-class”">
    <span id="”span_id”" class="”span-class”"></span>
  </li>
  <li>
    <p></p>
  </li>
</ul>

Supposing it is desired to put in red-color the text inside the span tag, then some possible selectors are the following (from the most to the least efficient):

/* Usin this selector, the browser will look element by element until it finds one with this ID */
#span_id {
  color: #ff0033;
}

/* In this case, it will look in all elements and it will select the ones having this class */
.span-class {
  color: #ff0033;
}

/* Here, it will look in all elements and it will select the span tags */
span  {
  color: #ff0033;
}

/* This time it will look in all the elements and it will pre-select the ones having this class, following that, it will inspect the parent of each pre-selected element and then filtering the elements being childrens of an element having this ID */
#li_id > .span-class {
  color: #ff0033;
}

/* Using the following selector, it will look in all the elements and it will pre-select the ones having this class, following that, it will inspect the ancestors of each pre-selected element and then it will filter the descendant elements of one element having this ID */
#li_id .span-class {
  color: #ff0033;
}

Conclusion:

  1. #element_id (selector by ID)
    Uses the element’s ID always possible.
  2. ul#main_menu (selector by tag and ID)
    Do NOT add a tag or any other selector as the prefix of a class if it is not necessary, such thing would only adds redundant information which would be also evaludated, slowing down the process.
  3. .main_menu > li (child selector)
    Child selectors are inefficient, because of, by each element matching the criteria indicated by the key, the browser must evaluate the parent of this, which results in a double expensive process. At less specified is the key, greater will be the number of nodes to be evaluated. It should be clarified that, in terms of performance, it is still preferable to use child-selectors instead of descendant-selectors.
  4. .main_menu li (descendant selector)
    Descendant selectors are very inneficients because of, by each element matching the criteria indicated by the key, evaluating each one of its ancestors through the DOM tree until it found a matching or until it reaches the root element. Again, at least specified is the key, the number of nodes to be evaluated will be greater.
  5. At last but not at least, it is necessary to keep in mind that there should be a balance between readibility and performance. In short, it is generally preferable to sacrifice a bit of speed in favor of readibility and manteanibility of the code. At the same way, it is good to keep present that a mobil phone will not interpret a web page with the same speed than a desktop computer

You can find the Spanish version of this article here.

References:
Mozilla – Writing efficient CSS
Google – Optimize browser rendering

Advertisements

Written by roger.padilla

June 2, 2010 at 22:27

Profundizando en los Selectores CSS

with one comment

Siempre es bueno preguntarse si el código que se escribe puede ser mejorado de alguna forma – Es posible improvisar su calidad y/o rapidez de ejecución?. En este caso voy a profundizar un poco en la forma en la que los navegadores leen el “código” CSS.

Los navegadores web utilizan un sistema encargado del proceso de pintado de los elementos del DOM. Para cada elemento, el sistema examina cuales estilos CSS deben ser aplicados al mismo (según las reglas CSS que coincidan con él). Cada regla es evaluada por partes, de derecha a izquierda (así es, en reversa). Se comienza desde la parte ubicada en el extremo derecho (llamada “llave” porque es la que señala que elementos se deben escoger) y consecutivamente se va moviendo por cada parte hasta llegar a la ubicada en el extremo izquierdo, o en su defecto, hasta que la regla sea descartada para ese elemento (si se concluye que no hay coincidencia).

De acuerdo al anterior sistema, entre menos reglas tenga que evaluar el motor y entre más especificas sean dichas reglas, será mejor (en términos de velocidad).

Los Selectores CSS, se clasifican según su eficiencia, en los siguientes grupos (ordenados del más al menos eficiente):

  1. #el_id_del_elemento (selector por ID) Los ID son únicos por definición, por consiguiente, esta es la regla más rápida.
  2. .menu-principal (selector por clase)
  3. span (selector por etiqueta)
  4. Reglas Universales – Todas las demás reglas clasifican en esta categoría

Para el ejemplo:

<ul id="”id_del_ul”" class="”clase-del-ul”">
  <li id="”id_del_li”" class="”clase-del-li”">
    <span id="”id_del_span”" class="”clase-del-span”"></span>
  </li>
  <li>
    <p></p>
  </li>
</ul>

Suponiendo que se desea poner en color rojo el texto dentro de la etiqueta span, algunos potenciales selectores serian los siguientes (del más veloz al más lento):

/* Usando esta regla, el navegador buscará elemento por elemento hasta que encuentre uno con este ID */
#id_del_span {
  color: #ff0033;
}

/* En este caso, buscará entre todos los elementos y aplicará los estilos a los que posean esta clase */
.clase-del-span  {
  color: #ff0033;
}

/* Aqui, buscará entre todos los elementos y aplicará los estilos a los de tipo span */
span  {
  color: #ff0033;
}

/* En este caso, buscará entre todos los elementos, pre-seleccionará los que tengan esta clase, seguidamente examinará el padre de cada elemento pre-seleccionado y al final filtrará  los que sean hijos de un elemento cuyo ID sea el especificado */
#id_del_li > .clase-del-span  {
  color: #ff0033;
}

/* Usando el siguiente selector, buscará entre todos los elementos, pre-seleccionará los que tengan esta clase, seguidamente examinará los ancestros de cada elemento pre-seleccionado y al final filtrará los que sean descendientes de un elemento cuyo ID sea el ID especificado */
#id_del_li .clase-del-span  {
  color: #ff0033;
}

Conclusión:

  1. #el_id_de_un_elemento (selector por ID)
    Utilizar el ID del elemento siempre que sea posible.
  2. ul#menu_principal (selector por etiqueta e ID)
    No anteponer una etiqueta o una clase como clasificadores a un ID. Esto solo agrega información redundante que necesita ser evaluada innecesariamente, por lo tanto, ralentiza el proceso.
  3. .menu-principal > li (selector hijo)
    Los selectores hijos son ineficientes porque, por cada elemento que coincida con el criterio indicado en la llave, el navegador debe evaluar el padre de este. Lo cual se convierte en un proceso doblemente costoso por cada selector hijo en la regla. Entre menos especifica sea la llave, mayor será el número de nodos a evaluar. Cabe aclarar que, en términos de velocidad, es preferible utilizar selectores hijos en vez de selectores descendientes.
  4. .main_menu li (selector descendiente)
    Los selectores descendientes son generalmente, muy ineficientes porque, por cada elemento que coincida con el criterio indicado en la llave, el navegador debe recorrer el árbol DOM, evaluando cada elemento ancestro hasta que se encuentre una coincidencia o hasta llegar al elemento raíz. Nuevamente, entre menos especifica sea la llave, mayor será el número de nodos a evaluar.
  5. Por último, pero no menos importante, hay que tener presente que debe haber un equilibrio entre legibilidad del código y la optimización del mismo. En general, es preferible sacrificar un poco de velocidad en pro de legibilidad y mantenibilidad del código. Así mismo, se debe tener claro que un teléfono móvil no interpretará una pagina web con la misma rapidez que un computador de escritorio.

La versión en Ingles de este articulo se puede encontrar aqui

Referencias:
Mozilla – Writing efficient CSS
Google – Optimize browser rendering

Written by roger.padilla

June 2, 2010 at 22:27