jueves, 22 de septiembre de 2022

👨‍💻 Herencia de propiedades de estilo



Hay ciertos detalles que hay que tener claros antes de empezar a profundizar en CSS. El concepto de herencia y el de cascada (que veremos más adelante) son dos de las características CSS más infravaloradas y que más problemas suelen producir, ya que sin lugar a dudas son los que menos se conocen y los que mayor frustración acarrean porque se utilizan indebidamente.


Pero ¿Qué es la herencia CSS? ¿Qué propiedades se pueden heredar y cuáles no?

Una lista completa de propiedades heredadas

Valores especiales de herencia

La importancia de la herencia en CSS

Cómo forzar la herencia de las propiedades

Cómo forzar a las propiedades para que no sean heredadas

Otras palabras clave para la herencia en CSS

Conclusión

Bibliografía

En este post veremos que el conjunto de etiquetas HTML forman en sí un árbol que en su raiz podemos identificar la etiqueta body de la cual se desprenden otras etiquetas contenidas en esta sección, como podrían ser las etiquetas h1,h2,h3,h4,h5,h6,p,div luego estas en su interior contienen otras etiquetas HTML como podrían ser em,b,i,pre etc.

Veremos con ejemplos que hay muchos estilos que se heredan, es decir si definimos la propiedad color para la etiqueta h1, luego si dicha etiqueta incorpora un texto con la etiqueta b (bold) en su interior, la propiedad color de la etiqueta b tendrá el mismo valor que la propiedad h1 (es decir la etiqueta b hereda las propiedades de la etiqueta h1)

Pero ¿Qué es la herencia CSS? ¿Qué propiedades se pueden heredar y cuáles no?

Empecemos puntualizando que existen relaciones en HTML, y estas relaciones nos permiten seleccionar y aplicar estilo a los elementos de una página web. Cuando un elemento HTML se encuentra anidado dentro de otro, el elemento exterior se conoce como padre, mientras que el elemento interior es el hijo.

Un elemento hijo puede convertirse en padre de otro elemento.

Entonces:

Herencia significa que algunas declaraciones CSS aplicadas a un elemento principal que llamamos «padre» se pasan a elementos «hijo», después de configurar el estilo del elemento «padre».

Cuando aplicas un estilo a un elemento padre, en algunos casos el estilo será heredado por sus elementos hijos. Digo que en algunos casos porque este tipo de herencia no siempre ocurre.

Los atributos comunes no heredables incluyen: visualización, atributos de texto (como alineación vertical: alineación de texto vertical, sombra de texto: efecto de sombra de texto), atributos de modelo de cuadro (como ancho, alto , Borde, margen, relleno), propiedades de fondo (como fondo, color de fondo), propiedades de posicionamiento (como flotante, claro, posición), etc .

Los atributos heredables comunes son: atributos de familia de fuentes (como fuente, familia de fuentes, tamaño de fuente), atributos de series de texto (como sangría de texto, alineación de texto) y visibilidad de elementos Visibilidad, atributos de diseño de la tabla (como el lado de la leyenda, colapso del borde), etc .;

Los elementos en línea pueden heredar los atributos: (1) Atributos de la familia de fuentes (2) Atributos de la serie de texto, excepto text-indent y text-align;

Atributos que los elementos de nivel de bloque pueden heredar son: text-indent, text-align

Debemos saber que algunas propiedades CSS, como color o font-family, se heredan desde los elementos HTML padres a los elementos HTML hijos, modificando el valor que tienen por defecto. Observa en el siguiente ejemplo, donde aplicamos un color verde al texto de la clase .container (padre):

<div class="container">
  <p>Texto del padre</p>
  <div class="child">
    <p>Texto del hijo</p>
  </div>
</div>

<style>
.container {
    
    color: green;           /* Propiedad heredable */
    border: 1px solid red;  /* Propiedad no heredable */
  }
  .hijo {
    font-size:31px;
    font-weight:600;
  }
</style>

Te dejo la página de fiddle para que veas cómo funciona el ejemplo.

Si observas el resultado, verás que tanto el texto de .container (padre) como el texto de .child (hijo) aparecerán de color verde. Esto en cierta forma debería resultarnos lógico, ya que el elemento .child se encuentra en el interior de .container, y no hay ninguna otra regla más especifica que le dé otro color de texto a ese elemento interior.

