
Margin considered harmful - whoisnnamdi
https://mxstbr.com/thoughts/margin
======
henriquez
It's funny how we've come full circle from using CSS the way it was intended
to be used to that being "considered harmful" and now we have the Javascript
framework equivalent of < img src="spacer.gif" />, an anti-pattern I was using
back in 1999.

The reality is that frontend is messy, browsers are still inconsistent with
respect to how they treat CSS, and creating new layers of abstraction to
handle trivial considerations like adding space on a display are just a way of
denying that reality by fixing something that isn't broken.

Creating new, completely useless components to "bring us closer to how
designers think" completely flies in the face of separating view from the
program layer. And in my experience, "designers think" everyone has a 27"
Thunderbolt display, or now increasingly a Pro Display XDR, so I wouldn't
really put too much stock in what they think. If you disagree, I would propose
spacer.gif as a much more succinct and widely accepted alternative to all the
harm being done here.

~~~
quotemstr
> browsers are still inconsistent with respect to how they treat CSS

Are they? CSS seems to be rock-solid and consistent now. The days of IE6
randomly breaking the box model are far behind us.

~~~
henriquez
Yes, some examples:

\- margin-top inconsistent between Firefox and Chrome in some cases, usually
near the start of a container element.

\- specifying percentage height for absolutely positioned elements
inconsistent in some cases between Firefox and Chrome (bugged in Chrome)

\- SVG elements or CSS backgrounds are handled inconsistently by Chrome,
Firefox and Safari. Which can depending on the use case can lead to issues
like exceeding max-width, failure to apply aspect ratio, or in the case of
Safari full page reflows every frame where an SVG is animated.

\- Chrome incorrectly renders any scrollable element with backface-visibility:
hidden. Requires non-scrollable nesting div.

\- Everyone has a different way of specifying custom scrollbars. On some
platforms you need to leave room in any scrolling design for a scrollbar which
will reliably be an unpredictable width. Chrome and Firefox still have
inconsistent non-standardized css proprties. Or (some) Apple users get the
self-hiding scrollbar. In practice this needs to be detected and fixed after
the fact with Javascript.

\- position: sticky unusably broken in Safari

I'm sure there are others, but my point is the browsers are quirky and better
to just face it and get over it.

------
Saaster
Oh my sweet summer child. As a pro having done this thing for decades, the
industry standard in 2020 is to randomly throw margins, negative margins, and
paddings on _everything_ (probably in JS/JSX) in the vicinity of the thing
you're trying to position and visually iterate until things looks okay-ish.
Probably by a dozen people simultaneously on the project, some of whom may
have read an article on CSS once. After a year or two the whole thing is
chucked out anyway. And that's all right, it gets the job done.

~~~
icedchai
This made me crack up. I do this all the time and thought it was because I was
"bad" at CSS, having not kept up with the times. Is there really no better way
in 2020?

~~~
hobofan
Of course there is a better way, but as he/she said most people don't know it.
And for a lot of projects that are built to spec once, and maintained with
minimal tweaks for a few years (traditional agency projects), the "bad" way is
good enough.

If you want a better way for a project that you will have to maintain for a
longer time that should be more flexible, I would personally suggest something
like BEM[0] + a few best practices (like the one suggested in the post). This
will already get you a long way.

