Sidebar collapses for a second and expands on page load - javascript

I have this sidebar which expands or collapses on a button click. Now I've successfully stored it's state in localStorage and it's working fine except there's a slight issue.
When the page loads and there is no state saved in localStorage, the sidebar collapses for a split second and expands. Expand is supposed to be the default state when there is no state stored in localStorage. I don't want it to collapse first and then expand. I just want the page to load with the sidebar expanded.
I have been trying to solve the issue with my own code. But it didn't work then I combined my code with of of SO's posts. It still doesn't work.
Full Code: Codepen
Here's the code(please note that localStorage won't work in SO):
$('document').ready(function() {
if (typeof window.isMinified === "undefined") {
window.isMinified = false;
}
const body = $('#body');
$("#sidebar-toggler").on("click", function () {
if (window.isMinified === false) {
// localStorage.setItem('menu-closed', !$(body).hasClass("sidebar-minified"));
body.removeClass("sidebar-minified-out").addClass("sidebar-minified");
window.isMinified = true;
} else {
// localStorage.setItem('menu-closed', !$(body).hasClass("sidebar-minified"));
body.removeClass("sidebar-minified").addClass("sidebar-minified-out");
window.isMinified = false;
}
});
const state = // localStorage.getItem('menu-closed');
if (state === null) {
$(body).removeClass('sidebar-minified');
} else {
const closed = state === "true" ? true : false;
if (!closed) {
$(body).removeClass('sidebar-minified');
}
}
});
#body {
background: #fff;
transition: all 0.3s;
}
aside.left-sidebar{
background-color: #2c0963;
height: 100vh;
}
.sidebar-minified-out .left-sidebar {
width: 180px;
transition: width .3s ease-in;
}
.sidebar-minified .left-sidebar {
width: 75px;
transition: width .3s ease-in;
}
.sidebar-toggle {
font-weight: 300;
font-size: 15px;
cursor: pointer;
height: 30px;
position: absolute;
left: 20%;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body id="body" class="sidebar-minified sidebar-minified-out">
<aside class="left-sidebar"></aside>
<button id="sidebar-toggler" class="sidebar-toggle">Collapse/Expand</button>
</body>

You can minimize the the flashing effect, by telling the browser to repaint just only one time, in one shot. BUT there will be always one initial size for Your sidebar: the size which has been defined inside Your markup.
In my example, I am using two Observers to track the style and size changes. Please, note the initial sidebar width. You may set the initial sidebar width equal to 0, or let it unassigned, or maybe You can style it the same size as Your expanded sidebar, but there will be always an initial repaint.
Finally, I strongly believe You need to remove the two initial classes from the body.
$(function() {
/* avoid SO unsecure operation error */
var storage = (function () {
return {
setItem: function(k,v){try{return localStorage.setItem(k,v)}catch(e){return !1}},
getItem: function(k){try{return localStorage.getItem(k)}catch(e){return null}}
};
})();
log("jQuery DOM Ready");
$("#sidebar-toggler").on("click", function() {
var isMinified = !$("body").hasClass("sidebar-minified-out");
$("body")
.toggleClass("sidebar-minified", !isMinified)
.toggleClass("sidebar-minified-out", isMinified);
storage.setItem('menu-closed', +!isMinified);
});
var closed = +storage.getItem('menu-closed');
log('Closed: ' + !!closed);
$("body")
.addClass(closed ? "sidebar-minified" : "sidebar-minified-out")
.css({"visibility": "visible"});
});
body {
background: #fff;
transition: all 0.3s;
}
aside.left-sidebar{
background-color: #2c0963;
height: 100vh;
}
.sidebar-minified-out .left-sidebar {
width: 180px;
transition: width .3s ease-in;
}
.sidebar-minified .left-sidebar {
width: 75px;
transition: width .3s ease-in;
}
.sidebar-toggle {
font-weight: 300;
font-size: 15px;
cursor: pointer;
height: 30px;
position: absolute;
left: 20%;
top: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sidebar State</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body style="visibility: hidden;">
<aside class="left-sidebar"></aside>
<button id="sidebar-toggler" class="sidebar-toggle">Collapse/Expand</button>
<div id="log" style="position:absolute;top:0;right:0;padding:1em;"></div>
<script>
/* only debug functions inside this script block */
function log(msg) {
$("<div>").appendTo("#log").text(msg);
}
var mo = new MutationObserver(function (ml){
for(var m of ml) {
if (m.type == 'attributes') log('Body ' + m.attributeName + ' changed');
}
});
mo.observe(document.getElementsByTagName('body')[0], {attributes: true});
var ro = new ResizeObserver(function (rl){
for(var r of rl) {
var w = r.contentRect.width;
if(w<=75 || w>=180) log('Sidebar width: ' + r.contentRect.width);
}
});
ro.observe(document.getElementsByClassName("left-sidebar")[0]);
</script>
</body>
</html>
EDIT:
If You look at the messages logged by the Observers, You will notice that there is always a repaint, as mentioned above.
After reading this solution of Your previous question: Dark mode flickers a white background for a millisecond on reload I believe You can implement Your Sidebar toggler the same way.
Instead of applying the CSS class to the body, You can apply it to the html. Here is the full code:
HTML
<!DOCTYPE html>
<html>
<head>
<script>
/* Render blocking script */
var c = +localStorage.getItem('menu-closed');
document.documentElement.classList.add(c ? 'sidebar-minified' : 'sidebar-minified-out');
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<aside class="left-sidebar"></aside>
<button id="sidebar-toggler" class="sidebar-toggle">Collapse/Expand</button>
</body>
</html>
JS
$(function() {
$("#sidebar-toggler").on("click", function (e) {
var isMinified = !$("html").hasClass("sidebar-minified-out");
$("html")
.toggleClass("sidebar-minified", !isMinified)
.toggleClass("sidebar-minified-out", isMinified);
localStorage.setItem('menu-closed', +!isMinified);
});
});
Your CSS will remain untouched beside of a small change (I just only removed the #body id).
Now, if You compare the Observed changes, You will notice that the second solution, which is using the blocking JS script in head, is showing only the initial Sidebar size, i.e.: the initial repaint is gone:
1st solution 2nd solution
==============================================================
Sidebar width: 601 Closed: false
jQuery DOM Ready Sidebar width: 180
Closed: false jQuery DOM Ready
Body class changed
Body style changed
Sidebar width: 180
(Credits: Roko C. Buljan):
More information:
The debug functions in my first example are used just only to depict the sequence of the resize and restyle events inside the browser.
Here is some documentation about that Observers:
MutationObserver
ResizeObserver

It is the transition from the css that let the sidebar expand. If you remove the transistion you will see that the sidebar ist immediately expanded on page load. So for the first time you should set CSS classes without transitions.

You could disable the transition via Javascript and enable it again for the click event:
jsfiddle demo
First remove the classes in the body tag:
<body id="body" class="">
<aside class="left-sidebar"></aside>
<button id="sidebar-toggler" class="sidebar-toggle">Collapse/Expand</button>
</body>
Just a few lines to change in the javascript:
$('document').ready(function() {
if (typeof window.isMinified === "undefined") {
window.isMinified = false;
}
const body = $('#body');
$("#sidebar-toggler").on("click", function () {
document.querySelector('.left-sidebar').style.transition = 'inherit';
if (window.isMinified === false) {
localStorage.setItem('menu-closed', !body.hasClass('sidebar-minified'));
body.removeClass('sidebar-minified-out').addClass('sidebar-minified');
window.isMinified = true;
} else {
localStorage.setItem('menu-closed', !body.hasClass('sidebar-minified'));
body.removeClass('sidebar-minified').addClass('sidebar-minified-out');
window.isMinified = false;
}
});
const state = localStorage.getItem('menu-closed');
if (state === null) {
body.addClass('sidebar-minified');
} else {
const closed = state === "true" ? true : false;
if (!closed) {
body.addClass('sidebar-minified-out');
document.querySelector('.left-sidebar').style.transition = 'none';
}
else {
body.addClass('sidebar-minified');
}
}
});
The important changes in above code are two things:
// in the clickevent section: change the transistion to default behaviour
document.querySelector('.left-sidebar').style.transition = 'inherit';
Set the right class depending on state and disable transition:
// ...
if (state === null) {
body.addClass('sidebar-minified');
} else {
// ...
if (!closed) {
body.addClass('sidebar-minified-out');
document.querySelector('.left-sidebar').style.transition = 'none';
}
else {
body.addClass('sidebar-minified');
}
}
*** Update ***
I refactored the code and optimized it a bit. fiddle
HTML:
<body id="body">
<aside class="left-sidebar"></aside>
<button id="sidebar-toggler" class="sidebar-toggle">Collapse/Expand</button>
</body>
CSS:
#body {
background: #fff;
transition: all .3s;
}
aside.left-sidebar {
background-color: #2c0963;
height: 100vh;
width: 75px;
}
.sidebar-minified-out .left-sidebar {
width: 180px;
}
.sidebar-transitions .left-sidebar {
transition: width .3s ease-in;
}
.sidebar-toggle {
font-weight: 300;
font-size: 15px;
cursor: pointer;
height: 30px;
position: absolute;
left: 20%;
top: 0;
}
JS:
$('document').ready(function() {
$("#sidebar-toggler").on("click", function () {
localStorage.setItem('menu-closed', $('#body').hasClass('sidebar-minified-out'));
$('#body').addClass('sidebar-transitions').toggleClass('sidebar-minified-out');
});
localStorage.getItem('menu-closed') === "true" ? $('#body').removeClass('sidebar-minified-out') : $('#body').addClass('sidebar-minified-out');
});

How about moving the animation to a separate class lets say
.sidebar-animated{
transition: width: 0.3s ease-in;
}
and removing it from anywhere else and then adding that class via timeout, so it gets added after the transition is done, you can use useTimeout with 0 seconds, like so,
setTimeout(() => {
$('aside').addClass('sidebar-animated')
},0)
Plus CSS uses Specificity to reach its element, so
.sidebar-minified-out .left-sidebar {
width: 180px;
}
.sidebar-minified .left-sidebar {
width: 75px;
}
Should be changed to this.
.sidebar-minified .left-sidebar {
width: 75px;
}
.sidebar-minified-out .left-sidebar {
width: 180px;
}
because when you have both on the same element, it will take the later because they have the same specificity rule, give it a last shot, thats the last resort for me :D.
thats enough to make it work
https://codepen.io/menawer_cpe/pen/qBZbEdw
here is a working example,
Note: you have an issue with managing state when the sidebar collapsed at first, but thats something related to how you deal with the state.
Why useTimeout with 0? because it pushes the execution to what is called "event loop" making sure it executes after all javascript normal code is executed.

You can try this :
$('document').ready(function() {
if (window.isMinified === undefined) {
window.isMinified = false;
}
const body = $('#body');
$("#sidebar-toggler").on("click", function() {
$('#body .left-sidebar').removeAttr("style");
if (window.isMinified === false) {
body.removeClass("sidebar-minified-out").addClass("sidebar-minified");
window.isMinified = true;
} else {
body.removeClass("sidebar-minified").addClass("sidebar-minified-out");
window.isMinified = false;
}
});
var firstTime = true;
var sidebar = $('#body aside.left-sidebar');
const state = !(null); //localStorage.getItem('menu-closed');
if (state === null) {
$(body).removeClass('sidebar-minified');
} else {
if (firstTime) {
sidebar.css('transition', 'none');
firstTime = false;
}
const closed = state === "true" ? true : false;
if (!closed) {
$(body).removeClass('sidebar-minified');
}
}
});
#body {
background: #fff;
transition: all 0.3s;
}
aside.left-sidebar {
background-color: #2c0963;
height: 100vh;
}
.sidebar-minified-out .left-sidebar {
width: 180px;
transition: width .3s ease-in;
}
.sidebar-minified .left-sidebar {
width: 75px;
transition: width .3s ease-in;
}
.sidebar-toggle {
font-weight: 300;
font-size: 15px;
cursor: pointer;
height: 30px;
position: absolute;
left: 20%;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body id="body" class="sidebar-minified sidebar-minified-out">
<aside class="left-sidebar"></aside>
<button id="sidebar-toggler" class="sidebar-toggle">Collapse/Expand</button>
</body>

Related

Vue.js: Play CSS animation on JavaScript event

In my Vue.js app, I have a login form, which I want to shake whenever login attempt fails.
I achieved the desired effect, but I'm not happy with my solution. Here's my simplified code:
const Home = {
data() {
return {
shakeForm: false
}
},
template: `
<div>
<form :class="{'form-shaking': shakeForm}"
#submit.prevent="login"
#animationend="shakeForm = false;"
>
form fields
</form>
</div>
`,
methods: {
async login() {
// ...
const rawResponse = await fetchLogin();
if (!rawResponse.ok) {
this.shakeForm = true;
return;
}
// login ok
}
}
};
.form-shaking {
position: relative;
animation: shake-horizontally .2s ease-out 2;
}
#keyframes shake-horizontally {
from {
left: 0;
}
25% {
left: 25px;
}
75% {
left: -25px;
}
to {
left: 0;
}
}
So basically, I'm playing with the shakeForm boolean property, which adds the form-shaking class to the <form>. Then I remove the class on #animationend event (to be able to play it again).
Is there a dedicated Vue.js feature to handle scenarios like this? I looked up the transition/animation features, but couldn't find anything suitable.
You could always manually edit the styles.animation attribute of the form on the fly, to make it shake, like so:
function shake() {
document.getElementsByClassName('form-shaking')[0].style.animation = 'shake-horizontally .2s ease-out 2';
// stop the animation after the animation ends
window.setTimeout(function() {
document.getElementsByClassName('form-shaking')[0].style.animation = 'unset';
}, 400);
}
(In order for the function to work, the animation must be unset at the time of function call.)
As an example, you could use the following as a demo (driver code):
function shake() {
console.log('Incorrect Login: shaking form...')
document.getElementsByClassName('form-shaking')[0].style.animation = 'shake-horizontally .2s ease-out 2';
// stop the animation after the animation ends
window.setTimeout(function() {
document.getElementsByClassName('form-shaking')[0].style.animation = 'unset';
console.log('Incorrect Login: form shake state reset.')
}, 400);
}
window.setTimeout(shake, 1000)
window.setTimeout(shake, 2000)
window.setTimeout(shake, 3000)
.form-shaking {
position: relative;
/* animation: shake-horizontally .2s ease-out 2; */
}
#keyframes shake-horizontally {
from {
left: 0;
}
25% {
left: 25px;
}
75% {
left: -25px;
}
to {
left: 0;
}
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>CSS Animation on JS Event</title>
</head>
<body>
<div class="form-shaking" style="margin: 32px; display: inline-block; background-color: black; min-width: 100px; min-height: 100px;"> </div>
</body>
</html>

Transition property not working using JavaScript

I am trying to create "Toast" messages in webpages like in Android. I am done with the creation and styling, but the only problem is the transition. I want the toast to fade in and fade out. This is the code I wrote so far :
function show(msg = "Hello") {
var t = document.getElementById("toast");
t.innerHTML = msg;
t.style.display = "flex";
t.style.opacity = 1;
setInterval(function() {
t.style.opacity = 0;
}, 2000);
}
* {
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
padding: 10px;
margin: 0;
}
#toast {
background-color: black;
color: white;
opacity: 0;
border-radius: 0.7em;
position: fixed;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
padding: 10px;
display: none;
text-align: center;
align-items: center;
justify-content: center;
transition: opacity 1s;
}
<html>
<head>
<title>Toast demo</title>
</head>
<body>
<div id="toast"></div>
<button onclick="show('Message')">Show toast</button>
<button onclick="show('Message<br>with<br>multiple<br>lines')">Show toast</button>
</body>
</html>
With this code, at the first instance, the fade-in is not there, and the subsequent ones are shown for a small time interval. Why does this happen and how to fix this behaviour? CSS solution is appreciated and I do not want to use jQuery.
instead of:
function show(msg = "Hello") {
var t = document.getElementById("toast");
t.innerHTML = msg;
t.style.display = "flex";
t.style.opacity = 1;
setInterval(function() {
t.style.opacity = 0;
}, 2000);
}
You can use Vanilla Javascript new .animate() Api, which is more performant than both setInterval & RequestAnimationFrame():
var t = document.getElementById("toast");
t.animate({
filter: ["opacity(1)","opacity(0)"]; // Start & End States of the Animation.
},{
duration: 488, // Duration in Ms
fill: 'forwards', // retains the end State of the animation.
iterations: 1, // Number of iterations or Infinity
delay: 88, // Delay for the Animation Start (2000)
easing: 'ease-in', // Easing Function
// direction:,
// endDelay:,
// iterationStart:,
});
This Also Gives you alot more control than Just pure Css Animations & better matches the browsers refresh/repaint Cycles.
More information can be found here MDN WebAnimation Api
If you want this to work via touch or mouseclick events then you need to add in the appropriate event handlers to deal with this.
https://developer.mozilla.org/en-US/docs/Web/API/Touch_events
You mentioned that the code above is not working, probably because it doesn't have any event listeners attached to is so I've made an update.
HTML::
<html>
<head>
<title>Toast demo</title>
</head>
<body>
<div id="toast"></div>
<button id="ShowMsg">Show toast</button>
<button id="ShowMsg2">Show toast</button>
<script src="LinkToYourJsFile.js">Or Include The Js In Here..</script>
</body>
</html>
JS::
let ShowMsg = document.getElementById("ShowMsg");
let ShowMsg2 = document.getElementById("ShowMsg2");
function showToast(){
var t = document.getElementById("toast");
t.innerHTML='<p>Message you want to display</p>'; // For multiline, just repeat with <br> or Js equivelent \n
t.animate({
filter: ["opacity(0)","opacity(1)"] // Start & End States of the Animation.
},{
duration: 488, // Duration in Ms
fill: 'forwards', // retains the end State of the animation.
iterations: 1, // Number of iterations or Infinity
delay: 88, // Delay for the Animation Start (2000)
easing: 'ease-in', // Easing Function
// direction:,
// endDelay:,
// iterationStart:,
});
}
ShowMsg.addEventListener("mousedown", showToast); // 1) What is the event, 2) name of the function to run when the event occurs
ShowMsg2.addEventListener("mousedown", showToast2StarvinMarvin); // Repeat the same process for toast 2.
** Note that in your Css your t => toast Msg should intially start with filter:opacity(0); and not have display:none; as in your original code. Javascript will over-ride this when the events are fired.
also the Js MUST either be at the bottom of the Html document OR be in an external file linked at the bottom of the Html. or alternatively wrapped inside of
document.addEventListener("DOMContentLoaded", (function(){
// Your Anime code & variables etc goes here;
}));
To fade the element out repeat but change the event listener to "mouseleave" and switch the opacity value in .animate() function around. So 0 = 1, 1 = 0;
I'm still learning this stuff myself so see if you can read some of the documentaion on Mozilla Developer Network & here on Stack Overflow to get it working how you would like..
Hope this helps.
I came up with a complete idea which can show as well as disappear the toast after a specified time and also, it works very smoothly even if the toast is invoked when it is already displaying. Here is my code:
var t = document.getElementById("toast");
var showing = false;
var timeout1, timeout2;
function showToast(msg = "") {
clearTimeout(timeout1);
clearTimeout(timeout2);
t.innerHTML = msg;
if (!showing) {
showing = true;
t.style.display = "flex";
t.animate({
opacity: ["0", "1"]
}, {
duration: 1000,
iterations: 1,
fill: "forwards"
});
}
timeout1 = setTimeout(() => {
showing = false;
t.animate({
opacity: ["1", "0"]
}, {
duration: 1000,
iterations: 1,
fill: "forwards"
});
}, 3000);
timeout2 = setTimeout(() => {
t.style.display = "none";
}, 4000);
}
* {
box-sizing: border-box;
}
#toast {
background-color: black;
color: white;
border-radius: 0.7em;
position: fixed;
left: 50%;
top: 50%;
opacity: 0;
display: none;
transform: translateX(-50%) translateY(-50%);
padding: 10px;
text-align: center;
align-items: center;
justify-content: center;
}
button {
width: 100%;
height: 50%;
}
<div id="toast"></div>
<button onclick="showToast('Hello')">Show toast</button>
<button onclick="showToast('Hi')">Show toast</button>
Any more suggestion is appreciated.

