diff --git a/scss/_buttons.scss b/scss/_buttons.scss index 265f35776dab44b8187b222a37582262c00bfec1..c30ce2185c0d43af3dec2cab31b39c0e73e9c423 100644 --- a/scss/_buttons.scss +++ b/scss/_buttons.scss @@ -37,16 +37,15 @@ outline: 0; @include box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); } +} - &.disabled, - &:disabled, - fieldset[disabled] & { - cursor: $cursor-disabled; - opacity: .65; - @include box-shadow(none); - } +@include form-state-disabled('.btn') { + cursor: $cursor-disabled; + opacity: .65; + @include box-shadow(none); } + // Future-proof disabling of clicks on `<a>` elements a.btn.disabled, fieldset[disabled] a.btn { @@ -58,44 +57,20 @@ fieldset[disabled] a.btn { // Alternate buttons // -.btn-primary { - @include button-variant($btn-primary-color, $btn-primary-bg, $btn-primary-border); -} -.btn-secondary { - @include button-variant($btn-secondary-color, $btn-secondary-bg, $btn-secondary-border); -} -.btn-info { - @include button-variant($btn-info-color, $btn-info-bg, $btn-info-border); -} -.btn-success { - @include button-variant($btn-success-color, $btn-success-bg, $btn-success-border); -} -.btn-warning { - @include button-variant($btn-warning-color, $btn-warning-bg, $btn-warning-border); -} -.btn-danger { - @include button-variant($btn-danger-color, $btn-danger-bg, $btn-danger-border); -} +@include button-variant('.btn-primary', $btn-primary-color, $btn-primary-bg, $btn-primary-border); +@include button-variant('.btn-secondary', $btn-secondary-color, $btn-secondary-bg, $btn-secondary-border); +@include button-variant('.btn-info', $btn-info-color, $btn-info-bg, $btn-info-border); +@include button-variant('.btn-success', $btn-success-color, $btn-success-bg, $btn-success-border); +@include button-variant('.btn-warning', $btn-warning-color, $btn-warning-bg, $btn-warning-border); +@include button-variant('.btn-danger', $btn-danger-color, $btn-danger-bg, $btn-danger-border); // Remove all backgrounds -.btn-primary-outline { - @include button-outline-variant($btn-primary-bg); -} -.btn-secondary-outline { - @include button-outline-variant($btn-secondary-border); -} -.btn-info-outline { - @include button-outline-variant($btn-info-bg); -} -.btn-success-outline { - @include button-outline-variant($btn-success-bg); -} -.btn-warning-outline { - @include button-outline-variant($btn-warning-bg); -} -.btn-danger-outline { - @include button-outline-variant($btn-danger-bg); -} +@include button-outline-variant('.btn-primary-outline', $btn-primary-bg); +@include button-outline-variant('.btn-secondary-outline', $btn-secondary-border); +@include button-outline-variant('.btn-info-outline', $btn-info-bg); +@include button-outline-variant('.btn-success-outline', $btn-success-bg); +@include button-outline-variant('.btn-warning-outline', $btn-warning-bg); +@include button-outline-variant('.btn-danger-outline', $btn-danger-bg); // @@ -110,9 +85,7 @@ fieldset[disabled] a.btn { &, &:active, - &.active, - &:disabled, - fieldset[disabled] & { + &.active { background-color: transparent; @include box-shadow(none); } @@ -129,16 +102,14 @@ fieldset[disabled] a.btn { text-decoration: $link-hover-decoration; background-color: transparent; } - &:disabled, - fieldset[disabled] & { - @include hover-focus { - color: $btn-link-disabled-color; - text-decoration: none; - } +} +@include form-state-disabled('.btn-link') { + @include hover-focus { + color: $btn-link-disabled-color; + text-decoration: none; } } - // // Button Sizes // diff --git a/scss/_forms.scss b/scss/_forms.scss index 72ec9b03f99800d33ba4469e1fef0c95f289701f..7922bf59097e5513c97a5fbca0bdf2e55be245ae 100644 --- a/scss/_forms.scss +++ b/scss/_forms.scss @@ -44,25 +44,22 @@ opacity: 1; } - // Disabled and read-only inputs - // - // HTML5 says that controls under a fieldset > legend:first-child won't be - // disabled if the fieldset is disabled. Due to implementation difficulty, we - // don't honor that edge case; we style them as disabled anyway. - &:disabled, - &[readonly], - fieldset[disabled] & { - background-color: $input-bg-disabled; - // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655. - opacity: 1; - } +} - &[disabled], - fieldset[disabled] & { - cursor: $cursor-disabled; - } +// Disabled and read-only inputs +// +// HTML5 says that controls under a fieldset > legend:first-child won't be +// disabled if the fieldset is disabled. Due to implementation difficulty, we +// don't honor that edge case; we style them as disabled anyway. +@include form-state-disabled('.form-control', $modifiers: ':disabled, [readonly]') { + background-color: $input-bg-disabled; + // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655. + opacity: 1; } +@include form-state-disabled('.form-control') { + cursor: $cursor-disabled; +} // Make file inputs better match text inputs by forcing them to new lines. .form-control-file, @@ -230,30 +227,17 @@ // Some special care is needed because <label>s don't inherit their parent's `cursor`. // // Note: Neither radios nor checkboxes can be readonly. -input[type="radio"], -input[type="checkbox"] { - &:disabled, - &.disabled, - fieldset[disabled] & { - cursor: $cursor-disabled; - } +@include form-state-disabled('input[type="radio"], input[type="checkbox"]') { + cursor: $cursor-disabled; } // These classes are used directly on <label>s -.radio-inline, -.checkbox-inline { - &.disabled, - fieldset[disabled] & { - cursor: $cursor-disabled; - } +@include form-state-disabled('.radio-inline, .checkbox-inline') { + cursor: $cursor-disabled; } // These classes are used on elements with <label> descendants -.radio, -.checkbox { - &.disabled, - fieldset[disabled] & { - label { - cursor: $cursor-disabled; - } +@include form-state-disabled('.radio, .checkbox') { + label { + cursor: $cursor-disabled; } } diff --git a/scss/_labels.scss b/scss/_labels.scss index 403504b864f1e9d6b179ec645b9b7b1e3902bcb9..400b8b2a6c669b1d46b998a2babe192c3a325211 100644 --- a/scss/_labels.scss +++ b/scss/_labels.scss @@ -19,12 +19,12 @@ &:empty { display: none; } +} - // Quick fix for labels in buttons - .btn & { - position: relative; - top: -1px; - } +// Quick fix for labels in buttons +.btn .label { + position: relative; + top: -1px; } // Add hover effects, but only for links diff --git a/scss/mixins/_buttons.scss b/scss/mixins/_buttons.scss index c64f0e8f787bc9765873aca53a691e18c6ac0510..37bc8c0f7544d9cd520d361564d7088bc78ce320 100644 --- a/scss/mixins/_buttons.scss +++ b/scss/mixins/_buttons.scss @@ -3,86 +3,84 @@ // Easily pump out default styles, as well as :hover, :focus, :active, // and disabled options for all buttons -@mixin button-variant($color, $background, $border) { - $active-background: darken($background, 10%); - $active-border: darken($border, 12%); +@mixin button-variant($selector, $color, $background, $border) { + #{$selector} { + $active-background: darken($background, 10%); + $active-border: darken($border, 12%); - color: $color; - background-color: $background; - border-color: $border; - @include box-shadow(inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075)); - - @include hover { - color: $color; - background-color: $active-background; - border-color: $active-border; - } - - &:focus, - &.focus { color: $color; - background-color: $active-background; - border-color: $active-border; - } + background-color: $background; + border-color: $border; + @include box-shadow(inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075)); - &:active, - &.active, - .open > &.dropdown-toggle { - color: $color; - background-color: $active-background; - border-color: $active-border; - // Remove the gradient for the pressed/active state - background-image: none; - @include box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); + @include hover { + color: $color; + background-color: $active-background; + border-color: $active-border; + } - &:hover, &:focus, &.focus { color: $color; - background-color: darken($background, 17%); - border-color: darken($border, 25%); + background-color: $active-background; + border-color: $active-border; } - } - &.disabled, - &:disabled, - fieldset[disabled] & { + &:active, + &.active, + .open > &.dropdown-toggle { + color: $color; + background-color: $active-background; + border-color: $active-border; + // Remove the gradient for the pressed/active state + background-image: none; + @include box-shadow(inset 0 3px 5px rgba(0, 0, 0, .125)); + + &:hover, + &:focus, + &.focus { + color: $color; + background-color: darken($background, 17%); + border-color: darken($border, 25%); + } + } + } + @include form-state-disabled($selector) { &:focus, &.focus { background-color: $background; - border-color: $border; + border-color: $border; } @include hover { background-color: $background; - border-color: $border; + border-color: $border; } } } -@mixin button-outline-variant($color) { - color: $color; - background-image: none; - background-color: transparent; - border-color: $color; +@mixin button-outline-variant($selector, $color) { + #{$selector} { + color: $color; + background-image: none; + background-color: transparent; + border-color: $color; - &:focus, - &.focus, - &:active, - &.active, - .open > &.dropdown-toggle { - color: #fff; - background-color: $color; - border-color: $color; - } - @include hover { - color: #fff; - background-color: $color; - border-color: $color; + &:focus, + &.focus, + &:active, + &.active, + .open > &.dropdown-toggle { + color: #fff; + background-color: $color; + border-color: $color; + } + @include hover { + color: #fff; + background-color: $color; + border-color: $color; + } } - - &.disabled, - &:disabled, - fieldset[disabled] & { + @include form-state-disabled($selector) { &:focus, &.focus { border-color: lighten($color, 20%); diff --git a/scss/mixins/_forms.scss b/scss/mixins/_forms.scss index 764c5e08350d19275c46d720b8dd41ad952b0e62..3aace2f352ee0466acd01551da265e22fa5d5378 100644 --- a/scss/mixins/_forms.scss +++ b/scss/mixins/_forms.scss @@ -87,3 +87,31 @@ height: auto; } } + +// Applies the content to the disabled state of the selector. +// +// For example: +// +// @include form-state-disabled('.btn') { +// color: #111 +// } +// +// Compiles to: +// +// .btn.disabled, +// .btn:disabled, +// fieldset[disabled] .btn { +// color: #111; +// } +// +// This avoids issues with using the parent selector suffix, as in `fieldset[disabled] &`. +// See https://github.com/sass/sass/issues/1817. +@mixin form-state-disabled($selector, $modifiers: ':disabled, .disabled') { + #{selector-unify($selector, $modifiers), selector-nest('fieldset[disabled]', $selector)} { + @content; + } +} + +@include form-state-disabled('button') { + color: red; +}