I have a toggle bar element I am working on and currently I have it working correctly to style the toggled button, but I want more animation. The idea is to have the curent active button slide to whichever button is newly active. So visually the only thing I would be adding to the current code is the slide animation. How to do that exactly is where I'm getting stuck. Now the active element isn't just getting a background and some styles, but a floating/sliding box will be needed (I think)
I don't want anyone to impliment it for me, but I am having trouble thinking of how to impliment it. Do I do something with a pseudoelements? How do I make sure that the white button background element is as wide as the word it needs to be behind?
This is more or less a general CSS question, but I am not sure how to even start this process.
If anyone has any advice or tricks on how to make this work or just pointing me in the right direction, I would greatly appreciate it! Cheers!
This is what I've built so far in CodeSandbox
CodePudding user response:
If you want to do it from scratch, and have the ability to control the position of the white box relative to the yellow box (position: relative or absolute), you could hardcode it by creating a function that takes the desired box coordinate, checks if the white box is in the correct place, and if not moves it x px in the right direction, then calls itself recursively with a timeout.
Essentially, move it a little bit every few milliseconds until it gets to the right spot. one move every (1000/24)ms or less should make it look fluid.
As for the size, you could either hardcode that and same idea, or make a function that finds the correct size based on the given text.
CodePudding user response:
You could 'create a gap' for the white block to travel in so it is behind the text but in front of the backgrounds by putting the background colors onto the elements using pseudo elements with lower z index.
On click of a button you can look at the previously clicked button and work out how far the white block has to move to get to the current button, and also how its width has to change.
In this snippet the 'white block' is in fact a pseudo element on the currently clicked button. This makes it easy to work out its final resting place which is directly under the currently clicked button.
const buttons = document.querySelectorAll('button');
function clicked(e) {
const el = e.target;
const prevEl = document.querySelector('button.animate');
const x = (prevEl == null) ? '0%' : (prevEl.getBoundingClientRect().x - el.getBoundingClientRect().x) 'px';
const w2 = window.getComputedStyle(el).width;
const w1 = (prevEl == null) ? 0 : window.getComputedStyle(prevEl).width;
buttons.forEach(button => {
button.classList.remove('animate');
});
el.style.setProperty('--x', x);
el.style.setProperty('--w1', w1);
el.style.setProperty('--w2', '100%');
el.classList.add('animate');
}
buttons.forEach(button => {
button.addEventListener('click', clicked);
}
);
nav {
display: inline-block;
position: relative;
}
nav::before {
content: '';
position: absolute;
background-color: gold;
width: 100%;
height: 100%;
left: 0 top: 0;
z-index: -3;
}
button {
margin: 2vmin;
background-color: transparent;
position: relative;
}
button::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: brown;
z-index: -2;
}
button.animate::after {
content: '';
position: absolute;
background-color: white;
width: 100%;
height: 100%;
animation-name: move;
animation-duration: 3s;
animation-fill-mode: forwards;
top: 0;
left: 0;
z-index: -1;
}
@keyframes move {
0% {
transform: translateX(var(--x));
width: var(--w1);
}
100% {
transform: translateX(0);
width: var(--w2);
}
}
@keyframes animate {
0% {}
100% {
background-color: white;
}
}
<nav>
<button>AAAA</button>
<button>AA</button>
<button>AAAAAA</button>
<button>A</button>
</nav>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>