WordPress.org

Make WordPress Core

Changeset 41329


Ignore:
Timestamp:
09/03/2017 04:01:18 PM (2 years ago)
Author:
afercia
Message:

Accessibility: Improve the color picker UI accessibility, interaction, and generated markup.

  • Refactors the UI controls around the Iris color picker to output valid and semantic markup
  • Simplifies the way elements visibility gets toggled
  • Properly associates the visually hidden label with the color input field
  • Makes the toggle button a real button
  • Adds aria-expanded to the toggle button
  • Keeps focus on the toggle button instead of moving it to the color input field
  • Adds aria-label attributes to give better context to some controls
  • Removes a redundant title attribute
  • Keeps the toggle button text to "Select Color" instead of changing it to "Current Color" when a color is selected
  • Slightly improves the responsive view
  • CSS clean-up

Fixes #39662.

Location:
trunk/src
Files:
6 edited

Legend:

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

    r41062 r41329  
    77}
    88
    9 .wp-color-result {
    10     background-color: #f7f7f7;
    11     border: 1px solid #ccc;
    12     border-radius: 3px;
    13     cursor: pointer;
    14     display: inline-block;
    15     height: 22px;
     9/* Needs higher specificiity. */
     10.wp-picker-container .wp-color-result.button {
     11    height: 24px;
    1612    margin: 0 6px 6px 0px;
    17     position: relative;
    18     top: 1px;
    19     -webkit-user-select: none;
    20     -moz-user-select: none;
    21     -ms-user-select: none;
    22     user-select: none;
    23     vertical-align: bottom;
    24     display: inline-block;
    25     padding-left: 30px;
    26     box-shadow: 0 1px 0 #ccc;
     13    padding: 0 0 0 30px;
     14    font-size: 11px;
    2715}
    2816
    29 .wp-color-result:after {
     17.wp-color-result-text {
    3018    background: #f7f7f7;
    3119    border-radius: 0 2px 2px 0;
    3220    border-left: 1px solid #ccc;
    3321    color: #555;
    34     content: attr( title );
    3522    display: block;
    36     font-size: 11px;
    3723    line-height: 22px;
    3824    padding: 0 6px;
    39     position: relative;
    40     right: 0;
    4125    text-align: center;
    42     top: 0;
    4326}
    4427
     
    5740}
    5841
    59 .wp-color-result {
    60     top: 0;
    61 }
    62 
    63 .wp-color-result.wp-picker-open:after {
    64     content: attr( data-current );
    65 }
    66 
    67 .wp-picker-container, .wp-picker-container:active {
     42.wp-picker-containers {
    6843    display: inline-block;
    69     outline: 0;
    7044}
    7145
     
    7549}
    7650
     51.wp-color-result:active {
     52    /* See Trac ticket #39662 */
     53    transform: none !important;
     54}
     55
    7756.wp-picker-open + .wp-picker-input-wrap {
    7857    display: inline-block;
     
    8059}
    8160
    82 .wp-picker-container .button {
    83     margin-left: 6px;
     61.wp-picker-input-wrap label {
     62    display: inline-block;
     63    vertical-align: top;
     64}
     65
     66/* For the old `custom-background` page, to override the inline-block and margins from `.form-table td fieldset label`. */
     67.form-table .wp-picker-input-wrap label {
     68    margin: 0 !important;
     69}
     70
     71.wp-picker-input-wrap .button,
     72.wp-customizer .wp-picker-input-wrap .button {
     73    margin-left: 6px;
    8474}
    8575
     
    10090    line-height: 16px;
    10191    margin: 0;
     92    vertical-align: top;
    10293}
    10394
     
    128119}
    129120
     121.iris-picker .iris-palette:focus {
     122    box-shadow:
     123        inset 0 0 5px rgba(0,0,0,.4),
     124        0 0 0 1px #5b9dd9,
     125        0 0 2px 1px rgba(30, 140, 190, .8);
     126}
     127
    130128@media screen and ( max-width: 782px ) {
    131129    .wp-picker-container input[type="text"].wp-color-picker {
    132         margin-right: 6px;
    133         padding: 3px 5px;
     130        width: 80px;
     131        padding: 6px 5px 5px;
     132        font-size: 16px;
     133        line-height: 18px;
     134    }
     135
     136    .wp-customizer .wp-picker-container input[type="text"].wp-color-picker {
     137        padding: 5px 5px 4px;
     138    }
     139
     140    .wp-picker-container .wp-color-result.button {
     141        height: auto;
     142        padding: 0 0 0 40px;
     143        font-size: 14px;
     144        line-height: 29px;
     145    }
     146
     147    .wp-customizer .wp-picker-container .wp-color-result.button {
     148        font-size: 13px;
     149        line-height: 26px;
     150    }
     151
     152    .wp-picker-container .wp-color-result-text {
     153        padding: 0 14px;
     154        font-size: inherit;
     155        line-height: inherit;
     156    }
     157
     158    .wp-customizer .wp-picker-container .wp-color-result-text {
     159        padding: 0 10px;
    134160    }
    135161}
     162
     163@media screen and ( max-width: 640px ) {
     164    .wp-customizer .wp-picker-container .wp-color-result.button {
     165        font-size: 14px;
     166        line-height: 29px;
     167    }
     168
     169    .wp-customizer .wp-picker-container input[type="text"].wp-color-picker {
     170        padding: 6px 5px;
     171    }
     172}
  • trunk/src/wp-admin/css/common.css

    r41062 r41329  
    35793579    }
    35803580
    3581     .wp-color-result {
    3582         height: auto;
    3583         padding-left: 45px;
    3584     }
    3585 
    3586     .wp-color-result:after {
    3587         font-size: 14px;
    3588         height: auto;
    3589         padding: 6px 14px;
    3590     }
    3591 
    35923581    /* Feedback Messages */
    35933582    .notice,
  • trunk/src/wp-admin/css/customize-controls.css

    r41062 r41329  
    859859}
    860860
    861 /* Color Picker */
    862 .customize-control-color .color-picker-hex {
    863     display: none;
    864 }
    865 
    866 .customize-control-color.open .color-picker-hex {
    867     display: block;
    868 }
    869 
    870861.customize-control-color .dropdown {
    871862    margin-right: 5px;
  • trunk/src/wp-admin/js/color-picker.js

    r41264 r41329  
    11/* global wpColorPickerL10n */
    2 ( function( $, undef ){
     2( function( $, undef ) {
    33
    44    var ColorPicker,
    5         _before = '<a tabindex="0" class="wp-color-result" />',
     5        _before = '<button type="button" class="button wp-color-result" aria-expanded="false"><span class="wp-color-result-text"></span></button>',
    66        _after = '<div class="wp-picker-holder" />',
    77        _wrap = '<div class="wp-picker-container" />',
    8         _button = '<input type="button" class="button button-small hidden" />';
     8        _button = '<input type="button" class="button button-small" />',
     9        _wrappingLabel = '<label></label>',
     10        _wrappingLabelText = '<span class="screen-reader-text"></span>';
    911
    1012    /**
     
    102104            self.initialValue = el.val();
    103105
    104             // Set up HTML structure and hide the color picker.
    105             el.addClass( 'wp-color-picker' ).hide().wrap( _wrap );
    106             self.wrap = el.parent();
    107             self.toggler = $( _before ).insertBefore( el ).css( { backgroundColor: self.initialValue } ).attr( 'title', wpColorPickerL10n.pick ).attr( 'data-current', wpColorPickerL10n.current );
    108             self.pickerContainer = $( _after ).insertAfter( el );
     106            // Add a CSS class to the input field.
     107            el.addClass( 'wp-color-picker' );
     108
     109            /*
     110             * Check if there's already a wrapping label, e.g. in the Customizer.
     111             * If there's no label, add a default one to match the Customizer template.
     112             */
     113            if ( ! el.parent( 'label' ).length ) {
     114                // Wrap the input field in the default label.
     115                el.wrap( _wrappingLabel );
     116                // Insert the default label text.
     117                self.wrappingLabelText = $( _wrappingLabelText )
     118                    .insertBefore( el )
     119                    .text( wpColorPickerL10n.defaultLabel );
     120            }
     121
     122            /*
     123             * At this point, either it's the standalone version or the Customizer
     124             * one, we have a wrapping label to use as hook in the DOM, let's store it.
     125             */
     126            self.wrappingLabel = el.parent();
     127
     128            // Wrap the label in the main wrapper.
     129            self.wrappingLabel.wrap( _wrap );
     130            // Store a reference to the main wrapper.
     131            self.wrap = self.wrappingLabel.parent();
     132            // Set up the toggle button and insert it before the wrapping label.
     133            self.toggler = $( _before )
     134                .insertBefore( self.wrappingLabel )
     135                .css( { backgroundColor: self.initialValue } );
     136            // Set the toggle button span element text.
     137            self.toggler.find( '.wp-color-result-text' ).text( wpColorPickerL10n.pick );
     138            // Set up the Iris container and insert it after the wrapping label.
     139            self.pickerContainer = $( _after ).insertAfter( self.wrappingLabel );
     140            // Store a reference to the Clear/Default button.
    109141            self.button = $( _button );
    110142
     143            // Set up the Clear/Default button.
    111144            if ( self.options.defaultColor ) {
    112                 self.button.addClass( 'wp-picker-default' ).val( wpColorPickerL10n.defaultString );
     145                self.button
     146                    .addClass( 'wp-picker-default' )
     147                    .val( wpColorPickerL10n.defaultString )
     148                    .attr( 'aria-label', wpColorPickerL10n.defaultAriaLabel );
    113149            } else {
    114                 self.button.addClass( 'wp-picker-clear' ).val( wpColorPickerL10n.clear );
    115             }
    116 
    117             el.wrap( '<span class="wp-picker-input-wrap" />' ).after( self.button );
     150                self.button
     151                    .addClass( 'wp-picker-clear' )
     152                    .val( wpColorPickerL10n.clear )
     153                    .attr( 'aria-label', wpColorPickerL10n.clearAriaLabel );
     154            }
     155
     156            // Wrap the wrapping label in its wrapper and append the Clear/Default button.
     157            self.wrappingLabel
     158                .wrap( '<span class="wp-picker-input-wrap hidden" />' )
     159                .after( self.button );
     160
     161            /*
     162             * The input wrapper now contains the label+input+Clear/Default button.
     163             * Store a reference to the input wrapper: we'll use this to toggle
     164             * the controls visibility.
     165             */
     166            self.inputWrapper = el.closest( '.wp-picker-input-wrap' );
    118167
    119168            el.iris( {
     
    213262                        self.options.clear.call( this, event );
    214263                    }
    215                 }
    216             });
    217 
    218             /**
    219              * @summary Enables the user to open the color picker with their keyboard.
    220              *
    221              * Enables the user to open the color picker with their keyboard.
    222              * This is possible by using the space or enter key.
    223              *
    224              * @since 3.5.0
    225              *
    226              * @param {Event} event The event that's being called.
    227              *
    228              * @returns {void}
    229              */
    230             self.toggler.on( 'keyup', function( event ) {
    231                 if ( event.keyCode === 13 || event.keyCode === 32 ) {
    232                     event.preventDefault();
    233                     self.toggler.trigger( 'click' ).next().focus();
    234264                }
    235265            });
     
    267297         */
    268298        open: function() {
    269             this.element.show().iris( 'toggle' ).focus();
    270             this.button.removeClass( 'hidden' );
     299            this.element.iris( 'toggle' );
     300            this.inputWrapper.removeClass( 'hidden' );
    271301            this.wrap.addClass( 'wp-picker-active' );
    272             this.toggler.addClass( 'wp-picker-open' );
     302            this.toggler
     303                .addClass( 'wp-picker-open' )
     304                .attr( 'aria-expanded', 'true' );
    273305            $( 'body' ).trigger( 'click.wpcolorpicker' ).on( 'click.wpcolorpicker', this.close );
    274306        },
     
    281313         */
    282314        close: function() {
    283             this.element.hide().iris( 'toggle' );
    284             this.button.addClass( 'hidden' );
     315            this.element.iris( 'toggle' );
     316            this.inputWrapper.addClass( 'hidden' );
    285317            this.wrap.removeClass( 'wp-picker-active' );
    286             this.toggler.removeClass( 'wp-picker-open' );
     318            this.toggler
     319                .removeClass( 'wp-picker-open' )
     320                .attr( 'aria-expanded', 'false' );
    287321            $( 'body' ).off( 'click.wpcolorpicker', this.close );
    288322        },
  • trunk/src/wp-includes/customize/class-wp-customize-color-control.php

    r41256 r41329  
    100100            defaultValueAttr = ' data-default-color=' + defaultValue; // Quotes added automatically.
    101101        } #>
    102         <label>
    103             <# if ( data.label ) { #>
    104                 <span class="customize-control-title">{{{ data.label }}}</span>
    105             <# } #>
    106             <# if ( data.description ) { #>
    107                 <span class="description customize-control-description">{{{ data.description }}}</span>
    108             <# } #>
    109             <div class="customize-control-content">
    110                 <# if ( isHueSlider ) { #>
    111                     <input class="color-picker-hue" type="text" data-type="hue" />
    112                 <# } else { #>
    113                     <input class="color-picker-hex" type="text" maxlength="7" placeholder="{{ defaultValue }}" {{ defaultValueAttr }} />
    114                 <# } #>
    115             </div>
    116         </label>
     102        <# if ( data.label ) { #>
     103            <span class="customize-control-title">{{{ data.label }}}</span>
     104        <# } #>
     105        <# if ( data.description ) { #>
     106            <span class="description customize-control-description">{{{ data.description }}}</span>
     107        <# } #>
     108        <div class="customize-control-content">
     109            <label><span class="screen-reader-text">{{{ data.label }}}</span>
     110            <# if ( isHueSlider ) { #>
     111                <input class="color-picker-hue" type="text" data-type="hue" />
     112            <# } else { #>
     113                <input class="color-picker-hex" type="text" maxlength="7" placeholder="{{ defaultValue }}" {{ defaultValueAttr }} />
     114            <# } #>
     115            </label>
     116        </div>
    117117        <?php
    118118    }
  • trunk/src/wp-includes/script-loader.php

    r41320 r41329  
    797797        $scripts->add( 'wp-color-picker', "/wp-admin/js/color-picker$suffix.js", array( 'iris' ), false, 1 );
    798798        did_action( 'init' ) && $scripts->localize( 'wp-color-picker', 'wpColorPickerL10n', array(
    799             'clear' => __( 'Clear' ),
    800             'defaultString' => __( 'Default' ),
    801             'pick' => __( 'Select Color' ),
    802             'current' => __( 'Current Color' ),
     799            'clear'            => __( 'Clear' ),
     800            'clearAriaLabel'   => __( 'Clear color' ),
     801            'defaultString'    => __( 'Default' ),
     802            'defaultAriaLabel' => __( 'Select default color' ),
     803            'pick'             => __( 'Select Color' ),
     804            'defaultLabel'     => __( 'Color value' ),
    803805        ) );
    804806
Note: See TracChangeset for help on using the changeset viewer.