简体   繁体   中英

How can I change color scheme when checkbox is checked?

I am trying to implement dark and light mode for my website. It should be loaded based on prefers-color-scheme and than user should be able to toggle between these two mods.

I have written this:

<div id="theme-togle">
    <input id="theme-toggle-dark" type="checkbox" />
    <span id="checkmark-dark"></span>
    <input id="theme-toggle-light" type="checkbox" />
    <span id="checkmark-light"></span>
</div>
@mixin dark-theme {
    --body-color:           #313131;
    --text-color:           #FFFFFF;
    --title-color:          #000000;
    --subtitle-color:       #808080;
    --logo-color:           #FFFFFF;
    --link-color:           #FFFFFF;
    --link-visited-color:   #FFFFFF;
    --quote-color:          #FFFFFF;
    --code-background-color:#787878;
    --text-highlight-color: #D3D3D3;
    --separator-color:      #525252;
}


@mixin light-theme {
    --body-color:           #313131;
    --text-color:           #FFFFFF;
    --title-color:          #000000;
    --subtitle-color:       #808080;
    --logo-color:           #FFFFFF;
    --link-color:           #FFFFFF;
    --link-visited-color:   #FFFFFF;
    --quote-color:          #FFFFFF;
    --code-background-color:#787878;
    --text-highlight-color: #D3D3D3;
    --separator-color:      #525252;
}

:root{
    @include light-theme;
}


#theme-toggle-dark {
    display: none;
}

@media (prefers-color-scheme: dark){
    @include dark-theme;

    #theme-toggle-light {
        display: none;
    }

    #theme-toggle-dark {
        display: block;
    }
}

@media (prefers-color-scheme: light){
    :root{
        @include light-theme;
    }

    .theme-toggle-dark {
        display: none;
    }

    .theme-toggle-light {
        display: block;
    }
}

#theme-toggle-dark:checked + :root{
    @include dark-theme;
}

#theme-toggle-light:checked + :root{
    @include light-theme;
}

It can successfully select default mode based on prefers-color-scheme , but I am not able to make it toggle with checkbox.

How Can I achieve that ? I am looking for javascript free solution.

Thank you for help

You will need to reorganize your HTML in order to get it to work.

Currently, you have the checkboxes as a child node of the body element, which is inside the :root element. That causes your selector to fail because you are using the direct sibling syntax. You won't be able to use :root either.

In order for it to work, your checkbox will need to be the first child inside the body element and then you'd need to apply selectors to everything else.

<body>
    <input id="theme-toggle-dark" type="checkbox" />
    <span id="checkmark-dark"></span>
    <input id="theme-toggle-light" type="checkbox" />
    <span id="checkmark-light"></span>

    ...
</body>
#theme-toggle-dark:checked ~ * {
    @include dark-theme;
}

#theme-toggle-light:checked ~ * {
    @include light-theme;
}

That said, this is not really an ideal solution, because re-painting all nodes with the asterisk selector can be relatively taxing depending on the amount of content in your page.

It may be best to wrap all of your content in one container element and only do the application to that:

<body>
    <input id="theme-toggle-dark" type="checkbox" />
    <span id="checkmark-dark"></span>
    <input id="theme-toggle-light" type="checkbox" />
    <span id="checkmark-light"></span>

    <div id="container">
       ...
    </div>
</body>
#theme-toggle-dark:checked ~ #container {
    @include dark-theme;
}

#theme-toggle-light:checked ~ #container {
    @include light-theme;
}

Also, you probably want to use a radio input instead of a checkbox. It wouldn't make sense to have both items selected.

Alternatively, you might consider only using one checkbox as a toggle switch. This way you don't have to keep track of the default user preference state (which would have to be done via JavaScript).

Here is an example of how it might work:

<body>
    <input id="theme-toggle" type="checkbox" />
    <span id="checkmark-theme"></span>

    <div id="container">
       ...
    </div>
</body>
@media (prefers-color-scheme: dark) {
   #container {
       @include dark-theme;
   }

   #theme-toggle:checked ~ #container {
       @include light-theme;
   }
}

@media (prefers-color-scheme: light) {
   #container {
       @include light-theme;
   }

   #theme-toggle:checked ~ #container {
       @include dark-theme;
   }
}

Here is a working example. Note: you'll need to do some clever sizing and positioning in order to get everything lined up. You'll probably need to replicate some of styling for the toggle label as well.

 @media (prefers-color-scheme: dark) { #container { background: black; color: white; } #toggle:checked ~ #container { background: white; color: black; } } @media (prefers-color-scheme: light) { #container { background: white; color: black; } #toggle:checked ~ #container { background: black; color: white; } }
 <input id="toggle" type="checkbox" /> <label for="toggle">Toggle Theme</label> <div id="container"> <p>Test</p> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM