Skip to content
This repository has been archived by the owner on Jan 21, 2022. It is now read-only.

Add standard ranges for z-index #144

Open
nottrobin opened this issue Dec 12, 2018 · 8 comments
Open

Add standard ranges for z-index #144

nottrobin opened this issue Dec 12, 2018 · 8 comments
Assignees

Comments

@nottrobin
Copy link
Contributor

Suggested ranges:

  • 0-50: Core website content
  • 51-100: Other plugins
  • 101+: Reserved for the core website to overlay plugins if needed

We could also recommend keeping z-indexes organised with a Sass z-index map (thanks @anthonydillon)

@matthewpaulthomas
Copy link
Contributor

matthewpaulthomas commented Dec 18, 2018

I’m not sure what “plugins” means in this context. It’s not defined here or in www.ubuntu.com#4442, and www.ubuntu.com#4513 refers only to “plugins (like global-nav)”.

However, snapcraft.io#1429 shows a tooltip with z-index: auto incorrectly appearing below part of the global navigation that has z-index: 100. I don’t think the ranges proposed here would address that issue.

Part of my work on Mir from 2012 to 2017 was specifying layering behavior for different types of surface. I think there are two details relevant to Web sites:

  • Tooltips and similar elements (called “tips” in the Mir spec) should have a layer to themselves, above everything else, even if they’re invoked by something that’s behind other things. For example, even if a tooltip is invoked from something lower than the global nav, the tooltip should still float on top of the global nav.

  • Menus and similar elements (“popups” in the Mir spec) should have a layer to themselves, above everything else except for tips. Vanilla has threetwo built-in varieties of popups, “Contextual menu” and “Modal”, and “Notification”, but there are custom varieties too, such as snapcraft.io’s “Options to install this snap” dropdown.

@nottrobin
Copy link
Contributor Author

nottrobin commented Dec 18, 2018

Thanks @matthewpaulthomas, this is useful work to build on.

I’m not sure what “plugins” means in this context.

"plugins", as I used it, means code controlled outside of the main website's codebase (e.g. the global nav is controlled in the global-nav module).

But I can see that you're using a different scheme - suggesting we define certain types of elements that may need to be layered, and assign those z-index ranges.

Maybe what we need is to define z-index ranges for types of elements, as you suggest, and then also maintain a mapping document (similar to e.g. the ports mapping) where we define explicitly the z-index ranges that plugins use. I've created a first-pass at this mapping document here: https://github.com/canonical-webteam/practices/wiki/z-index-values-reserved-for-plugins

