wikimedia/mediawiki-core

View on GitHub
resources/src/mediawiki.ui.radio/radio.less

Summary

Maintainability
Test Coverage
@import 'mediawiki.skin.variables.less';
@import 'mediawiki.mixins.less';

// Form input sizes, equal to OOUI at 14px base font-size
@size-input-binary: 1.5625em;
// Checked radio input `border-width`, in pixel as both the background and the dot are signals.
// Equal to OOUI.
@border-width-input-radio--checked: 6px;

// Radio
//
// Styling radios in a way that works cross browser is a tricky problem to solve.
// In MediaWiki UI put a radio and label inside a mw-ui-radio div.
// You should give the radio and label matching "id" and "for" attributes, respectively.
//
// Markup:
// <div class="mw-ui-radio">
//   <input type="radio" id="component-example-4" name="component-example-4">
//   <label for="component-example-4">Standard radio</label>
// </div>
// <div class="mw-ui-radio">
//   <input type="radio" id="component-example-4-checked" name="component-example-4" checked>
//   <label for="component-example-4-checked">Standard checked radio</label>
// </div>
// <div class="mw-ui-radio">
//   <input type="radio" id="component-example-4-disabled" name="component-example-4-disabled" disabled>
//   <label for="component-example-4-disabled">Disabled radio</label>
// </div>
// <div class="mw-ui-radio">
//   <input type="radio" id="component-example-4-disabled-checked" name="component-example-4-disabled" disabled checked>
//   <label for="component-example-4-disabled-checked">Disabled checked radio</label>
// </div>
.mw-ui-radio {
    display: inline-block;
    vertical-align: middle;
}

// We 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 radio buttons.
.client-js .mw-ui-radio {
    // Position relatively so we can make use of absolute pseudo elements
    position: relative;
    line-height: @size-input-binary;

    * {
        // reset font sizes (see T74727)
        font-size: inherit;
        vertical-align: middle;
    }

    [ type='radio' ] {
        // ensure the invisible radio takes up the required width
        width: @size-input-binary;
        height: @size-input-binary;
        // This is needed for Firefox mobile (See T73750 to workaround default Firefox stylesheet)
        max-width: none;
        // 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: @background-color-base;
                box-sizing: border-box;
                position: absolute;
                left: 0;
                width: @size-input-binary;
                height: @size-input-binary;
                border-width: @border-width-base;
                border-style: @border-style-base;
                border-radius: @border-radius-circle;
            }

            // Needed for `:focus` state's inner white circle
            &::after {
                content: ' ';
                position: absolute;
                top: 2px; // `px` unit due to pixel rounding error when using `@size-input-binary / 4`
                left: 2px;
                width: 1.14285em; // equals `@size-input-binary - 4px`
                height: 1.14285em;
                border: @border-width-base @border-style-base @border-color-transparent;
                border-radius: @border-radius-circle;
            }
        }

        // Apply a dot on the pseudo `:before` element when the input is checked
        &:checked + label::before {
            border-width: @border-width-input-radio--checked;
        }

        &:enabled {
            & + label::before {
                border-color: @border-color-input-binary;
                transition-property: @transition-property-base;
                transition-duration: @transition-duration-base;
            }

            &:hover {
                cursor: @cursor-base--hover;
            }

            &:hover + label::before {
                border-color: @border-color-input-binary--hover;
                cursor: @cursor-base--hover;
            }

            &:active + label::before {
                background-color: @background-color-progressive--active;
                border-color: @border-color-progressive--active;
            }

            &:checked {
                & + label::before {
                    border-color: @border-color-input-binary--checked;
                }

                &:focus + label::after {
                    border-color: @border-color-inverted;
                }

                &:hover + label::before {
                    border-color: @border-color-input-binary--hover;
                }

                &:active {
                    & + label::before {
                        border-color: @border-color-progressive--active;
                        box-shadow: @box-shadow-inset-small @box-shadow-color-progressive--active;
                    }

                    & + label::after {
                        border-color: @border-color-progressive--active;
                    }
                }
            }
        }

        &:disabled {
            & + label::before {
                background-color: @background-color-disabled;
                border-color: @border-color-disabled;
            }

            &:checked + label::before {
                background-color: #fff;
            }
        }
    }
}