JASoft.org

El blog de José Manuel Alarcón Aguín. Programación web y mucho más...

MENÚ - JASoft: JM Alarcón

La manera correcta de añadir y quitar clases CSS a elementos mediante JavaScript puro

Front-endSupongamos que tienes un elemento en tu página como este:

<div class="rojo">

que quieres localizar y cambiar la clase que tiene aplicada para que pase a ser "verde", o sea, equivalente a esto:

<div class="verde">

Nota: Dejemos de lado el hecho de que el nombre de la clase no es el más apropiado pues no es reutilizable y está atado al aspecto físico concreto. Este no es un artículo de buenas prácticas de CSS.

Para realizar ese cambio de clase, la gente que utiliza jQuery está muy acostumbrada a escribir código como este:

$('.rojo').removeClass("rojo").addClass("verde");

Este fragmento es muy sencillo y lo que hace es, primero localizar todos los elementos que tienen aplicada la clase "rojo", a éstos se la retira con removeClass y luego le añade la clase "verde" usando el método addClass de jQuery.

La verdad es que es muy fácil, pero ¿realmente merece la pena añadir una dependencia a jQuery (y todo su peso y procesamiento) a nuestra página para hacer algo tan sencillo?

La respuesta es que, desde luego solo para este tipo de cosas, no: no merece la pena.

Los navegadores actuales son capaces de hacer exactamente lo mismo con JavaScript puro sin necesidad de recurrir a bibliotecas externas, y además es casi igual de sencillo conseguirlo.

Vamos a ver cómo podemos lograr lo mismo sin jQuery, solo con lo que nos ofrece el navegador...

Localizar los elementos con una clase o clases aplicadas

Todos los navegadores modernos disponen del método getElementsByClassName. De hecho el único navegador que no lo soporta es Internet Explorer 8 o versiones más antiguas. Así que el soporte es casi universal.

Este método getElementsByClassName busca cualquier elemento descendiente del elemento al que se lo aplicas (no tiene por qué ser aplicado directamente a document, aunque es lo más común) que tenga aplicada la clase o clases que le indiques. Es decir, que si haces esto:

document.getElementsByClassName("rojo")

te encontrará el elemento anterior y todos los que tengan aplicada la clase con ese nombre dentro de la página actual. Es decir, es equivalente al $('.rojo')de jQuery.

Fíjate además en que la clase buscada no tiene que ser la única que está aplicada al elemento. Si tenemos este elemento:

<div class="rojo bordeNegro">

también lo encontrará porque tiene la clase 'rojo' aplicada además de otras.

Si en el argumento que le pasamos le indicamos más de una clase, por ejemplo así:

document.getElementsByClassName("bordeNegro rojo")

localizará los elementos que tengan todas estas clases aplicadas en cualquier orden (es decir, en este caso el elemento div anterior, aunque las tiene escritas al revés, claro).

La forma más básica de acceder y manipular las clases CSS de un elemento

Ahora que ya sabemos localizar elementos a partir de las clases CSS que tengan aplicadas, vamos a por lo segundo: manipular las clases que tienen aplicadas los elementos localizados.

La propiedad className que todo elemento del DOM posee, cambia el contenido del atributo class de dicho elemento, y está soportada incluso por versiones viejísimas de los navegadores.

Con esta propiedad para cambiar la clase "rojo" por "verde" podemos escribir por ejemplo:

var miElto = document.getElementsByClassName("rojo")[0];
miElto.className = "verde";

y el primer elemento localizado pasaría de color rojo a verde.

Sin embargo, esto presenta un grave problema: si el elemento tenía más clases aplicadas además de "rojo", las pierde. el motivo es que ahora le estamos asignando como única clase aplicada "verde".

O sea, asignar un valor a className es como asignárselo directamente al atributo class de un elemento HTML.

Eso solo lo podemos utilizar así si estamos seguros de que el elemento tiene una única clase aplicada, o si realmente lo que queremos hacer es dejarle un única clase aplicada.

Siempre podríamos usar expresiones regulares para analizar el contenido de esa propiedad y retirar y poner clases arbitrariamente. Pero eso es muy complicado y, ya puestos, es mucho mejor usar jQuery y no complicarnos la vida.-

La forma correcta de acceder y manipular las clases CSS de un elemento

Por suerte todos los navegadores modernos nos ofrecen una manera mucho más conveniente de manipular las clases de un elemento, y de hecho es muy parecida a la que ofrece Jquery.

