How to properly animate a bar gliding? - javascript

I have two buttons, when a user clicks on them it gets underlined. However, I'd like the .underline to be animated/glide horizontally to the button that is being clicked on.
Demo: https://jsfiddle.net/ds1wr736/11/
As of right now, the .underline just appears and disapears when a button is clicked. How can I animate this to smoothly glide (x values changing) to the selected button without hacks and JQuery?
function switchTab(tab) {
if (tab === 1) {
document.getElementById("tab2").classList.add("underline");
document.getElementById("tab1").classList.remove("underline");
}
else if (tab === 2) {
document.getElementById("tab1").classList.add("underline");
document.getElementById("tab2").classList.remove("underline");
}
}
.bar {
background-color: gray;
padding: 20px;
}
.underline {
border-bottom: 5px solid red;
}
button {
width: 100px;
height: 50px;
background-color: white;
}
button:focus {
outline: none;
}
<div class="bar">
<button id='tab1' class="underline" onclick='switchTab(2)'>Tab 1</button>
<button id='tab2' onclick='switchTab(1)'>Tab 2</button>
</div>

Rather than animating a border I've created an additional element that reacts to the the click events. This allows us to track the position of the "underline" and scale and animate it between buttons when clicked.
This can be modified to accept hover events instead using mouseover instead of click.
let buttons = document.querySelectorAll('button');
buttons.forEach(button => {
button.addEventListener('mouseover', hoverboard); // Hover event
//button.addEventListener('click', hoverboard);
});
function hoverboard(e) {
const board = document.querySelector('.hoverboard');
// - 1 due to the border of the button
let width = this.offsetWidth - 1;
const firstChild = document.querySelector('.bar button:first-child');
const lastChild = document.querySelector('.bar button:last-child');
// - 19 due to padding being 20px on the left and removing 1 for the button's border
let left = this.offsetLeft - 19;
board.style.cssText = 'transform: translateX(' + left + 'px); width: ' + width + 'px;';
}
.bar {
position: relative;
background-color: gray;
padding: 20px;
}
.underline {
border-bottom: 5px solid red;
}
button {
width: 100px;
height: 50px;
background-color: white;
}
button:focus {
outline: none;
}
.hoverboard {
position: absolute;
width: 100px;
height: 3px;
background: red;
transition: transform .25s ease, width .25s ease;
}
<div class="bar">
<button id='tab1'>Tab 1</button>
<button id='tab2' style="width: 65px;">Tab 2</button>
<button>Tab 3</button>
<div class="hoverboard"></div>
</div>

Here ya go. Only the edited classes are here:
.underline:after {
border-bottom: 5px solid red;
animation-name: slideIn;
animation-duration: 1s;
width: 100%;
content: '';
position: absolute;
bottom: 0;
left: 0;
}
#keyframes slideIn {
from {width: 0;}
to {width: 100%;}
}
button{
position: relative;
width: 100px;
height: 50px;
background-color: white;
}
What I did is that I used the abstract after element on the buttons and positioned it absolute to it's relative button. And used css animation.

Related

Hiding/Showing CSS elements does not work?

