Skip to content

[css-forms-1] For control-value() to be useful it needs a way to convert to other types. #11842

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
lukewarlow opened this issue Mar 5, 2025 · 10 comments

Comments

@lukewarlow
Copy link
Member

lukewarlow commented Mar 5, 2025

Currently CSS Forms defines control-value() to be able to return a string or number, but for this to be useful we would need a way to convert to other CSS types (#6408 ?).

Take <progress> as an example, it has a position property (which is probably more useful than the value one for this CSS func as it handles the maths between value and max to determine actual progress value) between 0 and 1. This is useful for sizing the fill portion of the control, but for that we'd need a way to make it a (percentage) length instead.

progress::fill {
    inline-size: convert(calc(content-value(type(<number>)) * 100), type(<length>), "%");
}

Alternatively if we could pass other types into content-value() and the browser could do the conversion for us that'd also work?

progress::fill {
    inline-size: calc(content-value(type(<length>), "%") * 100);
}

Either of these could also help with styling the color input too (along with #11837 )

The default style could be something like:

input[type=color]::color-swatch {
     background-color: content-value(type(<color>)); /* or convert(content-value(), type(<color>)) */
}
@lukewarlow
Copy link
Member Author

One possible way around this specifically for progress (and similar for meter( is to do something like below, because their values are encoded in the DOM.

progress:not(:indeterminate)::fill {
    inline-size: calc(100% * calc(attr(value, 0) / attr(max, 100)));
}

@nt1m
Copy link
Member

nt1m commented Mar 5, 2025

The current draft includes a type argument, I suppose that argument could just be extended to whatever people find useful, you'd also be able to use it within calc().

I haven't really thought about it too much tbh

@SebastianZ
Copy link
Contributor

With explicit type conversion as discussed in #6408, I think your examples would look different.

progress::fill {
    inline-size: convert(calc(convert(content-value(), <number>) * 100), <percentage>);
}

and

input[type=color]::color-swatch {
     background-color: convert(content-value(), <color>);
}

Note that there is no need for a type() function. And as @nt1m pointed out in the previous comment, it also isn't part of the draft spec.
With the type attribute from the spec., those examples should look like this:

progress::fill {
    inline-size: convert(calc(content-value(<number>) * 100), <percentage>);
}

and

input[type=color]::color-swatch {
     background-color: content-value(<color>);
}

Though maybe it is also possible to make the return value of the function context-sensitive, i.e. let it return a <number> value for <progress>, <input type="range"> and other elements, a <color> value for <input type="color">, a <url> value for <input type="url">, etc.

With that, you could skip the explicit type definition/conversion for the content-value() function for the given use cases and write this:

progress::fill {
    inline-size: convert(calc(content-value() * 100), <percentage>);
}

and

input[type=color]::color-swatch {
     background-color: content-value();
}

Sebastian

@nt1m
Copy link
Member

nt1m commented Mar 5, 2025

I'd also be OK with just supporting control-value(<percentage>) directly fwiw, rather than having to deal with unit conversions.

@lukewarlow
Copy link
Member Author

Ah the type() bit was me guessing based on the new attr() function stuff.

@yisibl
Copy link
Contributor

yisibl commented Mar 6, 2025

I would prefer to see a generalized conversion function(#6408).

@tabatkins
Copy link
Member

This function isn't doing parsing on a value; it shouldn't take a <syntax> argument. The form control knows what type of value it contains - a string, a number, a color, etc. It should just take a handful of keywords (probably just number, percentage, color, string?), and go IACVT if you request a type that the form control doesn't support.

  • All controls would support string, resolving to the same string value you get from the .value property.
  • number and range inputs support number.
  • Progress/meter support number and percentage (with the default ranges being 0-1 and 0%-100%)
  • Color inputs support color.
  • Maybe file inputs can support an image keyword? There's many complaints thru the years of not being able to easily do "upload previews" on the web (tho today you can wrangle it with blob: urls)

@cdoublev
Copy link
Collaborator

cdoublev commented Mar 8, 2025

Would it then be reasonable for it to take <syntax-type-name>? with string as its default?

cdoublev added a commit to cdoublev/css that referenced this issue Mar 9, 2025
- <attr()>: updated grammar
- <control-value()>: new function
- <random()>: updated grammar
- <random-caching-options>: updated grammar
- slider-orientation: new property

There are also a bunch of new pseudos from CSS Forms.

control-value() should be an arbitrary substitution (w3c/csswg-drafts#11860),
which is not implemented in this commit, and it should take a type as a keyword
(w3c/csswg-drafts#11842).

random() might now be simplified at parse time when <random-caching-options> is
specified as a <number>, which is not implemented in this commit.
@sorvell
Copy link

sorvell commented Mar 14, 2025

Just want to confirm that for % we mean the percent of the value between min and max (e.g. percentage = ((value - min) / (max - min)) * 100).

@tabatkins
Copy link
Member

@cdoublev

Would it then be reasonable for it to take <syntax-type-name>? with string as its default?

No, because like I said, this is not doing CSS parsing on a value. The element has already parsed its value in an HTML-specified way, and is holding onto both a parsed and a string form of it. We just need to indicate which version of the value we want, in a way that tells CSS what that type is going to be at stylesheet parse time. Thus, the handful of specialized keywords.

@sorvell

Just want to confirm that for % we mean the percent of the value between min and max

Yup, that's what I meant too. 👍

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

7 participants