Make WordPress Core

Changeset 39141


Ignore:
Timestamp:
11/04/2016 04:01:24 PM (10 years ago)
Author:
jorbin
Message:

Administration: Ensure collapse menu is usable with a keyboard

Currently, the "Collapse menu" item is not focusable and keyboard users can't collapse/expand the admin menu. This aims to fix it so that screen readers no longer announce it as a clickable but it remains unfocusable and thus unusable. So it's now a button.

Quoting joedolson at WordCamp Chicago 2014:
"If it's supposed to act like a button, it should be a button."

Also includes a grunt:precommit run that picked up some postcss changes to src/wp-includes/css/customize-preview.css

Fixes #29958.
Props ajercia, ipm-frommen for an iterative patch, valendesigns for an iterative patch, GaryJ for feedback, joedolson for feedback, helen for feedback

Location:
trunk/src
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/css/admin-menu.css

    r37365 r39141  
    265265.folded #adminmenu a.menu-top:focus + .wp-submenu,
    266266.folded #adminmenu .wp-has-current-submenu a.menu-top:focus + .wp-submenu,
    267 .no-js.folded #adminmenu .wp-has-submenu:hover .wp-submenu  {
     267.no-js.folded #adminmenu .wp-has-submenu:hover .wp-submenu {
    268268        top: 0;
    269269        left: 36px;
     
    548548}
    549549
    550 #collapse-menu {
    551         font-size: 13px;
     550#collapse-button {
     551        display: block;
     552        width: 100%;
     553        height: 34px;
     554        margin: 0;
     555        border: none;
     556        padding: 0;
     557        position: relative;
     558        overflow: visible;
    552559        line-height: 34px;
    553         margin-top: 10px;
    554         color: #a0a5aa;
    555         color: rgba(240,245,250,0.6);
    556         -webkit-transition: all .1s ease-in-out;
    557         transition: all .1s ease-in-out;
    558 }
    559 
    560 #collapse-menu:hover,
    561 #collapse-menu:hover #collapse-button div:after {
     560        background: none;
     561        color: #aaa;
     562        cursor: pointer;
     563        outline: 0;
     564}
     565
     566#collapse-button:hover,
     567#collapse-button:focus {
    562568        color: #00b9eb;
    563569}
    564570
    565 .folded #collapse-menu span {
     571#collapse-button .collapse-button-icon,
     572#collapse-button .collapse-button-label {
     573        /* absolutely positioned to avoid 1px shift in IE when button is pressed */
     574        display: block;
     575        position: absolute;
     576        top: 0;
     577        left: 0;
     578        line-height: 34px;
     579}
     580
     581#collapse-button .collapse-button-icon {
     582        width: 36px;
     583        height: 34px;
     584}
     585
     586#collapse-button .collapse-button-label {
     587        padding: 0 0 0 36px;
     588}
     589
     590.folded #collapse-button .collapse-button-label {
    566591        display: none;
    567592}
    568593
    569 #collapse-button,
    570 #collapse-button div {
    571         width: 15px;
    572         height: 15px;
    573 }
    574 
    575 #collapse-button {
    576         float: left;
    577         height: 15px;
    578         margin: 10px 8px 10px 11px;
    579         width: 15px;
    580         -webkit-border-radius: 10px;
    581         border-radius: 10px;
    582 }
    583 
    584 #wpwrap #collapse-button div {
    585         padding: 0;
    586 }
    587 
    588 #collapse-button div:after {
     594#collapse-button .collapse-button-icon:after {
    589595        content: "\f148";
    590596        display: block;
    591         line-height: 15px;
    592         left: -3px;
    593         top: -3px;
    594         color: #a0a5aa;
    595         color: rgba(240,245,250,0.6);
     597        position: relative;
     598        top: 7px;
     599        text-align: center;
    596600        font: normal 20px/1 dashicons !important;
    597601        speak: none;
    598         margin: 0 auto;
    599         padding: 0 !important;
    600         position: relative;
    601         text-align: center;
    602         width: 20px;
    603         -webkit-transition: all .1s ease-in-out;
    604         transition: all .1s ease-in-out;
    605602        -webkit-font-smoothing: antialiased;
    606603        -moz-osx-font-smoothing: grayscale;
     
    608605
    609606/* rtl:ignore */
    610 .folded #collapse-button div:after,
    611 .rtl #collapse-button div:after {
     607.folded #collapse-button .collapse-button-icon:after,
     608.rtl #collapse-button .collapse-button-icon:after {
    612609        -webkit-transform: rotate(180deg);
    613610        -ms-transform: rotate(180deg);
     
    615612}
    616613
    617 .rtl.folded #collapse-button div:after {
     614.rtl.folded #collapse-button .collapse-button-icon:after {
    618615        -webkit-transform: none;
    619616        -ms-transform: none;
    620617        transform: none;
     618}
     619
     620#collapse-button .collapse-button-icon:after,
     621#collapse-button .collapse-button-label {
     622        -webkit-transition: all .1s ease-in-out;
     623        transition: all .1s ease-in-out;
    621624}
    622625
     
    653656        .auto-fold #adminmenu .wp-has-current-submenu.opensub .wp-submenu,
    654657        .auto-fold #adminmenu a.menu-top:focus + .wp-submenu,
    655         .auto-fold #adminmenu .wp-has-current-submenu a.menu-top:focus + .wp-submenu  {
     658        .auto-fold #adminmenu .wp-has-current-submenu a.menu-top:focus + .wp-submenu {
    656659                top: 0px;
    657660                left: 36px;
     
    732735        }
    733736
    734         .auto-fold #collapse-menu span {
     737        .auto-fold #collapse-menu .collapse-button-label {
    735738                display: none;
    736739        }
    737740
    738         .auto-fold #collapse-button div {
    739                 background: none;
    740         }
    741 
    742741        /* rtl:ignore */
    743         .auto-fold #collapse-button div:after {
     742        .auto-fold #collapse-button .collapse-button-icon:after {
    744743                -webkit-transform: rotate(180deg);
    745744                -ms-transform: rotate(180deg);
     
    747746        }
    748747
    749         .rtl.auto-fold #collapse-button div:after {
     748        .rtl.auto-fold #collapse-button .collapse-button-icon:after {
    750749                -webkit-transform: none;
    751750                -ms-transform: none;
  • trunk/src/wp-admin/css/colors/_admin.scss

    r38660 r39141  
    228228/* Admin Menu: collapse button */
    229229
    230 #collapse-menu {
     230#collapse-button {
    231231    color: $menu-collapse-text;
    232232}
    233233
    234 #collapse-menu:hover {
    235     color: $menu-collapse-focus-text;
    236 }
    237 
    238 #collapse-button div:after {
    239     color: $menu-collapse-icon;
    240 }
    241 
    242 #collapse-menu:hover #collapse-button div:after {
    243     color: $menu-collapse-focus-icon;
    244 }
    245 
     234#collapse-button:hover,
     235#collapse-button:focus {
     236    color: $menu-submenu-focus-text;
     237}
    246238
    247239/* Admin Bar */
  • trunk/src/wp-admin/js/common.js

    r38983 r39141  
    197197                pinnedMenuBottom = false,
    198198                menuTop = 0,
     199                menuState,
    199200                menuIsPinned = false,
    200201                height = {
     
    212213        });
    213214
    214         $('#collapse-menu').on('click.collapse-menu', function() {
    215                 var respWidth, state;
     215        $( '#collapse-button' ).on( 'click.collapse-menu', function() {
     216                var viewportWidth = getViewportWidth() || 961;
    216217
    217218                // reset any compensation for submenus near the bottom of the screen
    218219                $('#adminmenu div.wp-submenu').css('margin-top', '');
    219220
    220                 if ( window.innerWidth ) {
    221                         // window.innerWidth is affected by zooming on phones
    222                         respWidth = Math.max( window.innerWidth, document.documentElement.clientWidth );
    223                 } else {
    224                         // IE < 9 doesn't support @media CSS rules
    225                         respWidth = 961;
    226                 }
    227 
    228                 if ( respWidth && respWidth < 960 ) {
     221                if ( viewportWidth < 960 ) {
    229222                        if ( $body.hasClass('auto-fold') ) {
    230223                                $body.removeClass('auto-fold').removeClass('folded');
    231224                                setUserSetting('unfold', 1);
    232225                                setUserSetting('mfold', 'o');
    233                                 state = 'open';
     226                                menuState = 'open';
    234227                        } else {
    235228                                $body.addClass('auto-fold');
    236229                                setUserSetting('unfold', 0);
    237                                 state = 'folded';
     230                                menuState = 'folded';
    238231                        }
    239232                } else {
     
    241234                                $body.removeClass('folded');
    242235                                setUserSetting('mfold', 'o');
    243                                 state = 'open';
     236                                menuState = 'open';
    244237                        } else {
    245238                                $body.addClass('folded');
    246239                                setUserSetting('mfold', 'f');
    247                                 state = 'folded';
    248                         }
    249                 }
    250 
    251                 currentMenuItemHasPopup();
    252                 $document.trigger( 'wp-collapse-menu', { state: state } );
     240                                menuState = 'folded';
     241                        }
     242                }
     243
     244                $document.trigger( 'wp-collapse-menu', { state: menuState } );
    253245        });
    254246
    255247        // Handle the `aria-haspopup` attribute on the current menu item when it has a sub-menu.
    256248        function currentMenuItemHasPopup() {
    257                 var respWidth,
    258                         $current = $( 'a.wp-has-current-submenu' );
    259 
    260                 if ( window.innerWidth ) {
    261                         respWidth = Math.max( window.innerWidth, document.documentElement.clientWidth );
    262                 } else {
    263                         respWidth = 961;
    264                 }
    265 
    266                 if ( $body.hasClass( 'folded' ) || ( $body.hasClass( 'auto-fold' ) && respWidth && respWidth <= 960 && respWidth > 782 ) ) {
     249                var $current = $( 'a.wp-has-current-submenu' );
     250
     251                if ( 'folded' === menuState ) {
    267252                        // When folded or auto-folded and not responsive view, the current menu item does have a fly-out sub-menu.
    268253                        $current.attr( 'aria-haspopup', 'true' );
     
    273258        }
    274259
    275         $document.on( 'wp-window-resized wp-responsive-activate wp-responsive-deactivate', currentMenuItemHasPopup );
     260        $document.on( 'wp-menu-state-set wp-collapse-menu wp-responsive-activate wp-responsive-deactivate', currentMenuItemHasPopup );
    276261
    277262        /**
     
    837822
    838823                trigger: function() {
    839                         var width;
    840 
    841                         if ( window.innerWidth ) {
    842                                 // window.innerWidth is affected by zooming on phones
    843                                 width = Math.max( window.innerWidth, document.documentElement.clientWidth );
    844                         } else {
    845                                 // Exclude IE < 9, it doesn't support @media CSS rules
     824                        var viewportWidth = getViewportWidth();
     825
     826                        // Exclude IE < 9, it doesn't support @media CSS rules.
     827                        if ( ! viewportWidth ) {
    846828                                return;
    847829                        }
    848830
    849                         if ( width <= 782 ) {
     831                        if ( viewportWidth <= 782 ) {
    850832                                if ( ! wpResponsiveActive ) {
    851833                                        $document.trigger( 'wp-responsive-activate' );
     
    859841                        }
    860842
    861                         if ( width <= 480 ) {
     843                        if ( viewportWidth <= 480 ) {
    862844                                this.enableOverlay();
    863845                        } else {
     
    913895        });
    914896
     897        /**
     898         * @summary Get the viewport width.
     899         *
     900         * @since 4.7
     901         *
     902         * @returns {number|boolean} The current viewport width or false if the
     903         *                           browser doesn't support innerWidth (IE < 9).
     904         */
     905        function getViewportWidth() {
     906                var viewportWidth = false;
     907
     908                if ( window.innerWidth ) {
     909                        // On phones, window.innerWidth is affected by zooming.
     910                        viewportWidth = Math.max( window.innerWidth, document.documentElement.clientWidth );
     911                }
     912
     913                return viewportWidth;
     914        }
     915
     916        /**
     917         * @summary Set the admin menu collapsed/expanded state.
     918         *
     919         * Sets the global variable `menuState` and triggers a custom event passing
     920         * the current menu state.
     921         *
     922         * @since 4.7
     923         *
     924         * @returns {void}
     925         */
     926        function setMenuState() {
     927                var viewportWidth = getViewportWidth() || 961;
     928
     929                if ( viewportWidth <= 782  ) {
     930                        menuState = 'responsive';
     931                } else if ( $body.hasClass( 'folded' ) || ( $body.hasClass( 'auto-fold' ) && viewportWidth <= 960 && viewportWidth > 782 ) ) {
     932                        menuState = 'folded';
     933                } else {
     934                        menuState = 'open';
     935                }
     936
     937                $document.trigger( 'wp-menu-state-set', { state: menuState } );
     938        }
     939
     940        // Set the menu state when the window gets resized.
     941        $document.on( 'wp-window-resized.set-menu-state', setMenuState );
     942
     943        /**
     944         * @summary Set ARIA attributes on the collapse/expand menu button.
     945         *
     946         * When the admin menu is open or folded, updates the `aria-expanded` and
     947         * `aria-label` attributes of the button to give feedback to assistive
     948         * technologies. In the responsive view, the button is always hidden.
     949         *
     950         * @since 4.7
     951         *
     952         * @returns {void}
     953         */
     954        $document.on( 'wp-menu-state-set wp-collapse-menu', function( event, eventData ) {
     955                var $collapseButton = $( '#collapse-button' ),
     956                        ariaExpanded = 'true',
     957                        ariaLabelText = commonL10n.collapseMenu;
     958
     959                if ( 'folded' === eventData.state ) {
     960                        ariaExpanded = 'false';
     961                        ariaLabelText = commonL10n.expandMenu;
     962                }
     963
     964                $collapseButton.attr({
     965                        'aria-expanded': ariaExpanded,
     966                        'aria-label': ariaLabelText
     967                });
     968        });
     969
    915970        window.wpResponsive.init();
    916971        setPinMenu();
     972        setMenuState();
    917973        currentMenuItemHasPopup();
    918974        makeNoticesDismissible();
  • trunk/src/wp-admin/menu-header.php

    r37488 r39141  
    235235        }
    236236
    237         echo '<li id="collapse-menu" class="hide-if-no-js"><div id="collapse-button"><div></div></div>';
    238         echo '<span>' . esc_html__( 'Collapse menu' ) . '</span>';
    239         echo '</li>';
     237        echo '<li id="collapse-menu" class="hide-if-no-js">' .
     238                '<button type="button" id="collapse-button" aria-label="' . esc_attr__( 'Collapse Main menu' ) . '" aria-expanded="true">' .
     239                '<span class="collapse-button-icon" aria-hidden="true"></span>' .
     240                '<span class="collapse-button-label">' . __( 'Collapse menu' ) . '</span>' .
     241                '</button></li>';
    240242}
    241243
  • trunk/src/wp-includes/css/customize-preview.css

    r39136 r39141  
    2424        background: transparent;
    2525        color: transparent;
     26        -webkit-box-shadow: none;
    2627        box-shadow: none;
    2728        outline: none;
     
    4950        background-color: #0085ba;
    5051        background: #0085ba;
     52        -webkit-border-radius: 50%;
    5153        border-radius: 50%;
    5254        border: 2px solid #fff;
     55        -webkit-box-shadow: 0 2px 1px rgba(46,68,83,0.15);
    5356        box-shadow: 0 2px 1px rgba(46,68,83,0.15);
    5457        text-align: center;
     58        display: -webkit-box;
     59        display: -webkit-flex;
     60        display: -moz-box;
     61        display: -ms-flexbox;
    5562        display: flex;
     63        -webkit-box-orient: horizontal;
     64        -webkit-box-direction: normal;
     65        -webkit-flex-direction: row;
     66        -moz-box-orient: horizontal;
     67        -moz-box-direction: normal;
     68        -ms-flex-direction: row;
    5669        flex-direction: row;
     70        -webkit-box-pack: center;
     71        -webkit-justify-content: center;
     72        -moz-box-pack: center;
     73        -ms-flex-pack: center;
    5774        justify-content: center;
     75        -webkit-box-align: center;
     76        -webkit-align-items: center;
     77        -moz-box-align: center;
     78        -ms-flex-align: center;
    5879        align-items: center;
    5980        cursor: pointer;
    6081        padding: 0;
     82        -webkit-animation-fill-mode: both;
    6183        animation-fill-mode: both;
     84        -webkit-animation-duration: .4s;
    6285        animation-duration: .4s;
    6386        opacity: 0;
     
    85108
    86109body.customize-partial-edit-shortcuts-shown .customize-partial-edit-shortcut button {
     110        -webkit-animation-name: customize-partial-edit-shortcut-bounce-appear;
    87111        animation-name: customize-partial-edit-shortcut-bounce-appear;
    88112        pointer-events: auto;
    89113}
    90114body.customize-partial-edit-shortcuts-hidden .customize-partial-edit-shortcut button {
     115        -webkit-animation-name: customize-partial-edit-shortcut-bounce-disappear;
    91116        animation-name: customize-partial-edit-shortcut-bounce-disappear;
    92117        pointer-events: none;
     
    102127}
    103128
     129@-webkit-keyframes customize-partial-edit-shortcut-bounce-appear {
     130        from, 20%, 40%, 60%, 80%, to {
     131                -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
     132                animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
     133        }
     134        0% {
     135                opacity: 0;
     136                -webkit-transform: scale3d(.3, .3, .3);
     137                transform: scale3d(.3, .3, .3);
     138        }
     139        20% {
     140                -webkit-transform: scale3d(1.1, 1.1, 1.1);
     141                transform: scale3d(1.1, 1.1, 1.1);
     142        }
     143        40% {
     144                -webkit-transform: scale3d(.9, .9, .9);
     145                transform: scale3d(.9, .9, .9);
     146        }
     147        60% {
     148                opacity: 1;
     149                -webkit-transform: scale3d(1.03, 1.03, 1.03);
     150                transform: scale3d(1.03, 1.03, 1.03);
     151        }
     152        80% {
     153                -webkit-transform: scale3d(.97, .97, .97);
     154                transform: scale3d(.97, .97, .97);
     155        }
     156        to {
     157                opacity: 1;
     158                -webkit-transform: scale3d(1, 1, 1);
     159                transform: scale3d(1, 1, 1);
     160        }
     161}
     162
    104163@keyframes customize-partial-edit-shortcut-bounce-appear {
    105164        from, 20%, 40%, 60%, 80%, to {
    106                 animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
    107         }
    108         0% {
    109                 opacity: 0;
    110                 transform: scale3d(.3, .3, .3);
    111         }
    112         20% {
    113                 transform: scale3d(1.1, 1.1, 1.1);
    114         }
    115         40% {
    116                 transform: scale3d(.9, .9, .9);
    117         }
    118         60% {
    119                 opacity: 1;
    120                 transform: scale3d(1.03, 1.03, 1.03);
    121         }
    122         80% {
    123                 transform: scale3d(.97, .97, .97);
    124         }
    125         to {
    126                 opacity: 1;
    127                 transform: scale3d(1, 1, 1);
     165                -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
     166                animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
     167        }
     168        0% {
     169                opacity: 0;
     170                -webkit-transform: scale3d(.3, .3, .3);
     171                transform: scale3d(.3, .3, .3);
     172        }
     173        20% {
     174                -webkit-transform: scale3d(1.1, 1.1, 1.1);
     175                transform: scale3d(1.1, 1.1, 1.1);
     176        }
     177        40% {
     178                -webkit-transform: scale3d(.9, .9, .9);
     179                transform: scale3d(.9, .9, .9);
     180        }
     181        60% {
     182                opacity: 1;
     183                -webkit-transform: scale3d(1.03, 1.03, 1.03);
     184                transform: scale3d(1.03, 1.03, 1.03);
     185        }
     186        80% {
     187                -webkit-transform: scale3d(.97, .97, .97);
     188                transform: scale3d(.97, .97, .97);
     189        }
     190        to {
     191                opacity: 1;
     192                -webkit-transform: scale3d(1, 1, 1);
     193                transform: scale3d(1, 1, 1);
     194        }
     195}
     196
     197@-webkit-keyframes customize-partial-edit-shortcut-bounce-disappear {
     198        from, 20%, 40%, 60%, 80%, to {
     199                -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
     200                animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
     201        }
     202        0% {
     203                opacity: 1;
     204                -webkit-transform: scale3d(1, 1, 1);
     205                transform: scale3d(1, 1, 1);
     206        }
     207        20% {
     208                -webkit-transform: scale3d(.97, .97, .97);
     209                transform: scale3d(.97, .97, .97);
     210        }
     211        40% {
     212                opacity: 1;
     213                -webkit-transform: scale3d(1.03, 1.03, 1.03);
     214                transform: scale3d(1.03, 1.03, 1.03);
     215        }
     216        60% {
     217                -webkit-transform: scale3d(.9, .9, .9);
     218                transform: scale3d(.9, .9, .9);
     219        }
     220        80% {
     221                -webkit-transform: scale3d(1.1, 1.1, 1.1);
     222                transform: scale3d(1.1, 1.1, 1.1);
     223        }
     224        to {
     225                opacity: 0;
     226                -webkit-transform: scale3d(.3, .3, .3);
     227                transform: scale3d(.3, .3, .3);
    128228        }
    129229}
     
    131231@keyframes customize-partial-edit-shortcut-bounce-disappear {
    132232        from, 20%, 40%, 60%, 80%, to {
    133                 animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
    134         }
    135         0% {
    136                 opacity: 1;
    137                 transform: scale3d(1, 1, 1);
    138         }
    139         20% {
    140                 transform: scale3d(.97, .97, .97);
    141         }
    142         40% {
    143                 opacity: 1;
    144                 transform: scale3d(1.03, 1.03, 1.03);
    145         }
    146         60% {
    147                 transform: scale3d(.9, .9, .9);
    148         }
    149         80% {
    150                 transform: scale3d(1.1, 1.1, 1.1);
    151         }
    152         to {
    153                 opacity: 0;
     233                -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
     234                animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
     235        }
     236        0% {
     237                opacity: 1;
     238                -webkit-transform: scale3d(1, 1, 1);
     239                transform: scale3d(1, 1, 1);
     240        }
     241        20% {
     242                -webkit-transform: scale3d(.97, .97, .97);
     243                transform: scale3d(.97, .97, .97);
     244        }
     245        40% {
     246                opacity: 1;
     247                -webkit-transform: scale3d(1.03, 1.03, 1.03);
     248                transform: scale3d(1.03, 1.03, 1.03);
     249        }
     250        60% {
     251                -webkit-transform: scale3d(.9, .9, .9);
     252                transform: scale3d(.9, .9, .9);
     253        }
     254        80% {
     255                -webkit-transform: scale3d(1.1, 1.1, 1.1);
     256                transform: scale3d(1.1, 1.1, 1.1);
     257        }
     258        to {
     259                opacity: 0;
     260                -webkit-transform: scale3d(.3, .3, .3);
    154261                transform: scale3d(.3, .3, .3);
    155262        }
  • trunk/src/wp-includes/script-loader.php

    r39132 r39141  
    7878        $scripts->add( 'common', "/wp-admin/js/common$suffix.js", array('jquery', 'hoverIntent', 'utils'), false, 1 );
    7979        did_action( 'init' ) && $scripts->localize( 'common', 'commonL10n', array(
    80                 'warnDelete' => __( "You are about to permanently delete these items.\n  'Cancel' to stop, 'OK' to delete." ),
    81                 'dismiss'    => __( 'Dismiss this notice.' ),
     80                'warnDelete'   => __( "You are about to permanently delete these items.\n  'Cancel' to stop, 'OK' to delete." ),
     81                'dismiss'      => __( 'Dismiss this notice.' ),
     82                'collapseMenu' => __( 'Collapse Main menu' ),
     83                'expandMenu'   => __( 'Expand Main menu' ),
    8284        ) );
    8385
Note: See TracChangeset for help on using the changeset viewer.