Open Bug 947340 Opened 11 years ago Updated 2 years ago

Consider putting the spin buttons for <input type=number> "outside" its text box

Categories

(Core :: Layout: Form Controls, enhancement)

enhancement

Tracking

()

People

(Reporter: jwatt, Unassigned)

References

(Blocks 1 open bug)

Details

This is something that would be nice to do at some point in the future.

Right now the spin buttons for <input type=number> are inside its border. This is (a) inconsistent with platform libraries number spinners which usually have the spinner outside the text field against its right edge, and (b) it means that the spin buttons have to be smaller than they otherwise might be in order to fit inside the border. From a user's perspective it would be better if the spinner was outside the text box, butted up against its right edge. This would mean the spinner could be bigger and easier to click on. Unfortunately this turns out to be rather hard to implement.

To understand why this is hard to implement you need to understand how the number control is currently implemented. nsNumberControlFrame creates a native anonymous content tree that looks like this:

  <input type=number>
    <div>                - outer wrapper with "display:flex" by default
      <input type=text>  - text input field
      <div>              - spinner box wrapping up/down arrow buttons
        <div>            - spin up (up arrow button)
        <div>            - spin down (down arrow button)

CSS properties such as 'border' are set on the <input type=number> since that's what content has access to set CSS on, while forms.css removes all styling from the grandchild text input so that there isn't a second border on that grandchild. This is why the border for the number control goes all the way around both the number text and the spinner.

Perhaps the most obvious way to "move" the spinner outside what visually appears to be the text field is to remove the border from the number control and put it on the anon text control.

The biggest problem with this idea is the issue of user style. CSS is not designed to make allowances for transferring specified properties through to a grandchild while _ignoring_ them on the element that they were specified on _and_ on any elements along the parent chain between the two. We can partially hack around that for certain things. For example, bug 946262 has a patch implementing an ugly hack to do that for -moz-appearance. Doing that on a larger scale for a larger set of properties (border properties, background properties, etc.) would simply be unacceptably invasive though (and hard).

Another way to "move" the spinner outside what visually appears to be the text field might be to leave the border on the number control, but absolutely position the grandchild spinner to the right in some way, adding some internal hardcoded margin amount matching the width of the spinner to any user specified margin-right on the number control so the spinner doesn't overlap elements that come after it. Or something. Hacking in that hardcoded margin may be tricky. It might also make it hard for chrome UA style sheets to change the style of the internals of number controls without needing the C++ to be changed too. Besides that, there's the issue of getting the height of the spinner to match the height of the _border box_ of its _grandparent_ number control.

Maybe the only realistic option here is to give up on trying to do the layout using purely CSS and just make nsNumberControlFrame::Reflow brute force whatever we need.

Or maybe we need to figure out a way of having a spinner that is not a descendant of the number control at all, perhaps using :after or something similar. But then how would UA style sheets get access to the spinner and its buttons to style them? And thinking longer term, how would content get access once we decide we're ready to allow it.
Depends on: 946262
Component: DOM: Core & HTML → Layout
Related issue: in bug 157846 we're making nsTextControlFrame push its padding down into the scrollframe so it appears inside any scrollbars. nsNumberControlFrame has similar problems, but they're hard to fix because we don't have a custom frame type for the "outer wrapper" DIV whose Reflow method could push the padding down.

If we could get rid of the "outer wrapper" DIV, that would make that issue easier to fix, and also make this bug easier to fix. As far as I can tell the "outer wrapper" is just used to lay out the textframe and the spin buttons, so we could just reimplement that layout in nsNumberControlFrame::Reflow.

Maybe that's what you meant in your second-to-last paragraph in comment #0.
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) (away January 20-24) from comment #1)
> Related issue: in bug 157846 we're making nsTextControlFrame push its
> padding down into the scrollframe so it appears inside any scrollbars.
> nsNumberControlFrame has similar problems

I don't think scrollbars should ever appear inside <input type=number>, so I assume you're thinking of something else? Can you give an example of a problem?

> If we could get rid of the "outer wrapper" DIV, that would make that issue
> easier to fix, and also make this bug easier to fix. As far as I can tell
> the "outer wrapper" is just used to lay out the textframe and the spin
> buttons

Specifically it's there because the parent of the anonymous text field and spin button div are laid out using flexbox, and that requires a |display:flex| parent. (Obviously we can't set the |display:flex| on the <input type=number> itself since that would be visible to content, and content may want to change that without breaking the internal layout of the text field and spin buttons.)

> so we could just reimplement that layout in nsNumberControlFrame::Reflow.
> 
> Maybe that's what you meant in your second-to-last paragraph in comment #0.

Right.
Severity: normal → enhancement
Component: Layout → Layout: Form Controls
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.