Skip to content

Proposal: a way to enable margin-collapse on BFC? or a new type of context like BFC but with margin-collapse? #6752

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
MichaelAllenWarner opened this issue Oct 21, 2021 · 7 comments

Comments

@MichaelAllenWarner
Copy link

It would be useful to either:

  1. have the ability to enable margin-collapse on the root of a block formatting context (BFC); or
  2. have a new type of context that's just like BFC except that it doesn't suppress margin-collapse on the root (and have a new display value that creates such a context, much like flow-root does with BFC).

Here is the problem that this would solve:

In prose/WYSIWYG situations—where the developer isn't in control of the order that various elements end up appearing in—some kind of "clearfix" is often needed to prevent certain elements from "overlapping" a floated neighbor. A typical example would be when a left-floated image ends up next to a ul whose bullets are styled as absolute-positioned ::before pseudo-elements on the lis.

The modern way to implement the "clearfix" is to give display: flow-root to the elements that create a problem if adjacent to a float. Doing so, however, creates a new BFC on the elements in question, thereby suppressing margin-collapse on them. This is a problem because margin-collapse is extremely useful for maintaining consistent vertical rhythm in these WYSIWYG contexts.

One can more or less work around this by "undoing" the outward-facing margins at the extremities of the flow-root element's interior, so that only the vertical-margins of the element itself remain:

ul {
  display: flow-root;
}

ul > :first-child,
ul > :first-child > :first-child,
ul > :first-child > :first-child > :first-child {
  margin-top: 0;
}

ul > :last-child,
ul > :last-child > :last-child,
ul > :last-child > :last-child > :last-child {
  margin-bottom: 0;
}

but it's ugly and, worse, unreliable (it only works for however many layers of > :first-child/> :last-child you include).

In short, the suppression of margin-collapse prevents display: flow-root from being a satisfactory "clearfix" solution in many situations. To my mind, what's missing is the ability to opt in to margin-collapse for a BFC (or to create a new type of context just like BFC but without the suppression of margin-collapse on the root).

@vrugtehagel
Copy link

vrugtehagel commented Oct 22, 2021

If I'm not mistaken, the margin-trim property should address this issue.

@MichaelAllenWarner
Copy link
Author

@vrugtehagel

Thanks, and I think you're right. Hope it gets implemented.

@Loirooriol
Copy link
Contributor

If you want a BFC but remove the start and end margins of the contents, margin-trim has been proposed for this.

But otherwise it sounds like you don't actually want BFC, you only want to clear floats. Why not use a "clearfix", then?

ul::after {
  content: "";
  display: block;
  clear: both;
}

@MichaelAllenWarner
Copy link
Author

@Loirooriol

Thanks for the reply.

It's possible I misused the word clearfix, because the old-school solution you have there actually doesn't address the problem I'm talking about, which I realize now I should have explained more clearly.

Say you have this markup:

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, blah blah blah ...</p>
<ul>
  <li>I am a list item</li>
  <li>I am also a list item</li>
</ul>

with these styles:

p {
  float: left;
  width: 10rem;
}

ul {
  list-style: none;
}

ul li {
  position: relative;
  padding-left: 1em;
}

ul li::before {
  position: absolute;
  left: 0;
  content: "•";
}

You end up with the absolute-positioned bullets all the way over to the left, overlapping the floated paragraph:

Screen Shot 2021-10-22 at 1 32 37 PM

The traditional clearfix you mentioned doesn't work here, but display: flow-root does. Sorry for the confusion.

@MichaelAllenWarner
Copy link
Author

Here is another example, where a left-border causes the same kind of problem:

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, blah blah blah ...</p>
<blockquote>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</blockquote>
p {
  float: left;
  width: 10rem;
}

blockquote {
  border-left: 4px solid black;
  padding-left: 1em;
  width: 15rem;
}

Screen Shot 2021-10-22 at 1 46 04 PM

Here again, display: flow-root works but the ::after trick doesn't.

@Loirooriol
Copy link
Contributor

Loirooriol commented Oct 22, 2021

OK, then margin-trim is not covering your usecase either.

But rather than introduce the concept of "like BFC root but with margin collapse", I think it may make more sense to add a property to force a block to not overlap floats in the same BFC, without forcing it to establish a BFC.

It could be like clear, which lets you specify just one side or both.

@MichaelAllenWarner
Copy link
Author

@Loirooriol

Yes, margin-trim is a bit tangential—it would just provide a better way than the > :first-child ... business to "compensate" for the suppression of the margin-collapse that the BFC introduces. The main point is to prevent the overlap in the first place, in a way that doesn't suppress margin-collapse (and that doesn't affect the layout of the item when it isn't against a float).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants