w3c / csswg-drafts

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

[css-ui] ? Allow <textarea> to be sized by contents. #7542

Open bfgeek opened 2 years ago

bfgeek commented 2 years ago

See: https://github.com/whatwg/html/issues/6807 for more context about the problem we'd like to solve. The TL;DR is that we'd like to allow the <textarea> element to be sized to its contents a little easier. I.e.

textarea-1

We explored different solutions in the whatwg thread. Folks seem to prefer a CSS solution to this problem - hence this issue!

One way to achieve the "minrows"/"maxrows" in that issue is to use the "lh" unit. (Fortunately the "lh" unit works exactly the same way textareas are implemented today - in that they use the first available font to calculate the line-height).

E.g.

textarea {
  min-height: 2lh;
  max-height: 5lh;
}

The only thing we are missing is the ability to use the "actual"[1] intrinsic size of the textarea. There are a few different potential solutions here.

Today the intrinsic-size of a textarea will (roughly) read the "rows" attribute, and multiply this by the "lh" unit. We need a switch to instead read the "rows" attribute to be based on the actual number of lines. One potential solution is:

textarea-rows: auto | <number>

If "auto" was set the user-agent would read the number of lines, then multiply this by "lh" to get the intrinsic block-size for the text-area.

We could then map the rows attribute to a presentation style hint to this property.

cc/ @tabatkins @lilles

fregante commented 1 year ago

Why not field-size: fit-content?

/* expand vertically */
textarea {field-size: fit-content}

/* expand horizontally */
input[type=text] {field-size: fit-content}

This property:value combo has a few benefits:

Then, if a wrapping input field were to be specced by CSS, it could automatically start expanding it vertically instead.

/* expand vertically */
input {
  wrap-property-tbd: wrap;
  field-size: fit-content;
}

They would need to be specified together just like overflow:hidden; white-space:nowrap; text-overflow:ellipsis

bfgeek commented 1 year ago

@LeaVerou

What are we bikeshedding? Is it the naming of the form-sizing property? A max-content value on another property? If so, which one?

We are bikeshedding the (current) form-sizing property, and the two values auto and normal.

Is this intended to eventually also control width autosizing, which is also a common request (though not equally common)? I really hope we don't introduce two entirely separate bits of syntax for these very similar things.

This is in the above resolution, and you can test the behaviour in Chrome Canary with experimental web platform features enabled.

bfgeek commented 1 year ago

Various bikeshedding suggestions:

@tabatkins suggests legacy | auto for the values in https://github.com/w3c/csswg-drafts/pull/9251#issuecomment-1696234210

I've also seen people suggest form-sizing: content . (personally I also don't mind field-size or field-sizing for the property name).

clshortfuse commented 1 year ago

I prefer field over form, because I can already see people thinking it's related to <form>. I don't like terms like legacy only because it doesn't actually describe what's going on. Basically, people would have to research externally what it used to do to then decide not to use it. But if there's no way to sum up the legacy behavior in one or two words, I can understand.

LeaVerou commented 1 year ago

Thanks both @bfgeek and @clshortfuse!

Then discussion come about the complexities of making <input> multiline.

Yeah, that's not going to happen, but autosizing width is still very useful! I've written a lot of fragile custom code to facilitate this.

We are bikeshedding the (current) form-sizing property, and the two values auto and normal.

Not sure if this is still on the table, but I would really, really prefer a value on width and height for this instead of a new property. Reasons:

If this is entirely a non-starter for <reasons>, the new property should at least make it clear what dimension is being altered (width/height/block/inline).

I also agree about the arguments against legacy as a value. Also, legacy implies this is not useful and only exists for legacy reasons, but there are plenty of use cases where you don't want to size form fields by their contents.

bfgeek commented 1 year ago

If this is entirely a non-starter for reasons, the new property should at least make it clear what dimension is being altered (width/height/block/inline).

We discussed this at length previously (see previous discussion), the concerns you've described above were considered, in particular see the discussion about compressibility, and interactions with percentages. This is agenda+ for a bikeshedding discussion.

