Problem/Motivation

The responsive menu in Umami has some accessibility problems:

  1. The button only does something when JS is enabled. When JS is off, the button is there in markup, but does nothing.
  2. Menu links are always in the tabbing order, changing the wrapper's height just hides them visually. A keyboard user will have to tab through these even when the menu is closed. For screen reader users, it defeats the object of the toggle button. For sighted keyboard users, the links are invisible-but-still-operable. This is a failure of WCAG 2.0 SC 2.4.7 Focus Visible.
  3. The open closed state of the menu is not conveyed to assistive tech. Screen reader users just know there's a button, not whether the menu is open or closed.
  4. Th menu open/close is animated, but some users prefer no motion. We're forming a Drupal core policy around this, see #2928103: [policy, no patch] Use "prefers-reduced-motion" media query to disable animations.
  5. The button is outside the navigation landmark. When closed, a screen reader user might search for the navigation landmark region, but find it empty. They should find the button inside the nav landmark region.
  6. There are some unnecessary <title> and <desc> elements inside the SVG icon. The accessible name comes from button's own aria-label.

Proposed resolution

  1. Remove the button from the Twig template, and create it using JS instead.
  2. Use display: none or visibility: hidden on the <ul> to remove the links from the tabbing order when the menu is closed.
    • If this is a problem for the animation, do it in two steps. When the menu opens, first remove the display:none, then change the height. Reverse order of these steps when closing.
  3. As well as toggling the CSS class for styling, toggle aria-expanded=true|false. This attribute goes on the <button>.
    • The <button> also wants an aria-controls=<IDREF>, pointing to the ID of the <ul> that gets toggled.
  4. Use the new prefers-reduced-motion media query to allow users to turn off animation if their platform allows it (currently just works in Safari).
  5. Move the toggle button to just inside the start of <nav>. Note, in the previous github issue this was highlighted as something that could be tricky, because the CSS currently assumes the button is outside the nav.
  6. Remove the <title> and <desc> elements from the SVG icon.

Remaining tasks

  1. Deferred to #2973257: Create the Umami Menu Toggle Button via JS so it's not present when JS is not enabled.
  2. Done.
  3. Done.
  4. Done.
  5. Deferred to #2973258: Place the Umami menu button inside the <nav> element.
  6. Done.

User interface changes

No visual changes. Accessibility wins:

  1. Conveys the menu open/closed state to assistive tech in a machine readable way.
  2. Fixes a failure of WCAG "Focus Visible" for sighted keyboard users
  3. Makes the menu button easier to find using landmark navigation in assistive tech.

API changes

None.

Data model changes

None.

Original report

Previously discussed in detail at issue #130 - Improve menu accessibility in the lauriii/umami Github repo.

CommentFileSizeAuthor
#85 umami-a11y-main-menu-2940023-85.patch21.42 KBshaal
#70 interdiff_68-70.txt633 bytesshaal
#70 umami-a11y-main-menu-2940023-70.patch21.38 KBshaal
#68 interdiff_66-68.txt11.78 KBshaal
#68 umami-a11y-main-menu-2940023-68.patch21.37 KBshaal
#66 interdiff_65-66.txt11.21 KBshaal
#66 interdiff_62-66.txt16.49 KBshaal
#66 umami-a11y-main-menu-2940023-66.patch21.56 KBshaal
#65 interdiff_58-65.txt3.14 KBfinnsky
#65 2940023-65.patch14.54 KBfinnsky
#62 interdiff_54-62.txt6.22 KBshaal
#62 umami-a11y-main-menu-2940023-62.patch13.14 KBshaal
#58 interdiff_55-56.txt1.09 KBfinnsky
#58 2940023-56.patch11.97 KBfinnsky
#57 interdiff_54-55.txt1.91 KBfinnsky
#57 2940023-55.patch10.88 KBfinnsky
#54 interdiff-2940023-49-54.txt2.81 KBandrewmacpherson
#54 2940023-54.patch10.88 KBandrewmacpherson
#49 2940023-49.patch7.88 KBandrewmacpherson
#48 interdiff-2940023-46-48.txt1.06 KBandrewmacpherson
#48 2940023-48.patch7.89 KBandrewmacpherson
#46 2940023-45-scrollbar-visible-during-menu-collapse.gif209.06 KBandrewmacpherson
#46 interdiff-2940023-45-46.txt567 bytesandrewmacpherson
#46 2940023-46.patch6.69 KBandrewmacpherson
#45 interdiff-2940023-44-45.txt2.68 KBandrewmacpherson
#45 2940023-45.patch6.69 KBandrewmacpherson
#44 interdiff-2940023-43-44.txt1.7 KBandrewmacpherson
#44 2940023-44.patch6.37 KBandrewmacpherson
#43 interdiff-2940023-41-43.txt976 bytesandrewmacpherson
#43 2940023-43.patch6.47 KBandrewmacpherson
#41 2940023-41.patch6.49 KBandrewmacpherson
#39 2940023-39.patch6.57 KBandrewmacpherson
#36 2940023-35.patch12.24 KBbenjifisher
#27 2940023-27.patch12.24 KBfinnsky
#27 interdiff-2940023-17-27.txt6.64 KBfinnsky
#17 interdiff-15-17.txt760 bytesmarkconroy
#17 2940023-17.patch5.46 KBmarkconroy
#15 2940023-15.patch5.45 KBmarkconroy
#15 2940023-12-15.txt793 bytesmarkconroy
#12 accessibility-changes-2940023-12.patch5.39 KBryanhayes

