margin-trim

Geoff Graham on

Get affordable and hassle-free WordPress hosting plans with Cloudways — start your free trial today.

The margin-trim property in CSS removes the additional margin along the edge of a container when the last child element in the container has a margin that bumps right up alongside it.

.element {
  margin-trim: block-end;
}

margin-trim is defined in the CSS Box Model Module Level 4 specification.

Syntax

margin-trim: none | block | inline | [ block-start || inline-start || block-end || inline-end ]
  • Initial value: none
  • Applies to: block containers, multi-column containers, flex containers, grid containers, including ::first-letter and ::first-line
  • Inherited: no
  • Computed value: a set of zero to four keywords indicating which sides to trim
  • Animation type: discrete

Values

/* Keyword values */
margin-trim: none;
margin-trim: block;
margin-trim: block-start;
margin-trim: block-end;
margin-trim: inline;
margin-trim: inline-start;
margin-trim: inline-end;

/* Global values */
margin-trim: inherit;
margin-trim: initial;
margin-trim: revert;
margin-trim: revert-layer;
margin-trim: unset;
  • none: The container does not trim margins from the last child elements.
  • block: The container trims margin from the last child elements in the block-start and block-end directions together.
  • block-start: The container trims margin from the last child elements in the block-start direction.
  • block-end: The container trims margin from the last child elements in the block-end direction.
  • inline: The container trims margin from child elements in the inline-start and inline-end directions together.
  • inline-start: The container trims margin from the last child elements in the inline-start direction.
  • inline-end: The container trims margin from the last child elements in the inline-end direction.

You’ll notice that the values for margin-trim align with other types of logical properties, meaning that they set what direction to trim margin based on the HTML dir attribute or the element’s writing-mode or direction in CSS. If you’re new to logical properties all that means is we talk about directions in terms of block and inline. In a typical left-to-right writing mode, like English, “block” refers to the top and bottom of the element, and “inline” is the left and right.

If the dir or writing-mode changes to, say, a right-to-left language like Arabic, then the inline directions change so that inline-start corresponds to the right side and inline-end is the left side. The same thing would be true if we changed to a vertical direction or writing mode, but in the block direction.

Why we need this property

margin-trim is designed to solve a super common layout issue. Take the following basic example of an unordered list of items:

See what’s happening there? I’ve added 1rem worth’s of margin to the bottom (or, more accurately, the block-end) of each <li> element. Then I added a background color to the <li> elements so we can see the spacing between then. Oh, and I drew a border around the container, the <ul> element, so we can see the margin between the <ul> and the last <li>.

Now let’s say we want to display another <ul> below the first one. Easy peasy.

But notice how the browser automatically adds margin to the <ul> by default…

Margin is added in the block-end direction by the browser’s default styles.

So, now we have double the margin we need! There’s the margin between the last <li> and the bottom of the <ul> container, and margin between the two <ul> elements.

The margin after the last <li> is unnecessary. We have a few ways to eliminate it…

Use the :last-child pseudo selector

This is how we’ve done it forever!

li {
  margin-block-end: 1rem;
}
li:last-child {
  margin-block-end: 0;
}

Nothing wrong with that. But it’s a pain to have to write that just to remove something we didn’t want there in the first place.

Use the :not() relational pseudo selector

A little fancier, but effectively does the same thing.

li:not(:last-child) {
  margin-block-end: 1rem;
}

Use the “Lobotomized Owl”

A bonafide and favorite CSS trick from Heydon Pickering.

ul > * + * {
  margin-block-start: 1rem;
}

The Universal Selector, *, is not only powerful in that it selects all the things, but it makes a nice logo for a site about making website, right? 😉

Placing an adjacent sibling selector (+) between two universal selectors is basically saying: Yo, anything inside an unordered list that has an element that precedes it… add some margin above it. In the case of our <ul> example, all <li> have an element that precedes it — except the first <li>. And since nothing precedes the first <li>, it’s skipped and doesn’t get the margin.

It’s a dang good trick. But it’s also pretty nuclear in the sense that it selects everything. It might take additional CSS to override what we don’t want to add margin to. That’s a downside for sure, even though it definitely gets the job done.

Use margin-trim instead!

It’s an elegant, hack-free way to remove space from whatever edge of the container you want.

ul {
  margin-trim: block-end;
}

Mmm. Nothing like solving a decades-long problem with a single declaration.

Browser support

Not a whole lot of support yet, but it was introduced in Safari Technology Preview 162 on January 25, 2023.

More information