Cómo comprender y trabajar con márgenes CSS

CSS tiene mala reputación por no comportarse como la gente espera. Una de las cosas que más desconcierta a la gente son los márgenes. Parecen tan simples, pero tienen el potencial de causar algunos problemas realmente extraños.

Para las personas que recién comienzan a usar CSS, es fácilmente una de esas cosas que pueden hacerte pensar "¡este es un lenguaje estúpido que no tiene sentido!"

Lo veo todos los días, tanto en el aula cuando la gente trata de resolver sus problemas de espaciado como también en las secciones de comentarios de YouTube.

En cierto modo, los márgenes son un microcosmos de CSS en general. CSS parece tan simple con sus property: valuepares, pero a medida que avanza con él, se da cuenta de que están sucediendo muchas cosas.

Los márgenes también parecen tan simples. Agregue un margen y agregue un espacio vacío alrededor de ese elemento. Pero luego, de repente, se comportan de manera un poco diferente en una situación que en otra, o agrega algo margin-topa un elemento secundario y, en cambio, es el elemento primario el que se mueve hacia abajo.

Sobreviene la frustración.

En este artículo, espero arrojar algo de luz sobre cómo funcionan los márgenes. Veremos algunos de los problemas comunes que ocurren, así como soluciones simples a esos problemas.

Para repasar todo esto, usaré ejemplos de mi Bootcamp de diseño web receptivo en Scrimba, del cual saqué este diseño simple:

Diseño CSS usando márgenes y relleno

¿Qué son los márgenes de todos modos?

Antes de que realmente saltemos al extremo profundo aquí, ¡quiero asegurarme de que todos sepamos qué son realmente los márgenes!

Voy a suponer que todos sabemos que los márgenes son parte del modelo de caja, con el margen en todo el exterior, después del contenido en sí, el relleno y el borde.

El MDN los explica muy bien (énfasis mío):

El margen es la capa más externa, que envuelve el contenido, el relleno y el borde como un espacio en blanco entre este cuadro y otros elementos . Su tamaño se puede controlar mediante el margen y las propiedades relacionadas.

En otras palabras, es efectivamente un espacio vacío que podemos usar para crear espacio entre un cuadro y otro en nuestro diseño.

Manejo de hojas de estilo de agente de usuario

Los navegadores vienen con una sorprendente cantidad de CSS por defecto, que llamamos hojas de estilo de agente de usuario . Estos estilos son la razón por la que, sin CSS de nuestra parte, un

es más grande que un

y por qué tiene un margen que solemos eliminar siempre.

Estos estilos son importantes, ¡pero también conducen a uno de los mayores problemas con los que se encuentran las personas con los márgenes! Los márgenes no están predeterminados 0en todos nuestros elementos, y esto puede causar todo tipo de problemas extraños que exploraremos en breve.

Las listas, las citas en bloque, los párrafos y los encabezados tienen todos marginellos (entre otros elementos). Si bien a veces son solo un pequeño inconveniente, el margen predeterminado en los párrafos y encabezados parece ser el que causa la mayoría de los problemas.

De forma predeterminada, los márgenes izquierdo y derecho de un elemento de texto están configurados en 0, pero todos vienen con margin-topy margin-bottom.

A menudo le digo a la gente que esos valores predeterminados superiores e inferiores son aproximadamente los mismos que los font-sizede ese elemento, ya que es cierto para

tanto como

mediante

. por

es en realidad 0.67emy para

es 0.83em.

Esto significa que existe espacio entre los elementos de nuestra página incluso si no hemos establecido un margen explícitamente.

Volveremos a estos valores predeterminados en un segundo.

Márgenes colapsados

Los márgenes que se derrumban son donde a menudo comienzan los dolores de cabeza.

Cuando dos elementos tienen márgenes verticales que se tocan entre sí, se fusionan efectivamente entre sí.

Ya es un comportamiento extraño, y luego lo agrego al hecho de que es solo para los márgenes verticales (superior e inferior), entiendo por qué la gente se confunde y se molesta con ellos.

Podemos ver esto en acción con el siguiente ejemplo:

p { font-size: 18px; margin-bottom: 40px; } .links { margin-top: 40px; } 

