Skip to content
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

[css-background-4] add background-layers property to set everything but background-color #8726

Closed
JaneOri opened this issue Apr 16, 2023 · 43 comments · Fixed by #9084
Closed

Comments

@JaneOri
Copy link

JaneOri commented Apr 16, 2023

spec: https://w3c.github.io/csswg-drafts/css-backgrounds/#the-background

We often run into situations where background-color has already been set for an element or component, and in a separate class we want to also add a background image to it.

In order to do this without overriding the color, we have to use the background-image property specifically.

Then we need to size, position, no-repeat it and that's 3 more longhand properties.

Add two bg images and we're managing parallel arrays in every longhand property above to avoid overriding the background-color set elsewhere.

It gets pretty tedious very quickly.

Fortunately, the spec already defines a <bg-layer> so it may not be a big ask to add background-layers as a shorthand property that defines everything for a background, excluding background-color.

background-layers = <bg-layer># | none

(suggesting plural background-layers even though the longhand bg properties are singular since they predate multiple image layers)

Thank you!

@LeaVerou
Copy link
Member

LeaVerou commented Apr 16, 2023

+1

We could then define background as a shorthand of background-layers and background-color.
I think I'd slightly favor background-layer for consistency, since the common case is one layer.

@Loirooriol
Copy link
Contributor

Note we can think about background in terms of background-layer(s) and background-color, but it should still expand to the full list of 9 longhands.

@tabatkins
Copy link
Member

I don't have a strong opinion on this, but it sounds reasonable, and the proposal itself seems right.

I think I'd slightly favor background-layer for consistency, since the common case is one layer.

Right, name-wise we almost never do plurals, so it would be background-layer.

but it should still expand to the full list of 9 longhands.

Yeah, it would be a separate shorthand, unrelated to the background shorthand.

@SebastianZ SebastianZ added the Async Resolution: Proposed Candidate for auto-resolve with stated time limit label Apr 18, 2023
@SebastianZ
Copy link
Contributor

As there's just positive feedback for this suggestion, so far, let's get a resolution on whether to add it.

The proposal is to add a background-layer shorthand that allows to define the background layers independently from background-color.

Sebastian

@astearns
Copy link
Member

astearns commented May 1, 2023

The CSSWG will automatically accept this resolution one week from now if no objections are raised here. Anyone can add an emoji to this comment to express support. If you do not support this resolution, please add a new comment.

Proposed Resolution: Add a background-layer shorthand for everything in background aside from background-color

@astearns astearns added Async Resolution: Call For Consensus Resolution will be called after time limit expires and removed Async Resolution: Proposed Candidate for auto-resolve with stated time limit labels May 1, 2023
@fantasai
Copy link
Collaborator

fantasai commented May 3, 2023

-1 to the proposal, mainly because having background-layer expand to multiple layers seems really off. If we don't want to make it plural, we should find a word that represents the whole stack of layers somehow.

@astearns astearns removed the Async Resolution: Call For Consensus Resolution will be called after time limit expires label May 3, 2023
@tabatkins
Copy link
Member

I don't understand your objection, @fantasai. We virtually never use plurals in property names, even tho a lot of properties are comma-separated multiple instances. Specifically *in the background-* properties, not a single one of them is plural despite accepting multiple values. The longhands don't even have the excuse that background might refer collectively to all the background images; background-image is very clearly talking about one image, background-position about one position, etc.

It would be a pretty big break from tradition to suddenly have one background-* property be pluralized.

@fantasai
Copy link
Collaborator

@tabatkins I'm not arguing for plural, I'm just arguing against background-layer. I think it's confusing for multiple reasons... And additional one would be, the color is itself a layer... but we're intentionally excluding it here.

@fantasai
Copy link
Collaborator

What about background-overlay? That addresses both of the concerns I raised:

  • It more clearly refers to the part of the background overlaying the color. (The background color is itself, functionally, a layer of the background so background-layer is confusing in this respect.)
  • It can be interpreted in a collective sense, so it doesn't feel odd that it's not plural.