JS function is passed a different value depending on whether I'm executing or debugging

PROBLEM: Element with id "containerLnkMenu" does not center correctly in it's parent div when passed into the js function "centerElementYParent" unless I put a break point in the function using google chrome's debugger.
The "getComputedStyle(f, null)" call returns a "0px" for height if executed normally so I end up with a '-57px' for the margin-top.
COMMENT: So I found a few people that had similar problems on the internet, but I couldn't find a way to map their solution to my needs.
Any help on this would be appreciated.
Let me know if you need me to explain anything further.
I would prefer a detailed response or links to further reading, that is related to my issue (so I can learn from this error), but any related/helpful comment is welcome.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link rel="stylesheet" href="main.css">
<script src="main.js"></script>
</head>
<body>
<div id="btnMenu" class="borderRadius" style="top: 10px; left: 10px;" onClick="btnMenuClicked(this)">
<div id="bar1" class="bar"></div>
<div id="bar2" class="bar"></div>
<div id="bar3" class="bar"></div>
</div>
<div id="menu" class="borderRadius" style="width: 0px; height: 0px;">
<div id="containerLnkMenu">
<a id="lnkNews" class="centerTxt lnkMenu" href="">NEWS</a>
<a id="lnkFiles" class="centerTxt lnkMenu" href="">FILES</a>
<a id="lnkTree" class="centerTxt lnkMenu" href="">TREE</a>
</div>
</div>
</body>
<script>
function btnMenuClicked(e) {
animateBtnMenu(e);
var menu = document.getElementById('menu');
var menuStyle = window.getComputedStyle(menu, null);
if (menuStyle.width == '0px' && menuStyle.height == '0px') {
openMenu(menu, menuStyle, e);
centerElementYParent(document.getElementById('containerLnkMenu'), document.getElementById('menu'));
} else {
closeMenu(menu, menuStyle, e);
}
}
</script>
</html>
body {
margin: 0;
font-family: Arial;
font-size: 16px;
}
a {
display: block;
text-decoration: none;
cursor: pointer;
}
/* Class Tools */
.centerTxt { text-align: center; }
.borderRadius { border-radius: 5px; }
.bar {
height: 5px;
transition: 0.4s;
background-color: #2E0A91;
}
.lnkMenu {
padding: 5px;
color: #FFD500;
font-size: 1.5em;
}
/*--- navigation ---*/
#btnMenu {
position: fixed;
width: 25px;
padding: 5px;
transition: 0.8s;
cursor: pointer;
}
#btnMenu:hover { background-color: #2E0A91; }
#btnMenu:hover .bar { background-color: #D4B100; }
#bar2 { margin: 5px 0 5px 0; }
.change #bar1 {
transform: rotate(-45deg) translate(-10px, 4px);
width: 141%;
}
.change #bar2 { opacity: 0; }
.change #bar3 {
transform: rotate(45deg) translate(-10px, -4px);
width: 141%;
}
#menu {
position: fixed;
z-index: 100;
top: 0;
left: 0;
overflow: hidden;
transition: 0.8s;
background-color: #2E0A91;
}
//NAME: centerElementYParent
//DESCRITPTION: e = element to center, f = parent element
// Adds margin top to e in order to vertically center element within parent (f)
function centerElementYParent(e, f) {
var eStyle = window.getComputedStyle(e, null);
var fStyle = window.getComputedStyle(f, null);
console.log(fStyle.height);
var eHeight = parseInt(eStyle.height.slice(0, eStyle.height.length - 2));
var fHeight = parseInt(fStyle.height.slice(0, fStyle.height.length - 2));
var marginTop = ((fHeight - eHeight)/2) + 'px';
e.style.marginTop = marginTop;
}
//NAME: animateBtnMenu
//DESCRIPTION: Attaches the 'change' class to the btnMenu element.
function animateBtnMenu(e) {
e.classList.toggle('change');
}
//NAME: openMenu
//DESCRIPTION: Applies a width and height to the menu whilst moving the menu button respectivley
function openMenu(e, eStyle, f) {
e.style.height = '250px';
e.style.width = '300px';
var eStyle = window.getComputedStyle(e, null);
f.style.left = '310px';
f.style.top = '260px';
}
//NAME: closeMenu
//DESCRIPTION: Sets width and height of the menu to 0 and moves the menu button respectivley
function closeMenu(e, eStyle, f) {
e.style.width = '0px';
e.style.height = '0px';
f.style.top = '10px';
f.style.left = '10px';
}
It may be because the element you want to center didn't rendered on the right position yet. Try adding setTimeout to call the function.
openMenu(menu, menuStyle, e);
setTimeout(function() {
centerElementYParent(document.getElementById('containerLnkMenu'), document.getElementById('menu'));
}, 800);

