I am new to Vue.
I made a change of theme from dark to light and back. I use Pinia (currentThemeStore). Now the color of the body background changes by the function so:
//currentThemeStore.ColorForBodyBackground returns string - 'white' or 'black'
document.body.style.backgroundColor = currentThemeStore.ColorForBodyBackground;
Meanwhile, in components the styles change differently, like this:
<div :class="$style[currentThemeStore.SomeStyle]">Some text</div>
//currentThemeStore.SomeStyle returns string - 'some_style_dark' or 'some_style_light'
<style lang="scss" module>
.some_style_dark {
//...
}
.some_style_light {
//...
}
</style>
Question: Is there a better way to dynamically change the body background color without
document.body.style.backgroundColor = currentThemeStore.ColorForBodyBackground;
I've been racking my brains and have no solution. Which solution is the best?
To answer your question: no, there is no better way to change body
's background color. That's the way to do it. Arguably, applying a class might be seen by some as superior, but it has the drawback of having to deal with CSS specificity and sometimes might fail, which is not the case with the method you're using.
However, the vast majority of experienced web developers would agree that's not the right thing to do in your situation. As a general principle, your app
should not interfere with body
— if at all possible (some things can't be achieved without it) –, and should even be able to function in a context where document
and/or body
are not defined (useful is testing, or when mounting the app in an <iframe />
or other similar contexts/viewports, etc...)
Therefore, you might want the #app
element to perform the same function as the body
performs, visually. And by that I mean, make sure it occupies the full size of the current viewport:
body { margin: 0; }
#app {
height: 100vh;
width: 100vw;
overflow: auto;
}
Now you can safely apply dynamic classes and/or styles to the #app
element and, most importantly, the background color of what the user percieves as <body />
can be data driven and set without any form of direct DOM manipulation, which is the recommended way of using Vue.
The main difference between your solution and what I'm suggesting is that your solution errors (and stops execution, breaking the app) when rendered in a context without a <body />
element whereas mine doesn't. Coding without relying on document
and body
is considered good practice when developing with Vue.