martes, 15 de julio de 2014

Profundizando en CSS. Selectores

Llevo una temporada intentado retomar el diseño web para cubrir, por una parte, ciertas inquietudes profesionales, y por otra, una serie de trabajos, de esos sin remuneración, a los que "obligan" los consabidos lazos afectivos. En la parte más temprana de mi recorrido profesional hice algunas modestas webs, pero me quedé en la maquetación con frames y tablas. Lo de maquetar una página con etiquetas div es una chulada, pero me parece una temeridad sin una buenísima planificación de estilos, por eso las posibilidades que se me están revelando con CSS me llevan a pensar que un día podría llegar a ser el Harry Potter del diseño web (sic)... En fin, coñas a parte, hay por ahí auténticas virguerías hechas -sólo- con HTML y CSS, y merece la pena profundizar un poco más en sus posibilidades.

Hace ya algún tiempo publicamos en este blog una pequeña guía con algunos conceptos básicos de CSS. En ella se decía que la sintaxis general de CSS se componía de selectores y sus correspondientes declaraciones de estilos o bloques de estilo. Hoy vamos a profundizar en los selectores.


Los selectores básicamente determinan que elementos se van a ver afectados por las reglas de estilo que aparecerán a continuación (delimitadas por llaves "{}"). CSS 2.1 incluye como una docena de tipos de selectores diferentes. CSS 3 añade algunos más. La verdad es que puede llegar a ser una locura y además todavía existen algunos problemas de compatibilidad con ciertos navegadores (sobre todo con el estándar CSS3); sin embargo el uso experto de estos selectores permite trabajar de forma muy precisa con elementos individuales o conjuntos de elementos dentro de una página web.

Intentaré ser tan meticuloso como pueda (Aunque espero que no cansino...)

Selectores Básicos

Podemos hablar de tres selectores básicos: Elementos, Identificadores y Clases.

Elementos: Todos los elementos de una página web (léase etiquetas) son susceptibles de recibir un estilo, siempre y cuando esos elementos estén en el body del documento (o sean la propia etiqueta <body> o la etiqueta <html>). Su sintaxis es: elemento{estilos...}. Por ejemplo: 
     
html{
     color:#000;
     background-color:#fff;
     font-family:arial, sans-serif;
}

h1{
     font-weight:bold;
     font-size:15px;
     padding:0.4em;
}

Identificadores: El objetivo de estos selectores serían los elementos con un atributo id. Su sintaxis es: #mi_div_molon_id{estilos...}.  Si tenemos la siguiente definición de estilo y el fragmento HTML:
     
#mi_div_molon_id {
     font-size:90%;
     text-align:center; }

<div id="mi_div_molon_id">
     <p>El contenido que sea...</p>
</div>

El estilo definido se aplicará a cualquier elemento cuyo id coincida con el descrito. Se supone que esto está concebido para usarlo con un único elemento, identificado por su id, en una página. En teoría no podemos utilizar el mismo identificador para dos elementos de una misma página (para eso está el siguiente tipo de selector que veremos); sin embargo en la práctica podemos hacerlo. Y por supuesto podemos tener elementos con el mismo id en páginas distintas de un mismo proyecto web.

Clases: Podemos definir estilos que se aplicarán a los elementos del documento que tengan un atributo class con un valor determinado. Su sintaxis es: .mi_clase{estilos...}. Por ejemplo:

.main_style{
      color:#FFF;
      background-color:#000;
      font-family:arial, sans-serif;
      font-style:italic;
      padding:0.75em;
      border:1px dotted #000;
}

.error_text{
     color:red;
}

Bueno, ¿Y qué pasa con la precedencia? En caso de que una etiqueta HTML tenga un atributo id y una class, id tiene preferencia sobre class. Es decir si tenemos algo como esto:

<p id="texto_rojo" class="texto_azul">Hola, este es mi texto</p>

#texto_rojo { color: red } 
.texto_azul { color: blue }

El texto de nuestro párrafo se presentará rojo. Obviamente, si cada selector define estilos sobre aspectos diferentes, se podrán aplicar ambos:

<p id="texto_rojo" class="texto_grandote">Hola, este es mi texto</p>

#texto_rojo { color: red }
.texto_grandote { font-size:130px; }

El párrafo de nuestra página web mostraría ahora unas desproporcionadas letras en color rojo chillón (infalible si lo que quieres es dar la nota...).

