Reputation: 261
I am trying to implement more elegant elements in my site using Javascript
.
Snippet
<script>
function nightmode(){
var el = document.getElementById('myStyles'); // get stylesheet
if ( el !== null ) { // if it exists
el.parentNode.removeChild(el); // remove it
} else { // if not, add it
var oLink = document.createElement("link")
oLink.id = 'myStyles';
oLink.href = "nightmode3.css";
oLink.rel = "stylesheet";
oLink.type = "text/css";
document.body.appendChild(oLink);
}
}
</script>
That switches the site to nightmode. If you click the button, it switches nightmode on, or off. Simple enough.
However, I'd like a .5 second fadein/fadeout effect on each click, to make it less jarring. I've tried adding it via CSS, but that only works for fade in. How can I get both fade in and fade out effects?
Upvotes: 3
Views: 254
Reputation: 26909
Here are a few different ways to keep transitions working whenever you switch between styles. The underlying thing to keep in mind is that you have to have a transition rule available for the transition to happen. If you have it in one style but not the other, it will only happen whenever you change to the style that has it because otherwise there is no rule saying that there needs to be a transition.
<link>
Swapping MethodBasically, make sure that the transition rules are always available. If they are in your night/day stylesheet but not other, then there is no longer a rule to transition. That's why it would only work whenever you fade in.
Ideally though, you would probably want both sets of rules in a single file and then change between the active styles using a class on the <body>
tag. However, there are certainly use cases where you might want to still use two separate stylesheets that aren't both loaded simultaneously. For example a high contrast stylesheet that might not be used by all users would waste memory. However, I'd still probably use the class attribute on the <body>
tag in case I ever wanted to combine them.
index.html
<html>
<head>
<title>CSS Test</title>
<link rel="stylesheet" href="base.css">
<script src="index.js"></script>
</head>
<body>
<main>
<h1>Hello!</h1>
<p>I am text</p>
<ul>
<li>
<button id="day_mode">Day</button>
</li>
<li>
<button id="night_mode">Night</button>
</li>
</ul>
</main>
</body>
</html>
index.js
/*jslint browser:true*/
(function () {
"use strict";
function addStylesheet(name, loc) {
var sheet = document.createElement("link");
sheet.id = name;
sheet.href = loc;
sheet.rel = "stylesheet";
sheet.type = "text/css";
document.head.appendChild(sheet);
return sheet;
}
function removeStylesheet(sheet) {
sheet.parentNode.removeChild(sheet);
//document.getElementById(name).removeChild();
}
function go() {
var dayButton = document.getElementById("day_mode"),
nightButton = document.getElementById("night_mode"),
daySheet,
nightSheet;
dayButton.addEventListener("click", function (e) {
e.preventDefault();
if (!daySheet) {
if (nightSheet) {
removeStylesheet(nightSheet);
nightSheet = null;
}
daySheet = addStylesheet("day", "day.css");
}
});
nightButton.addEventListener("click", function (e) {
e.preventDefault();
if (!nightSheet) {
if (daySheet) {
removeStylesheet(daySheet);
daySheet = null;
}
nightSheet = addStylesheet("night", "night.css");
}
});
}
document.addEventListener("DOMContentLoaded", go);
}());
base.css
h1 {
transition: color 1s;
}
p {
transition: background-color 1s, color 1s;
}
day.css
h1 {
color: orange;
}
p {
background-color: yellow;
color: red;
}
night.css
h1 {
color: blue;
}
p {
background-color: black;
color: blue;
}
<body>
Class NamespacingIf you do want to try the <body>
class method, here is a short implementation showing how to do that.
The basics of this is that you have a namespace for each version, day/night, of the CSS that you want to use and you prefix those mode rules with the relevant namespace.
Then, using JavaScript, you would remove or add the namespace class from your <body>
tag using document.body.classList.add()
and document.body.classList.remove()
.
/*jslint browser:true*/
(function() {
"use strict";
function go() {
var dayButton = document.getElementById("day_mode"),
nightButton = document.getElementById("night_mode");
dayButton.addEventListener("click", function(e) {
e.preventDefault();
document.body.classList.remove("night");
document.body.classList.add("day");
});
nightButton.addEventListener("click", function(e) {
e.preventDefault();
document.body.classList.remove("day");
document.body.classList.add("night");
});
}
document.addEventListener("DOMContentLoaded", go);
}());
h1 {
transition: color 1s;
}
p {
transition: background-color 1s, color 1s;
}
body.day h1 {
color: orange;
}
body.day p {
background-color: yellow;
color: red;
}
body.night h1 {
color: blue;
}
body.night p {
background-color: black;
color: blue;
}
<html>
<head>
<title>CSS Test</title>
<link rel="stylesheet" href="index2.css">
<script src="index2.js"></script>
</head>
<body class="day">
<main>
<h1>Hello!</h1>
<p>I am text</p>
<ul>
<li>
<button id="day_mode">Day</button>
</li>
<li>
<button id="night_mode">Night</button>
</li>
</ul>
</main>
</body>
</html>
One other thing to note, is that if you use the <link ... rel="stylesheet alternate" ...>
approach, the transitions will also still work. I'm not sure what browsers still provide a means for users to switch their preferred rendering style manually. Chrome does not provide a way, but FireFox does. See the below screenshot.
Here is the markup I'm using for my <head>
element.
<head>
<title>CSS Test</title>
<link rel="stylesheet" href="base.css">
<link rel="stylesheet" href="day.css" title="Day">
<link rel="stylesheet alternate" href="night.css" title="Night">
<script src="index.js"></script>
</head>
Upvotes: 2