Sin embargo, con el borde rojo sólo se aplica borde al .container. El elemento .child no se ve afectado. Esto ocurre porque algunas propiedades como color o font-family se heredan en los hijos, mientras que otras propiedades como border, no.

Si esta propiedad aplicara herencia a sus hijos, todos los elementos HTML situados en el interior de .container tendrían su propio borde rojo, comportamiento que no suele ser el deseado. Por esa razón, la herencia no ocurre con todas las propiedades CSS, sino sólo con algunas propiedades donde si suele ser deseable.

Con un ejemplo veremos el resultado de la herencia de propiedades entre las marcas HTML:


<html>
<head>
<title>Problema</title>
<style type="text/css">
body {
  color:#0000ff;
  font-family:verdana;
}
</style>
</head>
<body>
<h1>Este es un título de nivel 1 y con la marca 'em' la palabra: 
<em>Hola</em></h1>
<p>Todo este párrafo debe ser de color azul ya que lo hereda de la 
marca body.</p>
</body>
</html>
 

En este ejemplo hemos definido la siguiente regla para la etiqueta body:

 
body {
  color:#0000ff;
  font-family:verdana;
}
 

Inicializamos la propiedad color con el valor de azul y la fuente de tipo verdana. Con esto todas las marcas contenidas en el body que no redefinan estas dos propiedades recibirán los valores aquí definidos. En este ejemplo la cabecera de primer nivel es decir h1, el párrafo y el hipervínculo tienen como color el azul y la fuente es de tipo verdana.


Ahora bien en muchas situaciones podemos redefinir propiedades para marcas contenidas, veamos como podemos hacer que el texto contenido en las marcas em y p aparezcan de color distinto:


<!DOCTYPE html>
<html>
<head>
<title>Problema</title>
<style type="text/css">
body {
  color:#0000ff;
  font-family:verdana;
}
em {
  color:#008800;
}
p {
  color:#999999;
}
</style>
</head>
<body>
</body>
<h1>Este es un título de nivel 1 y con la marca 'em' la palabra: 
<em>Hola</em></h1>
<p>Todo este párrafo debe ser de color gris ya que lo redefine la 
marca p y no lo hereda de la marca body.</p>
</html>
 

Ahora hemos definido tres reglas, la primera igual que el problema anterior, define la propiedad color en azul y la fuente de tipo verdana para la etiqueta body:


body {
  color:#0000ff;
  font-family:verdana;
}
 

La segunda regla define la propiedad color en verde para la marca em, con esto no heredará el color azul de la etiqueta body (que es la etiqueta padre):


em {
  color:#008800;
}
 

Algo similar hacemos con la marca p para indicar que sea de color gris:


p {
  color:#999999;
}
 

Pero podemos ver que todas las marcas heredan la fuente verdana ya que ninguna marca la sobreescribe.

Una lista completa de propiedades heredadas

De acuerdo al W3C, estas son las propiedades que pueden ser heredadas.

  1. azimuth
  2. border-collapse
  3. border-spacing
  4. caption-side
  5. color
  6. cursor
  7. direction
  8. elevation
  9. empty-cells
  10. font-family
  11. font-size
  12. font-style
  13. font-variant
  14. font-weight
  15. font
  16. letter-spacing
  17. line-height
  18. list-style-image
  19. list-style-position
  20. list-style-type
  21. list-style
  22. orphans
  23. pitch-range
  24. pitch
  25. quotes
  26. richness
  27. speak-header
  28. speak-numeral
  29. speak-punctuation
  30. speak
  31. speech-rate
  32. stress
  33. text-align
  34. text-indent
  35. text-transform
  36. visibility
  37. voice-family
  38. volume
  39. white-space
  40. widows
  41. word-spacing

Puedes obtener más información acerca de esta lista en el sitio web del W3C (¡definitivamente no necesitas memorizar todo esto!).

Valores especiales de herencia

Además de los valores habituales de cada propiedad CSS que iremos viendo a lo largo de nuestros artículos, también podemos aplicar ciertos valores especiales que son comunes a todas las propiedades CSS existentes. Con estos valores modificamos el comportamiento de la herencia en dicha propiedad:

Valor Significado
inherit La propiedad hereda el valor que tiene la misma propiedad CSS en su elemento padre.
initial Establece el valor al valor inicial definido por la especificación CSS.
unset Resetea el valor. En propiedades heredables, actua como inherit, en otro caso, como initial.
revert Similar a unset, salvo que haya definido un origen de agente o de usuario (ver más adelante).

Siguiendo el mismo ejemplo anterior, nuestros estilos podrían ser los siguientes:


.container {
color: green;
border: 1px solid red;
}

.child {
border: inherit;
}

En el caso de que .child no tuviera la propiedad border establecida (o la tuviera a initial o unset), dicho .child no tendría borde ya que se trata de una propiedad no heredable. Sin embargo, si utilizamos el valor inherit, la propiedad hereda el valor de la propiedad border de su padre, y pasará a tener un borde propio, al igual que su elemento padre.

Veamos ahora el mismo caso, pero con la propiedad color, que es una propiedad heredable:

.container {
color: green;
border: 1px solid red;
}

.child {
color: inherit;
}

Por defecto, .child muestra el mismo color de texto que el elemento padre, ya que hereda su valor de color. Ocurre lo mismo si utilizamos el valor inherit o el valor unset. Sin embargo, si utilizamos el valor initial, pasa a utilizar un color negro para el texto, ya que es su valor inicial por defecto.

La importancia de la herencia en CSS

Si alguna vez has aplicado estilos al contenido de una página web, es muy posible que no hayas escrito un estilo de fuente para cada elemento que tenga que mostrar texto. Es posible que solamente hayas agregado tus estilos de fuente al elemento body, por ejemplo:

<body>
    <div>
    <h2>A h2 element</h2>
    <p>A paragraph</p>
    <div>
      <p>Another paragraph</p>  
    </div>
  </div>
  <div>
    <h3>A h3 element</h3>
  </div>
</body>

Si quieres tener un estilo de fuente uniforme para todo este contenido, solamente tienes que aplicar estilo al elemento body:

body {
  font-family: Arial, Helvetica, sans-serif;
}

Esto es posible debido a la herencia entre los elementos HTML. Y es útil, ya que no tenemos que repetir el mismo estilo font para los divs y los encabezados. Lo mismo ocurre con los estilos color, que cuando se aplican a un elemento padre serán aplicados a los hijos de ese padre, a menos que se aplique un estilo color diferente sobre los elementos hijos.

Si bien la herencia nos facilita las cosas, la situación no sería tan sencilla si todas las propiedades CSS se comportaran de esta manera.

Aquí tenemos otro ejemplo:

<ul class="main-list">
  <li>Dairy</li>
  <li>Vegetable</li>
  <li class="sub-list">
    Fruit
    <ul>
      <li>
        Drupe
        <ul>
          <li>Peach</li>
          <li>Coconut</li>
          <li>Olive
        </ul>
      </li>
      <li>
        Berry
        <ul>
          <li>Tomato</li>
          <li>Cucumber</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

¡¿Quién se imaginaría que los pepinos son bayas?! vamos a implementar algunos estilos en la lista padre y veremos qué se hereda a lo largo del linaje:

Te dejo el fiddle para que veas cómo funciona el ejemplo.

Los estilos font y color que fueron aplicados a la lista no ordenada son heredados por sus elementos hijos e incluso por sus elementos nietos. Sin embargo, no ocurre lo mismo en el caso de los estilos border.

Entonces, ¿qué otras propiedades se heredan?

Cómo forzar la herencia de las propiedades

Ya que algunas propiedades no pueden ser heredadas, quizá pienses que la solución es aplicarlas a los elementos hijos también. Los estilos que usamos anteriormente podrían verse de esta manera:

.main-list {
  border: 1rem solid #000;
  color: red;
  font-family: Verdana
}

.sub-list {
  border: 1rem solid #000;
}

Aún tendríamos estilos border solamente en la lista padre y en la primera sub-lista. Pero el problema es que hemos tenido que hacer una repetición. La molestia de copiar el mismo estilo una y otra vez se vuelve evidente.