Comments

andrewmacpherson created an issue. See original summary.

andrewmacpherson’s picture

Issue summary: View changes
andrewmacpherson’s picture

Title: Improve accessibility of Umami's responsive main menu » Improve accessibility of Umami's responsive main menu
Issue tags: +Out of the Box Initiative
andrewmacpherson’s picture

Issue summary: View changes
andrewmacpherson’s picture

Issue summary: View changes
ryanhayes’s picture

I'm gunna have a crack at this.

andrewmacpherson’s picture

Issue tags: +SprintWeekend2018
mgifford’s picture

Easy to test with here:
https://simplytest.me/project/drupal/8.6.x

The color contrast on "Super easy vegetarian pasta bake" with that pink background is borderline. Is it bigger than 18pt? http://leaverou.github.io/contrast-ratio/#white-on-%23e84265

The tab order doesn't in the header doesn't make a lot of sense for keyboard only issues either.

andrewmacpherson’s picture

@mgifford This issue is just about the responsive menu.

The pink button contrast is addressed already in #2938686: Pink button/link style in Umami fails WCAG 2.0 SC 1.4.3 Contrast (minimum)

The tab order is something I already have on a list, haven't got a d.o issue for it yet. We're in the midst of moving issues from the Umami github repos to d.o

Update: the old github issue is https://github.com/lauriii/umami/issues/140

mgifford’s picture

Thanks!

ryanhayes’s picture

StatusFileSize
new5.39 KB

I could't figure out how to create a new button with JS properly, so hopefully someone better at JS can pick that up. I added a simple conditional for the aria-expanded tags - feel like it could be more streamline though. There's a bug with adding visibility hidden to the menu and i couldn't find a way around it; on close, the menu would disappear before the animation finished.

ryanhayes’s picture

Status: Active » Needs review
andrewmacpherson’s picture

Issue summary: View changes

Thanks for working on this @ryanhayes. I took a quick glance at the patch, and it looks like a good start. I'll take a closer look in the next few days.

It might be worth splitting this into separate issues, if some parts are going to be tricker than others. Points 2 and 3 are the most important ones, the rest could be done in follow-ups. Accessibility often involves practical compromises, and I'm happy to go for quick-wins first.

markconroy’s picture

StatusFileSize
new793 bytes
new5.45 KB

Hi Ryan and Andrew,

Been looking at this this morning and running into the same issue that Ryan has.

If we set the <ul> to display:none then the transition is lost as you can't have transition between display types. Next, if we set the <li> to display:none instead we have the transitions working for when the menu is expanding (if we give the <li> a display: block when then <ul> is clicked). However, when you click the menu toggle again to retract the menu, the <li>s get back their display: none so the transition doesn't work, the menu just closes with no transition.

Here's a patch that show this in action - so the links should not be available to keyboard users, but also the transition is slightly out of kilter.

I've also set the transition to none for people who choose reduced motion.

andrewmacpherson’s picture

Thanks for working on this Mark.

re: #15...
Good idea to try display:none and animation properties on different elements.

You could try using visibility:none on the list items. That also has the effect of removing them from the tabbing order, but preserves space so maybe that will make the list height animate better?

I've also set the transition to none for people who choose reduced motion.

Apparently some browsers don't work well with the CSS shorthand transition: none. Using specific properties like transition-duration: 0s would be a more robust approach. See #2940012-9: Use prefers-reduced-motion media query on batch progress bar in a related issue.

I haven't tried patch #15 yet, need to wait till I'm near an Apple device.

markconroy’s picture

StatusFileSize
new5.46 KB
new760 bytes

Here's a patch with visibilty set to hidden and the transition set to 0s

andrewmacpherson’s picture

Review of patch #17....

Manual testing:

  1. The menu links are hidden a the wide breakpoint - BAD, unintended side effect.
  2. The menu links are not in the tabbing order when the menu is closed - GOOD, fixes problem 2 from the issue summary.
  3. aria-expanded should applied to the button when the page loads. NEEDS WORK.
    • In Firefox it doesn't appear until after the first button pressed. After that it's behaving correctly. A screen reader user won't know what state the button is in initially - they will only find out after pressing it.
    • In Chrome it isn't ever applied, even after pressing the button.
  4. aria-controls isn't being applied to the button. NEEDS WORK.

Not manually tested yet:

  • The prefers-reduced-motion part. Simplytest.me environment builds were failing, and I don't have a dev server set up on my mac. The code approach looks OK in theory. GOOD, progress towards fixing point 4 from the issue summary. Still needs manual testing though.
  • Screen readers other than ChromeVox.

=====