Adicionalmente, los selectores básicos se pueden combinar y hacer cosas un poco más específicas, por ejemplo, p.texto_azul afectaría a los párrafos (y sólo a ellos) que tuvieran un atributo class con el valor "texto_azul"; div#mi_div_molon sólo afectaría al elemento cuyo id fuera "div_molon" y además fuera, efectivamente, un div... (es un ejemplo un poco chorra, pero bueno...).

Selectores Avanzados

Los selectores avanzados permiten acotar de manera muy precisa distintas partes de un documento. La mayoría de estos selectores avanzados pueden ser sustituidos mezclando y combinando los selectores básicos (lo que puede llegar a ser insufrible); pero como nosotros aspiramos al nirvana de las hojas de estilo, vamos a echarles un vistazo. Lo único malo que puede llegar a tener el uso avanzado de selectores es que precisa de un conocimiento bastante profundo de la estructura de los documentos y de las relaciones de parentesco entre sus elementos. La relación entre los nodos de un documento HTML o XHTML puede llegar a conformar todo un árbol genealógico, con sus padres, hijos, hermanos, descendientes, ancestros, primos y hasta el vecino del quinto... Aunque no es el objetivo de esta entrada, haré unas pequeñas aclaraciones para poder seguir con los selectores sin comernos demasiado la cabeza. Vamos a usar un pequeño bloque de código HTML para ilustrar la explicación:

<html> 
     <head>
          <title>Mi Página</title> 
     </head> 
     <body>
          <div id="contenido">
               <h1>Cabecera</h1>
               <p>Primer párrafo.</p>
               <p>Segundo párrafo.</p>
               <p><i>Tercer párrafo, en cursiva.</i></p>
               <p>Párrafo final, <a href="cualquier.html">con un vínculo</a>.</p>
          </div> 
          <div id="pie"> 
               <p>El copyright, por ejemplo...</p>
          </div>
     </body>
</html>

Aquí podemos ver unos elementos anidados dentro de otros. Los elementos anidados en el nivel inmediatamente inferior de un elemento son sus hijos (y éste a su vez es su padre). Dos elementos que comparten padre son hermanos. Por otro lado, los elementos anidados dentro de un elemento, que a su vez está anidado dentro de otro elemento se consideran descendientes de este último. Lo mismo que si partimos de un elemento, cada uno que lo contiene (en cualquier grado) ha de ser considerado su antecesor (o ancestro)... Dicho así es un puñetero lío, pero veamos el ejemplo:

Si nos fijamos en uno de los elementos más "hundidos" en la jerarquía, el elemento a (que es un link), veremos que su padre es el párrafo p en el que está anidado. Así mismo a es descendiente del div "contenido", de body y finalmente de html.

Visto desde otra perspectiva, el elemento div "contenido" es hijo de body y descendiente de html. También es hermano del div "pie". Es padre de h1 y de todos los p entre sus etiquetas de apertura y cierre (h1 y los p son a su vez hermanos). Y por supuesto además es ancestro de a... ¿Más claro así?¿No? Bueno, esté claro o no, todo esto hay que tenerlo presente para construir una buena hoja de estilos. A eso me refería con aquello que dije de que maquetar un sitio web puede ser una temeridad sin una buenísima planificación de estilos... Ahora volvamos a los selectores...

A grosso modo podemos referirnos a dos tipos de selectores avanzados: los que se basan en relaciones de parentesco entre los nodos del documento y los que se basan en la selección de elementos por medio de sus atributos. Vamos con los primeros:

Selección de descendientes. Los elementos se seleccionan a través de la secuencia de nodos que seguimos hasta alcanzar el objetivo al que se aplicará en estilo. Su sintaxis es: elemento elemento ...{estilos...}. Por ejemplo:

#div_contenido p{
      font-size:15px;
}

En este caso el estilo sólo se aplicaría a los párrafos que fueran descendientes de un elemento (un div por ejemplo) cuyo id fuera "div_contenido".

Selección de hijos. Su sintaxis es: elemento1>elemento2{estilos...}

#div_contenido>p{
      font-size:15px;
}

Ahora el estilo se aplicaría a los párrafos p que fueran hijos del div "div_contenido", pero no a los posibles hijos de párrafos (u otros elementos) anidados en él.

Selección de hermanos adyacentes. Su sintaxis es: elemento1+elemento2{estilos...}. Este selector selecciona el elemento2 que es hermano de elemento1, y además es adyacente a él. Por ejemplo, veamos el estilo y el fragmento HTML siguientes:

h1+h2 {
      font-size:18px;
}