[0]: [http://getbem.com/](http://getbem.com/)

~~~
gentleman11
I rather like using BEM but have only used for 6 months or so on short
projects. What is the “BEM considered harmful” article in 5 years going to say
that we don’t know now?

------
__ryan__
This article is _not_ advocating using spacer components like so:

    
    
      <MyComponent></MyComponent>
      <div class="spacer"></div>
      <MyComponent></MyComponent>
    

They are describing using _layout_ components to define how children should be
oriented and spaced.

The article's example:

    
    
      <Stack space={3}>
        <Item />
        <Item />
        <Item />
      </Stack>
    

Would be basically equivalent to this:

    
    
      <style>
      .layout-space-3 {
        > * {
          margin: 6px; // Or whatever spacing value to use
        }
      }
      </style>
    
      <div class="layout-space-3">
        <Item />
        <Item />
        <Item />
      </div>

~~~
pikelet
Thank you! There are so many knee jerk reactions here which completely miss
the point of the article (especially the post about images as spacers). It's
not really anything new, wildly complex, or hacky. It doesn't even require
components or a frontend framework, it's just a good way to structure your
code.

------
keithwhor
The longer I spend engineering, the more I just want to get the job done and
get it over with. I've built, and will continue to build, strongly-opinionated
frameworks and platforms based on my experience. But this week's silver bullet
is next week's anti-pattern: mostly because of a misunderstanding of when,
how, and where to apply design patterns.

Truthfully, it's increasingly my opinion that design patterns (and by
extension, anti-patterns) only exist in the context of focused, internally
consistent systems architected by a small group of individuals and not a
committee. Rails, especially early on, is a great example. Actually -- a huge
chunk of programming languages are built this way. The web, however, is
designed by committee.

With this framing, "avoiding margins" works for the way Max builds design
systems -- and from what I know, he's very talented and the team(s) that work
with him should adhere to the systems he constructs. I'd love to see an
implementation of an entire framework / design system that avoids margins --
something like Tailwind CSS. I do not, however, really believe this is broadly
applicable advice. Most people are just trying to ship something that looks
nice, and margins can be overwritten and adjusted easily.

NOTE: I have components I've written that have margins I have to overwrite
nearly universally, but can't remove because of other UIs relying on the
margin behavior. So I understand where the argument comes from. It's just --
I'd have a hard time if anybody tried to pick a bone with a software engineer
on the team about the use of a margin if the initial intention was good /
legitimate.

~~~
tylerchilds
To chime in on good intentions. Some branding guidelines specify "this logo
must always have 20px of space around it".

Using margin will guarantee it'll have at least 20px and likely only 20px top
and bottom with the way margin collapsing works with CSS. Padding or spacers
would just add potentially more space than the minimum design requirement.

------
the_other
I tried something similar to “spacer components” in a recent project. When I
wrote them, I felt smug and clever: I had interpreted the suggestions in React
about using components; I had separated my presentation concerns from content
or functionality etc etc.

It turned out to be a mistake. It added a component (with JSX file, an
index.js and a folder, and imports and uses in the consuming file. 10s of
lines of code across multiple files and folders. After I had made it, I kept
seeing the layout pattern it encoded in other parts of my app. I’d reuse the
component, break it, refactor it to cover multiple uses, which sometime broke
the original. I’d give up and make a new component that was slightly
different. In the end I’d have several of these things, all with long names
that were hard to interpret and harder to use.

And I was the only coder on that project. Imagine if you had several people
doing this?

This kinda thing is the same as the problems people complain about when
working with large CSS codebases.

Doing it in CSS is marginally easier, in my view. You probably have fewer
files to maintain and fewer lines of code to work with.

Ultimately, I think the problem is in neither the CSS or JS. It’s that layout
is really hard. It’s as subtle as language. We strive for regularity and
consistency, but if we stick it it strictly, we hamper our ability to
communicate.

------
aphextron
Completely agreed. Margin should only ever be used at the page layout level,
where multiple components are being integrated. But spacer components are a
terrible idea. Just use CSS.

~~~
gkaemmer
Curious why you're so opposed to spacer components. In my experience they work
quite well--often a designer has specified that two widgets lie a certain
distance apart, either vertically or horizontally, and the programmer needs to
express that in code. Makes much more sense to use a spacer component than to
add a margin to one or both of the widgets themselves.

If responsiveness is what you're after, you can easily make your spacers
adaptable to different screen sizes.

~~~
city41
Why not let the parent lay its children out? In my experience, a lot of
engineers resort to things like spacer components due to not being very good
at css. Flex, grid and even table layout should give just about everything
needed for all but the most crazy layout needs. With flex and grid, you can
often build responsive layouts without needing media queries.

~~~
williamdclt
That's exactly what the article is talking about. "Let the parent lay its
children out" means "use layout components in the parent". This is what this
`Stack` component is: probably a flex container. They use the term "spacer
component" but "layout component" would be more accurate and wouldn't trigger
all these knee-jerk reactions

~~~
city41
My argument is that component isn't needed. The article is basically proposing
Parent -> Stack -> Children. I argue the parent should own both its parent
roles and the layout roles. The Stack component adds an unnecessary layer IMO.
It will probably add an unnecessary DOM node too which is unfortunate. My
experience with layout-like components such as this Stack is they often have
limitations people work around in bad ways, or sometimes they just end up
having props like `columnGap` and basically just end up being a little re-
implementation of inline styles. I have pretty much always found just having
the parent do layout using standard CSS to be better.

~~~
williamdclt
It's a more subtle argument, but a lot of people (me included) think that
`<Stack>...</Stack>` is better than `<div class="stack">...</div>`. More
readable, more reusable, that's the sort of thing Flutter went with (not a
Flutter user personally).

