Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Margin considered harmful (mxstbr.com)
124 points by whoisnnamdi on March 24, 2020 | hide | past | favorite | 123 comments


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.


> completely flies in the face of separating view from the program layer.

Why do people stick to this concept like a religion as if it's the only right way that has no tradeoffs though?

If you want a heavily designed look to your website or UI, at some point you're going to have to add annotations to your data for purely presentational reasons either because of limitations with CSS (e.g. there's no way to style the first word of a paragraph with only CSS) or because there's no semantic reason one piece of data should look different from another other than it "looks nicer that way" (e.g. adding a line break in the middle of a heading because you want a two word brand name to appear at the start of a line).

You might be able to avoid presentation-only HTML markup by preprocessing the HTML, modifying the HTML with JavaScript, using some CSS hack, excessive annotations that might never be used (like wrapping all brand names in tags) etc. but is it worth if for this purity of separating data from styling? It has tradeoffs.


>>> e.g. adding a line break in the middle of a heading because you want a two word brand name to appear at the start of a line

However using a &nbsp; in your brand name would likely be a better way to handle this, and makes actual semantic sense in your html. It's also coincidently more robust to changes in your layouts.

Purity for it's own sake is problematic, and definitely sometimes there won't be a good semantic approach. But thinking through cases a little deeper and trying to represent things better semantically can pay off big dividends by increasing the robustness of your solutions.


> However using a &nbsp; in your brand name would likely be a better way to handle this, and makes actual semantic sense in your html. It's also coincidently more robust to changes in your layouts.

I don't see how Brand&nbsp;Name is any more semantic than <div class="no-line-breaks"> Brand Name </div> though. Either way, I can't see how there's a general solution for that example.

- Maybe for another heading, the break in the middle of the brand name will look better because otherwise the previous line would contain only a single word.

- Or the &nbsp; approach works okay for short brand names but not very long ones (e.g. Department&nbsp;for&nbsp;Work&nbsp;and&nbsp;Pensions).

- Or maybe for one heading we want a break only because otherwise the brand name is going to overlap with the eyes of a person in a background photo.

CSS doesn't even have anything built in to do nice looking justified paragraphs yet (like LaTeX has), let alone simple stuff like dealing with text widows and text orphans.

You could conceivably come up with a general algorithm that encodes some of the design heuristics above but that's in the realms of automating graphic design and there's always going to be exceptions.

My point is, there's no clean separation between content/data and styling if you want your data presented in a very specific way. For heavily designed pages, this is underscored by it always being unavoidable that you'll end up modify the text content because you want it to look more presentable e.g. changing a heading so it to fits in a tight space or line breaks in a pleasing way.


I think the answer is to give up on wanting things to be presented in a specific way. The user may want, or need, for it to be presented a different way anyway. So just provide the content and let the user agent lay it out as the user needs or wants it.


> I think the answer is to give up on wanting things to be presented in a specific way.

I can't see how that's ever going to happen. You're going to tell Apple or a professional graphic designer to not care about small details in the way their pages are presented? Raw data and semantics isn't the single most important thing in all cases.


Yeah, not going to happen anytime soon. Branding is such a big part of every company and the bigger the company gets, the more important it will get. People spend a fortune just to control how every milimeter of their product looks and feels.

This is a honourable vision, sure, but also a completely unrealistic one.


I wasn't arguing in favor of separation of view and functionality as gospel. On the contrary, bringing them together can often be more performant _if done correctly._ However, in the context of adding layers of abstraction, I believe it should be a one way trip, ie. we can abstract code functionality from the view, but we should not abstract view functionality into code (and then back into the view at render time). That's like crossing the street twice and ending up where you started.


> I believe it should be a one way trip, ie. we can abstract code functionality from the view, but we should not abstract view functionality into code (and then back into the view at render time). That's like crossing the street twice and ending up where you started.

Can you give an example to illustrate this approach?


The OP gives a good example: https://seek-oss.github.io/braid-design-system/components/St...

This is overengineering, something that should be handled in a view with a CSS class, instead of an abstraction that ends up translating back into a CSS class after the overhead of parsing the abstraction.

I think in the case of your original comment to me, you're arguing something different. You want to bold the first word of an article or apply a line break after the first two words. For a use like that, there's nothing you can do other than to put some kind of view-related functionality in your code, and I agree. But handling that in code isn't fixing something for the sake of fixing it, because there's no way that it could be handled natively by the view in the context of whatever data you pipe into it dynamically.

A CSS class that provides margins to items in a div can be handled natively by the view and should.


I get type safety with that example, I don't with CSS.


Type safety for a CSS class? What?