<body>
     <h1>...</h1>
     <h2>...</h2>
     <p>...</p>
     <div>
           <h2>...</h2>
     </div>
<h2>...</h2>
</body>

El estilo de fuente declarado sólo afectará al primer h2, que es el único hermano de h1 que es adyacente a él en el código HTML. 

Selección general de elementos hermanos. Su sintaxis es: elemento1~elemento2{estilos...}. Este selector llega con CSS3 y amplía el anterior, ya que permite seleccionar todos los elementos hermanos -de un tipo- para un elemento dado. Así, si tomamos una variante del ejemplo anterior:

h1~h2 {
      font-size:18px;
}

<body>
     <h1>...</h1>
     <h2>...</h2>
     <p>...</p>
     <div>
           <h2>...</h2>
     </div>
<h2>...</h2>
</body>

Ahora el estilo se aplicaría a todos los h2 hermanos de h1, esto es, la primera y la tercera etiquetas <h2> recibirían el estilo (ambas son hijas de body). Sin embargo no recibía el estilo el h2 anidado en el div, ya que no es hermano de los otros dos (sólo son primos lejanos... :P).

Hablemos ahora un poco de selectores que se basan en la selección por atributo. Podemos destacar varios métodos: 

Selección de elementos por atributo. Se puede seleccionar un elemento concreto que tenga un atributo concreto. Sintaxis: elemento[atributo]{estilos...}.

div[title]{
    font-family:arial, sans-serif;
}

Sólo se aplicaría a los div que tuvieran un atributo title (sea cual sea el valor de este atributo).

Selección de elementos por atributo y valor. Igual que el anterior, pero además el atributo especificado debe tener un valor concreto: 

div[title="Noticias"]{
   font-family:arial, sans-serif;
}

Sólo los div cuyo atributo title fuera "Noticias" recibirían el estilo especificado.

En el estándar CSS3 se añaden tres nuevos selectores de atributos:

Selección de elementos por fragmento inicial del valor de un atributo. Su sintaxis es: elemento[atributo^="cadena"]{estilos...}. Se seleccionan todos los elementos que disponen de ese atributo y cuyo valor comienza exactamente por la cadena de texto indicada. Por ejemplo:

div[title^="Noticias"]{
    font-family:arial, sans-serif;
}

Se aplicaría el estilo a todos los elementos div cuyo atributo title comenzase exactamente por la cadena "Noticias". 

Selección de elementos por fragmento final del valor de un atributo. Su sintaxis es: elemento[atributo$="cadena"]{estilos...}. Igual que el anterior salvo que en este caso se buscaría coincidencia de la cadena de caracteres en la parte final del valor de atributo. 

Selección de elemento por fragmento contenido en valor de atributo. Sintaxis: elemento[atributo*="cadena"]{estilos...}. En este último caso sería suficiente que "cadena" estuviera contenida en el valor del atributo. 

Para terminar merece la pena dedicarle unas líneas a los pseudoselectores. Estas cosas, con un nombre tan chulo, no funcionan como los selectores descritos hasta ahora. Los pseudoselectores no actúan sobre elementos del lenguaje de marcado, sus aplicación depende del contexto, de estados y aspectos que no pueden ser marcados en el documento (como por ejemplo determinadas interacciones del usuario con la página). CSS 3 mantiene (y amplia) los pseudoselectores de CSS 2.1, aunque cambia su sintaxis, ahora se usa "::" en lugar de ":" (aunque se mantiene la sintaxis antigua por compatibilidad). Los pseudoselectores pueden clasificarse en Pseudoelementos y Pseudoclases. Veamos algunos de ellos. 

Pseudoelementos

Su sintaxis -en CSS 2.1- es: elemento:pseudoelemento{estilos...} (:: si es CSS3). Sólo pueden añadirse al último ítem simple del selector y además únicamente se pueden aplicar a elementos que contengan texto. Son los siguientes (como somos personas modernas y estamos a la última los ponemos con sintaxis de CSS3...):

::first-line. Selecciona la primera línea del texto de un elemento.

div::first-line {
     font-family:arial, sans-serif;
     font-size:18px;
}

::first-letter. Selecciona la primera letra del texto de un elemento.

div::first-letter {
      font-size:30px;
      letter-spacing:2px;
      text-decoration:underline;
}

::before. Selecciona la parte anterior al contenido de un elemento para insertar nuevo contenido.

h1::before { content: "Capítulo - "; }
::after. Selecciona la parte posterior al contenido de un elemento para insertar nuevo contenido.