@tabatkins
Copy link
Member

Not the hugest fan of that, since a background is, itself, an underlay for the element. ^_^

@Afif13
Copy link

Afif13 commented May 25, 2023

A few ideas

background-stack
background-list
background-canvas

@j-f1
Copy link

j-f1 commented May 25, 2023

Maybe background-pattern (kinda the opposite of the solid background-color)?

@manuelmeister
Copy link

What about background-sheet or background-screen?
I also thought about background-cover, but this would be definitely confusing.

@gavinmcfarland
Copy link

gavinmcfarland commented May 25, 2023

Can I confirm if I understand the proposal correctly? Would the proposal introduce a new way to control backgrounds, that instead of overriding, would combine, blend or overlay backgrounds from different rules?

For example:

.foo {
  background-layer: red;
}

.bar {
  background-layer: url("image.png") no-repeat right top;
}

.baz {
  background-layer: url("image2.png");
}

Would be equivalent to computed CSS of

background: red, url("image.png") no-repeat right top, url("image2.png");

If so, I feel like background-layer seems appropriate and matches up with the mental model of many design programs where fills can have several layers.

Rereading the thread, my hunch is that, this is not what's being proposed. 🤔

@Loirooriol
Copy link
Contributor

Loirooriol commented May 26, 2023

@gavinmcfarland You are misunderstanding, this proposal is for a normal shorthand, not for additive cascade.

It would just allow writing

background: url("image.png") no-repeat right top, url("image2.png") red;

as

background-something: url("image.png") no-repeat right top, url("image2.png");
background-color: red;

@gavinmcfarland
Copy link

Perhaps it's overkill, but could we draw inspiration from other CSS properties. Like grid-template-areas where you can name the areas and specify them in each individual rule?

For example:

div {
  background-layers: "base"  "artwork";
}

.foo {
  background-layer: "base";
  background: red;
}

.bar {
  background-layer: "artwork";
  background: url("image.png") no-repeat right top;
}

Which would compute to:

background: red, url("image.png") no-repeat right top;

I feel like this could play nicely with existing conventions and understanding of the background property?

@Loirooriol
Copy link
Contributor

Additive cascade is off-topic for this issue, it's discussed in #1594 instead.

@gavinmcfarland
Copy link

gavinmcfarland commented May 26, 2023

@gavinmcfarland You are misunderstanding, this proposal is for a normal shorthand, not for additive cascade.

It would just allow writing

background: url("image.png") no-repeat right top, url("image2.png") red;

as

background-something: url("image.png") no-repeat right top, url("image2.png");
background-color: red;

Thanks @Loirooriol for clarifying. So it is quite literally just another property that excludes background-color?

I'm not sure I'm in favour of this. I think it could introduce more confusion about the use of the existing background property. It's changing the mental model of how background works by introducing the idea that background has a primary base which is a colour and then everything else on top, ie `background-something (if I've understood it correctly). I think it could undo lots of learning that people have worked towards understanding CSS only to find out there's an expectation or special property that they need to factor into their existing knowledge.

I like the intent of the proposal, just not sure if I agree with the suggested implementation.

@gavinmcfarland
Copy link

Additive cascade is off-topic for this issue, it's discussed in #1594 instead.

Ok, thank you. I'll take a look at that issue. Perhaps then there's a chance that resolves the need for this proposal?

@retail-robot
Copy link

What about background-overlay? That addresses both of the concerns I raised:

  • It more clearly refers to the part of the background overlaying the color. (The background color is itself, functionally, a layer of the background so background-layer is confusing in this respect.)
  • It can be interpreted in a collective sense, so it doesn't feel odd that it's not plural.

I gotta agree with this, and I don’t think it’s particularly confusing, considering that despite background being an element underlay, it’s still got multiple layers, and the motivation for this specific feature requires that you understand that mental model.

@nt1m
Copy link
Member

nt1m commented May 26, 2023

