canonical-web-and-design / practices

Guides and principles from the web team at Canonical and Ubuntu
https://canonical-web-and-design.github.io/practices/
Other
45 stars 30 forks source link

Add standard ranges for z-index #144

Open nottrobin opened 5 years ago

nottrobin commented 5 years ago

Suggested ranges:

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

matthewpaulthomas commented 5 years ago

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:

nottrobin commented 5 years ago

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):

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 commented 5 years ago

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 commented 5 years ago

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 https://github.com/canonical-websites/www.ubuntu.com/issues/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 commented 5 years ago

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:

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

nottrobin commented 5 years ago

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)?

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 commented 5 years ago

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 commented 5 years ago

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?