So, how about the range specification looks like this (I'm choosing values that hopefully mean as little existing work has to change as possible):

  • 0 to 30: Available
  • 30 to 50: Main navigation (ubuntu.com's nav was recently updated to use 38 to 40)
  • 50 to 80: Available
  • 80 to 110: Global navigation (global nav module uses 98 to 100)
  • 110 to 150: Available
  • 150 to 220: Tooltips (cookie policy module uses 200)
  • above 220: Available

So this way, we define layers for explicit element types, with space in between each of them in case it's needed for anything we haven't thought of.

@matthewpaulthomas thoughts?

@matthewpaulthomas
Copy link
Contributor

This reminds me of choosing line numbers for BASIC programs … The issue is hard to think about, for a few reasons: unconnected popups are seldom open simultaneously; a tip usually relates to one focused/hovered item, so multiple tips are seldom open simultaneously; and on the Web, anything that invokes a popup or a tip is seldom behind anything else to begin with.

For all the same reasons, choosing a z-index manually would be hard to get right, so I think we should minimise how often people need to do it at all.

150 to 220: Tooltips (cookie policy module uses 100)

The ubuntu.com cookie notification is an example of what, in Mir, I called a floating regular. I didn’t mention those earlier, because I’d forgotten that one existed! Floating regulars are in a single group, above all normal surfaces, but below all popups and all tips.

30 to 50: Main navigation (ubuntu.com's nav was recently updated to use 38 to 40)
50 to 80: Available
80 to 110: Global navigation (global nav module uses 98 to 100)

Following a surface-role-based model, I think the Canonical navigation bars wouldn’t need z-index values at all. All the various navigation mega-menus wouldn’t layer above page content because they’re part of the main/global navigation. They’d layer above page content because they’re popups. That is, Vanilla would have something like:

.p-popup, .p-contextual-menu__dropdown, .p-modal {
// Any custom popups, plus the two provided by Vanilla
  z-index: 200;
}

Then each dropdown in the navigation would declare itself as class="p-popup" (along with any other classes it needed). And so would the snapcraft.io snap version chooser, and so would MAAS’s tag autocomplete, and any other custom popup. None of them would require custom z-index values.

A drawback of this approach is that it would require JavaScript that detects when any popup is defocused, and closes it. I think that should happen anyway, but if that wasn’t included, a custom popup opened just before a navigation mega-menu would float weirdly above the mega-menu.

Similarly, in a surface-role-based system, the snapcraft.io metrics tooltip wouldn’t float above the navigation because someone had thought “hmm, this could overlap the navigation, I’d better look up the z-index mapping document to see what values the navigation can have, and make sure I choose a bigger value”. It would float above the navigation merely because it had been declared as a tip, and Vanilla took care of the rest:

.p-tip, .p-tooltip__message {
// Any custom tips, plus the one built in to Vanilla
  z-index: 300;
}

@nottrobin
Copy link
Contributor Author

nottrobin commented Dec 18, 2018

It's a good idea for Vanilla to define helper classes for "popups" and "tips" (filing an issue about this over on vanilla-framework would be appreciated), and when those exist, their use should be recommended in any document that talks about this problem. But I don't think that covers every case, and also doesn't currently exist, so I don't think it negates the need for specific, documented ranges.

An example of a custom case where overlays are used that you might not have considered is the "Gaming" row in https://www.ubuntu.com/desktop/features. But there will definitely be others.

It's all well and good for you to flag individual issues like canonical/ubuntu.com#4436 so we can go and add logic to not allow two specific popups to be open simultaneously, but, at least at the moment, we're very far from having an overarching framework that automatically enforces this. We could, down the line, start to define custom JavaScript events for opening popups that all other popups are supposed to listen to and close themselves, but at the very least this won't help with popups that work without JavaScript (like the mobile nav). At the moment, we're very much in a world where each component that needs to overlay things on the page needs to specifically be aware of other things that may be on that same page.

So I think, for where we're at currently, having documented ranges will make things a lot safer than they currently are.

@matthewpaulthomas
Copy link
Contributor

Fair enough. I wasn’t hoping to cover every case (“minimise”, not eliminate!), so the Gaming animation would use manual values regardless.

I also realised I was wrong about global navigation layering, by asking myself how I’d layer something like an app session expiry warning that smothers the app (“You’ll be signed out in N seconds”). It would go below the global navigation (so you could navigate to other apps), but above everything that’s part of the app itself. So, navigation mega-menus wouldn’t “layer above page content because they’re popups”, they’d layer above page content because the global navigation as a whole is the Web equivalent of shell surfaces. Something that lets you navigate around the overall Canonical, uh, “environment”, outside of individual apps.

So now I’m a bit closer to what you proposed:

  • 0 ±20: most page contents (including dialogs invoked from those page contents)
  • 100 ±20: floaters, e.g. cookie notice, Juju bundle details, sales team chat widget
  • 200 ±20: popups, e.g. most menus, autocomplete widgets, image galleries
  • 250 ±20: overlays, e.g. lightboxes, session expiry
  • 300 ±20: shell surfaces, i.e. the global navigation bar and its menus
  • 400 ±20: tips, e.g. tooltips, balloons highlighting new app features

Most of the time, you should use just the base value for the role, varying only if really needed.

@nottrobin
Copy link
Contributor Author

My only problem with your proposal is that it would require that we change every existing z-index across our whole suite of projects - which will take a long time to work it's way through and lead to confusion in the interim.

Given that you have at least 60 spare values in between your layers, would you consider compressing them so that they work with existing use-cases (but keeping the order of layering)?

  • 10 (0-19): most page contents (including dialogs invoked from those page contents)
  • 25 (20-29): floaters, e.g. cookie notice, Juju bundle details, sales team chat widget
  • 40 (30-49): popups, e.g. most menus, autocomplete widgets, image galleries
  • 70 (50-79): overlays, e.g. lightboxes, session expiry
  • 100 (80-110): shell surfaces, i.e. the global navigation bar and its menus
  • 150 (111-180): tips, e.g. tooltips, balloons highlighting new app features

This would allow the existing navigation of ubuntu.com to remain where it is (38-40), and the global nav (98-100). The cookie policy (currently 200) would have to change as, in your schema, it is layered in entirely the wrong place.

@matthewpaulthomas
Copy link
Contributor

matthewpaulthomas commented Dec 21, 2018

The reason for gaps between the ranges is “What if we forgot a type?” Though we spent years refining the Mir types, there were some things that we deliberately excluded but that would be far more reasonable on the Web. Overlays above is an example: we regarded them as too confusing in a multi-window GUI, so I left them out, but lightboxes are quite reasonable on a Web page.

Apart from that, I don’t mind what the ranges are. The change to the ubuntu.com navigation layering was four lines of code, though, so I’d be skeptical of designing the whole allocation around not having to make another four-line change!

I wonder if it would be a reasonable policy to just leave values that aren’t currently causing a problem. The cookie notice has z-index: 200? Fine, it can stay like that unless+until it ever clashes with something, then it can switch to class="p-floater" or whatever instead, and the clashing element can assume its appropriate class too.

@nottrobin
Copy link
Contributor Author

Oh yeah good point. Gaps make sense, happy to add them in.

But I do think what's the point in defining a class range of the only example we have of that class doesn't conform to the range?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants