Aprende a decir NO con CSS

26/12/2018
Artículo original

No te alarmes por el título de este post. Esto no va de mindfulness ni de autoayuda, y, por supuesto, no te vamos a tocar los chakras. Es simplemente un ejercicio de pensar un poquito diferente para mostrar lo amplio que es el abanico de posibilidades al definir selectores CSS.

Tampoco es que estemos inventando la pólvora, simplemente se trata de darte pistas para encontrar alternativas eficaces a la hora de resolver tus maquetaciones que quizá no te habías planteado.

Por ejemplo, podemos usar uno de los selectores avanzados de CSS3 que más de uno se suele olvidar de que existe: la pseudo-clase :not()

Cómo usar la pseudo-clase :not()

La pseudo-clase :not() de CSS3 nos ayuda a apuntar con nuestra regla hacia elementos que no coinciden con una lista de selectores. Se lo conoce como la pseudo-clase de negación porque se usa para evitar que se seleccionen elementos específicos. 

Por ejemplo, si tenemos en nuestra página ciertos de elementos (por ejemplo, artículos) y queremos ponerle un borde rojo a todos excepto a los que tienen la clase .loquesea, pues en vez de hacer esto:

article {
   border:5px solid red;
}

article.loquesea {
   border:0;
}

Podríamos usar esta otra regla, mucho más eficiente:

article:not(.loquesea) {
   border:5px solid red;
}

Hay que tener un poco de cuidado con esta pseudo-clase, porque es muy fácil crear un selector que no sirva de nada. Por ejemplo, :not(*) selecciona cualquier elemento que no sea un elemento. Así que, en este caso, obviamente, nunca se va aplicar.

Vale, este es un caso extremo, pero quédate con que es fácil que se te vaya la mano y excluyas más de lo necesario. Pero no te preocupes, con un poco de práctica es fácil evitar estas situaciones. Simplemente ten en cuenta esa posibilidad.

También podemos ponerlo solo, sin modificar a otro elemento. Si usamos :not(.loquesea) coincidirá con cualquier elemento que no tenga la clase .loquesea, incluidos <html> y <body>.

Soporte de :not() en navegadores

En su versión más avanzada (selectores de nivel 4, donde los argumentos son una lista de selectores) en el momento de escribir esto todavía no tiene buen soporte en los navegadores, pero sí tiene buen soporte en el nivel 3 (con un solo selector) que ya es muy útil.

De todas formas, si lo necesitas en navegadores antiguos como IE9 o inferiores, podrías tirar de  http://selectivizr.com/.

Usando :not() para detectar soporte de selectores CSS3

Otro uso curioso que se le puede dar a :not() es usarla como una especie de detector de soporte de selectores avanzados de CSS3. En este post hay un buen ejemplo. Lo he adaptado al español y lo he reformulado de forma que se vea mejor. Puedes descargar el ejemplo desde aquí. Este código tiene la misma licencia CC que el original.

Se parte de un formulario varias opciones en radio-buttons:

En la imagen se ven tres selectores de tipo radio, ninguno de ellos seleccionado

En el momento que se marca la tercera opción, se usa el truco de evaluar en CSS con :checked() si está marcado para así poder modificar otro elemento. En este caso, si está marcada la opción "Otra" se le muestra un input del tipo text para ampliar la información:

En esta imagen se ha seleccionado el último botón de radio, mostrándose automáticamente una interfaz relacionada


<form>
  <div class="opciones opcion1">
    <inputclass="opciones" id="opcion1" type="radio" name="opcion1" value="Opción 1">
    <label for="opcion1">Opción 1</label>
  </div>
  <div class="opciones opcion2">
    <inputclass="opciones" id="opcion2" type="radio" name="opcion2" value="Opción 2">
    <label for="opcion2">Opción 2</label>
  </div>

  <div class="opciones otra-opcion">
    <inputid="otra-opcion" type="radio" name="otra-opcion" value="Otra opción">
    <label for="otra-opcion">Otra</label>
      <div>
        <label for="especifica">Por favor, especifica:</label>
        <input id="especifica" name="especifica" type="text">
      </div>
  </div>

</form>

Con este CSS:

.opciones {
padding:5px;
}

.otra-opcion div {
margin:5px5px5px26px;
}

.otra-opcion div{
    display : none;
}

.otra-opcion input:checked + label + div{
    display : block;
}

En el caso de que un navegador no soporte :checked nunca se vería el formulario, pero podemos arreglarlo de forma sencilla con :not().

Si un navegador no soporta :checked tampoco va a soportar :not (ni ningún otro selector avanzado de CSS3) así que, en este caso se reformulan las reglas para que :not() esté involucrado. Esto es, sólo se ocultará el input (y luego se mostrará cuando corresponda) en funcion de :checked() si su ancestro NO tiene la clase "old". Como esta clase no la usa ningún elemento, se cumplirá siempre, así que el navegador siempre esconderá el input hasta que el radio button esté marcado.

Ahora bien, si el navegador no soporta :not(), nunca se ocultará el input, así que no habrá problema tampoco porque no soporte :checked.

.otra-opcion:not(old) div{
    display : none;
}
.otra-opcion:not(old) input:checked + label + div{
display : block;
}

Exclusiones sin :not()

A pesar de que la pseudo-clase :not es muy potente y con muchas aplicaciones, hay otras formas muy interesantes de discriminar elementos, como usar pseudo-clases que son similares entre sí, pero que se aplican de forma totalmente opuesta.

Quizá esto te suene extraño ahora mismo, pero me refiero a casos como el descrito en este artículo. En ese artículo, José Manuel Alarcón (autor y tutor del curso de HTML5 y CSS3 para desarrolladores, entre otros cursos de front end de campusMVP) se vale de :nth-child() y de :nth-last-child() combinados de tal forma que nos sirven para elegir a qué elementos de un listado aplicar ciertos estilos y a cuáles no.

Te recomiendo leer y practicar lo mismo que se hace en ese post con calma, porque es un ejercicio muy interesante.

Lo visto en este post es solo una pequeña muestra de lo que se puede hacer, pero espero que te haya picado la curiosidad lo suficiente como para querer aprender un poco más sobre cómo jugar con selectores avanzados, o, quién sabe, incluso para apuntarte a nuestro curso de HTML5 y CSS3.