New to Javascript - changing style of element

So based on the value of a boolean, I want certain tabs in my sidebar to display/ hide when the page loads.
var someVar = true;
function show_ifTrue() {
if (Boolean(someVar) == true) {
document.getElementById('x').style.display = 'block';
console.log("I CHANGED IT");
}
else {
document.getElementById('x').style.background = 'red';
}
}
.sidebar {
position: fixed;
overflow-y: scroll;
top: 0;
bottom: 0;
float: left;
display: inline-block;
z-index: 50;
}
#tab {
display: block;
}
#x {
display: none;
}
<div class="sidebar">
Cats
Dogs
</div>
I have tried everything from taking out the display from .sidebar a{...} and giving each tab its own display property, using !important, changing in JS using style.cssText or setting attribute, I just can't get it to change the display.
In order to change the color, you have to call the function first, but you are never calling it, since onpageshow could only be added to <body>, so you could move it there - <body onpageshow='...'>. Or, if you still want to deal only with the div itself, do it onload:
window.onload=function(){
show_ifTrue();
}
This way too could also use your pageshow:
window.onpageshow=function(){
show_ifTrue();
}
Also, you don't need Boolean prefix in your function, just someVar == true.
It appears that you are missing the css closing braket for #tab (EDIT: OP edited this, but it could also have been part of the issue). Also, you might want to use window.onload, or onpageshow on the body element — it's the only element that it will work on. With that fixed, here's a working example:
window.onload = function () {
show_ifTrue();
}
var someVar = true;
function show_ifTrue() {
if (someVar === true) {
document.getElementById('x').style.display = 'block';
console.log('I CHANGED IT');
}
else {
document.getElementById('x').style.background = 'red';
}
}
.sidebar {
position: fixed;
overflow-y: scroll;
top: 0;
bottom: 0;
float: left;
display: inline-block;
z-index: 50;
}
#tab {
display: block;
}
#x {
display: none;
}
<div class="sidebar">
Cats
Dogs
</div>
I hope that helps!

