microsoft / fluentui

Fluent UI web represents a collection of utilities, React components, and web components for building web applications.
https://react.fluentui.dev
Other
18.33k stars 2.72k forks source link

Link: Focus outline prone to clipping; also poor visibility when wrapping images #6944

Closed BrendanMcK closed 5 years ago

BrendanMcK commented 5 years ago

Environment Information

Please provide a reproduction of the bug in a codepen:

Can repro both issues with this codepen

Actual/Expected behavior:

There's two issue with the current focus outline styles here -they're closely related, so reporting as a single issue - unlikely that they can be fixed independently of each other.

Some examples, using current Fabric outline:

image

We've ended up using inset 1px box-shadow as our focus outline to avoid this clipping. It works great for us, but can be fragile in some cases: if a link contains DIV or other block-layout elements, we need to ensure that the link also has block-layout, otherwise the box-shadow won't appear. We can manage this in our own UI, but it's not clear that it's a robust solution for Fabric to adopt.

Worth noting that the default browser outline also has this clipping issue: we were originally steering clear of using a specific focus outline style at all, and sticking with a 'browser knows best' approach - but clipping of the browser outline in Chrome/Safari and Firefox (both of which got called out during a11y reviews) forced us to explore alternatives, so we ended up going with a box-shadow-based approach (with additional style rules for Windows High Contrast mode).

The approach we've taken here is to add an option to our custom Link class to opt-in to a more visible focus outline as needed. This more visible outline also uses box-shadow, with multiple alternating shadows so that the resulting outline is a fully inset (to avoid clipping) white/black/white outline, guaranteeing good visibility even in confined layouts and with noisy images.

dzearing commented 5 years ago

@aneeshack4 Let's see what we can do here. We can sync on the area and I can help you :)

dzearing commented 5 years ago

Hey @BrendanMcK I see 2 problems here;

  1. The link you're truncating is not stretching to the container. This makes it unpredictable to render a border. It needs to be display: block or inline-block, so that maxWidth can be specified.

  2. The parent is clipping the link border, which is rendered outside of its "owned" layout space. The only fixes I see are:

a. Render the border on top of the content (this seems ugly because it covers some of it up.) b. Link itself adds inner padding to compensate for the focus rect (which seems bad because it can result in alignment problem.) c. Just adding padding to the container where it makes sense. I think this is the best approach.

I've updated your example with options 1 and "c", here:

https://codepen.io/micahgodbolt/pen/EGNqYm (new codepen with Stack)

Which renders the focus rectangle correctly. Thoughts?

BrendanMcK commented 5 years ago

Just adding padding

Back when I was initially looking at the focus outline clipping issue, I did briefly explore the option of adding padding to avoid this; but our CSS back then was sufficiently complex that I quickly realized it was not a viable approach: it's often not an immediate parent that's doing the clipping, but some higher-up ancestor (or, often, multiple ancestors). And adding padding somewhere also means adjusting some other property to keep the layout otherwise as-is, so there's all sorts of knock-on affects. It just didn't seem to be at all a robust or maintainable approach. While box-shadow has it's drawbacks (it's essentially a variation of option (a)), it's considerably more manageable.

It might be interesting to revisit this now that we're more Fabric based: what would this approach actually mean in practice? Would we need to add an addPadding or mayContainFocusableElements or similar property to some layout components? Would fixing outline clipping on a link be a relatively localized, or require a bunch of tweaks to many components?

BrendanMcK commented 5 years ago

At a first glance, adding padding might be more viable than it was for us in the past:

So this might provide an approach for dealing with outline rect clipping; will investigate more over the next few weeks and report back. IIRC, there were some other cases where we had link clipping - mostly lists of items in scrollable containers, which also have the side-effect of clipping.

--

Seems like we'll still need an option for higher-visibility focus on an as-needed basis. Any thoughts on that issue? At least that option is much easier to address via an option on Link.

dzearing commented 5 years ago

I'd seriously worry about adding padding. Users will not anticipate it and you end up with weird side effects.

First padding doesn't work on inline. Margin does, but then... same unpredictability issue.

Other than the overlapping border, I don't see a way to avoid clipping.

The only fix I see is overlapping focus rectangles. Which is a little sad. And if we want to do the white/black 2px treatment we have on buttons, it would be 2px of inset overlap. Which makes it worse.

Codepen to illustrate the 2 approaches:

https://codepen.io/dzearing/pen/ZmewZB

dzearing commented 5 years ago

Talking offline in a thread on the right approach here;

dzearing commented 5 years ago

The outcome here was:

For Link, render focus within the rendered boundary of the link.