Compat: The upgrade path to supporting width autosizing is unclear. If this feature launches working only for <textarea> then it may not be web compatible to also allow it to work for <input>. So then what do we do? Introduce a separate property for input? And what about <select> even later? Another one? Yikes!

I'm unclear what you are describing here - but the implementation in Chrome Canary (with the experimental web platform features enabled) sizes both <input> and <select> based on their contents. Please file implementation bugs if this doesn't work as you expect.

If this is entirely a non-starter for , the new property should at least make it clear what dimension is being altered (width/height/block/inline).

I believe we discussed this previously, and people thought that it was better just to control both axes simultaneously.

css-meeting-bot commented 1 year ago

The CSS Working Group just discussed [css-ui] ? Allow <textarea> to be sized by contents., and agreed to the following:

The full IRC log of that discussion <lea> Straw poll posted in https://github.com/w3c/csswg-drafts/issues/9102#issuecomment-1747785298
<fantasai> iank_: Put on agenda again because some discussion about current name and values and suggestions for other ones
<fantasai> iank_: so agenda to bikeshed these
<fantasai> iank_: I've seen a few variations. A lot keep 'form-sizing' but use 'content' instead of 'auto'
<fantasai> iank_: another suggestion was normal | auto?
<fantasai> TabAtkins: don't think we should go with generic keywords, Lea's suggestion is better
<TabAtkins> content | fixed
<TabAtkins> s/Lea's/later/
<fantasai> iank_: So 'form-sizing: content' and also 'field-sizing: content'
<lea> q?
<fantasai> TabAtkins: based on the suggestions in the thread, I suggest 'content' and 'fixed'
<lea> q+
<fantasai> TabAtkins: weak pref, but sound reasonable
<astearns> +1 to -sizing & content
<fantasai> TabAtkins: and even if the precise definition is wonky, it's easy to guess what the behavior is
<astearns> ack lea
<fantasai> TabAtkins: unlike auto / normal / default / legacy
<fantasai> lea: how does this interact with width/height?
<fantasai> iank_: this changes how you resolve the intrinsic values
<miriam> q+
<fantasai> iank_: if you specify 'width: 100%', during intrinsic sizing might behave as min-content/max-content
<fantasai> iank_: if you specify 'width: 100px', won't get a behavior change
<fantasai> TabAtkins: this makes form contents use the content-based sizing rules that normal non-replaced elements do
<fantasai> TabAtkins: form controls by default have weird intrinsic sizing due to legacy
<fantasai> iank_: This also disables the compressibility quirk
<fantasai> iank_: this quirk gets around the fact that form control elements have a fixed intrinsic size
<fantasai> iank_: if you set e.g. width: 100%, the min-content size will be zero
<fantasai> iank_: this will opt you out of that behaior
<fantasai> iank_: it existed because there wasn't a good intrinsic size before
<astearns> ack miriam
<fantasai> lea: does it have other effects? e.g. Chrome doesn't allow visible overflow
<fantasai> iank_: this only affects intrinsic sizing
<TabAtkins> compressibility thing: https://drafts.csswg.org/css-sizing/#min-content-zero
<fantasai> miriam: I'm liking 'content', but curious how it interacts with the sizing *-content keywords
<fantasai> miriam: they're doing slightly different things in different places, will it be confusing?
<fantasai> iank_: I don't think so, we suspect ppl already using min-content/max-content on these form controls already
<florian> q?
<fantasai> iank_: if you use this, set 'form-sizing: content', then this'll change how *-content behave, make them follow the content
<fantasai> florian: This is actually a good relationship, because it ties the *-keywords to be based on the contents
<fantasai> iank_: Any preferences on form sizing vs field sizing
<fantasai> astearns: slight preference for field, because form means other things too
<fantasai> miriam: same
<fantasai> lea: also form-sizing feels like it affects <form>
<lea> control-sizing?
<fantasai> iank_: we got similar feedback on Twitter
<TabAtkins> huh. I woudn't have thought about field-sizing. Like input fields?
<TabAtkins> I guess, sure.
<florian> q+
<astearns> ack fantasai
<TabAtkins> fantasai: We don't use "field" in a lot of othe rplaces
<TabAtkins> fantasai: what about input-sizing?
<TabAtkins> fantasai: This is all about input elements
<lea> fixed reminded me, what about something-layout to match table-layout as a precedent ?
<fantasai> iank_: also affects textareas, select, etc.
<TabAtkins> iank_: That might be a little confusing since it also affects textarea and select
<fantasai> iank_: so input might not be great
<fantasai> iank_: talking about these elements on MDN, "field" appears a lot, so I think it would match ppl's expectations
<fantasai> miriam: we also do have <fieldset> which refers to same idea
<TabAtkins> I wouldn't have thought of "field", but I suppose it makes sense, and we don't ahve any other concepts using that term in CSS so I think it's clear to use
<astearns> ack florian
<TabAtkins> (I do prefer form-sizing tho)
<lea> nah, I think -layout would be a bad idea here. auto | fixed might be good for the values though (same as table-layout)
<fantasai> florian: I think I like form better here, but just to be complete, we have a term for elements that can have native appearance, and we call them "widget".
<iank_> https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input ("field appears 29 times")
<fantasai> florian: I don't think it would be very helpful here, so my preference still goes to "form"
<iank_> https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input ("control" appears ~70 times)
<lea> input-sizing
<TabAtkins> fantasai: Seems like fixed|content for values. Any alternatives for fixed? Seems like we're happy for content
<TabAtkins> florian: Someone suggested legacy?
<fantasai> astearns: Should we resolve on 'fixed' and 'content'?
<TabAtkins> lea: There were many arguments in the thread about legacy being bad
<fantasai> lea: another would be 'auto' and 'fixed', which would match 'table-layout'
<fantasai> iank_: pretty strong to keep 'content'
<fantasai> astearns: Proposed 'content' and 'fixed' as values for this property, any objections?
<fantasai> RESOLVED: Values will be fixed | content
<TabAtkins> fantasai: Should we run a poll for these names too?
<chrishtr> form-sizing?
<TabAtkins> +1 to another poll
<fantasai> florian: not a fan of input-sizing because <input>
<lea> TabAtkins: sync or async?
<TabAtkins> async again
<fantasai> POLL: 1. form-sizing 2. field-sizing 3. input-sizing
<florian> 1
<miriam> 2
<TabAtkins> 1,2
<astearns> 2
<fantasai> no strong opinion
<lea> abstain, I think
<vmpstr> (abstain)
<iank_> 2,1
<chrishtr> 2,1
<iank_> (no strong opinion however)
<schenney> (abstain)
<changseok> 1
<flackr> 2
<fantasai> [discussion of poll results]
<TabAtkins> Since there's no active disagreement I'm fine with a straight majority, fwiw
<TabAtkins> We don't need a strong consensus when it's not controversial for the group
<fantasai> fantasai: I think it would be useful to poll authors on the two names, to see if there's a strong drift one way or another
<fantasai> lea: if we're pressed for time...
<fantasai> TabAtkins: we're not that pressed that a week is critical
<fantasai> astearns: faster to resolve on the call, after getting poll results
<dholbert> 2
<fantasai> [discussing poll mechanics]
<fantasai> proposed to have a poll using Lea's mechanism, but add in an emoji option
<fantasai> also discussing running polls over twitter / mastodon
<fantasai> astearns: So we will run a poll on form-sizing vs field-sizing, with values content and fixed.
<fantasai> astearns: We'll be able to also evaluate Lea's proposed async poll system
<fantasai> -> https://github.com/w3c/csswg-drafts/issues
LeaVerou commented 1 year ago

