Sådan forstå og arbejde med CSS-margener

CSS får en dårlig rap for ikke at opføre sig som folk forventer. En af de ting, der smider folk mest ud, er margener. De virker så enkle, men alligevel har de potentialet til at forårsage nogle virkelig mærkelige problemer.

For folk, der bare kommer ind i CSS, er det let en af ​​de ting, der kan få dig til at tænke "dette er et dumt sprog, der ikke giver mening!"

Jeg ser det hver dag - både i klasseværelset, når folk prøver at finde ud af deres afstandsproblemer og også i mine sektioner på YouTube-kommentarer.

På en måde er margener lidt af en mikrokosmos af CSS generelt. CSS virker så simpelt med sine property: valuepar, men når du udvikler dig med det, indser du, at der foregår meget.

Margener virker også så enkle. Tilføj noget margen, og du tilføjer noget tomt område omkring dette element. Men pludselig opfører de sig lidt anderledes i en situation end en anden, eller du tilføjer noget margin-toptil et barnelement, og i stedet er det forælderen, der bevæger sig ned.

Der opstår frustration.

I denne artikel håber jeg at kaste lidt lys over, hvordan margener fungerer. Vi ser på nogle af de almindelige problemer, der opstår, samt enkle løsninger på disse problemer.

For at gå igennem alt dette bruger jeg eksempler fra min Responsive Web Design Bootcamp på Scrimba, som jeg trak dette enkle layout fra:

CSS-layout ved hjælp af margener og polstring

Hvad er alligevel margener?

Før vi virkelig hopper ind i dybden her, vil jeg sørge for, at vi alle ved, hvad margener rent faktisk er!

Jeg antager, at vi alle ved, at margener er en del af boksmodellen, hvor margen er helt udefra og kommer efter selve indholdet, polstringen og grænsen.

MDN forklarer dem rigtig godt (min fremhævelse):

Margenen er det yderste lag, der indpakker indholdet, polstring og kant som mellemrum mellem denne boks og andre elementer . Dens størrelse kan kontrolleres ved hjælp af margen og relaterede egenskaber.

Med andre ord er det effektivt tomt rum, som vi kan bruge til at skabe plads mellem en boks og en anden i vores layout.

Håndtering af typografiark for brugeragenter

Browsere leveres med en overraskende mængde CSS som standard, som vi kalder brugeragent-stilark . Disse stilarter er grunden til, at uden CSS fra vores side

er større end en

, og hvorfor det har en margen på det, som vi altid har fjernet.

Disse stilarter er vigtige, men de fører også til et af de største problemer, som folk støder på med margener! Margener er ikke standard for 0alle vores elementer, og dette kan forårsage alle mulige underlige problemer, som vi snart vil udforske.

Lister, blockquotes, afsnit og overskrifter har alle marginpå dem (blandt andre elementer). Mens de nogle gange kun er en lille besvær, ser standardmargenen på afsnit og overskrifter ud til at være den, der forårsager de fleste problemer ud af kassen.

Som standard er venstre og højre margen for et tekstelement indstillet til 0, men de kommer alle med et margin-topog margin-bottom.

Jeg fortæller ofte folk, at disse øverste og nederste standarder er omtrent de samme som font-sizefor dette element, da det er sandt for

såvel som

igennem

. Til

det er faktisk 0.67emog til

det er 0.83em.

Dette betyder, at der findes plads mellem elementerne på vores side, selvom vi ikke udtrykkeligt har angivet en margen.

Vi vender tilbage til disse standarder om et sekund.

Margener, der kollapser

Margener, der kollapser, er hvor hovedpine ofte starter.

Når to elementer har lodrette margener, som berører hinanden, smelter de effektivt ind i hinanden.

Det er allerede en mærkelig opførsel, og tilføj det derefter til det faktum, at det kun er for lodrette margener (øverst og nederst), jeg får hvorfor folk bliver forvirrede og irriterede over dem.

Vi kan se dette i aktion med følgende eksempel:

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

For at hjælpe med at illustrere, hvad der sker her, er .linksklassen i sidste afsnit (

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 :)