Para ayudar a ilustrar lo que está sucediendo aquí, la .linksclase está en el último párrafo (

When people do something like this, they expect the margin between the middle paragraph and the links below it to be 80px (40px + 40px), but in reality, it's 40px. The two margins are touching each other, so they merge into one another.

Paragraph and links with 40px space between

To push it even more, let's give our

s' a  margin-bottom to 100px:

p { font-size: 18px; margin-bottom: 100px; } .links { margin-top: 40px; } 

Again, the two margins don't add together, they collapse into one another, so the total space here is 100px.

Paragraph and links with 100px space between

This is a good thing

In cases like this, it's actually a good thing, though. If there are several elements with different margins, there is no need to add the margins together to see how large the gap between the elements is because we can rely on the fact that the larger margin always wins.

We often don't even think about it, it just works the way we expect it to work.

When it's not a good thing

That said, one instance where margin collapse causes all sorts of confusion is when the first child within an element has a margin-top that merges with the parent's margin-top.

Let's look at that same screenshot again:

Paragraph and links with 100px space between

There is a white space between the top of the viewport and the black box. That's not from the body (it's much bigger than the 8px margin the body would have).

Care to guess where it's coming from?

It's actually coming from the

at the top of that black box.

Remember when I mentioned that the user-agent stylehsheets can do some odd things?

To help explain exactly what's happening here, let's add a much bigger margin-top to the h1.

.card { background: #000; color: white; width: 560px; margin: 0 auto; } h1 { font-size: 24px; margin-top: 100px; } p { font-size: 18px; margin-bottom: 100px; } .links { margin-top: 10px; } 

I see people do this all the time, trying to push the title down within its parent. However, rather than working as expected, we get a giant space on top of the entire card!

 h1 with collapsed margin

This is because the margin-top on the

merges with the margin-top on the parent element.

There is nothing separating the top of the child and the parent in this case. So when we add margin-top to the child, it touches the parent's margin-top. And, as we saw above, when two margins touch one another, they merge into a single margin.

So while we are giving the margin to the child, it's being applied to the parent.

This is why people hate CSS.

Similarly, in the code above we gave all paragraphs a margin-bottom. That margin on the p.link elements touches the margin-bottom of the .card element, which means that the two merge together and the margin affects the .card element instead of the links.

Card element with collapse margin

Although this isn't causing an issue for the site we are currently creating, it could cause problems if we later decided to add further elements to the page.

The problem is, we're using margin for the wrong purpose

If I want space between the top of the .card element and the children inside it, I shouldn't be using margin anyway.

Beginners often get mixed up between margin and padding. My general rule of thumb is if you want empty space, use margin. If you want more background, use padding.

In this case, we want our .card to have more background, so we shouldn't be adding a margin to its children. Instead we should add padding to that element itself.

Result of adding padding to the parent element

In the image above, we can see the padding and the margin. The

on top still has a margin, but it's no longer merging with the .card because the padding has added in a buffer. This prevents the .card's and h1 margin from touching one another.

As the padding adds sufficient space between the

s and the

s, we can now remove the margins we previously added to them.

Site with larger margin-bottom on last child element.

Margins don't always collapse

There are some exceptions to collapsing margins. The direct descendants of grid and flex parents do not have collapsing margins.

Cue the ?.

But there is a bit of a workaround for this as well, which brings us full circle back to those user agent-stylesheets we talked about at the start.

There is an easy way to avoid even thinking about collapsing margins

First off, there is my general rule of thumb that I talked about above:

  • If you need empty space, use margin
  • If you need more background, use padding

That will get you out of trouble most of the time. But let's add an extra rule to this that will help even more:

  • Try to avoid margin-top except when you really need it

This rule is in a bit of conflict with the user-agent-styles, which set a margin-top and margin-bottom to a bunch of elements, which is one reason I often will do something like this:

h1, h2, h3, h4, h5, h6, p, ul, ol { margin: 0 0 1em 0; }

It eliminates a lot of the issues that come from collapsing margins on their own, as well as differences in your layout when some places are using flex or grid and others are not.

(Note: if you inspect the code here on freeCodeCamp, you'll see they do something similar as well!)

It's not a perfect solution, and I often do use a little margin-top on certain subtitles or in specific situations where it's called for. But I'm doing it very intentionally instead of letting the user-agent-styles potentially get in the way in some unforeseen way.

These lessons are just a snippet of my much larger course on responsive web design. To continue this coding journey, take a look at the course.

In the course I cover an introduction to responsive web design, and dive into both flexbox and grid, all the while trying to show people how much fun CSS really is once you start to understand how it works.

Happy coding :)