Así, si necesitamos manipular las clases aplicadas a un elemento sin tener que preocuparnos por cosas como lo anterior disponemos de la propiedad classList de un elemento.

Esta propiedad nos ofrece varios métodos que nos permiten manipular las clases de un elemento de manera individual:

  • add: añade al elemento un nombre de clase o varios (se pasan separados por comas, como argumentos al método). Sería equivalente al método addClass de jQuery.
  • remove: le quita el nombre o nombres de clase que indiquemos. Equivalente al método removeClass de jQuery.
  • toggle: este es muy útil porque le quita o le pone el nombre de clase indicado dependiendo de si ya lo tiene o no. O sea, lo cambia: si ya lo tenía se lo quita y si no lo tenía se lo pone. Es equivalente al método toggleClass de jQuery
  • contains: devuelve true si el elemento tiene aplicado el nombre de clase que le indiquemos, siendo false en caso contrario. Muy útil. Es equivalente al método hasClass de jQuery.

Así, por ejemplo, si quisiésemos localizar todos los elementos de la página con la clase CSS llamada 'rojo' aplicada, quitársela y ponerle la clase 'verde' si no la tenían ya, el código necesario seria este:

var rojos = document.getElementsByClassName("rojo");
for (var i = 0; i<rojos.length; i++) {
   rojos[i].classList.remove("rojo");
   rojos[i].classList.add("verde");
}

No tan compacta como la versión de jQuery, ni con la facilidad "fluida" de encadenar llamadas de ésta, pero mucho más ligero al no depender de esta biblioteca, y también fácil de entender y escribir en unos segundos.

La única "pega" de esto es que classList no está soportado en versiones de Internet Explorer anteriores a la 10, o sea, por mucha gente aún hoy en día :-( Tampoco lo soporta Opera Mini para móviles.

Si dar soporte a estos navegadores antiguos es importante para nuestro proyecto, podemos utilizar un "shim" que nos de la funcionalidad mediante JavaScript si el navegador no la soporta.

Hay muchos por la Web adelante, pero este lo ha hecho la gente de la MDN (Mozilla Developer's Network) y va muy bien (aunque no funciona en versiones de IE más antiguas a la 7, pero vamos...).

¡Espero que te resulte útil!

José Manuel Alarcón José Manuel Alarcón
Fundador de campusMVP.es, el proyecto de referencia en formación on-line para programadores en lengua española. Autor de varios libros y cientos de artículos. Galardonado como MVP de Microsoft desde 2004. Gallego de Vigo, amante de la ciencia y la tecnología, la música y la lectura. Ayudando a la gente en Internet desde 1996.
Descarga GRATIS mi último libro (no técnico): "Tres Monos, Diez Minutos".
Banner

Comentarios (2) -

Marc Guerra

Hola, tengo el siguiente codigo con una parte muy parecida a la explicación pero por algun motivo cuando tengo dos cartas giradas y clico una tercera para que las dos anteriores se den la vuelta solo se me gira la primera de las clicadas. Alguna idea?

Gracias de antemano.


var cartas = [];
var cartasClicadas = [];
var cartasGiradas = [];
/*aqui cambio la classe del element amb id 'a_girar' per la classe 'clicked'*/
function cambiar_clase(){
  cartasClicadas.push(this);
  cartasGiradas = document.getElementsByClassName("flip-container clicked");
  alert("cartas:"+cartasGiradas.length);
  if(cartasGiradas.length==2){
    for (var i = 0; i <= (cartasGiradas.length)+2; i++) {
      alert("i:"+i);
      cartasGiradas[i].classList.remove("clicked");
      this.classList.add("clicked");
    }
  }else if(cartasGiradas.length < 2){
      this.classList.add("clicked");    
  }
}
/*aquesta funcio la utilitzo perque no s'executi la funcio de cambiar clase fins que s'hagi carregat tot l'html, per tal d'evitar possibles errors.
Afegeixo un event listener que al fer clic crida a la funcio 'cambiar_clase()'*/
function inicializar(){
  cartas = document.getElementsByClassName("flip-container");
  for(var i = 0; i < cartas.length; i++){
    document.getElementById("a_girar"+i).addEventListener( 'click', cambiar_clase);
    
  }
}

Responder

Muchas gracias, es justo la ayuda que necesitaba para resolver un ejercicio sin usar jQuery. Saludos.

Responder

Agregar comentario