From e491f22d8b1ada180b3c33f13227f8795d68ce0c Mon Sep 17 00:00:00 2001 From: Volker E Date: Mon, 14 Aug 2017 15:30:23 -0700 Subject: [PATCH] mediawiki.ui: Bring checkbox and radio on par with WikimediaUI design Bringing checkbox and radio on par with WikimediaUI design templates, also slightly enhancing accessibility by using colors of new palette. Width & height is taken from current OOUI size, based on 14px Vector base font-size. Adding several similar variables to variables.less, which will be replaced by WikimediaUI Base vars in future. Also: - removing necessity for images for radio checked states - replacing `margin` with `padding` between widget and label in order to have `cursor: pointer` on full element Bug: T148265 Change-Id: I68848d48ea45c67124ac75be58748b4e9fb3085d --- .../mediawiki.ui/variables.less | 23 ++- .../src/mediawiki.ui/components/checkbox.less | 126 ++++++++++------- .../components/images/checkbox-checked.png | Bin 0 -> 170 bytes .../components/images/checkbox-checked.svg | 4 + .../components/images/checked_disabled.png | Bin 260 -> 0 bytes .../components/images/checked_disabled.svg | 1 - .../components/images/radio_checked.png | Bin 210 -> 0 bytes .../components/images/radio_checked.svg | 1 - .../components/images/radio_disabled.png | Bin 176 -> 0 bytes .../components/images/radio_disabled.svg | 1 - .../src/mediawiki.ui/components/radio.less | 132 +++++++++++------- 11 files changed, 186 insertions(+), 102 deletions(-) create mode 100644 resources/src/mediawiki.ui/components/images/checkbox-checked.png create mode 100644 resources/src/mediawiki.ui/components/images/checkbox-checked.svg delete mode 100644 resources/src/mediawiki.ui/components/images/checked_disabled.png delete mode 100644 resources/src/mediawiki.ui/components/images/checked_disabled.svg delete mode 100644 resources/src/mediawiki.ui/components/images/radio_checked.png delete mode 100644 resources/src/mediawiki.ui/components/images/radio_checked.svg delete mode 100644 resources/src/mediawiki.ui/components/images/radio_disabled.png delete mode 100644 resources/src/mediawiki.ui/components/images/radio_disabled.svg diff --git a/resources/src/mediawiki.less/mediawiki.ui/variables.less b/resources/src/mediawiki.less/mediawiki.ui/variables.less index ff74b6e8a7..56824f2147 100644 --- a/resources/src/mediawiki.less/mediawiki.ui/variables.less +++ b/resources/src/mediawiki.less/mediawiki.ui/variables.less @@ -17,8 +17,9 @@ @colorGray13: #ddd; @colorGray14: #eaecf0; @colorGray15: #f8f9fa; // lightest +@colorBaseInverted: #fff; -// Semantic background colors +// Semantic colors // Blue; for contextual use of a continuing action @colorProgressive: #36c; @colorProgressiveHighlight: #447ff5; @@ -50,18 +51,32 @@ @colorWarningText: #705000; // UI colors +@backgroundColorInputBinaryChecked: @colorProgressive; +@backgroundColorInputBinaryActive: @colorProgressiveActive; @colorFieldBorder: #a2a9b1; @colorShadow: @colorGray14; @colorPlaceholder: @colorGray10; @colorNeutral: @colorGray7; +// Border colors +@borderColorInputBinaryChecked: @colorProgressive; +@borderColorInputBinaryActive: @colorProgressiveActive; + +// Checked radio input border-width, equal to OOUI at 14px base font-size +@borderWidthRadioChecked: 0.4285em; + // Global border radius to be used to buttons and inputs @borderRadius: 2px; +// Box shadows +@boxShadowWidget: inset 0 0 0 1px transparent; +@boxShadowWidgetFocus: inset 0 0 0 1px @colorProgressive; +@boxShadowProgressiveFocus: inset 0 0 0 1px @colorProgressive, inset 0 0 0 2px @colorBaseInverted; +@boxShadowInputBinaryActive: inset 0 0 0 1px @colorProgressiveActive; + // Icon related variables @iconSize: 1.5em; @iconGutterWidth: 1em; -// Form input sizes -@checkboxSize: 2em; -@radioSize: 2em; +// Form input sizes, equal to OOUI at 14px base font-size +@sizeInputBinary: 1.5625em; diff --git a/resources/src/mediawiki.ui/components/checkbox.less b/resources/src/mediawiki.ui/components/checkbox.less index 6412da5ba1..c1626db610 100644 --- a/resources/src/mediawiki.ui/components/checkbox.less +++ b/resources/src/mediawiki.ui/components/checkbox.less @@ -5,9 +5,9 @@ // // Styling checkboxes in a way that works cross browser is a tricky problem to solve. // In MediaWiki UI put a checkbox and label inside a mw-ui-checkbox div. -// This renders in all browsers except IE 6-8 which do not support the :checked selector; +// This renders in all browsers except IE 6-8 which do not support the `:checked` selector; // these are kept backwards-compatible using the `:not( #noop )` selector. -// You should give the checkbox and label matching "id" and "for" attributes, respectively. +// You should give the checkbox and label matching `id` and `for` attributes, respectively. // // Markup: //
@@ -30,97 +30,127 @@ // Styleguide 3. .mw-ui-checkbox { display: inline-block; + line-height: @sizeInputBinary; vertical-align: middle; } -// We use the not selector to cancel out styling on IE 8 and below +// We use the `:not` selector to cancel out styling on IE 8 and below // We also disable this styling on JavaScript disabled devices. This fixes the issue with // Opera Mini where checking/unchecking doesn't apply styling but potentially leaves other // more capable browsers with unstyled checkboxes. .client-js .mw-ui-checkbox:not( #noop ) { + display: table; // Position relatively so we can make use of absolute pseudo elements position: relative; - display: table; * { - // reset font sizes (see T74727) + // Reset font sizes, see T74727 font: inherit; vertical-align: middle; } - input[type='checkbox'] { - // we hide the input element as instead we will style the label that follows - // we use opacity so that VoiceOver software can still identify it - opacity: 0; - // Render *on top of* the label, so that it's still clickable (T98905) - z-index: 1; + [type='checkbox'] { + display: table-cell; position: relative; - // ensure the invisible checkbox takes up the required width - width: @checkboxSize; - height: @checkboxSize; - // This is needed for Firefox mobile (See T73750 to workaround default Firefox stylesheet) + // Ensure the invisible input takes up the required `width` & `height` + width: @sizeInputBinary; + height: @sizeInputBinary; + // Support: Firefox mobile to override user-agent stylesheet, see T73750 max-width: none; - margin: 0 0.4em 0 0; - cursor: pointer; - display: table-cell; + margin: 0; + // Hide `input[type=checkbox]` and instead style the label that follows + // Support: VoiceOver. Use `opacity` so that VoiceOver can still identify the checkbox + opacity: 0; + // Render *on top of* the label, so that it's still clickable, see T98905 + z-index: 1; & + label { display: table-cell; - cursor: pointer; + padding-left: 0.4em; } - // the pseudo before element of the label after the checkbox now looks like a checkbox + // Pseudo `:before` element of the label after the checkbox now looks like a checkbox & + label:before { content: ''; background-color: #fff; - .background-image-svg( 'images/checked.svg', 'images/checked.png' ); - background-position: center center; background-origin: border-box; + background-position: center center; background-repeat: no-repeat; .background-size( 0, 0 ); .box-sizing( border-box ); position: absolute; - // align the checkbox to middle of the text + // Ensure alignment of checkbox to middle of the text in long labels, see T85241 top: 50%; left: 0; - width: @checkboxSize; - height: @checkboxSize; - margin-top: -1em; + width: @sizeInputBinary; + height: @sizeInputBinary; + margin-top: -( @sizeInputBinary / 2 ); border: 1px solid @colorGray7; border-radius: @borderRadius; - line-height: @checkboxSize; - cursor: pointer; } - // when the input is checked, style the label pseudo before element that followed as a checked checkbox + // Apply a checkmark on the pseudo `:before` element when the input is checked &:checked + label:before { - .background-size( 100%, 100% ); + .background-image-svg( 'images/checkbox-checked.svg', 'images/checkbox-checked.png' ); + .background-size( 90%, 90% ); } - &:active + label:before { - background-color: @colorGray13; - border-color: @colorGray13; - } + &:enabled { + cursor: pointer; - &:focus + label:before { - border-width: 2px; - } + & + label { + cursor: pointer; + } + + & + label:before { + cursor: pointer; + .transition( ~'background-color 100ms, color 100ms, border-color 100ms, box-shadow 100ms' ); + } + + // `:focus` has to come first, otherwise a specificity race with `:hover:focus` etc is necessary + &:focus + label:before { + border-color: @colorProgressive; + box-shadow: @boxShadowWidgetFocus; + } + + &:hover + label:before { + border-color: @colorProgressive; + } - &:focus:hover + label:before, - &:hover + label:before { - border-bottom-width: 3px; + &:active + label:before { + background-color: @colorProgressiveActive; + border-color: @borderColorInputBinaryActive; + box-shadow: @boxShadowInputBinaryActive; + } + + &:checked { + & + label:before { + background-color: @backgroundColorInputBinaryChecked; + border-color: @borderColorInputBinaryChecked; + } + + &:focus + label:before { + background-color: @backgroundColorInputBinaryChecked; + border-color: @borderColorInputBinaryChecked; + box-shadow: @boxShadowProgressiveFocus; + } + + &:hover + label:before { + background-color: @colorProgressiveHighlight; + border-color: @colorProgressiveHighlight; + } + + &:active + label:before { + background-color: @backgroundColorInputBinaryActive; + border-color: @borderColorInputBinaryActive; + } + } } // disabled checkboxes have a gray background &:disabled + label:before { - cursor: default; - background-color: @colorGray14; - border-color: @colorGray14; - } - - // disabled and checked checkboxes have a white circle - &:disabled:checked + label:before { - .background-image-svg( 'images/checked_disabled.svg', 'images/checked_disabled.png' ); + background-color: @colorGray12; + border-color: @colorGray12; } } } diff --git a/resources/src/mediawiki.ui/components/images/checkbox-checked.png b/resources/src/mediawiki.ui/components/images/checkbox-checked.png new file mode 100644 index 0000000000000000000000000000000000000000..708bb396cdf0737c3ca00c4ea70ecad43915037d GIT binary patch literal 170 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-MU1D5 zV~9uR+lw1H4;b*U1~!X-)R<{jyyKJ1ttUZ8rcP8mD$cUz^;ec4&B$-F8>Cpx6F!u= zKQJp~zNPqs<&L6g-n|V^bgW&firIHR;g6lBaMav;%a2V<+8;!ITgh(Z^Yg + + + diff --git a/resources/src/mediawiki.ui/components/images/checked_disabled.png b/resources/src/mediawiki.ui/components/images/checked_disabled.png deleted file mode 100644 index 8217815d662d242fdc2e8800e8503210d090da8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 260 zcmV+f0sH=mP)*A%jgPKF6w=Q0UOQ;pZd+Xx)ID^_o z>R&F diff --git a/resources/src/mediawiki.ui/components/images/radio_checked.png b/resources/src/mediawiki.ui/components/images/radio_checked.png deleted file mode 100644 index adee2c984c2a972d67190bb12aff19d1216ef7c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjGd*1#Ln;`P7cfh(E=~w#mOi}e z98cTVxyu`W$g-5rO}cSm;yHt2HSN^4{CAVtq$>D2{y#pDE@@WgH8K6iA2z-Pr}dk7 zlp4+(=gdChw~JMJ7gu7Nz_Hk$Dzo{yiXZ8|uyE{SjqljL;Pd5#Eel?YTolWBVFOh6 z+G>+$N3+kQv+Sz2Ns~1-j4x>}4vY)=!;m;-QPZ;oksc<7Dck}l=KZ&u3Unlcr>mdK II;Vst05$kf1poj5 diff --git a/resources/src/mediawiki.ui/components/images/radio_checked.svg b/resources/src/mediawiki.ui/components/images/radio_checked.svg deleted file mode 100644 index c8b9b62579..0000000000 --- a/resources/src/mediawiki.ui/components/images/radio_checked.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/src/mediawiki.ui/components/images/radio_disabled.png b/resources/src/mediawiki.ui/components/images/radio_disabled.png deleted file mode 100644 index 75989e66856e3995e2c599095c6a9bf03d14fbf8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj<(@8%Ar*{ouN)O+aujGulu2s% zQ{XFf-JxLb-xq>2-yJL8|NT|eW8n(h`TQM>kqel8^fH+x6|!{w8Ef-iGkWG$GD&>A z!O)S-w&LNsMUo4ecP~q85Pc^WZ|NXi&U==D_0Cfh<|C}vO}^c1SNow=Ha%iL*L?p3 Zewls0%AUS=Qv^DJ!PC{xWt~$(69D&1Kt2Ef diff --git a/resources/src/mediawiki.ui/components/images/radio_disabled.svg b/resources/src/mediawiki.ui/components/images/radio_disabled.svg deleted file mode 100644 index ec8ffe3e8c..0000000000 --- a/resources/src/mediawiki.ui/components/images/radio_disabled.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/src/mediawiki.ui/components/radio.less b/resources/src/mediawiki.ui/components/radio.less index 7cb2849798..3d82e8eda2 100644 --- a/resources/src/mediawiki.ui/components/radio.less +++ b/resources/src/mediawiki.ui/components/radio.less @@ -40,7 +40,7 @@ .client-js .mw-ui-radio:not( #noop ) { // Position relatively so we can make use of absolute pseudo elements position: relative; - line-height: @radioSize; + line-height: @sizeInputBinary; * { // reset font sizes (see T74727) @@ -48,65 +48,103 @@ vertical-align: middle; } - input[type='radio'] { - // we hide the input element as instead we will style the label that follows - // we use opacity so that VoiceOver software can still identify it - opacity: 0; + [type='radio'] { // ensure the invisible radio takes up the required width - width: @radioSize; - height: @radioSize; + width: @sizeInputBinary; + height: @sizeInputBinary; // This is needed for Firefox mobile (See T73750 to workaround default Firefox stylesheet) max-width: none; - margin-right: 0.4em; - - // the pseudo before element of the label after the radio now looks like a radio - & + label:before { - content: ''; - background-color: #fff; - .background-image-svg( 'images/radio_checked.svg', 'images/radio_checked.png' ); - background-origin: border-box; - background-position: center center; - background-repeat: no-repeat; - .background-size( 0, 0 ); - .box-sizing( border-box ); - position: absolute; - left: 0; - width: @radioSize; - height: @radioSize; - border: 1px solid @colorGray7; - border-radius: 100%; - cursor: pointer; + margin: 0; + // Hide `input[type=radio]` and instead style the label that follows + // Support: VoiceOver. Use `opacity` so that VoiceOver can still identify the radio + opacity: 0; + + & + label { + padding-left: 0.4em; + + // Pseudo `:before` element of the label after the radio now looks like a radio + &:before { + content: ''; + background-color: #fff; + .box-sizing( border-box ); + position: absolute; + left: 0; + width: @sizeInputBinary; + height: @sizeInputBinary; + border: 1px solid @colorGray7; + border-radius: 100%; + } + + // Needed for `:focus` state's inner white circle + &:after { + content: ' '; + position: absolute; + top: 2px; // `px` unit due to pixel rounding error when using `@sizeInputBinary / 4` + left: 2px; + width: 1.14285em; // equals `@sizeInputBinary - 4px` + height: 1.14285em; + border: 1px solid transparent; + border-radius: 100%; + } } - // when the input is checked, style the label pseudo before element that followed as a checked radio + // Apply a dot on the pseudo `:before` element when the input is checked &:checked + label:before { - .background-size( 100%, 100% ); + border-width: @borderWidthRadioChecked; } - &:active + label:before { - background-color: @colorGray13; - border-color: @colorGray13; - } + &:enabled { + cursor: pointer; - &:focus + label:before { - border-width: 2px; - } + & + label:before { + cursor: pointer; + .transition( ~'background-color 100ms, color 100ms, border-color 100ms' ); + } - &:focus:hover + label:before, - &:hover + label:before { - border-bottom-width: 3px; - } + &:hover + label:before { + border-color: @colorProgressive; + } + + &:active + label:before { + background-color: @colorProgressiveActive; + border-color: @borderColorInputBinaryActive; + } + + &:checked { + & + label:before { + border-color: @borderColorInputBinaryChecked; + } - // disabled radios have a gray background - &:disabled + label:before { - background-color: @colorGray14; - border-color: @colorGray14; - cursor: default; + &:focus + label:after { + border-color: #fff; + } + + &:hover + label:before { + border-color: @colorProgressiveHighlight; + } + + &:active { + & + label:before { + border-color: @borderColorInputBinaryActive; + box-shadow: @boxShadowInputBinaryActive; + } + + & + label:after { + border-color: @borderColorInputBinaryActive; + } + } + } } - // disabled and checked radios have a white circle - &:disabled:checked + label:before { - .background-image-svg( 'images/radio_disabled.svg', 'images/radio_disabled.png' ); + &:disabled { + & + label:before { + background-color: @colorGray12; + border-color: @colorGray12; + } + + &:checked + label:before { + background-color: #fff; + } } } } -- 2.20.1