THE WHOLE CODE IN JSFIDDLE
I have been struggling to effectively remove the code and css created in the function Seifenblasen_blasen()
function Seifenblasen_blasen(){
btn1.style.display = 'none';
document.getElementById("text").innerHTML="Bubble"
const section = document.querySelector('section')
const createElement = document.createElement('spawn')
var size = Math.random() * 60;
createElement.style.width = 30 + size + 'px';
createElement.style.height = 30 + size + 'px';
createElement.style.left = Math.random() * innerWidth + "px";
section.appendChild(createElement);
setTimeout(() => {
createElement.remove()
},8000)
}
const Blaseninterval = setInterval(Seifenblasen_blasen, 100)
created CSS:
section {
width: 100%;
height: 100vh;
overflow: hidden;
background: #1F69FA;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
section.text{
font-size: 10em;
color: #333;
margin: 0 auto;
text-align: center;
font-family: consolas;
background-color:#1F69FA;
pointer-events: none;
border: none;
}
section spawn {
position: absolute;
bottom: -80px;
background: transparent;
border-radius: 50%;
pointer-events: none;
box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.5);
animation: animate 4s linear infinite;
}
section spawn:before {
content: '';
position: absolute;
width: 100%;
height: 100%;
transform: scale(0.25) translate(-70%, -70%);
background: radial-gradient(#fff, transparent);
opacity: 0.6;
border-radius: 50%;
}
#keyframes animate {
0% {
transform: translateY(0%);
opacity: 1;
}
99% {
opacity: 1;
}
100% {
transform: translateY(-2000%);
opacity: 0;
}
section span {
margin-top: 700px;
font-size: 1em;
color: #333;
margin: 0 auto;
font-family: consolas;
background-color: #1F69FA;
border: none;
position: absolute;
}
HTML:
<section id="section">
<div class="content">
<button id="btn"></button>
<button id="btn1"></button>
</div>
</section>
to then execute the next function function next(). This removal is needed because when I don't remove the elements from the first function the second wont work. I could just do document.head.innerHTML = "" but that would then also remove the css needed for the button appearing in the next function. So then I tried to make variables with const
const btn = document.getElementById('text');
const btn1 = document.getElementById('text1');
const section = document.querySelector('section')
// in function Seifenblasen_blasen()
btn1.style.display = 'none';
// in function next()
section.style.display = 'none';
btn.style.display = 'none';
btn1.style.display = 'block';
to hide and show only parts of the css without removing the css entirely to keep the styling intact, but now nothing works anymore.(the button on the next Screen doesn't show up at all and the first button does not contain any styling) My endgoal is that I can essentially switch between two screens one showing the bubbles and one the bouncy balls and when I click on the button it goes on. (for example start is bubbles. I click -> Bounce, click again -> back to Bubbles and so on)

Javascript is having problems with moving divs around

Here's a function:
function rollImgOnSwipe(direction) {
changeDirection(direction);
rollImage(direction);
}
The first called function (changeDirection(direction);) is supposed to place a div in either the left or right side of the screen, depending on the value of its argument. The second one (rollImage(direction);) is to make the div move from left to right or from right to left, depending on where the first function placed it.
Well, it seems like it first calls rollImage and then changeDirection because it takes rollImgOnSwipe to be called more than once in order for the div to be placed on the other side.
The best way to explain this to you is to show you - run the code snippet and try switching between the divs with the prev and next buttons and see how they behave.
var nextBtn = document.getElementById('next'),
prevBtn = document.getElementById('prev'),
shown = document.getElementsByClassName('shown')[0],
hidden = document.getElementsByClassName('hidden')[0];
function rollImage(direction) {
shown.classList.remove("shown");
shown.classList.add("hidden");
hidden.classList.remove("hidden");
hidden.classList.add("shown");
shown = document.getElementsByClassName('shown')[0];
hidden = document.getElementsByClassName('hidden')[0];
changeDirection(direction);
}
function rollImgOnSwipe(direction) {
changeDirection(direction);
rollImage(direction);
}
function changeDirection(direction) {
hidden.style.left = (105 * direction) + "%";
shown.style.left = 0;
}
nextBtn.addEventListener('click', function () { rollImgOnSwipe(1); });
prevBtn.addEventListener('click', function () { rollImgOnSwipe(-1); });
.img {
position: absolute;
display: block;
width: 80px;
height: 30px;
border-style: solid;
border-color: red;
border-width: 5px;
}
.shown{
left: 0;
transition: left .6s ease, transform .6s ease;
}
.hidden{
left: 105%;
}
.img-wrapper{
position: relative;
width: 80px;
height: 30px;
padding: 30px;
white-space: nowrap;
overflow: hidden;
}
<button id="prev">prev</button>
<div class="img-wrapper">
<div class="img shown"></div>
<div class="img hidden"></div>
</div>
<button id="next">next</button>
To fix this, i make the compiler wait for a bit before calling rollImage by using the setTimeout function in rollImgOnSwipe.
And now the program works as expected:
var nextBtn = document.getElementById('next'),
prevBtn = document.getElementById('prev'),
shown = document.getElementsByClassName('shown')[0],
hidden = document.getElementsByClassName('hidden')[0];
function rollImage(direction) {
shown.classList.remove("shown");
shown.classList.add("hidden");
hidden.classList.remove("hidden");
hidden.classList.add("shown");
shown = document.getElementsByClassName('shown')[0];
hidden = document.getElementsByClassName('hidden')[0];
changeDirection(direction);
}
function rollImgOnSwipe(direction) {
changeDirection(direction);
setTimeout(function() { rollImage(direction); }, 50);
}
function changeDirection(direction) {
hidden.style.left = (105 * direction) + "%";
shown.style.left = 0;
}
nextBtn.addEventListener('click', function(){ rollImgOnSwipe(1); });
prevBtn.addEventListener('click', function(){ rollImgOnSwipe(-1); });
.img {
position: absolute;
display: block;
width: 80px;
height: 30px;
border-style: solid;
border-color: red;
border-width: 5px;
}
.shown{
left: 0;
transition: left .6s ease, transform .6s ease;
}
.hidden{
left: 105%;
}
.img-wrapper{
position: relative;
width: 80px;
height: 30px;
padding: 30px;
white-space: nowrap;
overflow: hidden;
}
<button id="prev">prev</button>
<div class="img-wrapper">
<div class="img shown"></div>
<div class="img hidden"></div>
</div>
<button id="next">next</button>
My question is:
What is the problem and why is it fixed by making the compiler wait?

css transition effect for divs

I've the below Code.
function showOrHideDiv() {
var e = document.getElementById('pageRightMenu');
var l = document.getElementById('pageLeftMenu');
if (e.style.display == 'block') {
e.style.display = 'none';
l.style.width = '99%';
l.style.transition = "all 2s"; // Standard syntax
l.style.WebkitTransition = "all 2s"
}
else {
l.style.width = '60%';
l.style.transition = "width 2s"; // Standard syntax
l.style.WebkitTransition = "width 2s";
e.style.display = 'block';
}
}
html,
body {
position: fixed;
padding: 0px;
margin: 0px;
width: 100%;
height: 100%;
}
.blended_grid {
display: block;
width: 100%;
overflow: auto;
width: 100%;
height: 100%;
/* Webkit 35: */
-webkit-animation: fadeIn 1s linear;
/* Firefox 28, Opera 22, IE 11: */
animation: fadeIn 1s linear;
}
.pageHeader {
background-color: rgba(0, 0, 0, 0.5);
float: left;
clear: none;
height: 20%;
width: 100%;
border: 1px solid black;
}
.pageLeftMenu {
background-color: rgba(0, 0, 0, 0.5);
float: left;
clear: none;
height: 80%;
width: 100%;
border: 1px solid black;
}
.pageRightMenu {
background-color: rgba(0, 0, 0, 0.5);
float: right;
clear: none;
height: 80%;
width: 39%;
border: 1px solid black;
}
<div class="blended_grid">
<div class="pageLeftMenu" id="pageLeftMenu">
<input type="button" value="Click Me!" onClick="showOrHideDiv()" />
</div>
<div class="pageRightMenu" id="pageRightMenu" style="display: none">
This a textF
</div>
</div>
Here as part of my requirements, I've created 2 divs, and in left div there is a button, when I click, the other div will either appear or disappear, and everything is fine, but I want to have a css transition effect when I hide or show the div.
Update:
I'm able to do the transition. I've tried a js function that is doing what I actually require (updated in this question), but when you show the 2nd div, the div appears first below and then beside the other div. How can I fix it, I mean, after the entire transition, the 2nd div should be visible
please run the code snippet to get a better understanding of my issue.
please let me know how can I do this.
Thanks
I recommend using the jQuery fadeOut() function, which animates the opacity to zero and then sets the "display" property to "none" when the animation is finished:
function showOrHideDiv() {
var $e = $(document.getElementById('pageRightMenu'));
var l = document.getElementById('pageLeftMenu');
if ( $e.is(":visible") ) { //safer comparison in case you change things later
l.style.width = '100%';
$e.fadeOut(500); //fade out, taking 500ms
} else {
l.style.width = '60%';
$e.fadeIn(500); //fade in, taking 500ms
}
}
Here's how you do it:
Make this containing element a flexbox using display: flex
Give the pageLeftMenu a "fixed" width using flex: 0 0 auto, which means the width will be taken from the width property (and therefore animated)
Give the pageRightMenu a "flexible" width using flex: 1 1 0, which means it will take up all the remaining space in the parent not used by pageLeftMenu.
The example below shows the effect. Check out this guide for more on flexbox: https://scotch.io/tutorials/a-visual-guide-to-css3-flexbox-properties
function showOrHideDiv() {
var e = document.getElementById('pageRightMenu');
var l = document.getElementById('pageLeftMenu');
if (e.style.display == 'block') {
e.style.display = 'none';
l.style.width = '99%';
l.style.transition = "all 2s"; // Standard syntax
l.style.WebkitTransition = "all 2s"
}
else {
l.style.width = '60%';
l.style.transition = "width 2s"; // Standard syntax
l.style.WebkitTransition = "width 2s";
e.style.display = 'block';
}
}
html,
body {
position: fixed;
padding: 0px;
margin: 0px;
width: 100%;
height: 100%;
}
.blended_grid {
display: flex; //instead of display: block
width: 100%;
overflow: auto;
width: 100%;
height: 100%;
/* Webkit 35: */
-webkit-animation: fadeIn 1s linear;
/* Firefox 28, Opera 22, IE 11: */
animation: fadeIn 1s linear;
}
.pageHeader {
background-color: rgba(0, 0, 0, 0.5);
float: left;
clear: none;
height: 20%;
width: 100%;
border: 1px solid black;
}
.pageLeftMenu {
background-color: rgba(0, 0, 0, 0.5);
float: left;
clear: none;
height: 80%;
width: 100%;
flex: 0 0 auto; //use the width property to determine width
border: 1px solid black;
}
.pageRightMenu {
background-color: rgba(0, 0, 0, 0.5);
float: right;
clear: none;
height: 80%;
flex: 1 1 0; //use up all remaining space
border: 1px solid black;
}
<div class="blended_grid">
<div class="pageLeftMenu" id="pageLeftMenu">
<input type="button" value="Click Me!" onClick="showOrHideDiv()" />
</div>
<div class="pageRightMenu" id="pageRightMenu" style="display: none">
This a textF
</div>
</div>

Animate line wrapping of inline-block elements on content change

I have a container with a fixed width and overflow: auto; set.
It contains multiple items (display: inline-block;), also with fixed dimensions.
So if the container has enough children, the items will wrap around and create a grid-like pattern.
Now I dynamically remove children from the beginning and want to animate the position change of the items that are filling up the freed space and moving up from the start of a line to the end of the line above.
var counter = 1;
document.getElementById("additem").onclick = function() {
var item = document.createElement("div");
item.innerText = counter;
counter++;
document.getElementById('container').appendChild(item);
}
document.getElementById("removeitem").onclick = function() {
document.getElementById('container').removeChild(
document.getElementById('container').children[0]
);
}
#container {
width: 280px;
overflow: auto;
border: 1px solid red;
padding: 5px;
text-align: center;
}
#container > div {
width: 80px;
height: 90px;
border: 1px solid green;
margin: 5px;
display: inline-block;
}
<button id="additem">add item</button>
<button id="removeitem">remove item</button>
<div id="container">
</div>
EDIT: I am also able to use jQuery to accomplish this behaivor.
A reasonably clean solution is to use an inline style that sets the removed element's opacity to 0, accompanied by a transition and a setTimeout timed to run as soon as the transition finishes, effectively fading out the element and then sliding everything else into place. Here's a quick snippet I put together:
var counter = 1;
document.getElementById("additem").onclick = function() {
var item = document.createElement("div");
item.innerText = counter;
counter++;
document.getElementById('container').appendChild(item);
}
document.getElementById("removeitem").onclick = function() {
document.getElementById('container').children[0].setAttribute('style', 'opacity: 0');
window.setTimeout(function() {
document.getElementById('container').removeChild(
document.getElementById('container').children[0]
)
}, 300);
}
#container {
width: 280px;
overflow: auto;
border: 1px solid red;
padding: 5px;
text-align: center;
}
#container>div {
width: 80px;
height: 90px;
border: 1px solid green;
margin: 5px;
display: inline-block;
transition: opacity 0.3s;
}
<button id="additem">add item</button>
<button id="removeitem">remove item</button>
<div id="container">
</div>

Transition event listener doesn't execute

I'm working on transitions by using javascript. But i want to display element to none when the transition is end. I'm using addEventListener on element but function doesn't execute.
var fun;
var transitions = {
'transition':'transitionend',
'OTransition':'oTransitionEnd',
'MozTransition':'transitionend',
'WebkitTransition':'webkitTransitionEnd'
};
(function(){
var i=0,
containterget = document.querySelector('.container');
elementGet = document.querySelector('.Number');
fun = function(){
i++;
elementGet.innerHTML = i;
elementGet.style.transform = 'translateX('+(containterget.offsetWidth - 40 -35)+'px)';
elementGet.addEventListener(transitions,function(event){
console.log("Transition End Execute");
elementGet.style.display='none';
} );
};
})();
*{
margin:0;
padding:0;
box-sizing: border-box;
}
.container{
border:1px solid green;
max-width:85%;
margin: 2em auto 0;
}
button{
background-color:transparent;
padding: 15px;
margin:0;
color:#000;
border:2px solid #F44336;
text-align: center;
outline: 0;
transition: opacity 0.3s;
}
button:hover{
background-color:#F44336;
color: white;
opacity :.75;
}
button:hover{
cursor: pointer;
transition: opacity .4s;
}
span{
display: inline-block;
transition: transform 1.5s ease;
}
.Number{
font-size: 4em;
border:1px solid black;
/*transform: translateX(0);*/
}
.EndBoundry{
float: right;
font-size: 4em;
border:1px solid black;
}
.contain:after{
content: "";
display: table;
clear: both;
}
.btn{
text-align: center;
margin: 2em 0;
}
<div class="container contain">
<span class="Number">1</span>
<span class="EndBoundry">E</span>
</div>
<div class="btn">
<button onclick="fun()">Number Transition Click</button>
</div>
The following Snippet demonstrates the transitionend event. All details are commented in Snippet.
SNIPPET
// Reference the section#area and input#gone
var area = document.getElementById('area');
var chx = document.getElementById('gone');
// Register click event on #area call offON()
area.addEventListener('click', offON, false);
function offON(e) {
// Determine the clicked button
if (e.target !== e.currentTarget) {
var tgt = e.target;
// Switch clicked button classes .on and .off
tgt.classList.toggle('on');
tgt.classList.toggle('off');
}
// If the checkbox is checked call transEND()
if (chx.checked) {
transEND()
}
}
function transEND() {
// Register the transitionend event on #area
area.addEventListener("transitionend", function(e) {
// Determine which button was clicked
if (e.target !== e.currentTarget) {
var tgt = e.target;
// Clicked button will disappear after transition
tgt.style.display = 'none';
}
}, false);
}
/* All buttons will have the same
|| transition. This transition is
|| dependent upon another animatable
|| style to exist.
*/
/* This particular transition says:
|| ALL animatable styles have a
|| duration of 3 seconds,
|| with a timing function: ease,
|| and a delay of 300msec
*/
button {
width: 120px;
height: 40px;
transition: all 3s ease .3s
}
/* Classes .on and .off are "states"
|| to each #id the "states" have a
|| different meaning
*/
#fade.off {
opacity: 1;
}
#fade.on {
opacity: 0;
}
#move.off {
transform: translateY(0);
}
#move.on {
transform: translateY(200px);
}
#shrink.off {
transform: scale(1);
}
#shrink.on {
transform: scale(.3);
}
#gone {
width: 18px;
height: 18px;
}
p {
font-size: 12px;
}
<p>Click each button. Then click them again (the "FADER" is still there and clickable)</p>
<p>Now click the checkbox and push the buttons again. If you can't click the buttons back to original "state", then the event handler on transitionend was successful.</p>
<label for='gone'>Enable "transitionEND" </label>
<input id='gone' type='checkbox'>
<section id='area'>
<button id='fade' class='off'>FADER</button>
<button id='move' class='off'>MOVER</button>
<button id='shrink' class='off'>SHRINKER</button>
</section>
Use "transitionend" without prefixes
elementGet.addEventListener("transitionend", function(){});
You can listen to transitionend event on supported browsers.
I did some reshuffling of your codes and add an id tag to your button.
See snippet below
var fun;
var i = 0,
containterget = document.querySelector('.container');
elementGet = document.querySelector('.Number');
console.log(elementGet)
function execute(event) {
console.log("Transition End Execute");
alert("Transition End Execute");
elementGet.style.display = 'none';
}
fun = function() {
i++;
elementGet.innerHTML = i;
elementGet.style.transform = 'translateX(' + (containterget.offsetWidth - 40 - 35) + 'px)';
elementGet.addEventListener('transitionend', execute);
elementGet.addEventListener('webkitTransitionEnd', execute);
elementGet.addEventListener('mozTransitionEnd', execute);
elementGet.addEventListener('oTransitionEnd', execute);
};
document.getElementById("target").addEventListener("click", fun)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
border: 1px solid green;
max-width: 85%;
margin: 2em auto 0;
}
button {
background-color: transparent;
padding: 15px;
margin: 0;
color: #000;
border: 2px solid #F44336;
text-align: center;
outline: 0;
transition: opacity 0.3s;
}
button:hover {
background-color: #F44336;
color: white;
opacity: .75;
}
button:hover {
cursor: pointer;
transition: opacity .4s;
}
span {
display: inline-block;
transition: transform 1.5s ease;
}
.Number {
font-size: 4em;
border: 1px solid black;
/*transform: translateX(0);*/
}
.EndBoundry {
float: right;
font-size: 4em;
border: 1px solid black;
}
.contain:after {
content: "";
display: table;
clear: both;
}
.btn {
text-align: center;
margin: 2em 0;
}
<div class="container contain">
<span class="Number">1</span>
<span class="EndBoundry">E</span>
</div>
<div class="btn">
<script></script>
<button id="target">Number Transition Click</button>
</div>

Categories

Resources