I feel like the current proposal is a bit confusing because people already know background / background-image as different ways to set background images, and background-layers is adding another one on top. So there will be cases where those 3 will just have the same syntax (if you don't set the other properties), explaining the difference between the 3 props won't be trivial.

I'm sympathetic to the use case though and I'd suggest a shorthand that covers everything that background covers, but leaves out image and color.

@j-f1
Copy link

j-f1 commented May 26, 2023

I'm sympathetic to the use case though and I'd suggest a shorthand that covers everything that background covers, but leaves out image and color.

I like this idea too! Maybe something like background-placement for that

@MakhBeth
Copy link

my vote goes to background-stack. I found it more clear.
Also don’t dislike background-layer. In singular because the plural make create confusion with additive cascade. background-overlay has the issue that a background is actually an underlay? Don’t feel it natural

@GreLI
Copy link

GreLI commented May 26, 2023

Have you considered background-slice?

@ljharb
Copy link
Member

ljharb commented May 26, 2023

Is a new property a better choice than introducing some inline keyword in background to mean “ignore this one”? like, something that allows background to not override the color.

@Loirooriol
Copy link
Contributor

Loirooriol commented May 26, 2023

It's changing the mental model of how background works by introducing the idea that background has a primary base which is a colour and then everything else on top

@gavinmcfarland But that's precisely how the current model works, see https://drafts.csswg.org/css-backgrounds-3/#background-color

This property sets the background color of an element. The color is drawn behind any background images.

Your example with background: red, url("image.png") no-repeat right top; is precisely invalid syntax because red is not in the last layer.

@Crissov
Copy link
Contributor

Crissov commented May 27, 2023

I’m fine with the name and concept of background-layer, but what if this was available in a different way where you could access random background layers?

foo::background(1) {
  content: <background-image>;
  top: right: bottom: left: <background-position>;
  width: height: <background-size>;
  overflow[-x/-y]: <background-repeat>;
  position: <background-attachment>;
  sizing: <background-origin> <background-clip>;
}

@neetij
Copy link

neetij commented May 27, 2023

Is a new property a better choice than introducing some inline keyword in background to mean “ignore this one”? like, something that allows background to not override the color.

I like this idea of adding a keyword to reuse a previously defined value.
Keyword options: revert-value, inherit-value, specified, normal.

.foo {background:gray;}
.alert {background:red;}
.alert {background:inherit-value url("alert.png") no-repeat right top; /* takes color from .alert */}
.bar {background:inherit-value url("bar.png") no-repeat right top; /* no color found, so behaves like 'inherit' */}
.foo .bar {background:inherit-value url("foo-bar.png") no-repeat right top; /* takes color from .foo */}

If the above is not within scope...

  • background-image-stack / background-stack, or
  • background-media, which is conceptually close to background-image (though possibly unclear we can't use videos)

@Loirooriol
Copy link
Contributor

I don't think it can be a keyword, or be part of the value in general.
That's because shorthand expansion happens at parse time, but the value may not be known until computed-value time due to var(), so by then it's too late to decide whether a longhand should be part of the shorthand expansion or not.
Well, maybe it could work with a magical ignore (#5319) that skips that declaration and rolls back to the next winner of the cascade, but I'm not sure if that's doable.

Another idea could be using #8055, though you would still need to list the longhands once, an ugly universal selector, and a roundabout of setting via variables:

* {
  background-position: from-shorthand(background: var(--background));
  background-repeat: from-shorthand(background: var(--background));
  background-attachment: from-shorthand(background: var(--background));
  background-image: from-shorthand(background: var(--background));
  background-size: from-shorthand(background: var(--background));
  background-origin: from-shorthand(background: var(--background));
  background-clip: from-shorthand(background: var(--background));
}
.foo { --background: url('foo.png') content-box no-repeat; }
.bar { --background: url('bar.png') 10px 20px no-repeat; }

However, I think the best solution (and already works in browsers!) would be setting the full background shorthand inside a layer, and then reverting background-color to the previous layer:

@layer {
  .foo { background: url('foo.png') content-box no-repeat; background-color: revert-layer }
  .bar { background: url('bar.png') 10px 20px no-repeat; background-color: revert-layer }
}

@ljharb
Copy link
Member

ljharb commented May 28, 2023

A keyword could mean “skip” and at parse time the shorthand could be expanded to every longhand except the skipped ones; that doesn’t seem like an obstacle.

@gavinmcfarland
Copy link

gavinmcfarland commented May 28, 2023

It's changing the mental model of how background works by introducing the idea that background has a primary base which is a colour and then everything else on top

@gavinmcfarland But that's precisely how the current model works, see https://drafts.csswg.org/css-backgrounds-3/#background-color

This property sets the background color of an element. The color is drawn behind any background images.

Your example with background: red, url("image.png") no-repeat right top; is precisely invalid syntax because red is not in the last layer.

@Loirooriol You're right, how silly of me. It's been a while since I worked with colours and images together and I don't think I realised that the colour had to be at the end.

Ok, now I understand what the problem is. Eek, I'm not sure if there a great alternative. I now realise what Lea was trying to describe.

What is currently background-image should have really bean background-image-source, but obviously, we can't change how background-image works because that would break in every browser. Ultimately we're trying to find a word to describe a group of images, which is simply "images". And because most properties in CSS aren't plural, that sort of feels weird to have background-images. background-layer feels completely alien to me; it has little to do with images (regardless of any similarities it might have with how browser engines work).

My best suggestions are:

  • background-image-list
  • background-image-layer <- even this one makes me shudder a bit

@Loirooriol
Copy link
Contributor

@ljharb Consider this:

element.style.cssText = "background: var(--b)";
[...element.style].includes("background-color"); // ???

At specified-value time we don't know whether the variable will have the value that skips background-color from the expansion. So it's an obstacle.

@ljharb
Copy link
Member

ljharb commented May 30, 2023

@Loirooriol i mean, what does it say for that now?

@Loirooriol
Copy link
Contributor

It says true because background-color is part of the expansion, it's set to an internal pending-substitution value.

If in #5319 we add ignore, we could maybe say that this pending-substitution value will be treated as ignore if the shorthand has the value that skips the longhand. But otherwise it's not straightforward.

@ljharb
Copy link
Member

ljharb commented May 30, 2023

Yes, that's exactly what i'd say the default should be pending the var's value - but even if the default is true then the variable would be able to contain this new "ignore" keyword and override that. I'm not seeing a problem.

@Loirooriol
Copy link
Contributor

The problem is that ignore is just a proposal and it's not clear if the costs to implement it may be too high. Also no activity in the issue for almost 3 years, which I take as low implementation interest.

@SebastianZ
Copy link
Contributor

Summary of the proposals above:

  1. Add a new shorthand that includes all background layers but excludes the color. (Initial proposal by @JaneOri)
    Suggested names:
    • background-layer
    • background-overlay
    • background-stack
    • background-list
    • background-canvas
    • background-pattern
    • background-sheet
    • background-screen
    • background-cover
    • background-slice
    • background-image-stack
    • background-media
    • background-image-list
    • background-image-layer
  2. Add a new shorthand that covers the background positioning, sizing, etc. but excludes the images and color (proposed by @nt1m)
    Suggested name: background-placement
  3. Add a ::background() pseudo-element (proposed by @Crissov; also proposed by him earlier in another issue)
  4. Use additive cascade to add background layers instead of overwriting them (proposed by @gavinmcfarland; discussed separately in [css-cascade] Additive CSS #1594)
  5. Add a new keyword to background that skips overwriting the color (or any layer; proposed by @ljharb; related discussion in [css-variables][css-cascade] Proposal: additional CSS-Wide Keyword, "ignore" (primarily for css variable fallbacks) #5319)

Sebastian

@Loirooriol
Copy link
Contributor

  1. Close no change and tell authors to use background-color: revert-layer ([css-background-4] add background-layers property to set everything but background-color #8726 (comment))

@fantasai
Copy link
Collaborator

I think it's worth noting that we have a similar pattern of properties for fill, and might want to use the same name there: https://drafts.fxtf.org/fill-stroke-3/

@Schepp
Copy link

Schepp commented Jun 11, 2023

While this is not what the original poster asked for, here is a way to do exactly that: https://schepp.dev/posts/chaining-declarations-with-css-animation-composition/

So maybe the new thing might be based off whatever mechanic is at work here.

@fantasai
Copy link
Collaborator

@Schepp Ummmm, no, we definitely should not be using fill-forwards animations to declare normal specified values. :) https://www.w3.org/TR/web-animations-1/#fill-behavior

@Schepp
Copy link

Schepp commented Jun 20, 2023

Absolutely! 😅

But maybe the fact that this works opens up new ideas.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-background-4] add background-layers property to set everything but background-color, and agreed to the following:

  • RESOLVED: add shorthand for background-* minus background-color, name TBD
The full IRC log of that discussion <fantasai> SebastianZ: initial proposal was to create background-layers property that is separate from background-color but is otherwise same as 'background' shorhtand
<fantasai> -> summary comment https://github.com//issues/8726#issuecomment-1569020794
<fantasai> SebastianZ: The discussion went on and had different proposal to cover that use case
<fantasai> SebastianZ: 1st was new shorthand described above
<fantasai> SebastianZ: another that includes everything except images and color
<fantasai> SebastianZ: third was a ::background() pseudo-element
<SebastianZ> https://github.com//issues/8726#issuecomment-1569020794
<fantasai> SebastianZ: fourth was to add new keyword to skip overwriting the color
<fantasai> SebastianZ: and last was from Oriol to make no change, but teach authors to use background-color: revert-layer
<Rossen_> q?
<fantasai> SebastianZ: My personal opinion is to have something like the original proposal
<fantasai> SebastianZ: from my view it's the easiest way to achieve this as an author
<fantasai> SebastianZ: other suggestions have adantages as well
<fantasai> fantasai: agree with SebastianZ
<ntim> q+
<fantasai> fantasai: tackling list-editing cascade is a big project, worth doing, but unnecessary
<Rossen_> ack fantasai
<Rossen_> ack ntim
<fantasai> fantasai: just adding a shorthand is simple and solves the problem, biggest problem is naming the shorthand
<miriam> q+
<fantasai> ntim: Problem is you'll have 3 properties with similar syntax, hard to know the differences
<fantasai> ntim: you can do background: url, url, and then background-image: url, url; and then background-layers: url, url
<fantasai> miriam: I agree with SebastianZ and fantasai
<Rossen_> ack miriam
<fantasai> miriam: I mostly wanted to push against the 'revert-layer' option
<fantasai> miriam: teaching authors to use revert-layer is great! but it has specific cases where that's useful solution
<fantasai> miriam: but it requires adding new layers, and want to do that carefully
<fantasai> miriam: doesn't make sense as a universal solution to this problem
<fantasai> ??: I had a proposal to put positioning into shorthand without image, to avoid confusion of three properties that can take an image
<fantasai> s/??/ntim/
<fantasai> SebastianZ: that was my second option
<drott> fantasai: not a good idea, then you'd have to maintain two lists
<Rossen_> ack fantasai
<drott> fantasai: 1 for images, 1 for positioning
<drott> fantasai: sometimes there's use cases for splitting those things - but images and positioning are cascading together, so they should be declared together
<drott> fantasai: i'd advocate for original proposal, just need a shorthand name that makes sense
<fantasai> Rossen_: sounds like many folks leaning towards original proposal
<fantasai> Rossen_: would there be objections to resolve on the original proposal, and naming later?
<fantasai> RESOLVED: add shorthand for background-* minus background-color, name TBD

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

Successfully merging a pull request may close this issue.