w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.5k stars 664 forks source link

[css-sizing-3] add ability to make the padding size include the border-width #7770

Open jonathantneal opened 2 years ago

jonathantneal commented 2 years ago

I believe CSS borders and padding would be more intuitive if borders could collapse into padding.

described below
A css-like box model which depicts margin, border, padding, and content. In the model, border is shown as being a portion of padding.



To produce consistent inner-spacing when styles include padding and border, authors must currently use tricks to collapse inner-spacing. Considering the following element with padding:

.the-card {
  padding: 4px;
}

With the default behavior, when that element receives border, the actual rendered padding appears larger than the padding that was originally set.

.the-card.with-a-bordered-variant {
  border: 1px solid;
}

In the bordered variant example above, the distance from the edge of the box to its content is now 5px.

When a designer hands over a design like that, I am usually expected to produce CSS like this:

.the-card.with-a-bordered-variant {
  border: 1px solid;
  padding: 3px;
}

I think this is tricky CSS, because the 3px padding are an implicit pre-calculation of the desired 4px padding without the 1px border.

To preserve the intent of the design, I can use custom properties and a calculation:

.the-card.with-a-bordered-variant {
  --border-width: 1px;
  --padding: 4px;
  border: var(--border-size) solid;
  padding: calc(var(--padding) - var(--border-width));
}

However, this is somewhat fragile. If --padding becomes 4px 8px then the calculation fails. I can avoid the calculation by simulating the border with an inset box shadow:

.the-design {
  --border-width: 1px;
  box-shadow: 0 0 0 var(--border-width) inset;
  padding: 4px;
}

When I implement this design and hand it over to another author, they will need to know the tricks I used to produce the intended spacing, and they may need to use the same custom property abstractions.

Ultimately, I believe authors would prefer using border if they could handle the border as part of the padding.

I do understand that border and padding are separate parts of a box, but I believe developers and designers often think about them together as a single kind of inner-spacing thing. In a similar way, I believe developers and designers think about width and height as a kind of outer-sizing thing, which is why authors can prefer box-sizing: border-box.

I recommend CSS provide something like border-collapse: padding-box or border-collapse: content-box, to allow borders to collapse into the available space of an element, just as box-sizing: border-box allows border and padding to collapse into the available size of an element.

I also believe others would benefit from this feature. Here are some example projects where the proposed behavior could alleviate the use of tricks.

Example: Dell Design System

The Dell Design System describes spacing in multiples of 4 pixels. A button is given inner spacing and outer spacing of 12px, 16px, and 20px. However, a look at the implementation shows the padding values are actually 11px, 15px, and 19px. This trick is done to account for the additional 1px of border.

Example: Hashicorp Design System

The Hashicorp Design System maintains its vertical rhythm with the same trick, omitting 1px from each side of padding. The source code includes a note regarding the pre-calculation.

Example: Carbon Design System

The Carbon Design System meticulously documents spacing as tokens. However, to achieve the intended spacing, the CSS hard-codes the offset trick for borders.

Example: Figma Design Tool

The collapsing border behavior I am advocating for is the default behavior in Figma. Until recently, it was also the only possible behavior, which would lead to issues implementing designs from Figma to the web. One comment from the issue stuck out to me:

Right now we have to build a sass function to calculate what padding values will be based on what the border value is. It adds a lot of complexity to our code across multiple applications. This may seem like a small issue but the ramifications that the borders aren’t treated the same way in Figma as they are by the browser renderer are huge for either the development team or the design team. It adds a lot of tech/design debt for the team.

While I agree with the author that Figma would need to provide an option to match current CSS behavior — and they recently did — I think the sass function is a signal that CSS is also missing some desirable behavior.

markacianfrani commented 2 years ago

There's a strong need for this in the Design Token space. When it comes to spacing tokens, you need to draw straws for who has to do the calc/hack.

Some design systems like Paste resort to using shadow tokens for borders:

other box shadow tokens are duplicates of border tokens and are used to visually add a border without affecting the height of the component

bfgeek commented 2 years ago

One thing to note & explore is that the "css box-model" also potentially has scrollbar insets between the border insets, and the padding insets. How does this behave when scrollbars are present?

fantasai commented 8 months ago

Would this need a separate property, or could we fold this into box-sizing as like a border-in-padding keyword or something like that? (Preferably with a less awkward name, though.)

tabatkins commented 8 months ago

I think this should be a separate property. box-sizing already controls one thing well - which box is sized by width/height. This is a new ability that's vaguely thematically related (making it easier to keep boxes the same size), but doing something rather different, and which might want additional controls (like something around scrollbars).

css-meeting-bot commented 5 months ago

The CSS Working Group just discussed [css-sizing-3] border-collapse: padding-box, and agreed to the following:

The full IRC log of that discussion <jarhar> fantasai: this was a suggestion from a designer develoepr to be able to use simplify the amoutn that they have to track for sizing padding because frequenstly they want to have a constant amoutn for th epadding plus border and then be ???
<TabAtkins> Growing the border on hover without causing layout jitter, etc, is the use-case
<jarhar> fantasai: so the question is then do we want to have the ability to say that box sizing has the ability to say it includes the width of the padding and the borders to have the padding amount be both the padding and the border
<florian> q+
<jarhar> fantasai: two questions are do we want to add this feature where the number that the author specifies for the padding is the padding and the border, and the seconde question is do wwe want to do that by adding a keyword to box sizing or creating a new property
<iank_> q+
<miriam> ack florian
<jarhar> florian: third question is if we do that and the author specifies a border bigger than the padding, then what?
<jarhar> fantasai: then you take the max
<jarhar> TabAtkins: outside the use case, so do the obvious thing
<miriam> ack iank_
<jarhar> iank_: i think this is fine. the only question is how do scrollbars interact with this property and because they ? between the padding and the border, i agree that this should be in proper sizing
<emilio> q+
<fantasai> s/proper sizing/box-sizing/
<emilio> q- (fantasai had of course answered my question)
<emilio> q-
<miriam> ack dbaron
<jarhar> dbaron: i was gonna ask we probably do need to say no it interacts with the border collapse property but it sa proeprty where the interaction is messy, maybe if you use border collapse tables then you can tuse this feature
<lea> q?
<jarhar> iank_: you cant use box sizing in both
<jarhar> fantasai: dont we just not even ? the border when ?
<jarhar> iank_: no we do
<jarhar> dbaron: they still have padding
<florian> q+
<jarhar> iank_: i dont know that box sizing ...
<jarhar> dbaron: im also in the camp of ? reusing box sizing but making this distinct
<miriam> ack florian
<dbaron> s/? reusing/not reusing/
<jarhar> florian: for the scrollbar gugtter part of the problem ? if tyour padding is not enough to cinlude then you just increase the whole thing
<jarhar> fantasai: thats probably what people would expect
<dbaron> s/can tuse/can't use/
<jarhar> miriam: is there syntax here? are we resolving to do this then take it back to the issue for
<jarhar> fantasai: its a certain amount of bikeshedding. we need more clarity from usecases should this be a keyword as part of box sizing a separate property or should we split box sizing into two longhands, box sizing size and box sizing padding or something
<jarhar> florian: yeah we need more info about use cases which things need to cascade separately or not
<jarhar> florian: maybe all the info we need is already in the github issue but it hasnt been digested yet so we can resolve on what we have so far
<jarhar> fantasai: then we cna say heres the 3 options, tell us your thoughts on the pros and cons
<fantasai> PROPOSED: Add a control for making padding size include border-width; ask for feedback on its relationship to box-sizing
<jarhar> miriam: any objections to that proposal?
<jarhar> florian: do we need followup resolutions?
<jarhar> fantasai: the minutes are good enough
<fantasai> RESOLVED: Add a control for making padding size include border-width (and scrollbar width); ask for feedback on its relationship to box-sizing
<jarhar> dbaron: does anybody object to my retitling of the issue?
<jarhar> fantasai: go ahead
LeaVerou commented 5 months ago

To get more info on use cases, I asked a designer I know working on a popular design system and this is what they had to say:

Interesting... We do use calculations for consistent form control heights, which incidentally accomplishes what this issue is asking for. I do see the use case, though an inset box-shadow seems to cover this concept already from my POV. If I had, say, a typically borderless card, but I wanted to emphasize it with a border and keep all other proportions the same, I'd turn to box-shadow.

At first when this issue came up, I (alongside many other participants) were puzzled about use cases, but this is something I’ve encountered many times as well, and indeed, ideally people should not have to resort to hacks like box-shadow.

If use cases are similar to this one, it does seem like the border width should be subtracted from the padding, and not the other way around.

fantasai commented 5 months ago

@jonathantneal We discussed the idea and decided to adopt it, but we have an open question: Should this switch be

We're interested in hearing the pros and cons of each approach and how well they fit with the way this is likely to get used by authors. :)

nileshprajapati commented 6 days ago

I was wondering whether there has been any progress on this proposal.

In several recent projects, I have encountered this issue requiring workarounds a few times, using the following box-shadow and custom properties methods as described above, to effectively manage the collapsing of inner spacing and padding i.e. button and card components.

I would love to see this CSS feature become available across all browsers.

frivoal commented 5 days ago

For fallback purposes, I wonder if it should be an opt-in keyword in the border-with (and its longhands), so that if you try to change the width of the border without affecting the size of the box, if you're not in a browser that knows about this opt-in, it fails to change the border size and thus succeeds at preserving the box's size.

In any case, it'll be possible to @supports your way through this and have conditional styles, but if you don't go through that, what's more important in a legacy UA: respecting the desired border size, or respecting the lack of impact on the box's overall size?