Bootstrap Switch not visible in High Contrast Mode

Viewed 571

Bootstrap 4.6: The switch states are not visible in Windows High Contrast Mode.

Watch in High Contrast Mode:

<div class="custom-control custom-switch">
  <input type="checkbox" class="custom-control-input" id="customSwitch1">
  <label class="custom-control-label" for="customSwitch1">Toggle this switch element</label>
</div>

Here is a simple CodePen

Does anybody know what do do? My priority is MS Edge. All other browsers are not really relevant.

Unfortunately I have to stick with this standard control. Using a 3rd party switch or some other control is not an option.

2 Answers

The colors for the thumb appear to be controlled by the background-color set by .custom-switch .custom-control-input:checked~.custom-control-label::after and .custom-switch .custom-control-label::after, but in hi-contrast mode, those styles don’t seem to have any effect.

What about hiding the Bootstrap control and using the browsers own checkbox input?

<link href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js"></script>

<style>
@media screen and (-ms-high-contrast: active) {
    .custom-control-input {
        position: absolute;
        z-index: 1;
        opacity: 1;
        left: 0.25rem;
        top: 0.25rem;
    }

    .custom-switch .custom-control-label::before, .custom-control-input:checked~.custom-control-label::before, .custom-switch .custom-control-input:checked~.custom-control-label::after, .custom-switch .custom-control-label::after {
        opacity: 0;
    }
}
</style>

<div class="custom-control custom-switch">
        <input type="checkbox" class="custom-control-input" id="customSwitch1">
        <label class="custom-control-label" for="customSwitch1">Toggle this switch element</label>
    </div>

    <ul class="mt-3">
        <li>
            Switch works perfect in normal mode
        </li>
        <li>
            Now turn on Windows High Contrast Mode [Left-Alt]+[Left-Shift]+[Print] -> switch states are not visible any more
        </li>
        <li>
            I already added a media query for "-ms-high-contrast" ... no success
        </li>
    </ul>

The standard checkbox may not be as intuitive as a toggle switch, but if all of the inputs are that way, your users who are using high contrast mode will be expecting the standard checkbox, and so, may not have a problem with them.

Per a blog post on windows.com, when the user is using a high contrast theme, the user agent colors overrides the colors for elements on a page. To disable that override for part of a page, the element needs to be set to forced-color-adjust: none; Then the elements can be restyled.

To check for high contrast mode, the blog post also says to use @media (forced-colors: active), which works on the new version of Edge as well as Chrome on Windows (it does not currently work on Firefox – I do not know about Safari or Chrome on Macs), rather than @media (-ms-high-contrast: active).

To check for a light versus dark theme, the blog post says to use @media (forced-colors: active) and (prefers-color-scheme: light) and @media (forced-colors: active) and (prefers-color-scheme: dark).

According to MDN Web Docs, the browser triggers the appropriate value of prefers-color-scheme, so even if a user is using custom high contrast color palette, the prefers-color-scheme should have the right value.

I’ve included CSS options for both light and dark high contrast color requirements.

<link href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js"></script>

<style>
@media screen and (forced-colors: active) and (prefers-color-scheme: light) {
    .custom-switch .custom-control-label::before,
    .custom-control-input:checked~.custom-control-label::before,
    .custom-switch .custom-control-input:checked~.custom-control-label::after,
    .custom-switch .custom-control-label::after {
        forced-color-adjust: none;
    }

    .custom-control-label::before {
        background-color: #000;
        /* this sets the background fill color for off */
        border: #000 solid 1px;
        /* this sets the border around the switch */
    }

    .custom-switch .custom-control-label::after {
        background-color: #fff;
        /* this sets the color of the thumb for off */
    }

    .custom-control-input:checked~.custom-control-label::before {
        border-color: #000;
        /* this changes the border for on */
        background-color: #fff;
        /* this changes the fill color for on */
    }

    .custom-switch .custom-control-input:checked~.custom-control-label::after {
        background-color: #000;
        /* this sets the color of the thumb for on */
    }

    .custom-control-input:focus~.custom-control-label::before {
        box-shadow: 0 0 0 .2rem rgba(0, 0, 0,.25);
        /* this sets the highlight when the control has focus */
    }
}

@media screen and (forced-colors: active) {
    @media not screen and (prefers-color-scheme: light) {
        .custom-switch .custom-control-label::before,
        .custom-control-input:checked~.custom-control-label::before,
        .custom-switch .custom-control-input:checked~.custom-control-label::after,
        .custom-switch .custom-control-label::after {
            forced-color-adjust: none;
        }

        .custom-control-label::before {
            background-color: #fff;
            /* this sets the background fill color for off */
            border: #fff solid 1px;
            /* this sets the border around the switch */
        }

        .custom-switch .custom-control-label::after {
            background-color: #000;
            /* this sets the color of the thumb for off */
        }

        .custom-control-input:checked~.custom-control-label::before {
            border-color: #fff;
            /* this changes the border for on */
            background-color: #000;
            /* this changes the fill color for on */
        }

        .custom-switch .custom-control-input:checked~.custom-control-label::after {
            background-color: #fff;
            /* this sets the color of the thumb for on */
        }

        .custom-control-input:focus~.custom-control-label::before {
            box-shadow: 0 0 0 .2rem rgba(255, 255, 255,.50);
            /* this sets the highlight when the control has focus */
        }
    }
}
</style>

<div class="custom-control custom-switch">
        <input type="checkbox" class="custom-control-input" id="customSwitch1">
        <label class="custom-control-label" for="customSwitch1">Toggle this switch element</label>
    </div>

    <ul class="mt-3">
        <li>
            Switch works perfect in normal mode
        </li>
        <li>
            Now turn on Windows High Contrast Mode [Left-Alt]+[Left-Shift]+[Print] -> switch states are not visible any more
        </li>
        <li>
            I already added a media query for "-ms-high-contrast" ... no success
        </li>
    </ul>

The second set of styles, for a dark theme, use the not selector as the W3 working draft on Media Queries Level 5 recommends the first query be one value and the second query be not that value, just in case more values get added in the future.

Related