|
| 1 | +--- |
| 2 | +layout: "@layouts/BlogPost.astro" |
| 3 | +title: "New CSS Property margin-trim" |
| 4 | +date: "2023-12-11" |
| 5 | +description: "The new CSS property margin-trim is very simple, but incredibly useful when working in a component based design system." |
| 6 | +tags: ["CSS"] |
| 7 | +--- |
| 8 | + |
| 9 | +import MarginTrimCard from "@blogComponents/marginTrim/MarginTrimCard.astro" |
| 10 | + |
| 11 | +One of the most annoying things to deal with in CSS is margins. They have weird interactions with collapsing and more often than not you end up with extra spacing where you don't want it. This becomes an even larger pain when moving to a component based design system since now you need to ensure your components all work well with each other without leaking styles outside themselves. |
| 12 | + |
| 13 | +The new `margin-trim` property helps solve part of this problem by making it very easy to remove extra margin from the children of an element. |
| 14 | + |
| 15 | +## The Problem |
| 16 | + |
| 17 | +Let's say we have a simple card with a list of children inside it. |
| 18 | + |
| 19 | +```html |
| 20 | +<div class="card"> |
| 21 | + <div class="child">Child 1</div> |
| 22 | + <div class="child">Child 2</div> |
| 23 | + <div class="child">Child 3</div> |
| 24 | +</div> |
| 25 | +``` |
| 26 | + |
| 27 | +```css |
| 28 | +.card { |
| 29 | + background-color: var(--accent-color); |
| 30 | + padding: 1rem; |
| 31 | +} |
| 32 | + |
| 33 | +.child { |
| 34 | + margin-bottom: 2rem; |
| 35 | +} |
| 36 | +``` |
| 37 | + |
| 38 | +This will result in the following: |
| 39 | + |
| 40 | +<MarginTrimCard /> |
| 41 | + |
| 42 | +As you can see, the bottom margin of the last child is forcing the card to have extra |
| 43 | +space on the bottom which makes the card taller than it should be. This is relatively |
| 44 | +easy to fix if we change our CSS by using the `:last-child` selector to remove the |
| 45 | +margin from the last child. |
| 46 | + |
| 47 | +```css |
| 48 | +.child { |
| 49 | + margin-bottom: 1rem; |
| 50 | +} |
| 51 | + |
| 52 | +.child:last-child { |
| 53 | + margin-bottom: 0; |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +This will result in the following: |
| 58 | + |
| 59 | +<MarginTrimCard isTrimmed /> |
| 60 | + |
| 61 | +This works, but it is not ideal since this code does not work well in a component based system. Our child component needs to know that the parent component wants to remove margin from it. This is not ideal since it means that the child component is now coupled to the parent component. We could instead write our CSS like this to make it so the parent component handles everything. |
| 62 | + |
| 63 | +```css |
| 64 | +.card { |
| 65 | + background-color: var(--accent-color); |
| 66 | + padding: 1rem; |
| 67 | +} |
| 68 | + |
| 69 | +.card > :last-child { |
| 70 | + margin-bottom: 0; |
| 71 | +} |
| 72 | +``` |
| 73 | + |
| 74 | +This still isn't ideal, though, since now we are selecting elements outside the parent component which breaks the encapsulation of the component. This is where the `margin-trim` property comes in. |
| 75 | + |
| 76 | +## `margin-trim` Solution |
| 77 | + |
| 78 | +The `margin-trim` property is a very simple property that allows you to specify which edges of an element should be trimmed and it will remove all excess spacing from those edges. This means that we can now write our CSS like this: |
| 79 | + |
| 80 | +```css {4} |
| 81 | +.card { |
| 82 | + background-color: var(--accent-color); |
| 83 | + padding: 1rem; |
| 84 | + margin-trim: block-end; |
| 85 | +} |
| 86 | + |
| 87 | +.child { |
| 88 | + margin-bottom: 1rem; |
| 89 | +} |
| 90 | +``` |
| 91 | + |
| 92 | +This will result in the following: |
| 93 | + |
| 94 | +<MarginTrimCard isTrimmed /> |
| 95 | + |
| 96 | +As you can see, the `margin-trim` property removed the extra margin from the bottom of the card without us needing to write any extra CSS. |
| 97 | + |
| 98 | +This property can be used for any of the 4 directions `block-start`, `block-end`, `inline-start`, and `inline-end`. It can also be used with just `block` or `inline` to remove margin from both the start and end of the specified axis. |
| 99 | + |
| 100 | +```css |
| 101 | +.card { |
| 102 | + /* All these assume the direction is left to right, top to bottom */ |
| 103 | + margin-trim: block; /* Removes from top and bottom */ |
| 104 | + margin-trim: inline; /* Removes from left and right */ |
| 105 | + margin-trim: block-start block-end; /* Removes from top and bottom */ |
| 106 | + margin-trim: inline-start; /* Removes from left */ |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +By using `margin-trim` we are able to keep all our CSS inside the component without the need for any complex children selectors or `:last-child` selectors which makes it much easier to maintain and refactor our code. |
| 111 | + |
| 112 | +## Browser Support |
| 113 | + |
| 114 | +Unfortunately, Safari is the only browser that supports this feature which leads to just [14% support](https://caniuse.com/mdn-css_properties_margin-trim) across all browsers at the time of writing this article. Hopefully, in the coming months/years this number will increase as more browsers support this useful property. |
| 115 | + |
| 116 | +## Conclusion |
| 117 | + |
| 118 | +The `margin-trim` property is a very simple, but incredibly useful property that makes it easy to remove extra margin from the children of an element. This makes it easier to work with components in a component based design system since you no longer need to worry about parent/child components leaking styles outside themselves. |
0 commit comments