w3c / csswg-drafts

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

[css-values-5] Using `if()` to do dark/light switching of image urls. #10577

Open MattWilcox opened 1 month ago

MattWilcox commented 1 month ago

Please forgive me if this one's a bit vague as I'm adding an issue here at Chris Lilley's request, and I'm not familiar with the process too much.

There are times when I need to swap the background-image as well as text colour, and it's 100% dependant on the same logic as light-dark() value. But, you can't do this:

.thing {
  background-image: light-dark(
    url('/assets/light.svg'),
    url('/assets/dark.svg')
  );
}

I'd like to be able to do that instead of having to resort to media queries to do what in the end is the same thing, for the same reason, at the same time - but not working on a colour property. In my mind, light-dark() is a toggle to map key-value pairs based on a scheme - but does not need to be (and should not be) tied to outputting "colour" as a return value (or however this is currently implemented/specced).

In this specific case, I have a graphical decoration added to some link text, and need to change the decoration's colour to match the text colour. Because SVG images loaded in via CSS don't work the same as if they're embeded in HTML they will not inherit to text colour, and I have to specify an entirely different asset to load to match the text colour.

https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark

https://mstdn.social/@mattwilcox/112792513614070547

tabatkins commented 1 month ago

Yeah, in the discussions for light-dark() we discussed the need for a more general function that can return any value (provsionally called schemed-value()). It was put to the side pending more use-cases, because it requires giving it var()-like semantics, which isn't as good as a function with a proper type (like light-dark(), which is a <color>).

svgeesus commented 1 month ago

The use case (pointing to separate light and dark media versions) is certainly a strong one. Especially for SVG images, which for security reasons are forbidden to link to external stylesheets, fonts etc or to inherit the surrounding styling context, when used in CSS or in the HTML <img> element.

MattWilcox commented 1 month ago

I'm not read in on the thinking behind all of this, so take this with a grain of salt - but I will say from the perspective of someone using the language without having read the spec first, I don't find light-dark() being cast to a type useful. Nothing about the language used for the function name indicates it would or should return a colour type. From my perspective, its just a thing that should select one value or the other based on the match. If it had been called color-light-dark() then yeah, I'd expect that limitation because the function name implies it returns a colour.

SebastianZ commented 1 month ago

What if we extended light-dark() for this use case, which seems absolutely reasonable, and continue discussing a more general solution in #7561? I.e. I propose a variant of light-dark() that takes two <image> values and returns an <image> value.

Sebastian

tabatkins commented 1 month ago

We can't extend it. It being a <color> means it can be grammar-checked in 'color', in gradients, etc. If it can be multiple types, then we can't grammar-check it and have to treat it like var() - that's what I was referring to.

If you meant "add a second function that's just like light-dark() but for images", at that point we might as well do the full thing. It's not meaningfully harder.

SebastianZ commented 1 month ago

If you meant "add a second function that's just like light-dark() but for images", ...

That was my idea, yes. A function with the same name but for images instead of a color.

... at that point we might as well do the full thing. It's not meaningfully harder.

Meaning giving it var()-like semantics, as you wrote earlier, I assume. If that's the case, then let's aim for the full thing. I just thought restricting it to just <image> values would make it easier to spec. and implement.

... which isn't as good as a function with a proper type (like light-dark(), which is a <color>).

Maybe not from a Typed OM point of view, though from pure CSS view it does, IMO.

Sebastian

svgeesus commented 1 month ago

If you meant "add a second function that's just like light-dark() but for images", at that point we might as well do the full thing. It's not meaningfully harder.

Okay so lets do that, then.

I propose to go for light-dark(<foo>, <bar>), then extend to schemed-color or schemed-value in the future, if needed?

I'd propose to do this for <color> (or <color> and <image>) for now, rather than everything.

Originally posted by @emilio in https://github.com/w3c/csswg-drafts/issues/7561#issuecomment-1644625985

svgeesus commented 1 month ago

@bramus also blogged about why we went for light-dark() but seemed to argue that a more general function was gated behind custom color-scheme support.

I don't see why that has to be the case.

romainmenke commented 1 month ago

Is there sufficient overlap with https://github.com/w3c/csswg-drafts/issues/10064 to consider something like color-scheme(dark) as a condition for <<if-cond>> ?

So that you can do : if(color-scheme(dark): blue, else: cyan)

In other words do we need a dedicated function for color schemed values if we are already considering other syntax for more generic inline conditions?

tabatkins commented 1 month ago

That is a very good point! It's a little longer, but it does neatly solve the parsing issues we'd have to address in a generic schemed-value() (which don't apply to light-dark(), since we know the value is a color).

svgeesus commented 1 month ago

So that you can do : if(color-scheme(dark): blue, else: cyan)

So, what would that look like for two image urls such as foo-dark.svg and foo-light.svg ?

tabatkins commented 1 month ago

if(color-scheme(dark): url(foo-dark.svg), else: url(foo-light-svg))

svgeesus commented 1 month ago

Okay, re-tagging to https://github.com/w3c/csswg-drafts/labels/css-values-5 because if() seems to be the way forward

svgeesus commented 1 month ago

@MattWilcox thanks for raising this, and I hope that the current direction meets your needs even though it doesn't use your proposed solution. I think it is a good way forward, and a solution is certainly needed.