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-values] String concatentation #542

Open
LeaVerou opened this issue Sep 28, 2016 · 40 comments
Open

[css-values] String concatentation #542

LeaVerou opened this issue Sep 28, 2016 · 40 comments

Comments

@LeaVerou
Copy link
Member

As discussed with @tabatkins during TPAC last week.

Now with variables (custom properties), string concatenation is coming up in more and more use cases. Constructing URLs from variables for instance (see #541) is useless without concatenation.
Also, building SVG paths from variables.

Tab suggested a concat() function. I wonder if we can reuse the syntax from content which already allows for concatenation in a simple and elegant way, and special case the few cases where existing widely used property values accept <string>+ (e.g. quotes) if they are sufficiently few and concatenation isn't needed there. Sure, it's weird if concatenation doesn't work in a few places, but I think the usability benefits of doing concatenation in the same simple way that authors are already used to, are worth it. Otherwise, CSS will end up like LISP with all the parentheses (imagine things like concat(var(--text), calc(1% * var(--foo))), which will be pretty common).

Related specs:

@dauwhe dauwhe added the css-values-4 Current Work label Sep 28, 2016
@AmeliaBR
Copy link
Contributor

AmeliaBR commented Jul 8, 2017

I'm intrigued by the idea of automatic concatenation of consecutive string tokens, but I'm worried that this might derail the general possibility of concatenation.

I personally don't think one extra layer of function notation will create an overwhelming number of parentheses. But maybe I've just been programming too long.

One thing I've mentioned elsewhere (and Lea seems to be assuming it, as well) is the idea that a concatenation function could do double-duty as a string coercion function, forcing any number or other non-string variables inside it into string version. This is very important for building SVG path data from variables. I'm worried that if you combine this with the default concatenation option you'd really make a mess of parsing.

So my vote is for a concat() or cat() or string() function. And sooner rather than later.

@LeaVerou
Copy link
Member Author

@tabatkins @fantasai Any thoughts? This is standing in the way of many cool CSS variable use cases, and once we agree on a syntax, not particularly hard to implement.
I got reminded of this because I was trying to use CSS variables in d: path(); yesterday, and quickly realized it was impossible :/.

@tabatkins
Copy link
Member

I'm strongly against the proposal to just make adjacent <string> values auto-concat; it clashes with existing grammars, restricts our ability to design reasonable grammars in the future, and this ability in 'content' isn't well-known anyway.

I'm supportive of concat() or string(). Having it auto-coerce things also seems fine to me, with the understanding that it'll use some well-defined notion of serialization, rather than necessarily preserving the exact input from the author.

(That is, string(1.0) might resolve to "1".)

@LeaVerou
Copy link
Member Author

@tabatkins Awesome, can we make it happen?

Regarding the name, I'd suggest text(). string() assumes knowledge of programming which doesn't necessarily apply to CSS authors, and concat() looks weird with only one argument. text() is also shorter.

@AmeliaBR
Copy link
Contributor

+1 to text() for being understandable and flexible.

Also +1 to Tab's suggestion that string serialization of numbers and lengths be independent of the formatting of the initial value. If there is demand in future, separate number formatting options could be considered, based on the number formatting options in counter().

@MeFoDy
Copy link

MeFoDy commented May 1, 2018

There is string() function here: https://www.w3.org/TR/css-gcpm-3/#using-named-strings.

Some printing tools have already implemented the behaviour from that working draft. I believe it's not really a good idea to have some new string() meaning. But it will be awesome to have a concatenating function named like text() or concat().

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed String Concatenation, and agreed to the following:

  • RESOLVED: work on astring-coercion-and-concatenation function
The full IRC log of that discussion <fantasai> Topic: String Concatenation
<astearns> github: https://github.com//issues/542
<fantasai> leaverou: There's a bunch of string value accepting proeprties in CSS, and can't use variables in there
<fantasai> leaverou: paths
<fantasai> leaverou: Lots of places where concatenation would be useful
<fantasai> leaverou: and don't have a way to do it
<fantasai> leaverou: Didn't recall any objections to the propsoal, just questions about what it's called
<fantasai> leaverou: I don't care, we just need a way to do it
<AmeliaBR> q+
<fantasai> chris: ppl using preprocessors take string concatenation for granted, it's simple there
<fantasai> chris: they're astounded when they find it's not available in raw CSS
<fantasai> leaverou: Primarily useful in URLs, but also useful in other places like paths
<fantasai> TabAtkins: I agree with the need for a function here, prefer concat() but fine with anything else
<chris> q?
<fantasai> leaverou: We've also had suggestions for a function that converts things to strings,
<xfq> ack AmeliaBR
<fantasai> leaverou: text() is generic enough to do both
<fantasai> string() sgtm
<fantasai> AmeliaBR: Problem with that is that for string coercion you often also want number formatting
<fantasai> AmeliaBR: so that might need to be a separate function
<fantasai> AmeliaBR: butwould need to be partof the system if you are going to make useful path dat from numeric variables
<fantasai> AmeliaBR: need to concatenate not just letters but numbers from variables
<fantasai> AmeliaBR: calc expressions
<dbaron> q+ to ask what the inputs to this function can be, and where it can be used
<fantasai> AmeliaBR: etc.
<fantasai> TabAtkins: What are the use cases for coercion? Debugging ovviousl, anything else?
<fantasai> leaverou: ...
<fantasai> Am Big in dataviz
<leaverou> s/.../generated content to display a variable value in the UI/
<leaverou> q+
<fantasai_> AmeliaBR: e.g. bar graphs, want to use value in drawing but also labelling
<fantasai_> AmeliaBR: don't want to duplicate content
<fantasai_> TabAtkins: I really don't want to get into string formatting
<fantasai_> TabAtkins: otherwise do see the value in do see value in displaying 50% on bar chart while 50% also used to size the bar chart
<fantasai_> AmeliaBR: So if we want to leave the generic number formatting issue for later, that's fine
<fantasai_> AmeliaBR: So long as we still have idea that basic concat function can take non-string values and simply print them out
<fantasai_> AmeliaBR: so you can use them for path data
<fantasai_> AmeliaBR: In path data you generally want to preserve maximum precision anyway
<fantasai_> leaverou: example ... interpolation
<fantasai_> leaverou: Don't want to define how concat() interpolates with each other
<xfq> ack db
<Zakim> dbaron, you wanted to ask what the inputs to this function can be, and where it can be used
<fantasai> dbaron: Reading the proposal wasn't clear to me what the inputs of this function is and what the output is in terms of types
<fantasai> dbaron: What CSS value types can be used in here?
<fantasai> TabAtkins: output tpe is tring
<fantasai> TabAtkins: input type is any thing, standard serialization of the token
<fantasai> dbaron: There will be a spec defining standard serialization of a token?
<leaverou> s/example ... interpolation/yes, that simplifies interpolation as well, if types of arguments were not coerced we'd need to define interpolation between two concat() calls
<fantasai> TabAtkins: Need that for variables anyway
<fantasai> TabAtkins: If it doesn't exist yet, some othe rspec is implicitly relying on it and it needs to be defined
<fantasai> astearns: Wrt used, it's anywhere with a string?
<fantasai> fremy: Exception for url?
<fantasai> TabAtkins: No, works in url()
<xfq> ack lea
<fantasai> TabAtkins: url() can take a string
<TabAtkins> s/take a string/take only a literal string, there's another issue for generic <string> input/
<fantasai> astearns: I'm hearing lots of nods on having this thing. Any implementer interest?
<fremy> (to clarify what tab said, url() can take a string but not a <string>)
<fantasai> astearns: From silence sounds like, yes this would be a good thing, no it's not a priority
<fantasai> emilio: Expectation is that you can do like sth(var(--whatev))?
<fantasai> emilio: Then how can you define it to be any token?
<fantasai> TabAtkins: var() is processed at a higher level than any value
<fantasai> fremy: If you want a string, you do text("string")
<TabAtkins> (It's specific as taking a <string> in the syntax, but in Syntax we handle url() in special ways that prevent it from taking string-producing functions.)
<fantasai> emilio: If it takes any token
<fantasai> fremy: If it's not a string, then you convert
<fantasai> TabAtkins: I think Emilio got it
<fantasai> astearns: OK, naming. What do we call the thing?
<fantasai> AmeliaBR: Lea suggested text(), but there's already a text() function in paged content
<fantasai> fantasai: How about string? was in Lea's original proposal
<fantasai> leaverou: sounds fine
<fantasai> chris: sounds fine
<bkardell_> lol
<fantasai> AmeliaBR: Sorry, confused things. It's the string() function that exists, text() does not
<fantasai> AmeliaBR: and already implemented
<chris> I care more that it exists, than what precisely it is called
<xfq> https://drafts.csswg.org/css-gcpm-3/#using-named-strings
<tantek> I for one an all for the cat() function, I bet it would poll well on Twitter 😺
<bkardell_> lol
<fantasai> astearns: Any objections to text()?
<chris> Lets go with text
<fantasai> dydz: Prefer concat(), but ...
<Rossen> combine()
<fantasai> AmeliaBR: Want names that are understandable by non-programmers in CSS
<fantasai> AmeliaBR: Also, we tend not to truncate identifiers in CSS
<chris> concat is not immediately obvious to non programmers either. both cat and concat are abbreviations
<fantasai> TabAtkins: We are not using cat(), tantek!
<tantek> 😿
<fantasai> bkardell_: I don't have a better suggestion, but text() is not very clear to me
<TabAtkins> text(50%)
<Rossen> +1 to bkardell_
<fantasai> bkardell_: There are so many ways that I coudl interpret "text"
<tantek> +1 to bkardell_
<fantasai> flatten() :P
<fantasai> chris: I think it's pretty clear
<fantasai> myles__: We should think about whether concatenation or coercion is more common use case
<TabAtkins> url(text("http://example.com", var(--foo)))
<florian> echo() ?
<tantek> printf()
<florian> printf()
<fantasai> AmeliaBR: text() is clear for coercion, maybe less clear for concatenation
<TabAtkins> No unixisms!
<TabAtkins> y'all weirdos!
<chris> and text(var(--foo)) with one param is clearer than concat(var(--foo))
<Rossen> stringify()
<Rossen> toString()
<TabAtkins> to-string()
<chris> DOTtoString
<dbaron> hopefully everybody has forgotten XPath by now?
<tantek> Time for a Twiter survey!
<fantasai> iank_: Spreadsheets use concatenate and concat
<fantasai> TabAtkins: It's terrible and hard to spell
<fantasai> TabAtkins: These are all great names, except for all the ones that are bad.
<chris> https://developer.mozilla.org/en-US/docs/Web/XPath/Functions/concat
<fantasai> TabAtkins: Let's table this and put together a non-binding Twitter poll
<fantasai> florian: Make sure you include an international audience
<fantasai> bkardell_: That works best if we all promote it so let us know
<fantasai> leaverou: Twitter doesn't have enough space for examples, and based on what examples you use can get different reactions
<fantasai> TabAtkins: I'll put together coercion example and concat example, and you can review them
<chris> https://stackoverflow.com/questions/9493732/difference-between-text-and-string
<fantasai> astearns: Sounds like we'll do this and decide the name later, would be interested in implementer interest
<fantasai> astearns: Any objections?
<fantasai> RESOLVED: work on astring-coercion-and-concatenation function

@kizu
Copy link
Member

kizu commented Feb 27, 2019

One thing I want to mention: what would be really nice if that future string concatenation could work with anything that accepts strings, especially, grid-template-areas, to allow generating named areas from other variables, for example.

Of course, this should work also by allowing converting idents into strings, so those could be reused both inside grid-template-areas and other grid properties.

And this also brings me to another kinda related topic: ident concatenation. Probably also related to converting anything into anything, and related to the attr()'s second argument. All of this is probably off-topic for this issue, but my point is: if we'd want to think about the name for string concatenation, we should remember that we could potentially have other functions in the future doing similar things, and we should come with a name that could work best in the wider picture.

@AmeliaBR
Copy link
Contributor

@kizu
I think the grid template use case would work with what we decided. If you use a non-string inside the function, it gets converted to a string based on its serialized value. The serialization of an ident is its character sequence. And it would definitely apply in any function that accepts a string data type.

Converting a string to a non-string (string to ident, string to parsed number or length) would be a separate issue. But I agree that adding a general parse function for that case is tied in with the unimplemented second parameter to attr.

@tabatkins
Copy link
Member

Yes, this function's type will be <string>; any place that accepts a <string> should accept it.

@BigBadaboom
Copy link

Playing devil's advocate for a moment... calc() already accepts seven different literal types. Why couldn't string be the eighth?

@SebastianZ
Copy link
Contributor

Playing devil's advocate for a moment... calc() already accepts seven different literal types. Why couldn't string be the eighth?

Because calc() is obviously for calculating something and deals with numeric values.

Sebastian

@AmeliaBR
Copy link
Contributor

AmeliaBR commented Mar 1, 2019

@BigBadaboom And overloading calc() to do string concatenation would mean having to do calc("" + 50%) to get type coercion. And even if JS devs are used to that, it's still ugly.

@bradkemper
Copy link
Contributor

string() already produces strings, and is understandable to css authors. I would rather not have string() produce a string one way, and text() produces a string another way. I would rather just extend string(). It seems doable. If the argument is an identifier that matches a string-set, then parse it as existing string(). Otherwise, coerce space-separated arguments into a string. Then allow this string to be used anywhere that strings are allowed.

I don’t buy the argument that CSS authors don’t know what “string” means. If that was the case, we shouldn’t have used it for GCPM. We have it there now, it exists, and it can be the single tool that authors reach for when they need a string.

@bradkemper
Copy link
Contributor

It more CSS-y without the commas anyway.

@faceless2
Copy link

faceless2 commented Mar 12, 2020

Minutes from the meeting where this was discussed suggested this was going to a twitter poll on naming - did that go anywhere?

The name summary seems to be concat, cat, text, stringify, combine, to-string - I'm excluding string as that's already in css-gcpm (and I see no advantaged in trying to merge this functionality into that). I would like to add join to that list (athough only because tab says we're not allowed "cat", despite 50 years of the One True Operating System saying otherwise).

We're certainly going to implement this (as -bfo-join(<string> [<ws> <string>]*) until a name is finalised) - it ties in with something else we're working on, it's neat, and it's about 20 lines of code.

@Crissov
Copy link
Contributor

Crissov commented Mar 12, 2020

Iʼm all for a name that is easily understood by non-programmers. Unfortunately, most candidates already have some established meaning (and thus user expectations) in one programming language or the other.

join, for instance, is known as a function to concatenate the items of an array, list or map into a string, but with a custom separator string between them. chain and link sound similar to me, but have other drawbacks, although they are not abbreviations like concat and, way worse, cat.

I like text and now wish calc had been math. Itʼs better than type, write, line and log, which have not been suggested yet, but appear in other languages for similar functions, as does print which does not work well for CSS.

A special kind of stringify functions is slugify for generating slugs (short titles, URL-friendly). I think itʼs too narrow-focused.

@noamr
Copy link
Collaborator

noamr commented Oct 29, 2020

join, for instance, is known as a function to concatenate the items of an array, list or map into a string, but with a custom separator string between them. chain and link sound similar to me, but have other drawbacks, although they are not abbreviations like concat and, way worse, cat.

concat is a standard abbreviation, already used in the web platform for a similar purpose (String.prototype.concat). Seems like the choice I would go with.

@LeaVerou
Copy link
Member Author

@noamr concat() only makes sense when you have 2+ arguments. For a single argument, concat(foo) looks awfully confusing.

@noamr
Copy link
Collaborator

noamr commented Oct 29, 2020

@noamr concat() only makes sense when you have 2+ arguments. For a single argument, concat(foo) looks awfully confusing.

Hrm you're right.
My second favorite was to-string.

@noamr
Copy link
Collaborator

noamr commented Oct 29, 2020

So:

  • concat cat and combine may be strange for a single string, though on Linux for example cat is often used for a single string.
  • text has a different meaning than string, e.g. innerText vs. innerHTML
  • stringify is usually meant for non strings, e.g. an object -> JSON

So IMO to-string makes the most sense.

@noamr
Copy link
Collaborator

noamr commented Oct 30, 2020

Suggesting an alternative approach here.
Maybe general-purpose string concatenation is too low-level for CSS.

Instead, I'm suggesting to treat every string-requiring CSS property differently.

  • For paths, allow constructing paths without strings (see here: [css-shapes] Allow CSS grammar for path shapes #5674 (comment))
  • For urls, allow the url function to take more than one argument and have that function concat them.
  • For some of the other props requiring strings, like content, allow string concatenation in the same way that it's done today, by having several arguments (e.g. content: "(" attr(title) ")", or font-family: "Times-New-Roman", var(--fallback))

The reason for this is a sense that strings inside CSS may create a "language within a language" for each property, (which is already my sense with e.g. path strings).

@LeaVerou
Copy link
Member Author

Not sure how innerText demonstrates the difference between "text" and "string", since there's no innerString. Also note that innerText was never the output of a rigorous consensus-driven process, but a Microsoft extension that was later standardized to pave the cowpaths.

Do note that in spreadsheets, it's a text() function that converts to a string.

I don't think adding string concatenation on a case by case basis is a good idea at all. It makes each individual property more complicated, it makes the language less consistent (which properties support concatenation and which don't?) and adds overhead to learning each property, since each property does concatenation differently (lack of internal consistency). Also it would mean that authors need to wait for the full standards lifecycle (proposal + draft + implementation + test) for every single concatenation use case that we did not foresee early on.

Also note that font-family doesn't support concatenation. If you have a variable with "Times" and another one with " New Roman", you cannot turn them into a single font family by just placing them next to each other. The only property that currently supports actual concatenation is content.

@tabatkins
Copy link
Member

Yeah, I'm strongly against special-casing string concatenation per usage site, and I've already given reason why I do not want to go down the "putting them next to each other implies concatenation" route (it ties our hands wrt grammar design later).

@SebastianZ
Copy link
Contributor

Was the introduction of new syntax already considered for this? Many languages use an operator for string concatination like + or &. Would that be possible for CSS? I mean something like

"string1" + 1.0 + "string2"

Note that this is independent of the discussion about automatic type conversion. A function could still be required for converting different types into a string, i.e.

"string1" + string(1.0) + "string2"

Sebastian

@noamr
Copy link
Collaborator

noamr commented Oct 30, 2020

Not sure how innerText demonstrates the difference between "text" and "string", since there's no innerString. Also note that innerText was never the output of a rigorous consensus-driven process, but a Microsoft extension that was later standardized to pave the cowpaths.

Do note that in spreadsheets, it's a text() function that converts to a string.
In spreadsheets and in other places, yes. In the web, my connotation of the word 'text' is more about text that is accessible to users (like innerText and text nodes) or about encoding/decoding, while string is usually neutral about its content.

I don't totally object to text, but saying that e.g. JSON.stringify and Object.toString are closer to what this function does than TextEncoder, createTextNode and innerText.

I don't think adding string concatenation on a case by case basis is a good idea at all. It makes each individual property more complicated, it makes the language less consistent (which properties support concatenation and which don't?) and adds overhead to learning each property, since each property does concatenation differently (lack of internal consistency). Also it would mean that authors need to wait for the full standards lifecycle (proposal + draft + implementation + test) for every single concatenation use case that we did not foresee early on.>

I'm not suggesting to add concatenation on a case by case basis, but rather attempt to solve the problems that require concatenation in a case-by-base basis, without using strings if possible (e.g. what we're doing with paths).

Also note that font-family doesn't support concatenation. If you have a variable with "Times" and another one with " New Roman", you cannot turn them into a single font family by just placing them next to each other. The only property that currently supports actual concatenation is content.

This is where I think this feature might become more powerful than we realize, and can change CSS and the web in unpredictable ways.

For example:

  • you could start to be able to write full SVGs with CSS custom properties and inheritance and concatenate them in a data: URI.

  • If you have a font used somewhere, you wouldn't be able to statically analyze which stylesheet it came from, as it might be a concatenation of many CSS properties, inheritances and calcs.

  • I can see how people would start creating CSS uglifiers, that turn readable CSS into CSS that you can't understand with a whole bunch of variable-concatenated URLs, background SVGs, font-families, and clip-paths.

I'm not against any of the above, but I think that we should give them a consideration. This feature enables a lot more than meets the eye.

@LeaVerou
Copy link
Member Author

LeaVerou commented Nov 2, 2020

I believe concatenating data URI SVGs with custom properties is one of the primary use cases, not "more than meets the eye".

@noamr
Copy link
Collaborator

noamr commented Nov 2, 2020

I believe concatenating data URI SVGs with custom properties is one of the primary use cases, not "more than meets the eye".

It wasn't an obvious one to me and wasn't in the description of the issue.

Dynamically constructing full SVGs from CSS and uglifying are use-cases that can IMO fundamentally change the way CSS is used, reminiscent of eval in Javascript. It doesn't make it an undesirable feature but I'm not sure the implications were given full consideration.

@LeaVerou
Copy link
Member Author

LeaVerou commented Oct 9, 2021

There is string() function here: w3.org/TR/css-gcpm-3/#using-named-strings.

Some printing tools have already implemented the behaviour from that working draft. I believe it's not really a good idea to have some new string() meaning. But it will be awesome to have a concatenating function named like text() or concat().

If we do decide that string() is a better option, I don't think this conflict makes it a dealbreaker, given that no browser has implemented this. Print formatters are like preprocessors in the sense that they are upgraded explicitly and run explicitly, so they can deal with a migration. They could even detect these cases and print out a warning and even auto-migrate, since the ident used in this function needs to be defined somewhere else via string-set.

I think we should name it string() and rename the GCPM one to string-get(), which complements string-set nicely. I was against string() in 2018 when we started discussing this, because I felt CSS authors would not necessarily understand what strings are. However, @property brings CSS types front and center, so CSS authors need to become familiar with the concept of strings anyway, so calling this function text() or whatever other thing is doing them a disservice.

@clulece
Copy link

clulece commented Mar 25, 2023

Hi, I'd like to add another use case I haven't seen mentioned here: concatenating units to variables for css functions that require them. For example, for passing hsl components that need to be modified in css:

--h: 35;
--s: 100;
--l: 50;
background-color: hsl(var(--h), var(--s), calc(var(--l) * 0.5));   /* does not work */
/*                hsl(var(--h), concat( var(--s), "%" ), concat(calc( var(--l) * 0.5 )), "%" );  */

@tabatkins
Copy link
Member

That will not work with the feature we're discussing here; it's for concatenating strings to produce strings, not concatenating raw CSS text to produce more raw CSS text which is then parsed. You'd just get the string "100%", which is invalid as an argument to hsl().

What you're asking for is already possible with calc(). calc(var(--s) * 1%) "converts" a plain number into a percentage (or any other unit).

@kizu
Copy link
Member

kizu commented May 18, 2023

While experimenting with anchor positioning, I find myself often creating ”namespaced” anchor names, where an ability to use a variable and produce multiple namespaced dashed idents would be very very useful.

Basically, currently I have to write something like

<span
    class="context"
    style="
        --is: --foo;
        --is-content: --foo-content;
        --is-extra: --foo-extra;
    "
></span><span
    class="anchor"
    style="
        --for: --foo;
        --for-content: --foo-content;
        --for-extra: --foo-extra;
    "
></span>

Basically, when I want to have two components, and connect multiple parts of one to multiple parts of another, I have to write these verbose definitions.

If we would have something like concat(), we could do something like this:

<span class="context" style="--is: foo;"></span><span class="anchor" style="--for: foo;"></span>

and define all the things in the CSS:

.context {
  --is-root: concat(--, var(--is));
  --is-content: concat(--, var(--is), -content);
  --is-extra: concat(--, var(--is), -extra);
}
.anchor {
  --for-root: concat(--, var(--is));
  --for-content: concat(--, var(--is), -content);
  --for-extra: concat(--, var(--is), -extra);
}

Making it possible to use as many different anchors in a certain context, namespaced by just one CSS variable defined on the root element of our component.

@yisibl
Copy link
Contributor

yisibl commented Jan 6, 2024

I think we should name it string() and rename the GCPM one to string-get(), which complements string-set nicely. #542 (comment) in 2018 when we started discussing this, because I felt CSS authors would not necessarily understand what strings are. However, @Property brings CSS types front and center, so CSS authors need to become familiar with the concept of strings anyway, so calling this function text() or whatever other thing is doing them a disservice.

I agree with @LeaVerou.

I don't think CSS authors will have a hard time understanding what string() means, especially since the @property already brings in the <string> type, which they need to be familiar with anyway.

So I give string() a vote.

The user's actual use case

  1. Displays a tooltip for the value of the <input type=range>.
image

For now, we're stuck with a relatively hacky approach.

<div class="box" style="--range: 38;">
  <input type="range" value="30" min="20" max="90" id="range">
  <output class="tooltip"></output>
</div>

<style>
@property --range {
  syntax: "<integer>";
  initial-value: 0;
  inherits: true;
}
.tooltip::before {
    counter-reset: range_integer var(--range);
    content: counter(range_integer);
}
<style>

Cons: If it's a decimal it can't be displayed, but a lot of times the value of <input type=range> is a decimal.

After the improvements, we just need:

.tooltip::before {
    content: string( var(--range, 0) );
}
  1. https://twitter.com/anatudor/status/1394680457711788038

@SebastianZ
Copy link
Contributor

As there's an active discussion about generating idents in #9141 and string concatenation was mentioned there as well, I think it makes sense to align both syntaxes.

And it seems most people are leaning towards a string() function for this use case.

So I'd like to concretize the previous resolution and get a resolution to name it string() and settle on a syntax for it, which should then also be used for the function discussed in #9141.

Furthermore, I'd like to get a resolution on whether we want to introduce an operator as an alternative to the function.

Sebastian

@LeaVerou
Copy link
Member Author

I think the MVP is definitely a function, an operator comes at a much higher cost and the benefit is questionable. We can always start with a function and if it turns out that authors are concatenating all over the place, we can explore making that easier, but I think a resolution for an operator right now would be premature.

@astearns
Copy link
Member

@SebastianZ I’m not sure we need call time just yet for the name. My interpretation of the previous resolution is that when this gets added to the draft it’s up to the editors to choose a name. Then we can open a new bikeshedding issue if anyone thinks they picked incorrectly.

@astearns astearns removed the Agenda+ label Apr 15, 2024
@kizu
Copy link
Member

kizu commented Jan 14, 2025

Now that #9141 is closed, and we will have ident(), should we return to this issue as well, while we're at it?

I'd vote for string() for the function name, as it will have a nice consistency and discoverability based on the already existent <string> type and the <ident> + ident() pair.

cc @bramus @tabatkins

@bramus
Copy link
Contributor

bramus commented Jan 14, 2025

Would string() also cast arguments to a <string>? If not then I believe concat() would be more correct as a name, otherwise string() seems fine.

@kizu
Copy link
Member

kizu commented Jan 14, 2025

Would string() also cast arguments to a ? If not then I believe concat() would be more correct as a name, otherwise string() seems fine.

I think so: many use cases mentioned in this issue point towards this (like all the usage of the content property for displaying a value of some variable).

@kizu
Copy link
Member

kizu commented Jan 27, 2025

I just published an article about my experimental native CSS mixin that allows displaying some of the values as strings: https://kizu.dev/preview-mixin/

How hacky it is? Very hacky. A lot of juggling of registered custom properties, math, and custom counter styles. Having a native string() would allow doing most of what I am doing there several orders of magnitude easier :)

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