Async Straw poll

Please edit this comment, add your at-username next to the option you support and update the count next to it. Votes have been pre-added for people that have expressed a clear preference already here or in the telcon. If you don't have permissions to edit this comment, please add your vote using reactions (emoji indicated in the beginning of each option)

  1. 👀 Abstain (1): @vmpstr @fantasai
  2. ❤️field-sizing: content | fixed (8): @leaverou @mirisuzanne @astearns @bfgeek @chrishtr @SebastianZ @jfkthame @bramus
  3. 👍 form-sizing: content | fixed (2): @frivoal @tabatkins
nt1m commented 1 year ago

I lean towards contents instead of content.

From https://proofed.com/writing-tips/word-choice-content-vs-contents/#:~:text=Content%20is%20an%20uncountable%20noun,“table%20of%20contents”). :

Content is an uncountable noun. We use it when referring to the ideas or subject matter of something (e.g., the “content of a speech”). Contents is a plural countable noun. We use it for things in a container or for sections of a publication (e.g., book chapters in a “table of contents”).

nt1m commented 1 year ago

Also I wonder if the property name should have intrinsic-size in it, since it only affects intrinsic-sizing. The concept is already exposed to web devs with contain-intrinsic-size, so it should be OK.

brandonmcconnell commented 1 year ago