Una buena solución sería aquella en la que solamente es necesario aplicar el estilo una vez, de preferencia en el padre, y hacer pequeños ajustes en el hijo para heredarlo. Esto mantendrá todo limpio.

La palabra clave Inherit

De acuerdo a los documentos de MDN:

"La palabra clave inherit de CSS hace que el elemento al cual se aplica tome el valor calculado de la propiedad de su elemento padre". –

MDN

En otras palabras, es una manera de decir que el valor de una propiedad en particular debe obtenerse a partir del padre del elemento. Esta palabra clave puede ser usada en cualquier propiedad CSS.

Volviendo a nuestro ejemplo, esta es la manera en la que se vería el estilo:


.main-list {
  border: 1rem solid #000;
  color: red;
  font-family: Verdana;
}

.sub-list {
  border: inherit;
}

Con eso, el resultado tendrá esta apariencia:

Te dejo la página de fiddle para que veas cómo funciona el ejemplo.

Por lo tanto, si fuera necesario cambiar nuestros estilos border en algún momento, solamente necesitaríamos cambiarlos en un lugar.

Cómo forzar a las propiedades para que no sean heredadas

Si bien es posible forzar la herencia en las propiedades que no son heredables de forma predeterminada, en algunos casos puede tener sentido no hacerlo. Una alternativa es hacer uso de los valores iniciales de la propiedad.

La palabra clave Initial

Puedes establecer el valor inicial o predeterminado de una propiedad CSS mediante el uso de la palabra clave initial de CSS. Esto ocasionará que el valor heredado de la propiedad regrese a su valor inicial.

En este ejemplo suceden un par de cosas. Tenemos dos elementos div cuyas propiedades de color rojo son heredadas por los elementos h1 y p anidados en el interior. Sin embargo, también aplicamos un estilo h1 global (color azul), pero nos aseguramos de que el segundo h1 no herede ningún estilo de la siguiente manera:

h1 {
  color: blue;
}

div {
  border: 1rem solid #000;
  color: red;
  font-family: Verdana;
  margin-bottom: 10px;
}

.berries h1 {
  color: initial;
}

Nuestro h1 en el bloque .berries vuelve a tener el color que el navegador haya aplicado originalmente. Así es como se ve eso:

Te dejo la página de fiddle para que veas cómo funciona el ejemplo.


Otras palabras clave para la herencia en CSS

Además de las palabras clave inherit e initial, también podemos usar revert y unset. De hecho, estas alternativas se recomiendan porque initial puede generar algunos resultados inesperados.

La palabra clave Unset

La palabra clave unset es sutilmente diferente. Esta restablece el valor de un elemento al valor heredado, si es que heredó uno, y a su valor inicial si no es así. Aquí tenemos nuestro ejemplo de nuevo:

h1 {
  color: blue;
}

div {
  border: 1rem solid #000;
  color: red;
  font-family: Verdana;
  margin-bottom: 10px;
}

.berries h1 {
  color: unset;
}

En este caso, la propiedad color de nuestro segundo h1 regresa a su valor heredado (rojo) en vez de a su valor inicial (negro):

Te dejo la página de fiddle para que veas cómo funciona el ejemplo.

La palabra clave Revert

Por último tenemos la palabra clave revert, que funciona de manera similar a unset en la mayoría de los casos. Esta restablece la propiedad a su valor heredado (si hereda de su padre), o al valor predeterminado establecido por la propia hoja de estilo del usuario (si existe), o bien a los estilos del navegador.

Conclusión

Cuando se declara una regla de estilo en una hoja de estilo, hay muchos lugares de los que podría provenir el valor de la propiedad:

  1. La hoja de estilo definida por el autor web.
  2. Estilos definidos por el usuario.
  3. Estilos definidos por el navegador.

El lugar del que se obtienen los estilos depende de la manera en la que funciona la propiedad con respecto a la herencia. Si la propiedad es heredable entonces su valor vendrá de su padre, lo que será declarado en la hoja de estilo creada por el autor web. De lo contrario vendrá de la segunda o de la tercera fuente.

¡La herencia en CSS puede ser un poco confusa! espero que este tutorial te haya ayudado a comprenderla.