p::after { content: "."; }
Hay algún otro como ::selection (propuesto en CSS3), que aplica las reglas al texto que ha seleccionado un usuario con el ratón o el teclado. Pero actualmente no está incluido en los estándares y no se recomienda su uso (probablemente es soportado por pocos navegadores). 

Pseudoclases 

Aquí es donde probablemente podamos empezar a perder la cordura. CSS 2.1 contaba con poco más de media docena de pseudoclases y CSS3 propone un montón más. Su sintaxis es: elemento:pseudoclase{estilos...} (con :: si es CSS3). La diferencia con los pseudoelementos es que pueden usarse con cualquier ítem de un selector. Vamos a hacer un breve recorrido por ellos (empezando por los de CSS 2.1): 

::link. Se aplica a hipervínculos y hace referencia al estado de un vínculo que aún no se ha visitado. 

::visited. Igual que el anterior, pero se refiere al estado de vínculo ya visitado. 

::hover. Vale para cualquier elemento. El estilo se aplica cuando el usuario sitúa el puntero del ratón sobre el elemento. Si queremos que esta pseudoclase funcione correctamente al aplicarla a los elemento de tipo vínculo (a::hover), tenemos que ponerla delante de los elementos a::link y a::visited en la definición de la hoja de estilos. 

::active. También válido para cualquier elemento, hace referencia al estado cuando un usuario hace clic sobre él. 

::focus. Vale para cualquier elemento. En este caso el elemento debe tener el foco. 

::first-child. Se puede aplicar a cualquier elemento, y se refiere al primer hijo del mismo. 

::lang. Permite definir reglas de estilo diferentes dependiendo del lenguaje.

Algunos de los que ofrece CSS3... 

 ::nth-child(número). Selecciona el elemento indicado pero con la condición de que sea el hijo enésimo de su padre. 

::nth-last-child(número). Igual al anterior, pero el número indicado se empieza a contar desde el último hijo. 

 ::empty. Selecciona el elemento indicado siempre y cuando no tenga ningún hijo. Esto implica que tampoco puede tener ningún contenido de texto. 

::first-child y ::last-child. Seleccionan los elementos indicados pero con la condición de que sean respectivamente los primeros o últimos hijos de su elemento padre. 

::nth-of-type(número). Selecciona el elemento indicado pero con la condición de que sea el enésimo elemento hermano de ese tipo.

::nth-last-of-type(número). Igual que el anterior, pero el número indicado se empieza a contar desde el último hijo.

::first-of-type y ::last-of-type. Se seleccionan los elementos indicados pero con la condición de que sean respectivamente el primer o el último nodo hijo que aparece con su tipo de selector en su elemento padre.

::only-child. El elemento que recibe el estilo debe ser hijo único

::only-of-type. El elemento seleccionado tiene un selector único entre sus hermanos. 

::root. Selecciona al elemento principal de un documento. 

::target. Hace referencia al objetivo de un enlace. 

::enabled y ::disabled. Se seleccionan los elementos si están respectivamente activos o inactivos.

::checked. Hace referencia al estado de elementos de tipo checkbox o radio buttons. 

Cabe mencionar que las pseudoclases que admiten un parámetro "número" permiten el uso de expresiones numéricas complejas para realizar selecciones más avanzadas. Así por ejemplo, reglas como la siguiente permitirían alternar cuatro estilos diferentes para los párrafos:

p:nth-child(4n+1) {
     font-size:18px;
     color:blue;  
}
p:nth-child(4n+2) {
     font-size:15px;
     color:lightblue;   
}
p:nth-child(4n+3) {
     font-size:12px;
     color:green;   
}
p:nth-child(4n+4) {
     font-size:9px;
     color:lightgreen;  
}

En fin, como veis puede llegar a ser una verdadera locura. Si a esto le añadimos los problemas de compatibilidad que todavía existen con algunos navegadores, o las posibilidades -enormes- que ofrecen los diferentes selectores y pseudoselectores para combinarse entre ellos y dar lugar a reglas de estilo de lo más bizarras, la verdad es que puede apetecerte saltar desde un puente ante la perspectiva de crear una hoja de estilos desde cero... Afortunadamente existen multitud de sitios donde obtener plantillas bien estructuradas que nos permiten tener una web bastante maqueada con mucho menos esfuerzo.

En cualquier caso, para más y mejor información de primerísima mano ya sabéis, siempre está el consorcio.

No hay comentarios:

Publicar un comentario