I think either content or contents could work here, both functionally and grammatically, but between the two, I think content is more familiar to other property/value names (e.g. align-content, justify-content, fit-content).

Those three cases, and this one, could arguably be considered uncountable and will fit their contained content(s) regardless of the count of "how many contents" there are.

Again, just my 2 cents. Either is fine.

clshortfuse commented 1 year ago

contents is good in natural language, "sized by its contents" but it would be the only use case I know of where plural is used and I'd lean on content for uniformity.

The group discussed control in relation to property names. I'm old and remember when we called them controls decades ago probably from "knobs and controls" like mechanical items. Then came widgets. But while I think of them as Form Controls, so are checkboxes, radio buttons, and buttons. Even labels and legend. field is more specific to what we're doing here since you're unlikely to think this relates to checkboxes or labels, or even consider it would affect those. You don't have to explain that "this is for controls, but only the controls that are text fields".

I'll state my biases. I've worked on Material Design elements for about a decade now and they're called "Text Fields" there. Before, in Android it was "widgets". And before that, in WinForms, it was "controls".

nt1m commented 1 year ago

contents is already used in CSS with display: contents fwiw.

bleper commented 1 year ago

However, in the context of sizing, content is more common than contents, see content, especially with similar min-content, max-content, and fit-content.

clshortfuse commented 1 year ago

Yeah. contents in display refer to the element tree. content in flex and sizing refers to the same as the objective here. It would be consistent with the singular.

annevk commented 1 year ago

The DOM is inconsistent here too: node.textContent, but range.selectNodeContents(). Good times.

Kout commented 1 year ago

Don't complicate it for people not native in English. Content or contents, sign up or sign in… It is true, it's not consistent already, but why adding more cognitive load. So content for me everywhere.

mrleblanc101 commented 1 year ago

I don't see anyone talking about the fact that we already have minmax(). Can't we find a way to make use of it, when the first value of minmax is a the unitless number of row//columns depending on the axis ? (vertical for textarea, horizontal for input)

Exemple: minmax(4, 8) would give a <textarea> with 4 rows when there is no content, grow up to 8 rows when there is more than 8 rows of content. minmax(4, auto) would be the same but always expand with no upper limit.

bleper commented 1 year ago

@mrleblanc101 The current solution is better: which does not limit the authors to just a grid layout; does not tie a change of size mode to something that should not essentially differ from a simple synonym for length with lh unit; and does not introduce a potential compatibility issue with the existing web in the case of both auto, of course only if we want to cover all use cases with it.

jensimmons commented 1 year ago

I posted a poll on Mastodon to bikeshed the name: https://front-end.social/@jensimmons/111212178918345738

Someone replied with the suggestion of input-sizing, which is a good idea.

mrleblanc101 commented 1 year ago

I posted a poll on Mastodon to bikeshed the name: https://front-end.social/@jensimmons/111212178918345738

Someone replied with the suggestion of input-sizing, which is a good idea.

form-sizing, input-sizing, kinda similar. I like resizing-behavior: content | fixed

LeaVerou commented 1 year ago

I posted a poll on Mastodon to bikeshed the name: front-end.social/@jensimmons/111212178918345738

Is this the correct link? I get a 404.

Someone replied with the suggestion of input-sizing, which is a good idea.

This was discussed in the call (proposed independently by both me and @fantasai ), people thought it sounds like it refers to <input> only which is a fair argument.

