Table of Contents
1. Introduction
This short article has been inspired by the author of this interesting and simple but interesting question: How to change CSS through local storage, ssharma21, who wanted to change CSS style through the HTML5 local storage, avoiding the use of any server-side techniques. It would be a simple solution implementing some themes for Web pages. The inquirer wanted to have just two themes: "default" and "high contrast".
Actually, local and session storage, initially introduced for HTML5, became a separate W3C specification: http://en.wikipedia.org/wiki/Web_storage, so we should call it Web storage.
2. How the Solution Works?
First, let's assume the simplest case: there is a set of Web pages, and the styles of each page are defined by a single CSS file common for this page. Each theme can be represented by a separate CSS file, one per theme. It should be apparent to anyone that this scheme could be easily generalized.
Now, we need a procedure for switching the themes at any time. It looks quite trivial, and the only problem would be having the theme switch control only on one page, but this switch should affect all other opening page (using this mechanism) thereafter. Also, we don't want to use any server-side scripting. I guess it, makes the choice of local or session Web storage pretty obvious. I also will be using jQuery library. This Javascript library, being not really essential for the solution, makes all kind of things a snap.
First, let's show how it should look on usage. For illustration, I'll use two HTML files, "index.html" and "second.html", to show the effect of Web storage across Web pages. First file is the sample page illustrating the theme switching with some control. In this case, this is a HTML <select>
element:
<html>
<head>
<title>Here we choose the theme</title>
<script src="../jQuery/jquery-2.1.3.min.js"></script>
<script src="themes.js"></script>
<link type="text/css" rel="StyleSheet" href="default.css" />
</head>
<body>
<p>Choose theme: <select>
<option selected="selected" value="default">Default</option>
<option value="highContrast">High Contrast</option>
</select></p>
<p>Test</p>
<script>
var selectElement = $("select");
selectElement.change(function() {
$("select option:selected").each(function() {
switchTheme($(this).val());
})
});
</script>
<p><a href="second.html">Load the another page to observe application of the chosen theme</a></p>
</body>
</html>
And this is "second.html":
<html>
<head>
<title>Some other page…</title>
<script src="../jQuery/jquery-2.1.3.min.js"></script>
<script src="themes.js"></script>
<link type="text/css" rel="StyleSheet" href="default.css" />
</head>
<body>
<script>switchTheme(null);</script>
<p>Test</p>
</body>
</html>
This are the two "theme" CSS files, very short for simplicity, "default.css" and "highContrast.css":
default.css:
html, body {
font-family: "Verdana", sans-serif;
background-color: wheat;
}
highContrast.css:
body {
font-family: "Verdana", sans-serif;
font-weight: 900;
background-color: white;
}
From the HTML sample, we can see that the CSS file names simply corresponds to the values of the <option>
elements of the <select>
elements; we should switch the CSS file names in response to the change in the selection. The switch is the call to the Javascript function written in the file "themes.js ". This function, switchTheme is to be called with null parameter to pick up the theme name from the Web storage, and with some string representing the theme name (then name of the CSS file to be applied), to put this name in Web storage and cause other Web pages to use this CSS.
3. The Implementation
Now, let's see how it is implemented. This is all the theme switching code, "themes.js":
themeKey = "theme";
function switchTheme(themeName) {
var name = "default";
if (themeName == null) {
var storedName = sessionStorage.getItem(themeKey);
if (storedName != null)
name = storedName;
} else {
name = themeName;
sessionStorage.setItem(themeKey, name);
}
var link = $("link, [type='text/css']");
link.attr("href", name + ".css");
}
I already explained the principle in the previous section: the parameter of the function is checked for null, then the theme name is chosen and used as a base of the CSS file name; in one case, it is taken from the Web storage, or "default" is used (so this "default" name should be in sync with the selected element of the HTML theme switch control); in other case, the Web storage is set with the chosen name.
The iQuery combination (multiple) selector used in assignment to the jQuery wrapper link
is used to exactly match the HTML element <link type="text/css" …>
. Its href attribute is changes correspondently. Please see:
http://api.jquery.com/multiple-selector,
http://api.jquery.com/category/selectors/attribute-selectors,
http://api.jquery.com/attr.
Now, this is the important detail: I've used the Web storage object sessionStorage
mostly for the readers' convenience, to avoid permanent changes to the storage data of the browsers. For the permanent use of some permanently deployed Web site, using the object localStorage
could be more convenient for the users, because then the chosen style would persist, so it will be applied even if the user starts new session from any other URL using this mechanism.
4. Generalizations
It is pretty obvious that this solution can be easily generalized. Suppose we need to have different CSS files for different sub-set of Web pages using the same mechanism. Then the "theme name" (we can add any number of themes) could be used as a prefix (or suffix) to the CSS file names. For example, if we have CSS file names "index.css", "content.css", "toc.css", they can be replaced by sets of files with prefixed names, such as "default.index.css", " default.content.css", " default.toc.css", " highContrast.index.css", " highContrast.content.css", " highContrast.toc.css". It can be done at the cost of quite minor complication to the Javascript code.
Better yet, the set of different CSS files with identical names can be put in separate directories named per theme name, such as: "default/index.css", " default/content.css", " default/toc.css", " highContrast/index.css", " highContrast/content.css", " highContrast/toc.css". In all cases, In all cases, the function switchTheme
will accept two parameters, theme name and basic stylesheet file name, compose relative file name for each theme/stylesheet combination and modify the stylesheet used by every HTML file.
Of course, the site can contain independent classes of Web pages not related with common style, with style switching not affecting each other. To achieve it on the same site, the values of the constant themeKey
should be different.
5. Credits
I am grateful to the CodeProject member ssharma21 for giving me the topic for this article.