How to achieve theme effects on the interface, mainly switching between the day and night color schemes of the web page
I recorded several ways
CSS variables
It can be used, but my experience is not very good. The value will be displayed in the label style
attribute.
body {
--size: 100px;
--time: 500ms;
--color1: #fff;
--color2: #000;
margin: 0;
width: 100vw;
height: 100vh;
background: var(--color1);
transition: background var(--time);
}
div {
width: var(--size);
height: var(--size);
color: var(--color1);
background: var(--color2);
transition: background var(--time);
}
<div>
文本
</div>
<script>
const div = document.querySelector("div")
const style = document.body.style
div.onclick = (() => {
let isDark = false
return () => {
if (isDark) {
style.setProperty("--color1", "#fff");
style.setProperty("--color2", "#000");
} else {
style.setProperty("--color1", "#000");
style.setProperty("--color2", "#fff");
}
isDark = !isDark
}
})()
</script>
dynamic writing
When writing this paragraph, I was looking for
@keyframes
a way to dynamically modify using JavaScript, and I got a solution
Get the tag and modify the content directly
<style id="root">
:root {
--size: 300px;
--color1: #000;
--color2: #990;
--color3: #090;
--color4: #099;
}
</style>
<style>
div {
width: var(--size);
height: var(--size);
background: var(--color1);
animation: play 5s infinite;
}
@keyframes play {
0% {
background: var(--color1);
transform: translate(0, 0);
}
25% {
background: var(--color2);
transform: translate(var(--size), 0);
}
50% {
background: var(--color3);
transform: translate(var(--size), var(--size));
}
75% {
background: var(--color4);
transform: translate(0, var(--size));
}
100% {
background: var(--color1);
transform: translate(0, 0);
}
}
</style>
<input type="number">
<button>
修改 size
</button>
<div></div>
<script>
const btn = document.querySelector("button")
const input = document.querySelector("input")
const style = document.querySelector("#root")
btn.onclick = () => {
style.innerText = `
:root {
--size: ${
input.value}px;
--color1: #000;
--color2: #990;
--color3: #090;
--color4: #099;
}
`
}
</script>
CSS variables were used, and a problem was discovered: --size
after the change, div
the size changed accordingly, but @keyframes
the rhythm did not change, and it still moved at a distance of 300
This also means that @keyframes
it is fixed at the moment of definition and will not track changes in variables and change accordingly.
Of course, there is no problem with responsive animations. When triggered, the latest variable value will be obtained.
@media (min-width: 500px) {
:root {
--size: 100px;
--color1: #000;
--color2: #990;
--color3: #090;
--color4: #099;
}
@keyframes play {
0% {
background: var(--color1);
transform: translate(0, 0);
}
25% {
background: var(--color2);
transform: translate(calc(var(--size) / 3), 0);
}
50% {
background: var(--color3);
transform: translate(calc(var(--size) / 3), calc(var(--size) / 3));
}
75% {
background: var(--color4);
transform: translate(0, calc(var(--size) / 3));
}
100% {
background: var(--color1);
transform: translate(0, 0);
}
}
}
@media (min-width: 800px) {
:root {
--size: 300px;
--color1: #000;
--color2: #990;
--color3: #090;
--color4: #099;
}
@keyframes play {
0% {
background: var(--color1);
transform: translate(0, 0);
}
25% {
background: var(--color2);
transform: translate(var(--size), 0);
}
50% {
background: var(--color3);
transform: translate(var(--size), var(--size));
}
75% {
background: var(--color4);
transform: translate(0, var(--size));
}
100% {
background: var(--color1);
transform: translate(0, 0);
}
}
}
However, this cannot be used for dynamic insertion. You need to manually trigger responsive refresh. If you want a good experience, you need to rewrite the variables together @keyframes
with
The JavaScript part is omitted and only the fixed part is added at the end
@keyframes
:root {
--size: 300px;
--color1: #000;
--color2: #990;
--color3: #090;
--color4: #099;
}
@keyframes play {
0% {
background: var(--color1);
transform: translate(0, 0);
}
25% {
background: var(--color2);
transform: translate(var(--size), 0);
}
50% {
background: var(--color3);
transform: translate(var(--size), var(--size));
}
75% {
background: var(--color4);
transform: translate(0, var(--size));
}
100% {
background: var(--color1);
transform: translate(0, 0);
}
}
Dynamic tags
Write the CSS file in advance, insert it into the HTML when triggered, and use overlay to achieve the effect
:root {
--bg-color: #fff;
--text-color: #000;
}
body {
margin: 0;
width: 100vw;
height: 100vh;
font-size: 5em;
text-align: center;
color: var(--text-color);
background: var(--bg-color);
}
body::before {
content: 'light';
}
/* dark.css */
:root {
--bg-color: #000;
--text-color: #fff;
}
body::before {
content: 'dark';
}
document.body.onclick = (() => {
let isDark = false
return () => {
if (isDark) {
const link = document.querySelector("#darkTheme")
link.remove()
} else {
const link = document.createElement('link')
link.id = "darkTheme"
link.rel = "stylesheet"
link.href = "./css/dark.css"
document.head.append(link)
}
isDark = !isDark
}
})()
This method is very simple, not violent, and is also recommended.
summary
It can be seen that the existence of CSS variables omits many things. Before there are variables, if you want to implement the third solution, you need to rewrite the entire
Dynamicity can be achieved using the CSS-in-JS solution @keyframes
, but we have not yet studied how to implement it. Is there a better solution than brute force writing