Type safety for CSS properties. See TypeStyle for instance: https://github.com/typestyle/typestyle


Now I've seen everything. Clearly I'm past my prime. I'm going to give up web development and go live in a cave or something.


I'm curious, what don't you like about CSS type safety?


At almost every job I've had to push back on designs with low contrast and large fixed headers for UI elements. These things look fine on a 27" 4k screen in office lighting, but they're horrible on a 13" laptop with glare from sunlight.

Similar to Facebook's 2G Tuesdays, I'd love to see what designers would come up with if you made them spend one day a week using a 13" 1366x768 200 nit TN screen.


> completely flies in the face of separating view from the program layer

HTML is the view layer. The "program" layer is JS manipulating JSON (ultimately fetched from a DB).

Separating HTML and CSS made sense when content lived in HTML, and styling lived in CSS. Content hasn't lived in HTML in a long time— it lives in a DB now. (Maybe markdown if you're making a static site.) Separating HTML from CSS is separating view layer from view layer— just an unnecessary and expensive indirection


The article does not suggest any of those ideas you think it presents (especially, it does NOT suggest an react equivalent of "spacer.gif") and your comment completely misses the point of the article.


Beware - what this article calls a "spacer component" is nothing like <img src="spacer.gif">. Rather it is a container that specifies the spacing between its child components.

The article just argues that spacing between sibling components should be specified by the container rather than by the individual components.

This makes sense in some contexts where you have a uniform spacing between components. In other contexts, like an article with headers and paragraphs, it doesn't make sense. But you probably wouldn't use React for that in the first place.

In CSS you can do both and the article is not pro or con CSS in any sense.


> 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.


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.


CSS is still a big mess of hacks if you try to have consistent styles across browsers, it's not ie 7 zoom level hacks but you still need various extra properties to make things work.


grid and flexbox are still not carved in stone, so catering to tbe lowest common denominator sometimes means e.g. nesting divs to mimic functionality in another browser


Exactly my thoughts, I had to check twice make sure the article was not parody. This will probably come across as provocative, but it's my honest feeling: I'm glad I got out of whatever frontend development has become.


You will have to elaborate I think. The article seems to me to simply be saying that rather than an individual component being responsible for the margins around itself it should not make assumptions about the context it is used in and should instead let the context or container decide the margins/spacing. That seems sensible does it not? I don't think it really has anything to do with components or using CSS in a non-standard way, it's just about good structure. Why do you think it's so crazy?


> everyone has a 27" Thunderbolt display

Insert Game of Thrones too dark meme here...


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.


This is reality (business) vs college (academic) lesson (and similar to the tired jokes about brushing off your algorithms books only for interviews).

One time I asked a musician with a degree if I should go back to school for music. I was wondering if he thought it was worth the money and time. He said:

"You can go learn all this stuff and you'll know everything about every song you hear. You'll understand all the underlying structures and how to write it out on paper. And music will become an entirely different thing to you. But guess what? You'll be broke, because that's not what people pay musicians for. They pay musicians to sound good and sell alcohol. All that other stuff only matters to people trying to pass their final."


> 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

I wish this were not the case, but having researched the front page HTML of the 10 top trafficked websites during a new framework selection for a client, this is exactly how things are done.


What other things did you learn through this research, if I may ask?


You make it sound ironical and cynical, but that is actually how things are done in real world. I mean, I admit I have done that sort of thing after I read first article about css after someone required me to move something first time ...


> 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.

That's always been the industry standard though. It's a wonder the web works at all.


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?


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/


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?


there is, it just sometimes doesn't matter.

Styling an important or often reused component? You best find a better way.

Adding a tagline to a marketing site or temporary banner? Yea, do whatever you want to get the job done. Just don't let your whole site look like that or you'll have angry teammates.


Don't forget the occasional translateY for good measure!


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>


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.


even better:

Stack { display: grid; gap: 6px; }

https://codepen.io/tychi-nflx/pen/OJVBZzV


In QML/QtQuick, the Positioner does exactly this[1]

[1]: https://doc.qt.io/qt-5/qml-qtquick-column.html#spacing-prop


This should be the top comment.

It makes a lot of sense. Margin should be a property of the enclosing container, not the items in it.


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.


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.


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.


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.


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.


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.


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


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.


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


Because then the designer comes back and decides to change that spacing by 5% on one page, but not another. And now you're using the same spacer component across your entire application, so you're adding config to a component that needs to be documented and learned by the next developer using it. Instead, just express that spacing in CSS that is specific to a page. Use mixins if you like to set a base default spacing, then extend it whenever needed. Application/component structure should be completely divorced from presentation. It's literally the same problem we had with <table> based layouts.