jensimmons commented 1 year ago

That is the correct link.

Here's the current screenshot, but also be sure to read the replies. There's a lot of conversation happening.

Screenshot 2023-10-10 at 6 00 32 PM
yisibl commented 1 year ago

Against input-sizing, which makes it look like it only works on <input> elements.

annevk commented 1 year ago

form-control-sizing? (After HTMLFormControlsCollection.)

SelenIT commented 1 year ago

There was a nice suggestion in the Twitter discussion:

How about "dynamic-sizing" to represent what it does instead of what element it applies to?

Another option, assuming it can apply to inline size of inputs and, potentially, to both dimensions of textareas: what about auto-size: none (default) | inline | block | both?

fantasai commented 1 year ago

Another poll on twitter, including all three options of form-sizing, field-sizing, and input-sizing; the comments are interesting also: https://twitter.com/csswg/status/1711816620534886464

clshortfuse commented 1 year ago

Open UI list of how different libraries call input text: https://open-ui.org/components/inputtext.research/

Doesn't exactly differentiate <input> form <textarea> though

css-meeting-bot commented 1 year ago

The CSS Working Group just discussed [css-ui] ? Allow <textarea> to be sized by contents., and agreed to the following:

The full IRC log of that discussion <florian> s/The proposal is: field-sizing: content | fixed//
<fantasai> async poll https://github.com/w3c/csswg-drafts/issues/7542#issuecomment-1747805436
<TabAtkins> field-sizing: content | fixed
<florian> WFM
<fantasai> Rossen_: objections to resolving?
<fantasai> +1
<fantasai> RESOLVED: field-sizing: content | fixed
<chrishtr> yay!
<chrishtr> I love this feature
jensimmons commented 1 year ago
Screenshot 2023-10-11 at 12 48 08 PM
jensimmons commented 1 year ago

On the call, @fantasai said people preferred field-sizing over input-sizing in her poll... so the working group moved quickly past input-sizing and resolved to choose field-sizing. But then I looked at Elika's poll, screenshotted above ^. Actually people really preferred input-sizing.

So I created a new poll on Mastodon just to see what happens: https://front-end.social/@jensimmons/111217420404388282

We are still resolved on field-sizing, but maybe we should reconsider. Or at least confirm our resolution knowing what developers actually prefer (in these very unscientific quick polls).

LeaVerou commented 1 year ago

@jensimmons My recollection is that @fantasai did say that input-sizing was winning, but that field-sizing still had a sizeable percentage, and those opposed to input-sizing feel much stronger than those opposed to field-sizing.

fantasai commented 1 year ago

No, Jen's right, I got it backwards on the call... they are pretty close though, and we did have comments about how input-sizing would be confusing for something that applies to textarea.

hfhchan commented 1 year ago

Since this actually affects how the intrinsic size is used, why isn't the property named intrinsic-size?

In other parts of CSS, resizing according to content in one or more axes is the default mode. Having a new property called field-sizing which only applies to form controls and has different behaviour to input / select (auto-resize in inline direction) vs textarea (auto-resize in block direction) also feels too magical and is introducing even more specific sizing behaviour.

It also doesn't address the pain points around special sizing behaviour for other replaced elements like img and video which have their own width and height even when you set display: block, nor for iframes which have this weird 300px x 150px size even if you set it to display: block.

I suggest this property be called intrinsic-size, and instead of content and fixed, it should be none and auto.

When none is coupled with display: block, it causes all replaced elements and form controls to assume the width of the container and resize its height to fit the content (if height is auto). This would disable the default width of iframe of 300px, ignore the platform defined width for select, input and textarea, and cause video, img, select, input, iframe etc to actually behave like block elements everywhere else in CSS.

(For iframe maybe dynamically resizing its height according to content is too difficult to implement and/or introduces security risks. But at least the width should behave like all other display: block elements. Potentially the height should just resolve to 0px as if there were no contents?)

When coupled with display: inline, this will cause the textarea, video, img, select or input to shrink according to its content (i.e. use the natural width as it is for video and img, and just resize itself according to the content for textarea, select or input). This should also cause them to overflow the containing block without resizing itself, behaving as if there was just one long line of text.