There's no reason it would add unnecessary DOM nodes. You can add styling on
top of any component if needed (styled-components is one way but not the only
one). Having a `columnGap="small"` is perfectly acceptable for me
(`columnGap={3}` too if 3 refers to some scaling, `columnGap="10px"` is bad).

It's similar to the Tailwind approach: have ready-made pieces of UI you can
compose. But I also get why you wouldn't like it, and I think any of these
approaches work fine enough if you they're used diligently

------
cousin_it
I agree that spacers are better than margins (and sometimes better than
paddings, when people use paddings as margins). Since whitespace is almost
always between A and B, ideally the piece of code defining whitespace would be
between the pieces of code that are responsible for A and B.

For example, it feels nice to define margin or padding on a <p> element, but
what does that mean - distance between two paragraphs? Between paragraph and
heading? Between paragraph and bulleted list? Using spacers seems like the
only way out of this madness.

~~~
coffeefirst
It means minimum distance. A key feature is margin is it can collapse. So if
paragraphs have 1rem between them, and headings have 2rem above and 1rem
below, you won’t wind up with 3rem between the paragraph and the following
heading. Padding adds together, and space mechanisms seem like overkill when
css can already do the thing in a straightforward way.

What’s befuddling to me about these threads is that they keep trying to make
an absolute case. It’s true, I use margin less now that I have grid gap, but
there’s still a place for it.

~~~
lolc
Most people don't understand collapsing margins. I know I don't. I always have
to read up when I deal with margins.

And protip: Whenever you have a CSS problem, think: "Oh, I'll just use
negative margins!"

------
tylerchilds
<br /> <br /> <br />

~~~
laurentdc
I'm more of a <p>&nbsp;</p> kind of guy. Frontend is all a hack anyways

~~~
diegoperini
I know nothing but sometimes `!important` works.

------
jpochtar
HTML is for styling. JSON is for content.

If you've heard "separate content from presentation" all your career, you
might autonomically hear it as "separate HTML from CSS". I used to.

In a React app world, your content hasn't lived in HTML for a long time. It
lives in your DB, and comes to you through JSON.

Your React codebase exists to style that JSON. That includes "HTML" (JSX),
CSS, and whatever else you've got in there.

Since your HTML is for styling, and your CSS if for styling, why separate
them? If you do, you're not separating content from presentation, you're
separating presentation from presentation, and that's just wasteful.

Personally, I'd prefer to use inline styles for everything, though of course
will use CSS for :hover of @media queries where I have to.

------
williamdclt
So, the point is that margins on the UI boundaries of a component are a bad
idea. Margins are a visual side-effect, which break the idea of keeping
components encapsulated.

