7

I am using prefers-color-scheme: dark to create a dark theme in CSS (it applies to Safari in macOS v10.14 (Mojave)). Is there a way to force the page to use my dark mode code on other browsers that don't support it, like the following?

document.querySelector('#toggleDarkMode').addEventListener('click', function () {
    -- Force page to use dark mode defined in CSS
})
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
AWE
  • 64
  • 4
  • 14
  • Possible duplicate of [Detect dark mode using JavaScript](https://stackoverflow.com/questions/56393880/detect-dark-mode-using-javascript) – MattHamer5 Oct 24 '19 at 13:40
  • 4
    Not a duplicate - totally different questions. OP is asking about toggling dark mode using JS in browsers that do not support the `prefers-color-scheme: dark` query while linked question addresses detecting and leveraging the query. – Quangdao Nguyen Oct 24 '19 at 13:44

3 Answers3

9

No.

A workaround is to move every property that changes to a custom property.

Then you can do something like:

p {
    color: var(--body-colour);
}

And combine it with:

/* default, light scheme */
body {
    --body-colour: black;
}

@media (prefers-color-scheme: dark) {
    body {
        --body-colour: white;
    }
}

body.light-mode {
    --body-colour: black;
}

body.dark-mode {
    --body-colour: white;
}

Then your JavaScript just needs to add a light-mode or dark-mode class to the body element to force that mode (overriding the default (if the browser doesn't support the feature, or if it is set to light mode) or the dark mode media version).

tom
  • 21,844
  • 6
  • 43
  • 36
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
2

I'm guessing you're using media-queries to know if the browser / OS is set to dark-modus. If older browsers don't understand the media-query they will skip it all together. This is often used to make browser specific 'hacks'.

A way to make it work is to set the sass code outside the query within a general class that you can add to the <body> tag. You can store this preset within localStorage or cookies so it won't reset on a page reset.

About localStorage: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage

I would make the current sass code a mixin so you won't need to declare it a second time and make your code easier to maintain. More info about it: https://sass-lang.com/documentation/at-rules/mixin

Arno Tenkink
  • 1,480
  • 2
  • 9
  • 16
  • I'm no expert on manipulating 'browser settings' with javascript, so i'm not saying it's not possible but I find it highly unlikely. – Arno Tenkink Oct 24 '19 at 14:10
-1

You can use this code

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <title>Dark & Light Mode</title>
    <link rel="stylesheet" href="style.css">
    <style type="text/css">
        @import url("https://fonts.googleapis.com/css?family=Fredoka+One&display=swap");
        html {
            background: var(--backg);
            --btn: #2ab1ce;
            --backg: #fff;
            --colorx: #232323;
            width: 100%;
            height: 100vh;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
        }

        html[data-theme='dartheme'] {
            background: var(--backg);
            --btn: #ea4b3c;
            --backg: #232323;
            --colorx: #fff;
        }

        h1 {
            font-family: 'Fredoka One', cursive;
            font-weight: 300;
            color: var(--colorx);
        }

        h2 {
            font-family: 'Fredoka One', cursive;
            font-weight: 100;
            color: var(--colorx);
        }

        input[type=checkbox] {
            visibility: hidden;
            height: 0;
            width: 0;
        }

        label {
            margin: 0 auto;
            display: flex;
            justify-content: center;
            align-items: center;
            border-radius: 100px;
            position: relative;
            cursor: pointer;
            text-indent: -9999px;
            width: 55px;
            height: 30px;
            background: var(--btn);
        }

        label:after {
            border-radius: 50%;
            position: absolute;
            content: '';
            background: #fff;
            width: 20px;
            height: 20px;
            top: 5px;
            left: 4px;
            transition: ease-in-out 200ms;
        }

        input:checked + label {
            background: #ea4b3c;
        }

        input:checked + label:after {
            left: calc(100% - 5px);
            transform: translateX(-100%);
        }

        html.transition,
        html.transition *,
        html.transition *:before,
        html.transition *:after {
            transition: ease-in-out 200ms !important;
            transition-delay: 0 !important;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Light & Dark Mode</h1>
        <h2>Demo</h2>

        <input class="container_toggle" type="checkbox" id="switch" name="mode">
        <label for="switch">Toggle</label>
    </div>

    <script src="function.js"></script>
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
    <script type="text/javascript">
     var checkbox = document.querySelector('input[name=mode]');

            checkbox.addEventListener('change', function() {
                if(this.checked) {
                    trans()
                    document.documentElement.setAttribute('data-theme', 'dartheme')
                } else {
                    trans()
                    document.documentElement.setAttribute('data-theme', 'lighttheme')
                }
            })

            let trans = () => {
                document.documentElement.classList.add('transition');
                window.setTimeout(() => {
                    document.documentElement.classList.remove('transition');
                }, 1000)
            }
    </script>
</body>
</html>
Piyush Teraiya
  • 739
  • 4
  • 7