(For iframe it may not be feasible to actually resize the width according to its contents. Potentially it should just resolve to 0px as if there were no contents?)

When intrinsic-size is set to auto, all the crazy sizing behaviours for img, video, input, select, textarea and iframe are kept as they are currently defined, with img and video sized to their natural width, input, select and textarea to platform defined widths, and iframe to be 300px x 150px, regardless of whether they are block or inline.

brechtDR commented 1 year ago

I would like the idea to choose on which axis the field gets (re)sized. So a property with multiple values might be an idea...

Also, shouldn't this be more consistent with a "resize" terminology?

field-resize-type: content; field-resize-direction: inline/block/x/y

Resulting in a field-resize: content block. Yes, the use case for inline will be a lot less, but I don't think we should exclude this completely.

Also: Could we do this by updating the resize property? resize: vertical; would still do what it does today. But upgrading it to have more possible values and possibly create a shorthand from it. Not sure if that last one is even slightly possible. But just putting it out there.

Then the new properties would be: resize-type: content; resize-direction: horizontal, vertical, inline, block

And shorthand: resize: content vertical; While making sure that resize: vertical; is still allowed and keeps working

I am not an expert on the matter, but wanted to make sure that options like this were considered. Not sure if it's possible, but going this route feels a bit more consistent.

Loirooriol commented 1 year ago

@brechtDR This is just about the intrinsic size, so you can always set e.g. width to some explicit value, and that will take precedence over the contents. So individual axis control may not be needed.

The resize property seems an entirely different functionality, so I would be against conflating the two.

SebastianZ commented 1 year ago

@hfhchan wrote:

I suggest this property be called intrinsic-size, and instead of content and fixed, it should be none and auto.

...

(For iframe maybe dynamically resizing its height according to content is too difficult to implement and/or introduces security risks. But at least the width should behave like all other display: block elements. Potentially the height should just resolve to 0px as if there were no contents?)

...

(For iframe it may not be feasible to actually resize the width according to its contents. Potentially it should just resolve to 0px as if there were no contents?)

When intrinsic-size is set to auto, all the crazy sizing behaviours for img, video, input, select, textarea and iframe are kept as they are currently defined, with img and video sized to their natural width, input, select and textarea to platform defined widths, and iframe to be 300px x 150px, regardless of whether they are block or inline.

Resizing iframes based on their contents is discussed in #1771. And it was resolved on adding a contain-intrinsic-size: from-element.

So that somewhat overlaps with your suggested intrinsic-size property. And I wonder whether that should be reused for this use case.

In any case, I like the idea of introducing something that covers all the mentioned cases, as they are related.

Sebastian

hfhchan commented 1 year ago

I gave this some more thought of how this should play with intrinsic sizes of replaced elements, and I suggest renaming my previous proposal to intrinsic-sizing to make it clearer that the intrinsic size isn't the thing being changed, but how the intrinsic size affects the layout is being changed.

Suppose you have an <img src="file.jpg" width="1600" height="900">. Assuming we apply display: block and intrinsic-sizing: none, and the containing block had 800 pixels, the img tag should occupy the space of 800 x 450 pixels. So the intrinsic size of the replaced element is still 1600 x 900, but the intrinsic size now only contributes to the intrinsic aspect ratio, and not directly to the width and/or height.

For form elements (input, select, textarea), it works either way to describe it as the intrinsic size no longer being platform defined but relying on the content, or the platform defined intrinsic size no longer applies and the element is laid out like a normal element.

Loirooriol commented 1 year ago

@hfhchan The width="1600" will set width: 1600px as a presentational hint, see https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images. So the width should be 1600px, not 800px.

yisibl commented 10 months ago

Now there is a problem, when field-sizing: content is set, the cursor is missing. See https://bugs.chromium.org/p/chromium/issues/detail?id=1523248

https://github.com/w3c/csswg-drafts/assets/2784308/16e12026-a7dc-47b3-bdc6-8badce1fa2a3

tabatkins commented 10 months ago

That's an implementation issue, not a spec issue.