It's not anything new really, everybody has experienced pain to try to reuse a
component but it's badly encapsulated so it's painful to fit in a new context.
It's always worth making it clear and reiterating basic principle under
different lights, but this "considered harmful" like you discovered a new law
of physics always feels pretentious to me

~~~
gyrgtyn
You could argue that margins are part of the element, just like padding and
border are, so

~~~
williamdclt
You could, but this mental model probably won't be as helpful as thinking of
margin as the element pushing its neighbors away (or pushing itself away).

It's hard to define margin without any relation to neighboring elements, it's
easy for padding and border. It seems logical that a reusable component
shouldn't make assumptions about its neighbors, therefore avoid margins on its
boundaries.

------
bpsh
I was expecting a finance related article.

~~~
anaphor
Same, but I guess everyone knows buying on margin is harmful, they just do it
anyway.

~~~
bpsh
What? You know when you take out a loan to buy a car or a house you are buying
on margin right?

It's just a tool to be used. Sure it can be harmful if you don't understand
it.

------
raphaelrk
I like the way @wongmjane put it, "Basically margin is like side-effect"

[https://twitter.com/wongmjane/status/1242370883320049664?s=2...](https://twitter.com/wongmjane/status/1242370883320049664?s=20)

I remember @jpochtar and @gablg1 had a similar take in "Technical lessons from
building a compiler startup for 3 years". Under "Don’t trust standards", they
wrote "We had no issue w/ using invisible spacer divs instead of the more
“semantic” margins or paddings."

[https://medium.com/@gabriel_20625/technical-lessons-from-
bui...](https://medium.com/@gabriel_20625/technical-lessons-from-building-a-
compiler-startup-for-3-years-4473405161cd)

------
tengbretson
I guess we're done trying the whole "semantic HTML" thing.

~~~
jakelazaroff
Margin is a CSS property; using it (or not) is entirely consistent with
semantic HTML. The "spacer" component in the article can be achieved with gaps
using CSS grid.

~~~
pixelbash
CSS grid is a lifesaver, but grid-gap does not replace margin unless you have
a very regular design.

------
Tade0
Am I missing something here? Why not just define the margin for those
components in that place in the parent component?

------
superfrank
I semi-agree with the point being made, but I don't like the solution. Spacer
components isn't the solution, IMO, separating the reusable styles from one
time styles is.

so instead of:

<div class="link"/>

<div class="spacer"/>

<div class="link"/>

<div class="spacer"/>

<div class="link"/>

We should be doing:

<div class="link space-right"/>

<div class="link space-right"/>

<div class="link"/>

This allows the reusable styles to be reused and the spacing to be one off.

P.S. since I'm more of a react/styled-components kind of guy, this is how I
would look to do it there

const Link = styled.div`

//... styles

` const LinkWithSpacer = styled(Link)`

//... margin

`

<LinkWithSpacer />

<LinkWithSpacer />

<Link />

------
hjanssen
Using spacing components makes sense for small applications where there is a
predictable set of spacings used everywhere in the app.

Once you get to the size of an app which requires a dashboard, and many
specific distances, some just a tiny bit smaller or bigger, this gets unwieldy
very fast. You end up coding around the spacer component or not using it
entirely for some situations which makes the whole approach kinda useless.

The approach I take is the "pass your own classname"-approach. Im sure
somebody has found a fancy name for it.

Having a componenent A:

    
    
      const A = ({ className }) => (
        <div className={`${COMPONENT_CLASSNAME} ${className}`}>
          Hello, World!
        </div>
      )
    

You can then just pass your own classname from the parent into the child
component. If your component A does not define any margins, it should be easy
to define those and not break anything. As simple as that. I find that to be
way more flexible than a spacer component, because most of the time, spacing
depends _heavily_ on context. The spacing component therefore either becomes
too complex and unwieldy or does not get used at all.

The approach from above does have a drawback: if you dont pass a className to
your component, the resulting class attribute will contain
"COMPONENT_CLASSNAME undefined". I have not found that to ever be a problem,
although if you really want to, you can also write the template string as
follows to mitigate this:

    
    
      `${COMPONENT_CLASSNAME} ${!!className ? className : ""}`
    

But I do find that to be unnecessarily verbose.

~~~
ickelbawd
Your template string logic doesn't actually mitigate the problem. Short-
circuit evaluation in JavaScript means that `falsey && something_else` will
always evaluate to `falsey` and then you'll still get undefined in your
className string. You would have to use a ternary to avoid this.

~~~
hjanssen
Yes you are right, I have edited my post. It is pretty late.

------
disillusion
In my experience, margin isn't harmful. Using a container to space components
relative to each other is harmful.

In fact, using margin correctly can prevent an explosion of exceptions on the
relative positioning of your components. It also brings you more in line with
how a designer thinks.

Consider this: one of the things a designer takes into consideration is
composition and whitespace. In effect, this means that distances between
components might change, depending on what their layout is, and what
components are situated around it.

When you have a wrapper component, you can set some sensible spacing defaults
for its children. But some components visually need more breathing room, while
others need less. This depends on the design of the component. It also depends
on what components comes before or after, so a simple padding won't suffice.
Two visually heavy components need more space in between as compared to two
that are visually airy. You'll eventually end up with a long list of +
selectors to precisely tune every single combination. This quickly gets out of
hand. With or without a wrapper element, those exceptions must be applied
somewhere.

However, when using margins, you avoid all that. Since margins collapse, you
can be assured that any combination of components has the minimum amount of
whitespace between them, determined by who needs the most. Now this isn't
perfect, but it gets pretty close; any component that needs a bit more
breathing room can force a larger distance. This way, you might still have one
or two combination exceptions, but these will be rare.

So, looking at it like this, margins _are_ a property of the component itself:
it's the equivalent of a guy stretching his arms out and saying "don't come
too close, I need my space!".

------
neya
Call me old school if you like, but the cleaner solution in my eyes are to
create well-defined CSS classes for such margins and use them in my designs.

    
    
        <div class="margin-10">..</div>
        <div class="margin-20">..</div>
        <div class="margin-30">..</div>
    

is MUCH cleaner than:

    
    
        <div space={3}>..</div>
        <div space={4}>..</div>
    
    

The difference being, first of all, I don't need to dig into the source to see
what `space` does. Next, appearance layer is tied to CSS and the JS takes care
of the rest of the structure of the component.

~~~
hjanssen
What would stop you from calling the space attribute just "margin" in your
react component? For me, the second approach does look much cleaner and if I
really want to see what you are doing, I also have to open your CSS
Stylesheet. I guess it does come down to preference and familiarity.

------
austincheney
I have never understood why developers think in absolutes and then try to
force this absurdity on other people. It feels immature to me and makes me
feel like I am in a prison or an insane asylum.

Just use the correct tool for the given task.

~~~
chickenpotpie
The quest for absolutes makes a lot of sense to me. I understand they are
rare, but when we find them they're a godsend. We have to consider so much at
once and there's so many ways to do the same thing that having an absolute can
make things much easier.

------
jacobush
I thought it would be a lean management or economics piece of how low margins
are essential to a smooth economy. Or a denouncing thereof. You know, in the
days of hospitals being run on just-in-time deliveries.

------
tcgarvin
Moving spacing concerns to the parent is an interesting idea, would be fun to
try out.

That said, I almost didn't read the post simply because "Considered Harmful"
is the most obnoxious title format I know of.

~~~
phlakaton
Complaints About "Considered Harmful" Titles Considered Harmful...

I like the colorful history of this phrase, and how it usefully marks the
following argument as an unbridled assault against purportedly common wisdom,
so we can treat it with the huffy disdain with which we should normally treat
such cheeky endeavors.

------
graemebenzie
Adam Wathan & Mark Dalgleish chatting about this
[http://www.fullstackradio.com/134](http://www.fullstackradio.com/134)

------
jhpriestley
Spacer components + flexbox + components defined in JS/JSX is basically a copy
of how TeX does things (single unified macro language, hspace/vspace, boxes
and glue algorithm which is pretty much flexbox).

Feels like we could have saved a lot of time if we'd considered at the outset
that maybe Knuth, an actual genius who spent years on this problem, had some
pretty good ideas?

------
pastelsky
If you start thinking as margin as a relationship between two or more blocks
instead of property on a block, some of the issues with it are solved.

Whenever possible, I try to use the sibling selector for this –

.header + .nav { margin: // }

This way, both header and nav elements remain re-usable and the margin only
comes into play if they're used in a specific layout, and it is defined in its
parent.

------
DaniAkash
I have a blank spacer component for react-native
[https://github.com/DaniAkash/react-native-blank-
spacer](https://github.com/DaniAkash/react-native-blank-spacer). I have been
using this to eliminate margins in my existing projects

------
doublejosh
Sorry to be unpleasant... but DUH. This was true long before React. It's a
core idea in assembled layouts, that is to say all layouts.

Margins need to come from the assembling component, rather than the detail
item. Spacing requires awareness of multiple elements, which you usually don't
have internally.

------
winrid
But the parent consuming a component can add margin to the child component
without breaking encapsulation.

------
madjam002
Been doing this for years! In addition to this I recommend a <Content>
component which lays out margins for typography just like you would get in a
vanilla HTML document for h1,p,etc, but outside of that everything should use
spacing components

------
campsafari
Having layout and component design decoupled is the way to go in largescale
component driven systems. Not Necessary in your small wordPress theme like
site though

------
quotemstr
Can't you just override margin with an "!important" rule? I disagree with this
article's exhortation. Cascading style sheets have priorities and override
mechanisms for a reason.

------
naringas
I hope for a "considered harmful considered harmful" article

~~~
devmunchies
"Considered Harmful articles are problematic, and that's a good thing"

~~~
scarejunba
Haha, brilliant. If I may write the first paragraph:

> _Facebook has quietly marked Considered Harmful articles problematic, and
> that 's a good thing._

> _When I was a child, my father often took me fishing as a way for us to get
> out of the house. I remember the dappled early Sunday sunlight playing
> across the dashboard as we drove up to the lake in our 1998 Subaru Forester,
> a car whose longevity is likely to be greater than mine. Subaru, as it turns
> out, tapped into a fundamental part of the American psyche that had, at the
> time, been left completely untouched out of sheer unawareness_.

------
the_mitsuhiko
Every web frontend codebase I have every aged incredibly badly. System A was
replaced (inconsistently) with system B after half a year. Ideas and concepts
thrown out as well.

------
rustybolt
Ha, I thought 'Margin' would be the name of the latest javascript framework.
I'm not sure if the claim that margin is bad is funnier or less funny.

------
klodolph
Fuck it, I’m gonna use SVG for layout in my next web app.

------
choward
I almost didn't read the article because of the horrible title. Anyway, I just
want to say this is one of the things I like about elm-ui (a ui-library for
the elm programming langauge that replaces HTML/CSS). It has the concepts of
spacing and padding. No such thing as margin. [https://package.elm-
lang.org/packages/mdgriffith/elm-ui/late...](https://package.elm-
lang.org/packages/mdgriffith/elm-ui/latest/Element#padding-and-spacing)

------
aen
Design for the sake of shipping, not for the sake of design.

------
leeoniya
...and watch your DOM weight at least double in size and JS perf drop
substantially due to a ton more components.

------
msla
Ironic that this is on a page with grotesquely huge margins.

~~~
Veen
Lines of 60 characters are at the lower end of what's usually recommended by
typographers, but I wouldn't say it's grotesque. A bit too narrow on large
screens though.