Problems toggling animation play state

I'm trying to start/stop the rotate animation with a button. Not sure what I'm doing something wrong. I'd rather avoid JQuery if possible....I'm already in above my head.
<head>
<style type='text/css'>
#spinner {
-webkit-animation: spin 2s linear infinite;
-webkit-animation-play-state:running;
border: 1px dashed;
border-radius: 50%;
width: 5em;
height: 5em;
margin: 2em auto;
padding: 2em;
}
#-webkit-keyframes spin {
from {
-webkit-transform:rotate(0deg);
}
to {
-webkit-transform:rotate(360deg);
}
}
</style>
<script type='text/javascript'>//<![CDATA[
window.onload=function(){
function spin() {
var spinner = document.getElementById("spinner");
if (spinner.style.webkitAnimationPlayState === 'running') {
spinner.style.webkitAnimationPlayState = 'paused';
document.body.className = 'paused';
} else {
spinner.style.webkitAnimationPlayState = 'running';
document.body.className = '';
}
}
}//]]>
</script>
</head>
<body>
<div id="spinner">spin!</div>
<button onClick="spin();">start/stop</button>
</body>
http://jsfiddle.net/uc9c5/1/
Thanks in advance
Firstly, in your jsFiddle you were running it onLoad in your jsFiddle when you should have been using the No wrap in <head> section option.
Secondly, I've made changes to your CSS - namely, changing -webkit-animation-play-state:running; to -webkit-animation-play-state:paused; as the initial state, ready for the function call to start the animation.
Here's a working jsFiddle.
Edit: In regard to the flicker, it seems like sadly it's a webkit bug.
There are few errors in your code. The click is not triggered. This should work:
http://jsfiddle.net/uc9c5/3/
document.getElementById('button').onclick = function(){
var spinner = document.getElementById("spinner");
if (!spinner.style.webkitAnimationPlayState) {
spinner.style.webkitAnimationPlayState = 'paused';
} else if (spinner.style.webkitAnimationPlayState === 'paused') {
spinner.style.webkitAnimationPlayState = 'running';
} else if (spinner.style.webkitAnimationPlayState === 'running') {
spinner.style.webkitAnimationPlayState = 'paused';
}
}

Categories