To do this the rect must use something that wraps. Outline renders outside of the boundary. Borders or inset box-shadow would work.

Neither of those work with high contrast. So, for high contrast media queries we can fall back to outline, but it means we can't solve the clipping issue in that case.

BrendanMcK commented 5 years ago

Neither of those work with high contrast

I don't understand this bit - why don't outline / borders / inset box-shadow work in HC mode? Can't you just re-state the style in terms of Window/WindowText within a HC media query?

aneeshack4 commented 5 years ago

@BrendanMcK the border & box-shadow disappear in high contrast mode so I believe in HC mode only, we'll have to switch to outline. David & I spoke about this early last week - the approach he suggested is to not use OS HC support & instead to rely on theming to solve HC. I will try the HC media query approach to restate the style in terms of Window/WindowText though. My plate was full til now with another big PR but I finished that so I'm starting to work on this now. I'm new to all of this so I'm still digging into the code trying to understand the context - might reach out to you with questions as David's oof atm.

BrendanMcK commented 5 years ago

the border & box-shadow disappear in high contrast mode so I believe in HC mode only, we'll have to switch to outline.

Restating the styles within a HC media selector (using the HC theme colors) is exactly the way to address this.

Having clipping in HC mode would be continued and accessibility bug in its own right. HC users want good focus outlines too!

to not use OS HC support & instead to rely on theming to solve HC

My take is that this is non-trivial: the problem is that HC mode's default processing essentially ends up ignoring all of your theming styles. The only way to get this to work, as I understand it, would be to use the -ms-high-contrast-adjust: none style somewhere near the root to turn off the default HC processing so that your theme colors show through instead. But then you are 100% on the hook for all HC work; and this may also cause issues for other hosted HTML fragments (say custom renderers) that are relying on the default HC processing to do the HC stuff for them. It's quite an all-or-nothing approach.

dzearing commented 5 years ago

If it is as simple as restating the border to use an hc color in the hc query, then cool! We could solve the clipping in hc then too.

aneeshack4 commented 5 years ago

@BrendanMcK I'm trying to repro this locally so I can test the fix against it but I don't know how to do this on the Fabric site - do you know how I can repro this clipping on https://developer.microsoft.com/en-us/fabric#/components/link? I've also been trying to use the Codepen you provided but nothing is rendered on there - any idea why? image

BrendanMcK commented 5 years ago

It seems that VerticalStack is no longer available (or has moved), so the codepen is no longer working.

While box-shadow appears to work in this case, I'm not sure it's the right approach for Fabric to take, because, as I mentioned in the original post above, it's somewhat fragile.

The problem with focus outlines is that there's no one-size-fits-all solution. I think Fabric will have to decide which default makes the most sense for its use cases, and then provide options to use the other approaches. The default that we've chosen in Yammer makes sense for us (we have our own a11y QA process, so can find and fix broken focus issues), but may not be the right fit for Fabric.

Here's a summary of the different approaches, and their pros and cons. Note that any approach can be made work in HC mode, so that's not a factor in these decisions.

With clickable content (whether hyperlink or button), it seems we have at least three different use-cases that have different - and in some cases, non-overlapping - requirements:

We've gone with the box-shadow approach as our default because we have a lot of text links that can wrap or get truncated with ellipsis. But doing this means we have to keep an eye out for places where the link contains block content, and add a block=true option there to avoid the outline disappearing. We also need to find any tightly-wrapped images and use another option there to get a higher-visibility focus outline.

Maybe the best fix for Fabric is to instead provide a focusOutline=inset|strong|default option on Link?

aneeshack4 commented 5 years ago

Thank you @BrendanMcK for providing this detailed breakdown - really appreciate it! Just wanted to update you - I'm working on trying out the focusOutline=inset|strong|default option on Link. If it works, I'll send out a PR.

aneeshack4 commented 5 years ago

Another update, discussed this a bit with @micahgodbolt: we're still trying to figure out what the right solution is for Fabric. Right now, I'm considering the different contexts Link's used in because defining focusOutline=inset|strong|default would mean allowing a top level prop to directly control CSS styles which we're not sure is ok for scenarios that Link's used differently in.

BrendanMcK commented 5 years ago

we're still trying to figure out what the right solution is for Fabric

Great; this is really more of a DCR or similar rather than a simple bug-fix, so needs plenty of due diligence. Once we add an option to our API, we'll be stuck with it for some time.

msft-github-bot commented 5 years ago

:tada:This issue was addressed in #7793, which has now been successfully released as office-ui-fabric-react@v6.135.0.:tada:

Handy links: