-
Notifications
You must be signed in to change notification settings - Fork 711
[css-backgrounds] background-clip: border-area #9456
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
Comments
I will add one of my most active (and searched) Stack Overflow answer around this topic: https://stackoverflow.com/a/51496341/8620333 |
One use case would be the classic border-only pie chart where we can rely on conic-gradient() but we need to mask the inside part: https://codepen.io/t_afif/pen/XWaPXZO With the above, the code can be as simple as:
(for the rounded part, two extra radial-gradient will do the job and no need to clip them) |
I don't think this is necessarily the ideal solution because once you clip the content inside the element is invisible, only the border remains. So you would need a second element for the actual content. I see this more as a border-image extension. I also wonder if mask-border covers this. |
Love this use case! Now with animation of custom properties via
This property is The main advantage that I see over The first use case that came to my mind was that of gradient ghost buttons. I wrote an article detailing it a couple of years back https://css-tricks.com/css-ing-candy-ghost-buttons/ The article dissects multiple methods of achieving this they are either more complicated than what this proposal would allow for or they're less than ideal due to using either non-standard, non-cross-browser methods or due to not achieving the exact result we're after. Or both. This proposal would allow us to create a gradient sized relative to the
The 1st method dissected in the article is layering and XORing three fully opaque The 2nd method uses an extra pseudo with the first two The 3rd method uses The 4th method uses blending. This is very limited when it comes to the backgrounds we can use behind the ghost buttons. Even worse, we can only make it work in Firefox by using up an extra pseudo for it, as it fails there due to bug 1481498 (mentioned above). So overall, this is one use case where having a The second use case that comes to mind is "gradient" borders for images obtained out of the image source. Let's say we have an image:
And let's say that we want a spaced out gradient border that goes with the image itself.
There's so much stuff that is poorly supported/ doesn't work in any browser in the code above, but oh, well... We could of course do this with And what we need to do nowadays to get such a result is a bit like scratching with the foot behind the ear https://codepen.io/thebabydino/pen/VwqEapG A demo with pattern borders + rounded corners + (semi)transparent backgrounds examples (Lea might know those gradients, as they're adaptations of some of those from her 10+ year old CSS 3 Patterns gallery). This is not achievable with There are also gradient border situations where this wouldn't work however and that's dashed/ dotted gradient borders. There are various ways we could achieve them, but some are terribly hacky and awful (examples one, two, three), others are limited (using a There's no good, consistent CSS way for getting dashed/ dotted gradient borders on elements that maybe have rounded corners without being circular. Maybe some extension of |
Love the idea. Definitely something that I’ve needed before. I like the “quick win” aspect of this proposal, but worry that by using the background as a border it could create issues. Possible accessibility concern: in a non-supporting UA, users may end up with text contrast issues when the background intended for the border is not clipped. section {
border: solid 10px transparent;
color: black;
background: linear-gradient(to bottom, black, gray);
background-clip: border-area;
} This can be avoided when authors make use of section {
border: solid 10px transparent;
color: black;
}
@supports (background-clip: border-area) {
section {
background: linear-gradient(to bottom, black, gray);
background-clip: border-area;
}
} But we can expect that many authors will not do that (usually because they were testing in a supporting browser, and didn’t realize this was a need). So a better failure mode would be great. Another related concern is how High Contrast / Forced Colors modes would handle this. Maybe better if they force the background color or replace it with a backplate, and force the border color too. |
@fvsch Yes, it has the same issue as I'm not sure if there is a good way to fix this outside of the This way it would be possible to do bad by wrapping only the |
@nt1m As @thebabydino mentioned, this does not clip the element at all, it's a @thebabydino Your post made me wonder if what we actually need is @fvsch Your code suffers from this issue primarily because it's specifying background: linear-gradient(to bottom, black, gray) border-area; This reminded me, if we add this we should specify that if it's used in the shorthand as a single value it sets @kizu It does not have the same issue as Also CCing my css-backgrounds-4 co-editors @fantasai @SebastianZ |
If you have black theme then you can also use neon effects in background of image. It would look great!! |
I created a video to show how much we need such a feature in CSS! |
Ok, given the support expressed in the reactions, and the pervasiveness of the use cases, I'm gonna Agenda+ this. Issues to decide on:
|
@LeaVerou Sorry for not answering earlier! Allowing to clip the background image to the border area is one approach. Though personally, I find it a little hacky to reuse background images for that. I'd rather like to be able to turn off slicing to achieve this, so something like Also note #9183 as a tangential issue. Sebastian |
@SebastianZ Aside from the name matching more closely, what would be the benefit of going that route? It seems like a lot of complication to add to |
The CSS Working Group just discussed
The full IRC log of that discussion<emilio> lea: There's a bunch of examples in the thread<emilio> ... happy to find more if the use cases are not obvious to everybody <emilio> ... use case is image border but without the border-image scaling, they want a continuous border <emilio> ... looks like a background image that is clipped only for the border-area <emilio> ... even though it's not conceptually the best way to do it it seems straight-forward <emilio> ... proposal is background-clip: border-box area <emilio> ... which clips to border-box - padding-box <emilio> ... a better decomposition might be allowing other substraction <fantasai> +1 to adding border-area to background-clip, this seems straightforward and useful <emilio> ... but since this is the only use case this seems simpler <emilio> q+ <astearns> ack emilio <iank_> q+ <dholbert> emilio (IRC): this is kind of a clip, but an outside clip with an inside clip... seems fine. <dholbert> emilio (IRC): I'm curious if you've found a use-case with a semitransparent background <dholbert> lea (IRC): I think it can be conceivable to have a semitransparent bg overlaid on another bg <dholbert> lea (IRC): or even have it on the outside, and clip the bg to padding-box <lea> q+ just remembered another design decision to make (clip to border-style or not?) <dholbert> emilio (IRC): I'm looking at an example with oriol. There's a way to do this if you just draw a solid background on the same element <lea> q+ <dholbert> emilio (IRC): seems fine to do this. thinking about use-cases for translucent elements. <dholbert> emilio (IRC): Presumably this wouldn't interfere with border-image? <dholbert> fantasai (IRC): it'd be underneath <dholbert> emilio (IRC): seems fine I think <astearns> ack iank_ <emilio> iank_: What happens with scrollable areas? <emilio> fantasai: same that happens with backgrounds, it's just a background <emilio> ... it's clipping out the entire padding area <schenney> q+ <emilio> ... so you're only drawing the background inside the border area <astearns> ack lea <emilio> lea: one thing I'm not sure about is clipping border-box - padding-box <emilio> ... not sure if we have use cases for other boxes <emilio> ... someone pointed out that you can use a solid background over the padding box <astearns> ack dbaron <emilio> ... but that is not quite general because it might not be a solid color <emilio> dbaron: I just want to clarify that this is clipping to border-area but it's not affected by border-style <dbaron> dashed/dotted/double <emilio> lea: yes, we might get use cases for that but this proposal covers most use cases <astearns> ack schenney <emilio> schenney: re. scrolling backgrounds, what about background-position: fixed?w <emilio> s/w// <emilio> lea: I think fixed is fixed to the viewport, local is what you are pointing out <emilio> ... it'd move like it does now <emilio> schenney: in the local area you don't want to clip necessarily to the padding box <iank_> q+ <astearns> ack fantasai <emilio> fantasai: you'd use a repeating pattern and you're painting that on the border box and subtracting the padding box <astearns> ack iank_ <emilio> schenney: not sure what'd happen, and I know Chromium's background code very well <emilio> iank_: one thing to consider is interaction with table parts <emilio> ... what does border collapsing mean with this feature, columns <emilio> fantasai: I think that falls down from the definitions we already have <astearns> seems like we should have specified how borders work in all these cases <emilio> ... there's a border-box we paint into and a padding-box we paint into <emilio> ... might be that we don't paint anything if they are the same <emilio> iank_: as long as the spec is clear <emilio> fantasai: if it's unclear it's unclear about everything that already exists <emilio> iank_: might be worth mentioning in an out about the expected interaction <emilio> ... so that they explicitly think about this case <emilio> florian: even better with test-cases <emilio> iank_: sure, both! <emilio> nicole: seems weird to think when a border starts with collapsing <fantasai> If you paint `background: url(red-swatch) border-box, url(blue-swatch) padding-box`, the part that's red is the part we're proposing to clip to <emilio> fantasai: I implemented something and got ripped out IIRC, I think right now there's no border <fantasai> s/no border/no border area for internal table elements/ <emilio> astearns: so proposal is to add a border-area background-clip <emilio> lea: this is nothing new, it uses existing concepts <fantasai> s/table elements/table elements in collapsed borders mode/ <emilio> schenney: the result would be the result of background-clip: border-box - background-clip: padding-box right? <emilio> ... that makes the impl very clear <emilio> lea: there's an example in IRC from fantasai where that explains <emilio> RESOLVED: add background-clip: border-area <lea> 🎉 |
Was poking around with a checkerboard patterned border as a clipped/masked background. Easy enough to get the pattern to line up correctly on the left and top borders but much harder for the right and bottom. Note that in this case each corner has a transparent square from the pattern. This would be the same if wanting a white square in each corner. Maybe I'm missing something. Feels like it should be more straight forward than this. background-image: repeating-conic-gradient(rgb(255 255 255/.5) 0 25%, #0000 25% 50%);
background-size: calc(100% * (2/3) / 11) calc(100% * (2/3) / 11);
background-origin: border-box; |
There's |
Unfortunately not. I'm looking to recreate the design labeled as "2" here created with an SVG https://codepen.io/jsnkuhn/pen/oWYowL On the right side of element "2", for example, the last repeat of the generated conic-gradient would need to get cut in half. Trying to make this responsive seems like a separate nightmare: |
A solution using
|
We can also rely on background-origin. By default it's padding-box so we add that "half" as a border and the repetition will do the job. div {
--s: 1em;
width: 12em;
aspect-ratio: 1;
border: solid transparent;
border-width: 0 calc(.5*var(--s)) calc(.5*var(--s)) 0;
padding: calc(1.5*var(--s)) var(--s) var(--s) calc(1.5*var(--s));
background:
repeating-conic-gradient(#000 0% 25%,#0000 0% 50%)
0 0/ var(--s) var(--s) space;
mask: linear-gradient(red 0 0) exclude, linear-gradient(red 0 0) content-box
} |
@nt1m suggests that we should allow for clipping to both the border-area and the text: |
This is an |
It really looks like everybody missed that... So, since it's already specified, I go ahead and close this issue. Sebastian |
Apologies for not keeping up here — could somebody clarify — does this mean the use cases above are already catered for by using ‘border’ alongside ‘background-clip’ already? Or it should because it is in the spec, but it is not yet implemented? Or something else entirely? 🤣 |
@benfrain NO, the latest specification has been updated to |
played around with the webkit implementation a bit and found I was making a bad assumption that we'd be able to use different Was able to add a fake "background-color" with a |
No, it takes a comma-separated list. https://drafts.csswg.org/css-backgrounds-3/#background-clip |
Yes, the WebKit implementation should work with a comma separated list. |
Here's a demo with background-clip on both border-area and text: https://codepen.io/smfr/pen/xxoaLNg |
@Afif13 I've rewritten it with background-clip: border-area and the code is much easier to understand. https://codepen.io/yisi/pen/gONdebO?editors=0100
|
Recreated as best as possible an example from above: #9456 (comment) Not going to be perfect without https://codepen.io/jsnkuhn/pen/OJeoapM Am I understanding this right? To get the background-image: linear-gradient(), none;
background-clip: border-area, border-box; |
@LeaVerou @smfr It looks like we need a mechanism to preserve bg-color without having to define multiple bg-images. |
@smfr Do you plan to implement this in WebKit? |
I don't think the cost-benefit of that is worth it, unless it provides additional value. Keep in mind that when using the background shorthand the background: linear-gradient(...) border-area,
yellow; /* background-clip: border-box is the initial value */ |
Updated the pen (https://codepen.io/jsnkuhn/pen/OJeoapM) with a second element using the @supports (background-clip: border-area) {
.dqx {
border-color: transparent;
background-image:
linear-gradient(to right, var(--border-color-highlight), var(--border-color-primary) 10% 90%, var(--border-color-highlight)),
none;
background-origin: border-box;
background-clip: border-area, border-box;
}
.dqx-shorthand {
border-color: transparent;
background:
linear-gradient(to right, var(--border-color-highlight), var(--border-color-primary) 10% 90%, var(--border-color-highlight)) border-box border-area,
#000;
}
} |
If there's agreement, and a draft spec update, sure. |
played around with
|
One of those fancy border animations with a custom property registered as an https://codepen.io/jsnkuhn/pen/LYKXGPo Everything seems to be working as intended. |
Just as a last thought, I've been playing around with multiple background image layers for each It's probably worth pointing out to developers in public documentation that when we use separate It's also worth pointing out that even though these backgrounds might now look like borders or text they are still in fact backgrounds on the background layer. For example background-clipped text will not take Please correct me if I'm wrong but this all seems to come down to the fact that these are provided as temporary hacky solutions to problems while we wait for more complicated official properties like |
Lots of use cases around specifying a continuous image across the border area, including gradient borders, patterned borders etc.
From a quick search:
Many of these use cases cannot be done with the 9-slice scaling of
border-image
, and for othersborder-image
introduces unnecessary restrictions and additional complexity, when essentially all that is needed is to be able to cut the padding-box part of the background out.Today some of these can be achieved by specifying a
border-box
background and overlaying apadding-box
background with the same color as the backdrop, but that doesn't work in every case. Authors use pseudo-elements to achieve some of these effects.Why not a syntax to subtract from the area defined by
background-clip
?Reading the description above, it's conceivable to ask: If what is needed is the ability to subtract
padding-box
fromborder-box
, why not just add a syntax to subtract background areas? It could bebackground-clip
syntax (e.g.background clip: border-box - padding-box
) or a separatebackground-subtract: <box>#
property.The reason is this introduces 4 * 3 = 12 combinations that need to be implemented and tested, only one of which is actually useful. 6 of which would never even produce an area (e.g.
content-box - border-box
) and 4 of which (text - *
) would almost never produce an area, yet introduce unfathomable implementation complexities.A single
border-area
addresses the vast majority of use cases, and keeps implementation complexity in check.The text was updated successfully, but these errors were encountered: