Re: [csswg-drafts] [css-values-4] Add vhc value (#4329)

It appears I'm arriving at this a bit late. I'm interested in this because I work at a company where, amongst other things, we develop mainly non-public web applications for our clients. We commonly make use on what is sometimes referred to as the [holy grail](https://en.wikipedia.org/wiki/Holy_grail_(web_design)) layout, having:

- header fixed to top of viewport
- footer fixed to bottom of viewport
- one or more vertically scrollable columns in the middle section.

Two public examples are:

- https://www.quintessa.org/updates/sign-up
- https://www.oecd-nea.org/fepdb 

This used to be difficult to achieve without various hacks or javascript until the `vh` unit and `flexbox` arrived and made it all easy. The fixed header and footer could then be achieved using `vh` and `flexbox` with some simple HTML [like this](https://bug1663000.bmoattachments.org/attachment.cgi?id=9187912):

```html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>test flex fixed header & footer</title>
    <style>
* { margin: 0; }
body { height: 100vh; flex-direction: column; display: flex; }
main { height: 100%; overflow-y: scroll; background-color: grey; }
header, footer { background-color: green; }
    </style>
  </head>
  <body>
    <header>Header: Always visible at the top</header>
    <main>
      <ol>
        <li>First item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Item</li><li>Last item</li>
      </ol>
    </main>
    <footer>Footer: Always visible at the bottom</footer>
  </body>
</html>
```

Just over a year ago we had several web applications using this technique, working consistently across desktop and mobile... and then they broke on mobile only. The bottom of the page (sometimes just the footer, sometimes the footer and then some, sometimes part of the footer and also action buttons that had been positioned for easy access by fingers on mobile at the bottom of the page using `position: sticky; bottom: 0`) was cut-off, hidden under part of the browser UI. Worse, these parts of the web application sometimes couldn't be accessed at all unless the user scrolled right down to the bottom of the central region, and then in some cases, could simply not be accessed at all. The fact that these applications now behave differently on desktop and on mobile, meaning that we will now potentially have to detect mobile vs desktop and do something different on each is a real pain. I had thought those days of being force to do device type/user-agent probing or of needing to use javascript to acheve simple goals, like a basic layout with elements fixed to the top and bottom of the viewport, were long gone - but apparently not, and that's incredibly frustrating.

I started filing various bugs against Firefox for Android, this having the worst behaviour and apparently being the most buggy, but have ended up here. Having read through everything that's gone on, and what is proposed... I'm a bit shocked to be honest.

There's a lot to get a grip on, but my understanding of what has gone on at high level is as follows:

- Mobile browsers decided to hide the address bar when not needed to make more space for content. I get why you'd want to do that and support it. The chosen method of implementation though is that the scrollbar would gradually start to disappear when the user starts to scroll down and gradually reappear when the user starts to scroll back up, meaning that the visible viewport height would always change while the user was scrolling. This, perhaps unsurprisingly looks/feels bad and takes significant processing power.
- This is where the problems start. As @frehner says above "That’s actually how vh units initially behaved! But it turns out that it’s a horrible UX because content would actually move/change size as you scrolled." This is conflating two things. There is nothing wrong with `vh` as a unit or a concept. `vh` is not the problem here. Changing the viewport size while scrolling; that is, the particular chosen design of the hiding address bar feature, is the problem. However, it was decided to blame and, worse re-interpret `vh` instead, breaking websites in the process. I've looked at the standard, and I've read comments along the lines of `vh` being defined in an ambiguous way anyway, but I don't agree that that's the case. It clearly links it to the size of the viewport (which, by definition, is the what is visible) and says that it should change when the viewport changes.
- Then problems became even worse because other browsers started copying the flawed design that is incompatible with the behaviour defined for `vh` in the spec.
- Then the situation became worse still, because there is this proposal, already approved, to unnecessarily change the definition of `vh` again, thus potentially not just breaking sites on mobile but on desktop too. Isn't that a problem for anyone? It is for me. Furthermore, this proposal doesn't even solve the problem: My understanding is that, for my simple example above, it will either lead to websites with content that is cut off or content that is unnecessarily smaller than the viewpoint most of the time on mobile. So, rather than having an extremely broken solution, as a developer, I've got the choice between two badly broken solutions.

So, rather than simply complaining, I'd like to go back to the root of the problem and try to propose an alternative.

# Proposed solution

The problem is with:

1. a browser design that uses scrolling as a trigger for changing the viewport size by sliding some piece of browser UI into or out of it, causing both scrolling and a change to viewport size to happen simultaneously, and
2. a browser design that means that `vh` is calculated based on a something that is NOT actually the visible viewport as required by its definition, most of the time.

So let's start by banning that simultaneous scroll and changing of the viewport size by sliding some toolbar into or out of view. If a toolbar is in the process of being slid into or out of view when the user starts to scroll, pause that while the user scrolls, and then continue it when they are done.

So, now we are left with two challenges: How can we hide the address bar when not needed? How can we show the address bar when needed? We need to do this in a way that leaves the definition of `vh` in tact most, if not all of the time.

## Hiding the address bar when not needed

There are various possibilities here, and I don't think it would matter too much if different browsers choose different approaches. Some possibilities I can think of are:

1. Hide it immediately as soon as an HTTP request has been made. From a security point of view this is perhaps not the best idea, because the user doesn't get to see where they are being (re)-directed to.
2. Start hiding it as soon as an HTTP request has been made and while the page is loading. In the meantime take the viewport to be the full height it will eventually achieve with the address bar gone, so that either a) the content briefly loads underneath the address bar while it is getting out the way or b) the content slides into full view as the address bar gets out the way. Only once this transition is complete can the user start interacting/scrolling.
3. Fully load the page with the address bar in place, but with the viewport at its maximum possible size and so with either the top or bottom being cut off temporarily. Start hiding the address bar as soon as possible provided the user doesn't interact with the page by scrolling. As the address bar is hidden the full viewport will become exposed or will slide back into view.
4. Fully load the page with the address bar in place and with the viewport having a reduced size because of that, and then provided the user doesn't interact with the page by touching/scrolling - start hiding it, making the viewport expand in size at that point in time.
5. Like 4, but making the address bar disappear after some period of non-interaction.

## Showing the address bar when needed

At present, scrolling in the reverse direction is used as a trigger for re-showing the address bar. That will need to change. Here, I think it would be helpful if there could be a consistent approach across all browsers to the gesture for achieving this. I don't know what the best approach is, but possibilities include:

1. dragging from the edge of the window where the address bar once was (like opening a drawer or pulling out a tray), noting that doing this again once the address bar is visible could result in a page reload;
2. touching anywhere non-interactive and holding;
3. touching anywhere non-interactive and dragging slowly away from an edge (instead of slowly scrolling);
4. touching anywhere non-interactive and dragging fast away from an edge (instead of rapid scrolling).

In terms of the viewport, the address bar could slide over it, noting that this is only a temporarily infringement (like a temporary keyboard/form input control might), or it could cause the viewport to shrink in size (change in `vh`).

## Re-hiding the address bar on a loaded page

If the user calls up the address bar, but then chooses not to interact with it for some period of time, it could be re-hidden. Whether or not this results in a recorded change in `vh` will depend on what the browser has decided to do when showing the address bar. I don't think it's critical either way provided the default is for the address bar to be hidden and it's appearance is only fleeting/temporary. (Whereas, at present, you typically have to scroll down the the very bottom of all content, and then some, to be able to reveal content that should *always* be in view.)

# Conclusion

I believe that if browsers take an approach like described above, the problem can be considered fully addressed:

- standards compliance restored:
  * `vh` behaves as defined by the spec, either with possible minor short-lived infringements only during a transitions or with a changing viewport size (but not at the same time as user scrolling), depending on exact implementation
- consistency of layout between desktop and mobile - possible to use `vh` and `flexbox` to position items at top and/or bottom with central scrollable region for both mobile and desktop once again!
- problem with simultaneous scrolling and viewport size change eliminated
- possible for browsers to implement this in a way that avoids the `vh` unit changing at all due to address bar movements, with the compromise being that some content will be hidden when the address bar is in place - but only temporarily and briefly, and will be exposed or slide back into view when it gets out the way.

So in this case, I suppose I am saying that I think that browsers should adjust the design of the address bar hiding feature to comply with the CSS spec in a way that provides a good user experience, not the spec being broken to support questionable browser design choices and poor user experience. (If that can't be done in a way that is good for user experience, then perhaps hiding address bars will have to be disabled until such time that CSS provides some new functionality to make it work well - but I don't think this proposal is it, and I think the the proposed solution above can be made to work adequately.)

As such, you could argue that this proposed change to the CSS spec is perhaps no longer required. I think there is still merit in an additional `vhmax` unit though, which would be based on the maximum size the viewport could have (i.e. with hide-able toolbars hidden). If you want to scale font-sizes, then you would probably want that to be relative to browser window size and may not wish that to be sensitive to minor changes in viewport size which you could get with `vh` (depending on browser implementation of the address bar hiding). `vhmax` would give you that.

Whatever is ultimately decided, please don't redefine `vh` and further break backwards compatibility. Keep `vh` as is so that websites like ours with elements pinned to the top and bottom are not broken and a central scroll region are not broken, and add new units if that helps.

Thank you.

-- 
GitHub Notification of comment by mind-bending-forks
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/4329#issuecomment-730549876 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Thursday, 19 November 2020 18:14:58 UTC