In this scenario, you can add props/params to override defaults.


>In this scenario, you can add props/params to override defaults.

Of course. But why? You're just adding complexity at that point. It's the same problem with frameworks like Bootstrap that use complex combinations of class names for styling. Now instead of having a semantic BEM style class name on the component that I can look up in a stylesheet and modify, I have to memorize an entire framework of esoteric 'col-md-whatever' class names and know how/where/when to apply them. It adds a massive cognitive load beyond just using CSS. In the instance of a custom spacer component described above, I'm now also on the hook for documenting and testing a component that is entirely visual, rather than just writing a couple lines of CSS.


Well then what’s the alternative? Using the same spacer component everywhere is bad because the designer might want to change the spacing in only one spot? Okay. But what if the designer wants to change the spacing in all spots? That’s a much more likely scenario in my experience, but the point is you need to be able to do both.


The point is that layout should be handled at the highest level possible. Have a CSS file at the application shell component level which defines a baseline margin and grid for components, then have individual page component level CSS that can tweak those layouts where needed. Actual UI components should then only ever need to use padding.


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.


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.


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!"


> 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.

I don't want to be rude but you are completely misunderstanding what CSS and HTML are supposed to do.

1) The <p> tag denotes that the content in the element is a paragraph in the document.

2) The styling is just tell the client (which is typically a browser) how the element is supposed to be styled. It isn't supposed to mean anything in relation to other elements and it isn't supposed to convey meaning.

Generally wherever possible you should try to separate the markup and its styling. You can't always do that, but you should try to.


> 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.

Can you explain what spacers are and why they'd be better for this example? Why not use CSS rules that say e.g. "use 1em spacing between p tags", "adding 2em spacing between h1 tags and p tags"?


Yeah, my bad. I realized after writing that comment that pairwise spacing is possible in CSS:

    p+p{margin-top:1em}
    h1+p{margin-top:2em}
This says more or less directly "1em between p and p, 2em between h1 and p". The values can be changed independently, with no need for collapsing margins and so on. It's a bit unusual though.


That's the approach I use though. Spacer divs is going to lead to lots of repetition and attaching the margin to a single element always leads you to having to undo it when there's an exception later.


<br /> <br /> <br />


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


I know nothing but sometimes `!important` works.


This also responds well to changes in em size. I like doing it this way because it makes the sizing consistent on mobile vs desktop, as vertical spacing truly should be relative to the font size.


Tailwind helped me break that bad habit with ‘mx-‘ and ‘my-‘


There’s a component with awfully wide margins? No problem, -mx-?, -my-?.


Every element has 0 margin by default in Tailwind, meaning this is never a problem.

The only other case where I can imagine an element being improperly spaced is when its parent’s padding is messed up.


Well, there’s no “component” by default in Tailwind. I was addressing the “component with margins” problem in the article.


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.


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


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


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.


Margin is usually added in response to nearby elements. Making assumptions about nearby elements is what makes components hard to reuse.


If you avoid them at component definition time and only inject them when using a component, things should be fine.


A simple example with React would be anything using the rebass library (https://rebassjs.org). You can extend its Box/Flex components or do a pass-through (e.g. `({a, b, ...rest}) => <Box {...rest}>{... your stuff here ...}</Box>`), at which point when using your own component you can do `<MyComponentHere marginLeft="0.5em"/>` and have native CSS margins without embedding them into the component or into stylesheets for the component.


I was expecting a finance related article.


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


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.


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

https://twitter.com/wongmjane/status/1242370883320049664?s=2...

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...


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


You should still write semantic HTML, but that doesn't mean every character in an HTML page has to be directly tied to some meaning that isn't to do with styling.

Google and screen readers aren't going to be confused by you putting a < div class="spacer > < / div > tag in the middle of some < h1 > and < p > tags on a page.

I think coders just need to accept that it's a failed experiment to keep all styling data out of HTML. We've been trying for decades now and it's not practical, especially when you're adding a high level of polish to the presentation of your page while dealing with current web standards.


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.


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


You are if you want to spend the entire project fighting the browser.


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


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.


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.


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 />


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.


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.


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


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!".


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.


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.


This is basically tailwindcss, and is an excellent approach when done well.


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.


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.


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.


Then you haven't considered how obnoxious a title like "Make Margins Great Again" is.


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...


I hope for a "considered harmful considered harmful" article



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


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.


Adam Wathan & Mark Dalgleish chatting about this http://www.fullstackradio.com/134


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?


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.


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.


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


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


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


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.


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.


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


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.


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


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


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


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


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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: