Mastering Theme Switching: 8 Proven Methods to Implement Dark/Light Modes in Web Apps
This article explores eight practical techniques for implementing theme switching in web applications—including class toggling, stylesheet swapping, CSS variables, alternate rel links, Less modifyVars, Ant Design/Vant custom themes, Element‑UI dynamic theming, and JSS—detailing code snippets, advantages, and limitations of each approach.
Theme switching can be achieved in many ways; choose the solution that best fits your project.
1. Switch styles via class
CSS:
<code>body {
background: #000000;
}
body.theme-light {
background: #000000;
}
body.theme-dark {
background: #ffffff;
}</code>HTML:
<code><html class="theme-light">
<body>
theme
</body>
</html></code>JS:
<code>document.documentElement.className = 'theme-dark';</code>Note: Large stylesheet files can be hard to maintain.
2. Prepare multiple stylesheets and change link href via JS
CSS files:
<code>// theme-light.css
body { background: #000000; }
// theme-dark.css
body { background: #ffffff; }</code>HTML:
<code><link id="theme" href="theme-light.css" rel="stylesheet" type="text/css"></code>JS:
<code>document.getElementById('theme').href = 'theme-dark.css';</code>Drawback: Requires maintaining multiple stylesheets and may cause a delay when switching.
3. Use CSS variables for theming
Define variables in theme files:
<code>// theme/light.css
:root {
--bg-color: #000000;
--text-color: #ffffff;
}
// theme/dark.css
:root {
--bg-color: #ffffff;
--text-color: #000000;
}</code>HTML:
<code><html lang="en">
<head>
<link id="theme" rel="stylesheet" type="text/css" href="css/theme/light.css">
</head>
<body>
<div id="app"></div>
</body>
</html></code>Use variables in components:
<code>.content {
color: var(--text-color, #000000);
background-color: var(--bg-color, #ffffff);
}</code>JS handler:
<code>onThemeChange(name) {
document.getElementById('theme').setAttribute('href', `css/theme/${name}.css`);
}</code>In production, consider using
css-vars-ponyfillfor compatibility.
4. Alternate stylesheet via rel attribute
<code><link href="theme-light.css" rel="stylesheet" type="text/css" title="light">
<link href="theme-dark.css" rel="alternate stylesheet" type="text/css" title="dark"></code>Firefox supports switching through the UI. For other browsers, toggle the
disabledattribute:
<code><link href="theme-light.css" rel="stylesheet" type="text/css" title="light" disabled>
<link href="theme-dark.css" rel="alternate stylesheet" type="text/css" title="dark"></code>5. Browser‑side Less modifyVars method
Include Less and configuration in
<head>:
<code><link rel="stylesheet/less" type="text/css" href="styles.less" />
<script>
less = {
env: "development",
async: false,
fileAsync: false,
poll: 1000,
functions: {},
dumpLineNumbers: "comments",
relativeUrls: false,
rootpath: ":/a.com/"
};
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/less.js/3.11.1/less.min.js"></script></code>Theme change handler:
<code>onThemeChange (color) {
less.modifyVars({
'@primary-color': color
})
.then(() => {
console.log(`修改主题 ${color} 成功`);
});
};</code>Suitable for development environments or user‑customizable themes; production should use pre‑compiled CSS.
6. Ant Design / Vant theme customization (Less)
Define global variables:
<code>@primary-color: #1890ff; // main color
@success-color: #52c41a; // success
@warning-color: #faad14; // warning
@error-color: #f5222d; // error</code>Override via
modifyVarsin
vue.config.js(Less loader 6):
<code>module.exports = {
css: {
loaderOptions: {
less: {
lessOptions: {
modifyVars: {
'primary-color': '#40A9FF',
'success-color': '#56d41a',
'warning-color': '#fabd14',
'error-color': '#f6232d'
},
javascriptEnabled: true,
},
},
},
},
};</code>7. Element‑UI dynamic theming
Define color formulas (formula.json):
<code>{
"shade-1": "color(primary shade(10%))",
"light-1": "color(primary tint(10%))",
"light-2": "color(primary tint(20%))",
"light-3": "color(primary tint(30%))",
"light-4": "color(primary tint(40%))",
"light-5": "color(primary tint(50%))",
"light-6": "color(primary tint(60%))",
"light-7": "color(primary tint(70%))",
"light-8": "color(primary tint(80%))",
"light-9": "color(primary tint(90%))"
}</code>Map original colors to variable names:
<code>const colorMap = {
'#409eff': 'primary',
'#3a8ee6': 'shade-1',
'#53a8ff': 'light-1',
'#66b1ff': 'light-2',
'#79bbff': 'light-3',
'#8cc5ff': 'light-4',
'#a0cfff': 'light-5',
'#b3d8ff': 'light-6',
'#c6e2ff': 'light-7',
'#d9ecff': 'light-8',
'#ecf5ff': 'light-9'
};</code>After loading the full Element‑UI CSS, replace all color literals with the variable names to obtain
originalStyle. When a user selects a theme color (e.g.,
#24BA9C), generate a palette:
<code>this.colors = {
primary: "#24BA9C",
shade-1: "rgb(32, 167, 140)",
light-1: "rgb(58, 193, 166)",
light-2: "rgb(80, 200, 176)",
light-3: "rgb(102, 207, 186)",
light-4: "rgb(124, 214, 196)",
light-5: "rgb(146, 221, 206)",
light-6: "rgb(167, 227, 215)",
light-7: "rgb(189, 234, 225)",
light-8: "rgb(211, 241, 235)",
light-9: "rgb(233, 248, 245)"
};</code>Replace variables in the style template and update the
<style>tag:
<code>let cssText = this.originalStyle;
Object.keys(this.colors).forEach(key => {
cssText = cssText.replace(new RegExp('(:|\s+)' + key, 'g'), '$1' + this.colors[key]);
});
// ...
document.head.lastChild.innerText = cssText;</code>8. JSS dynamic theming (React)
<code>import React from "react";
import { render } from "react-dom";
import { createUseStyles, ThemeProvider, useTheme } from "react-jss";
const useStyles = createUseStyles({
wrapper: {
padding: 40,
background: ({ theme }) => theme.background,
textAlign: "left"
},
title: {
font: {
size: 40,
weight: 900
},
color: ({ theme }) => theme.color
},
link: {
color: ({ theme }) => theme.color,
"&:hover": {
opacity: 0.5
}
}
});
const Comp = () => {
const theme = useTheme();
const classes = useStyles({ theme });
return (
<div className={classes.wrapper}>
<h1 className={classes.title}>Hello React-JSS!</h1>
<a className={classes.link} href="http://cssinjs.org/react-jss" target="_blank">See docs</a>
</div>
);
};
const theme = {
background: "#f7df1e",
color: "#24292e"
};
const App = () => (
<ThemeProvider theme={theme}>
<Comp />
</ThemeProvider>
);
render(<App />, document.getElementById("root"));</code>Related Links
Alternative style sheets: https://developer.mozilla.org/enUS/docs/Web/CSS/Alternative_style_sheets
Ant Design Vue custom theme: https://www.antdv.com/docs/vue/customize-theme-cn/
Vant custom theme: https://youzan.github.io/vant/#/zh-CN/theme#jie-shao
Element‑UI theme preview: https://github.com/ElementUI/theme-chalk-preview
Xueersi 1-on-1 Technology Team
Official account of the Xueersi 1-on-1 Technology Team
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.