Code review:

  1. +++ b/core/profiles/demo_umami/themes/umami/css/components/navigation/menu-main/menu-main.css
    +.menu-main li {
    +  visibility: hidden;
    +}
    

    Only do this at the narrow breakpoint, the links are hidden in the wide breakpoint.

  2. +++ b/core/profiles/demo_umami/themes/umami/css/components/navigation/menu-main/menu-main.css
    .menu-main--active li {
      visibility: inherit;
    }
    

    Likewise I guess this wants to move into the narrow breakpoint media query?
    Why is it visibility: inherit? Is visibility: visible more reliable?

  3. +++ b/core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.es6.js

    The aria-expanded and aria-controls attributes should be initialised in JS, after finding the right elements.
    Need to add this code here.

  4. +++ b/core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.es6.js
    + var aria = false;
    1. Should be const in ES6
    2. aria is a bit vague, maybe call it expanded
  5. +++ b/core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.es6.js
    function toggleMenu()
    
    1. The logic of toggleMenu() is a bit verbose, the if/else for expanded state can be reduced
    2. possibly fragile - need to guard against the classes falling out of step with aria-expanded. Suggest we get the current value of one property from the DOM (aria-expanded, or a data attribute, or a class) and compute all classes and aria-expanded off that.
    3. no need to return false; - <button type="button> doesn't have a default action to begin with. Not sure if propagation needs to be stopped?
  6. +++ a/core/profiles/demo_umami/themes/umami/templates/components/navigation/block--umami-main-menu.html.twig
    -<div class="menu-main-togglewrap">
    -  <button type="button" name="menu_toggle" class="menu-main-toggle" data-drupal-selector="menu-main-toggle" aria-label="Toggle the menu">{% include active_theme_path() ~ '/images/svg/menu-icon.svg' %}</button>
    +<div id="menu-main-toggle" class="menu-main-togglewrap">
    +  <button type="button" name="menu_toggle" class="menu-main-toggle" data-drupal-selector="menu-main-toggle" aria-label="Toggle the menu" aria-expanded="false" aria-controls="menu-main-toggle">{% include active_theme_path() ~ '/images/svg/menu-icon.svg' %}</button>
    
    1. just say aria-label="main menu". No need to have toggle in the button name, aria-expanded will convey that.
    2. aria-expanded="false" aria-controls="menu-main-toggle". Never initialize dynamic aria properties in the HTML source, add both of these via JS.
    3. aria-controls="menu-main-toggle" - this shouldn't point at the DIV wrapping the button. It should point to the ul.menu-main, which doesn't currently have an ID attribute.
  7. +++ a/core/profiles/demo_umami/themes/umami/templates/components/navigation/menu--main.html.twig
    -      <ul{{ attributes.addClass(menu_classes).setAttribute('data-drupal-selector','menu-main') }}> {# 1. #}
    +      <ul{{ attributes.addClass(menu_classes).setAttribute('data-drupal-selector','menu-main').setAttribute('aria-expanded', 'false') }}> {# 1. #}

    This has 2 mistakes:

    1. The UL needs an ID so the button can point to it with aria-controls
    2. aria-expanded attribute should go on the button only, not the list element. JS toggleMenu() isn't touching it in any case, so just remove it here.
      BTW never initialize dynamic ARIA states in the HTML source. Always add them via JS. Doesn't matter in this case, since we need to remove the aria-expanded form the UL

Other notes:

  1. .menu-main {
      ...
      max-height: 0;
      overflow: hidden;
    }
    .menu-main--active {
      max-height: 18.75rem;
      overflow-y: auto;
    }
    

    The default state is closed, since the .menu-main--active class is not present in HTML source. This means that if JS fails to run for some reason, the main menu links will not be operable. This was discussed in the earlier github issue. The menu should be open by default with HTML + CSS, and only closed if JS runs.

  2. The SVGs have moved to separate files. Part 6 from the issue summary still stands, the useless title and desc elements should be removed. Could move that to a follow-up issue to review all SVG files though.
andrewmacpherson’s picture

Status: Needs review » Needs work
andrewmacpherson’s picture

Next steps - let's split this into must-should-could priorities.

  • Must:
    • Use visibility:hidden to remove the links form tabbing order when menu is closed (point 2 in issue summary).
      DONE, works for narrow breakpoint.
      NEEDS WORK: avoid hiding them at wide breakpoint, per #18.1
    • Convey open/closed state of menu to assistive tech using aria-expanded and aria-controls(point 3 in issue summary).
      NEEDS WORK: review in #18 identifies the mistakes.
  • Should:
    • Use prefers-reduced-motion to disable animation (point 4 in issue summary).
      DONE, still needs manual test to confirm.
    • Move the menu toggle button inside the NAV element. (point 5 in summary).
      TODO. In the earlier github issue, it was explained that this could be tricky because the CSS was built around a certain HTML pattern, so there's lots to unpick to achieve this.
  • Could:
    • Remove the button from HTML source, initialize it in the JS (point 1 in issue summary). Low priority.
    • Remove title and desc elements from the SVG icon (point 6 in issue summary). EASY, but let's review all the icons now they live in a separate folder.

Right, lets fix the must-haves here, and move the rest to follow-up issues.

andrewmacpherson’s picture

Category: Task » Bug report

Treat the must-have points from #20 as bugs.

andrewmacpherson’s picture

Issue tags: +Needs followup
andrewmacpherson’s picture

Issue summary: View changes

updating summary, to indicate which tasks need follow-ups, vs ones already in progress or done here.

markconroy’s picture

Issue tags: +dclondon
markconroy’s picture

Issue tags: +Umami stable blocker
finnsky’s picture

Also in COULD part should be added wierd animation on collapse.
https://gyazo.com/cba99932c4b273f045d5b98a92494509
Items dissapears immidiately, then menu starts to collapse.

finnsky’s picture

Status: Needs work » Needs review
StatusFileSize
new6.64 KB
new12.24 KB

Hi! I added patch according last notes. Now menu:

  1. Expanded without js.
  2. Added special class for transition .menu-main--transition to avoid transitions of collapsing on page load.
  3. styles order should be reviewed. Now seems queries has wierd order.
  4. prefers-reduced-motion: reduce tested in safari on ios simulator and in safari on macos. Works ok. With animations: https://gyazo.com/2b5fea1653409b26d9bc8cd7cb0b0be8
    Without: https://gyazo.com/7d8e063934b76725b1d26038aa87ee2f
  5. Managed WAI attributes. Cleaned templates and moved to js.
ckrina’s picture

Issue tags: +Nashville2018
markconroy’s picture

Issue tags: -SprintWeekend2018, -dclondon
mgifford’s picture

In the Proposed resolution

#2 Seems to be done.

So for #3, the patch seems to do the trick. Initially it gives:

<button type="button" name="menu_toggle" class="menu-main-toggle" data-drupal-selector="menu-main-toggle" aria-label="Toggle the menu"><svg width="23" height="23" viewBox="0 0 23 23" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-labelledby="menu-toggle-title menu-toggle-desc"><title id="menu-toggle-title">Menu toggle icon</title><desc id="menu-toggle-desc">Hamburger icon for menu toggle.</desc><use xlink:href="#a" fill="#5F635D"></use><use xlink:href="#a" transform="translate(0 18)" fill="#5F635D"></use><use xlink:href="#a" transform="translate(0 9)" fill="#5F635D"></use><defs><path id="a" fill-rule="evenodd" d="M0 0h23v5H0V0z"></path></defs></svg>
</button>

with the patch though it gives:

<button type="button" name="menu_toggle" class="menu-main-toggle" data-drupal-selector="menu-main-toggle" aria-label="Main menu" aria-expanded="false" aria-controls="menu-main"><svg width="23" height="23" viewBox="0 0 23 23" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-labelledby="menu-toggle-title menu-toggle-desc"><title id="menu-toggle-title">Menu toggle icon</title><desc id="menu-toggle-desc">Hamburger icon for menu toggle.</desc><use xlink:href="#a" fill="#5F635D"></use><use xlink:href="#a" transform="translate(0 18)" fill="#5F635D"></use><use xlink:href="#a" transform="translate(0 9)" fill="#5F635D"></use><defs><path id="a" fill-rule="evenodd" d="M0 0h23v5H0V0z"></path></defs></svg>
</button>

Which switches to aria-expanded="true" when expanded.

I tested #4 in Safari @media screen and (prefers-reduced-motion: reduce) { seems to be respected. This is not something supported currently in other browsers. So this is good.

The rest seem to be "DEFERRED, NEEDS FOLLOW-UP ISSUE".

markconroy’s picture

Thanks @mgifford.

Can we mark this issue as RTBC so? I have created follow up issues for the other items, which we can deal with one-by-one:

1 - #2973257: Create the Umami Menu Toggle Button via JS so it's not present when JS is not enabled
5 - #2973258: Place the Umami menu button inside the <nav> element
6 - #2942258: Remove unnecessary TITLE and DESC elements from Umami SVG files - deals with SVGs in general, not just the menu icon one.

markconroy’s picture

Ping!

It'd be great to have this committed if someone from the ally team could mark it RTBC. I think it'd be a great win for Drupal + ally.

benjifisher’s picture

I have not done any testing myself. I am just updating the IS based on @mgifford's comments in #30 and the issues that @markconroy referenced in #31. Since all the points in the IS have either been done (according to the review in #30) or else have follow-up issues, I think we can mark this RTBC.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 27: 2940023-27.patch, failed testing. View results

benjifisher’s picture

Status: Needs work » Needs review

It looks as though #2943107: Umami support for Internet Explorer 11 changed one line in menu-main.css, which caused the patch to fail.

The re-roll was pretty easy. I checked out the last commit before #2943107, applied the patch from #27 on this issue, and merged with the current HEAD of 8.6.x.

benjifisher’s picture

StatusFileSize
new12.24 KB

Here is the patch I neglected to attach.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

andrewmacpherson’s picture

Assigned: Unassigned » andrewmacpherson
Status: Needs review » Needs work
Issue tags: +Needs re-roll

Needs another re-roll, patch didn't apply to 8.7.x on my machine. Working on this now.

../patches/2940023-35.patch:76: trailing whitespace.
 
../patches/2940023-35.patch:97: trailing whitespace.
 
../patches/2940023-35.patch:107: trailing whitespace.
 
../patches/2940023-35.patch:126: trailing whitespace.
 
../patches/2940023-35.patch:134: trailing whitespace.
 
error: patch failed: core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.es6.js:7
error: core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.es6.js: patch does not apply
andrewmacpherson’s picture

Assigned: andrewmacpherson » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs re-roll
StatusFileSize
new6.57 KB

Patches #27 and #35 both contain the whole of patch #17 as a new file. Sounds like the re-roll approach in #35 would have missed this problem....

diff --git a/2940023-17.patch b/2940023-17.patch
new file mode 100644
index 0000000000..85ea3ef683
--- /dev/null
+++ b/2940023-17.patch
@@ -0,0 +1,148 @@
...

The patch here is another re-roll, like #35 starting from the commit before #2943107, applying #27, merging latest 8.7.x. Then I removed the stray patch #17, and made a diff.

I'll do a manual a11y review next.

Status: Needs review » Needs work

The last submitted patch, 39: 2940023-39.patch, failed testing. View results

andrewmacpherson’s picture

Status: Needs work » Needs review
StatusFileSize
new6.49 KB

Needed another re-roll since #2981652: [Aug. 9 2018] Format core JavaScript using recently add Prettier. Nothing's changed here except a context line in main-menu.es6.js

andrewmacpherson’s picture

The name="menu_toggle" attribute can be removed from the button element. This attribute is only relevant if the button is part of a form. It's not being used for anything - it's the only of instance of the "menu_toggle" string.

andrewmacpherson’s picture

StatusFileSize
new6.47 KB
new976 bytes

removes name attribute from the button.

andrewmacpherson’s picture

StatusFileSize
new6.37 KB
new1.7 KB

This patch is just whitespace indentation fixes, effectively a re-roll, so we don't undo the coding standards clean-up from #2983355: JS codestyle: indent.

andrewmacpherson’s picture

StatusFileSize
new6.69 KB
new2.68 KB

Some more clean-up in this patch:

  1. toggler.classList.toggle('menu-main-toggle--active');
    Removing this, because it isn't used for anything. It's been there since Umami was committed to core, and this is the only place it's ever mentioned. Now aria-expanded is the only attribute on the button which changes.
  2. (function() {
       // ...
    
       menu.classList.toggle('menu-main--collapsed');
       // ...
      
       function toggleMenu() {
    

    This is initializing the class for the first time, so I changed it to classList.add() for clarity.

  3.   function toggleMenu() {
        // ...
        menu.classList.add('menu-main--transition');
    

    It took me a while to realize what this was doing. It looks like one-time set-up, but it's happening inside the click handler, instead of being initialized at the same time as the other attributes. This is by design, and it was explained back in comment #27:

    Added special class for transition .menu-main--transition to avoid transitions of collapsing on page load.

    I think this deserves a comment about why it's being done inside the click handler.

  4.   function toggleMenu() {
        const expanded = toggler.getAttribute('aria-expanded');
    
        // ...
        menu.classList.toggle('menu-main--collapsed');
    
        if (expanded === 'false') {
          toggler.setAttribute('aria-expanded', 'true');
        } else {
          toggler.setAttribute('aria-expanded', 'false');
        }
    

    This is potentially fragile. When setting aria-expanded, it explicitly checks what the current value is, but then it toggles the class without being sure whether it's present currently. It's important to ensure these never fall out of sync, so I replaced the classList.toggle() with separate add() and remove() in the if/else block. Now they're both tied to the same check.

andrewmacpherson’s picture

StatusFileSize
new6.69 KB
new567 bytes
new209.06 KB

There's a visual bug: during the collapse animation, we briefly see a scrollbar in the UL list....

Animated GIF, opening and closing main navigation menu.  A scrollbar briefly appears whilst it is closing.

This affects all the desktop browsers we support: IE11, Edge, Firefox, Opera, Chrome, Safari (Windows, Linux, macOS versions). I also saw it on an Android/Chrome tablet, but not on phone-sized Android/iOS. It may not be apparent when testing with a Mac, because of the way the scrollbars get hidden. You can see it if you make the scroll bars visible at System Preferences > General > Show scroll bars - I think Apple's default setting is to make you guess which areas are scrollable.

The culprit is .menu-main--collapsed { overflow-y:auto; }, which is overriding .menu-main { overflow: hidden; }. The patch here fixes it.

Manual accessibility testing:

I tested this using a keyboard in all our supported desktop browsers, on macOS 10.13, Windows 7, Windows 10. I also tried it with a decent range of screen readers: NVDA 2018.2 (Win 7 + 10), JAWS 2018 (win 10), Narrator (Win 10), Voiceover (macOS), Voiceover + Safari (iOS latest), Android 8.0 + Talkback + Chrome/Firefox. Generally everything was as expected, but there were a few odd things:

  • IE11 + JAWS (on Win 7 I think) - The links were announced when the menu was collapsed. That's unexpected, but it works in all the other combinations I tested so that's good. Meh, you can't win them all in screen reader testing... I might keep scratching this itch, but it isn't enough to block this issue.
  • IE11 + JAWS (Win7 + Win 10) - The menu button's name, role, and state were announced correctly. However in the arrow-keys reading mode, the nested SVG was also announced, using the title and description elements. These are verbose, unnecessary, and irrelevant. We have a follow-up for this at #2942258: Remove unnecessary TITLE and DESC elements from Umami SVG files.
  • There's an invisible tab-stop in the site-branding block - the visually-hidden site-name link. This is a failure of WCAG "focus visible", so I'll file a separate follow-up. It's not part of the responsive menu, so out of scope here.

This is great work - thanks @ryanhayes, @markconroy, @finnsky for working on this. The prefers-reduced-motion is ace, and we've seen upstream issues for Firefox to implement the media query too.

I think this is RTBC-worthy, but someone else will have to review my recent changes.

andrewmacpherson’s picture

I did a quick test of moving the button inside the nav region, between the H2 and UL, by editing just the block--umami-main-menu.html.twig template. As expected, some CSS changes will be needed, so it's right to defer that to #2973258: Place the Umami menu button inside the <nav> element.

andrewmacpherson’s picture

Issue summary: View changes
StatusFileSize
new7.89 KB
new1.06 KB

I did the SVG clean-up, removed the unhelpful title and desc.

andrewmacpherson’s picture

StatusFileSize
new7.88 KB

Needed a re-roll after #2983568: Audit and improve focus styles across the Umami theme for logged out users, it appiled cleanly with git apply --3way. The previous issue changed a colour value in menu-main.css which was used for context in the patch.

shaal’s picture

Re: #46

On narrow screens in responsive mode there's a visual scrollbar when opening the menu (tested on Firefox and Chrome) -
Line 26 (inside the class .menu-main--active) in the file menu-main.css
from
overflow-y: auto;
to
overflow-y: hidden;
Is fixing the problem.

andrewmacpherson’s picture

Status: Needs review » Needs work

@shaal - That's exactly what I changed in patch #46.

But this introduces another problem. Using overflow: hidden with max-height is a high accessibility risk, because content cannot be seen once it exceeds a certain height. Bizarrely, I don't think this is an explicit failure of WCAG! It doesn't fail WCAG "Focus Visible", because tabbing will cause the content of the overflow to move, (in Firefox and Chrome at least; I tested these). However sighted pointer users won't be able to access the links hidden inside the overflow, so that's definitely an accessibility and usability problem.

The goal, I think, is we don't want to show the scrollbar during the brief transition, if the list content height never exceeds the max-height of the list container ul. But if the content exceeds the max-heigh, it's essential to show provide access to links on the overflow, so we can't use overflow: hidden; when the menu is fully open.

I notice we apply the .menu-main--transition class once, on the first transition, and never remove it. Maybe we can use transition start/end JS events to suppress the scrollbar during the transition.

andrewmacpherson’s picture

Another problem: using max-height: 18.75 rem accommodates a maximum of 5 menu links. I think evaluators playing with Drupal's menus will easily exceed this when adding some pages.

The menu can overflow to multiple rows at the wider breakpoints, and I found it could hold 7 one-word links on one row (in English). It would be a good idea to increase the max-height of the mobile menu to reduce the likelihood of menu links disappearing on the small breakpoints.

andrewmacpherson’s picture

This will be a good one to work on during the Drupal Global Contribution Weekend 2019.

andrewmacpherson’s picture

Status: Needs work » Needs review
Issue tags: -Accessibility +accessibility, +Needs tests
StatusFileSize
new10.88 KB
new2.81 KB

The work in #49 is RTBC worthy I think, but we can add tests. I had a go at writing some FunctionalJavascript tests for the keyboard behaviour, as a way to get some momentum for #3029206: [policy, no patch] Require functional test coverage for keyboard accessibility. These tests aren't finished yet, just uploading my progress.

Status: Needs review » Needs work

The last submitted patch, 54: 2940023-54.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

finnsky’s picture

finnsky’s picture

StatusFileSize
new10.88 KB
new1.91 KB

Fixed codesniffer and namespace.

finnsky’s picture

StatusFileSize
new11.97 KB
new1.09 KB

Added [JUST FOR TEST] patch with nightwatch test.
Currently nightwatch cannot install custom installation profiles.
So test #7 patch also should be applied from here: https://www.drupal.org/project/drupal/issues/3017176#comment-12957150
Next:

  1. install nightwatch according core/tests/README.md
  2. run `yarn run test:nightwatch --tag demo_umami`

Actual patch do almost same checking as core/profiles/demo_umami/tests/src/FunctionalJavascript/DemoUmamiMainMenuTest.php

andrewmacpherson’s picture

But if we can't use nightwatch yet, why not move forward with WebDriverTestBase? This menu a11y bug is major, so I'd prefer not to postpone this for tbe nightwatch issue.

finnsky’s picture

@andrewmacpherson it can be temporary drupalProfileInstall nightwatch function in umami profile until core nightwatch will support it

andrewmacpherson’s picture

@finnsky - Can you elaborate on #60? I can move the WebDriverTestBase approach forward, but I don't understand the extra Nightwatch thing you mention. Is drupalInstallProfile a function name, or something else? I don't see it in your patch.

Meanwhile, the problem with the way max-height is used (#51-52) needs addressing.

shaal’s picture

Status: Needs work » Needs review
StatusFileSize
new13.14 KB
new6.22 KB

Based on patch #54, I added an improved javascript that doesn't require max-height and make the transition smoother.
This should solve #51 and #52

Status: Needs review » Needs work

The last submitted patch, 62: umami-a11y-main-menu-2940023-62.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

andrewmacpherson’s picture

Thanks @shaal. Review of patch #62...

  1. We don't have @finnsky's first stab at a Nightwatch test from #58. I think this is worth moving forward with. In Slack, @finnsky explained that we might be able to have a temporary version of the drupalInstall.js command if #3017176: Support install profile and language code params in drupalInstall Nightwatch command isn't fixed before this one. For now, we'll be able to use the patch there, and keep working on the Nightwatch test.
  2. We're also missing the whitespace cleanup from #57. No worries, we can add those back. They are in the latest codesniffer fixes patch, generated in #63.
  3. ../patches/umami-a11y-main-menu-2940023-62.patch:187: trailing whitespace.
        
    ../patches/umami-a11y-main-menu-2940023-62.patch:191: trailing whitespace.
        
    ../patches/umami-a11y-main-menu-2940023-62.patch:193: trailing whitespace.
        // explicitly set the element's height to its current pixel height, so we 
    ../patches/umami-a11y-main-menu-2940023-62.patch:198: trailing whitespace.
          
    ../patches/umami-a11y-main-menu-2940023-62.patch:203: trailing whitespace.
          
    warning: squelched 1 whitespace error
    warning: 6 lines add whitespace errors.
    

    Errors seen when applying the patch. Several lines have trailing whitespace, inside the new collapsSection() function in menu-main.es6.js.

  4. Comments in collapseSection() and expandSection() should use capitals at the start of sentences, full stops at the end, and be wrapped at 80 chars.
  5. --- a/core/profiles/demo_umami/themes/umami/css/components/navigation/menu-main/menu-main.css
    +++ b/core/profiles/demo_umami/themes/umami/css/components/navigation/menu-main/menu-main.css
    @@ -11,20 +11,22 @@
       font-size: 1.266rem;
       font-weight: 400;
       line-height: 1.2;
    -  max-height: 0;
       overflow: hidden;
       padding: 0;
    -  transition: max-height 0.5s ease-in;
    +  transition: height 0.5s ease-in-out;
    +  height: 0;
    

    This is a regression since patch #54. If JS is disabled, or fails to run, the menu links will not be visible, so pointer users cannot navigate the site. The links are still in the tabbing order though, which means screen reader users can navigate the site, howevere it's a failure of WCAG 2.4.7 Focus Visible for sighted keyboard users. The way the patch in #54 works, the menu will be expanded if JS fails to run, so users can still navigate the site.

  6. --- b/core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.es6.js
    +++ b/core/profiles/demo_umami/themes/umami/js/components/navigation/menu-main/menu-main.es6.js
    @@ -13,19 +13,58 @@
     
    +  function collapseSection(element) {
    +    
    +    // temporarily disable all css transitions
    +    var elementTransition = element.style.transition;
    +    element.style.transition = '';
    +    
    +    // on the next frame (as soon as the previous style change has taken effect),
    +    // explicitly set the element's height to its current pixel height, so we 
    +    // aren't transitioning out of 'auto'
    +    requestAnimationFrame(function() {
    +      element.style.height = sectionHeight + 'px';
    +      element.style.transition = elementTransition;
    +      
    +      // on the next frame (as soon as the previous style change has taken effect),
    +      // have the element transition to height: 0
    +      requestAnimationFrame(function() {
    +        element.style.height = 0 + 'px';
    +      
    +        requestAnimationFrame(function() {
    +          // remove "height" from the element's inline styles, so it can return to its initial value
    +          element.style.height = null;
    +        });
    +      });
    +    });
    +  }
    

    The comments here are a bit hard to follow, and could be clearer. When it says "the previous style change", is that referring to the previous line which assigns element.style.transition?

  7. +
    +    // when the next css transition finishes (which should be the one we just triggered)
    +    element.addEventListener('transitionend', function(e) {
    +      // remove this event listener so it only gets triggered once
    +      element.removeEventListener('transitionend', arguments.callee);
    +    });
    

    This looks a bit esoteric. We're adding an event listener which apparently does nothing, except remove itself. Can you explain why it's here? My only guess is it might be there to suppress (or ensure) something elsewhere, but I can't tell what it's for by reading this snippet.

  8. +      element.removeEventListener('transitionend', arguments.callee);
    

    The use of arguments.callee is deprecated. The anonymous event listener for transitionend can be replaced with a named callback. That's good, because the name can explain the mysterious purpose in the previous point :-)

finnsky’s picture

StatusFileSize
new14.54 KB
new3.14 KB

@andrewmacpherson hi! please have a look at interdiff. it is actually core drupalInstall function with this https://www.drupal.org/project/drupal/issues/3017176#comment-12957150 patch applied. so we can use nightwatch with custom profile here and now.

shaal’s picture

Status: Needs work » Needs review
StatusFileSize
new21.56 KB
new16.49 KB
new11.21 KB

This patch combines tests from #65,

This patch fixes all the issues raised in #64:

  1. Combines tests from #65
  2. I added/removed extra/missing spaces.
  3. (same)
  4. I format the comments in Javascript
  5. Regression fixed, when JS is off - mobile menu is open
  6. Cleaned unneeded pieces of code
  7. Comment nd
  8. Removed piece of code
  9. Removed piece of code

Status: Needs review » Needs work

The last submitted patch, 66: umami-a11y-main-menu-2940023-66.patch, failed testing. View results

shaal’s picture

StatusFileSize
new21.37 KB
new11.78 KB

oops. I left console.log debug line in the last patch.
(2am coding side effects)

shaal’s picture

Status: Needs work » Needs review
shaal’s picture

StatusFileSize
new21.38 KB
new633 bytes

Removing saving-screenshot which was causing test to fail.

The last submitted patch, 65: 2940023-65.patch, failed testing. View results

The last submitted patch, 68: umami-a11y-main-menu-2940023-68.patch, failed testing. View results

tim.plunkett’s picture

Issue tags: -accessibility (duplicate tag), -Nashville2018, -ContributionWeekend2019 +Accessibility

Fixing tags

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

smaz credited Mukeysh.

smaz credited incrn8.

smaz credited pixelite.

smaz’s picture

Adding related issue & adding credits.

smaz credited AndrewHD.

smaz’s picture

smaz credited brahmjeet789.

smaz’s picture

pawandubey’s picture

Status: Needs review » Needs work

@shaal

Tried to test this patch but its failed to apply. Please re-roll this patch again so we can verify it further.

shaal’s picture

Version: 8.8.x-dev » 8.7.x-dev
Status: Needs work » Needs review
StatusFileSize
new21.42 KB

Re-rolled patch #70.
(interdiff was not possible)

pawandubey’s picture

@shaal

Patch#85 works fine as per proposed resolution.

Verified menu expand and collapse working smoothly as per previous fix along with the accessibility.

Patch#85 have minor end line issue in JS file along with the commented code if ts require to remove.

Let's wait for others to provide their feedback on this and according to that you can re-roll the final one.

shaal’s picture

andrewmacpherson’s picture

The patch still has my stub/pseudocode WebDriverTestBase approach. If we use Nightwatch, we won't need the WebDriverTestBase class.

+  'Test expand': browser => {
+    browser
+      .resizeWindow(400, 700)
+      .drupalRelativeURL('/test-page')
+      .waitForElementVisible('body', 1000)
+      .assert.elementPresent('.menu-main-toggle')
+      .assert.hidden('#menu-main')
+      .assert.attributeEquals('.menu-main-toggle', 'aria-expanded', 'false')
+      .click('.menu-main-toggle')
+      .assert.attributeEquals('.menu-main-toggle', 'aria-expanded', 'true')
+      .assert.visible('#menu-main')
+      .drupalLogAndEnd({ onlyOnError: false });
+  },

This is on the right lines, however...

  • Note that it doesn't test keyboard accessibility. To do that we'd need to assert:
    • The button is in the tabbing order, not merely that it has a click handler. We could check that using jQueryUI's :tabbable selector, or similar approach. The point of asserting that it is tabbable is to guard against implementations of fake buttons like <div role="button" onclick="toggleMenu()">menu</div> (which isn't keyboard tabbable).
    • Add keypress<code> checks for space and enter keys. The point here is to guard against implementations of fake buttons like <code><div role="button" tabindex="0" onclick="toggleMenu()">menu</div> (which is tabbable, but still isn't keyboard operable without a keypress handler), or <a role="button" href="#" onclick="toggleMenu()">menu</a> (which is tabbable, and operable with enter, but things with the button role should be operable with spacebar too).
  • It asserts the #main-menu container is visible. But what we really want to know is that the links inside it are visible. During this issue we have encountered various problems with animating the height, and the visiblility of the overflow scrollbar, and the need to do open it in several steps. So whatever JS/CSS implementation we end up with, the desirable outcome to test is that the links themselves are visible, not their container.

shaal’s picture

Status: Needs review » Needs work
markconroy’s picture

@andrewmacpherson

Just by way of summary, is this issue okay for RTBC once we have those tests written? Are you okay with the actual implementation of the main menu from an accessibility standpoint?

If so, would you be able to write the tests that are needed? I'm not sure any of us on the OOTB team have experience writing Nightwatch tests?

If you could do that, then perhaps we can get someone else to RTBC this who can verify your tests.

smaz’s picture

Title: Improve accessibility of Umami's responsive main menu » [PP-1] Improve accessibility of Umami's responsive main menu
Status: Needs work » Postponed
Related issues: +#3042417: Accessible dropdown for Umami's language-switcher and mobile main-menu

I'm marking this as postponed until we have #3042417 finished. The idea is to use the javascript produced from that issue & try to make it a bit more generic, so it's the same code used in both places. This will make it easier to maintain & hopefully easier to test (as one test would cover everywhere the dropdown menu style is used).

shaal’s picture

Version: 8.7.x-dev » 8.8.x-dev

I created a global dropdown function, and an example of main-menu using that global function:
https://www.drupal.org/project/drupal/issues/3042417#comment-13288103

after language switcher gets committed, we can create copy that part of the patch to this issue.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.