I'm trying to create an infinite horizontal "scroll" like a marquee effect (like this one, for example).
This is my code:
.parent {
border: 1px solid black;
width: 100%;
height: 2rem;
}
.container {
height: 100%;
display: flex;
padding-left: 10%;
border: 1px solid tomato;
animation: marquee 5s linear infinite;
}
#keyframes marquee {
0% {
transform: translate(0%, 0);
}
100% {
transform: translate(-100%, 0);
}
}
.child1 {
width: 10rem;
height: 100%;
background-color: #84B7DF;
}
.child2 {
width: 18rem;
height: 100%;
background-color: #f58db6;
}
.child3 {
width: 13rem;
height: 100%;
background-color: #ffc410;
}
.child4 {
width: 21rem;
height: 100%;
background-color: #C8E7C1;
}
<div class="parent">
<div class="container">
<div class="child1"></div>
<div class="child2"></div>
<div class="child3"></div>
<div class="child4"></div>
</div>
</div>
As you can see, it works but not perfectly.
I would like that as soon as the green rectangle has shifted, the blue (slightly spaced) one immediately appears, I don't want there to ever be a whole white screen.
I hope is clear what I mean...
Thanks a lot!
You could just add one more container element with same children, and then use display: flex with overflow: hidden on parent element. Also you can set width of the .container element to be larger then the window width using vw units and flex property.
Adjust width and padding properties on container if you have to.
.parent {
border: 1px solid black;
width: 100%;
height: 2rem;
display: flex;
overflow: hidden;
}
.container {
height: 100%;
flex: 0 0 120vw;
display: flex;
padding-right: 10%;
border: 1px solid tomato;
animation: marquee 5s linear infinite;
}
#keyframes marquee {
0% {
transform: translate(0%, 0);
}
100% {
transform: translate(-100%, 0);
}
}
.child1 {
width: 10rem;
height: 100%;
background-color: #84B7DF;
}
.child2 {
width: 18rem;
height: 100%;
background-color: #f58db6;
}
.child3 {
width: 13rem;
height: 100%;
background-color: #ffc410;
}
.child4 {
width: 21rem;
height: 100%;
background-color: #C8E7C1;
}
<div class="parent">
<div class="container">
<div class="child1"></div>
<div class="child2"></div>
<div class="child3"></div>
<div class="child4"></div>
</div>
<div class="container other">
<div class="child1"></div>
<div class="child2"></div>
<div class="child3"></div>
<div class="child4"></div>
</div>
</div>
Another solution is to add padding-right width vw units on container.
.parent {
border: 1px solid black;
width: 100%;
height: 2rem;
display: flex;
overflow: hidden;
}
.container {
height: 100%;
display: flex;
padding-right: 50vw;
border: 1px solid tomato;
animation: marquee 5s linear infinite;
}
#keyframes marquee {
0% {
transform: translate(0%, 0);
}
100% {
transform: translate(-100%, 0);
}
}
.child1 {
width: 10rem;
height: 100%;
background-color: #84B7DF;
}
.child2 {
width: 18rem;
height: 100%;
background-color: #f58db6;
}
.child3 {
width: 13rem;
height: 100%;
background-color: #ffc410;
}
.child4 {
width: 21rem;
height: 100%;
background-color: #C8E7C1;
}
<div class="parent">
<div class="container">
<div class="child1"></div>
<div class="child2"></div>
<div class="child3"></div>
<div class="child4"></div>
</div>
<div class="container other">
<div class="child1"></div>
<div class="child2"></div>
<div class="child3"></div>
<div class="child4"></div>
</div>
</div>
Javascript / jQuery solution, you can first create clone of the original element and append it to parent. Create a function that will decrease left position of the elements with setInterval function. If the offset is less then -width of the same element that means that element is off the screen. In that case you should move element to the end of the window or to the end of the other element with some offset.
const parent = $(".parent");
const container = $(".container");
const offset = 250;
const clone = cloner(container, parent, offset);
function cloner(element, parent, offset) {
const clone = element.clone();
const width = element.width();
clone.css({left: width + offset})
parent.append(clone)
return clone;
}
function move(element, size = 1) {
const position = element.position().left;
const width = element.width();
if (position < -width) {
const next = element.siblings().first();
const nPosition = next.position().left;
const nWidth = next.width();
const wWidth = $(window).width();
if (nPosition + nWidth < wWidth) {
element.css({left: wWidth})
} else {
element.css({left: nPosition + nWidth + offset})
}
} else {
element.css({left: position - size})
}
}
window.mover = setInterval(() => {
move(container)
move(clone)
}, 5)
.parent {
border: 1px solid black;
width: 100%;
height: 2rem;
display: flex;
overflow: hidden;
position: relative;
}
.parent>div {
position: absolute;
left: 0;
}
.container {
height: 100%;
display: flex;
border: 1px solid tomato;
}
.child1 {
width: 10rem;
height: 100%;
background-color: #84B7DF;
}
.child2 {
width: 18rem;
height: 100%;
background-color: #f58db6;
}
.child3 {
width: 13rem;
height: 100%;
background-color: #ffc410;
}
.child4 {
width: 21rem;
height: 100%;
background-color: #C8E7C1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="parent">
<div class="container">
<div class="child1"></div>
<div class="child2"></div>
<div class="child3"></div>
<div class="child4"></div>
</div>
</div>
.marquee {
position: relative;
width: 100%;
height: 1.5em;
line-height: 1.5em;
overflow: hidden;
> div {
position: absolute;
display: flex;
flex-wrap: nowrap;
animation: marquee 10s linear infinite;
transform: translateX(100%);
> * {
display: inline;
white-space: nowrap;
&:last-child {
padding-right: 100%;
}
}
}
}
#keyframes marquee {
0% {
-moz-transform: translateX(100%);
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
100% {
-moz-transform: translateX(-100%);
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
}
Related
Just like the above image or an idea or reference to achieve this design, I appreciate the help or suggestion given by community thank you
I have got reference of progress bar which is circular but not able find an approach to solve it.
const boxes = document.querySelectorAll(".box");
const colors = ['red', 'blue', 'green', 'yellow', 'orange', 'violet']
boxes.forEach((box) => {
const insideContent = box.innerText;
box.style.border = `6px solid ${colors[insideContent]}`
})
#app {
display: flex;
}
.box {
width: 50px;
height: 50px;
margin: 10px;
background-color: cyan;
display: flex;
justify-content: center;
align-items: center;
}
<div id="app">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
</div>
As per your question I think this is what you are trying to achieve.
First define a pseudo class root
:root {
--color-val: blue;
}
Note: In order to use the --color-val you need to write it as color: var(--color-var) in CSS
Second use JavaScript to update the variable --color-val
let colors =
var root = document.querySelector(':root');
const delay = ms => new Promise(res => setTimeout(res, ms));
const colorChange = async () => {
await delay(1000);
color = colors[Math.floor(Math.random() * colors.length)]
console.log(color)
root.style.setProperty('--color-val', color);
};
colorChange()
Note:
Add the color list you want to select from or go to CodePen for a list of 1000+ hex codes.
Promise are used for asynchronous function and can be skipped by using setTimeOut for a delayed loop or if used with another eventlistener.
I apologize if I misunderstood the question. Wrote in a hurry and without beautyful visualisation, if you disassemble the principle, you can customize it.
h1 {
display: block;
margin:0 auto;
text-align: center;
padding-top:20%;
}
.container {
display:flex;
width: 150px;
height: 150px;
border: 1px solid black;
z-index: 110;
margin:0;
margin: -10px;
}
.top {
display:block;
background-color: green;
height: 24px;
width: 150px; /* gorizontal top */
animation: top 1s linear;
animation-fill-mode: forwards;
}
#keyframes top {
0% {
width: 0px;
}
100% {
width: 150px;
}
}
.right {
background-color: green;
height: 0%;/* right */
width: 32px;
animation: right 1s linear;
animation-fill-mode: forwards;
animation-delay: 1s;
z-index: 10;
}
#keyframes right {
0% {
height: 0%;
}
100% {
height: 100%;
}
}
.box {
position: fixed;
top: 32.5px;
left: 32.5px;
width: 100px;
height: 100px;
border: 1px solid black;
margin: auto;
z-index: 120;
margin: -10px -10px;
}
.bottom {
position: absolute;
top: 123px;
left: 150px;
background-color: green;
width: 0px;
height: 27px;
z-index: 10;
animation: bottom 1s linear;
animation-fill-mode: forwards;
animation-delay: 2s;
/* animation-direction: reverse; */
}
#keyframes bottom {
0% {
transform: translate(0,0);
}
100% {
transform: translate(-250px,0);
-webkit-transform: translate(-250px,0); /** Safari & Chrome **/
-o-transform: translate(-250px,0); /** Opera **/
-moz-transform: translate(-250px,0); /** Firefox **/
width: 250px;
}
}
.left {
position: absolute;
top: 122px;
background-color: green;
width: 25px;
height: 0px;
animation: left 1s linear;
animation-fill-mode: forwards;
animation-delay: 3s;
}
#keyframes left {
0% {
transform: translate(0,0);
}
100% {
transform: translate(0,-250px);
-webkit-transform: translate(0,-250px); /** Safari & Chrome **/
-o-transform: translate(0,-250px); /** Opera **/
-moz-transform: translate(0,-250px); /** Firefox **/
height: 277px;
}
}
<div class='head'>
<div class='container'>
<div class='top'></div>
<div class='box'>
<h1 id='timer'>
1
</h1>
</div>
<div class='right'></div>
<div class='bottom'></div>
<div class='left'></div>
</div>
</div>
<script type="text/javascript">
init()
function init()
{
sec = 0;
setInterval(tick, 1000);
}
function tick()
{ if (sec<3) { sec++
document.getElementById("timer").
childNodes[0].nodeValue = sec;
} else {
clearInterval(0);
}
}
</script>
Also, instead of the SetInterval script, you can take values from your block width and height styles and output a mathematical calculation in h1 instead of a stopwatch.
upd: After your comment, I decided to do what I wrote about above. You can play with values and math, I add a snippet of another solution that changes the progress bar from the entered values within the entered range. (of course, it would be easier on react than on pure js)
function grade () {
let grade = +document.getElementById("grade").value;
let range = +document.getElementById("range").value;
document.getElementById("timer").innerHTML = `${grade}/${range}`;
progress(grade,range)
}
function progress (value, grade) {
document.getElementById('1').style.backgroundColor = `white`
document.getElementById("left").className = "noactive";
document.getElementById('top').style.width = `0%`
document.getElementById('right').style.height = `0%`
document.getElementById('bottom').style.width = `0%`
let GradeValuSide = grade/4;
if (value <= GradeValuSide) {
document.getElementById('top').style.width =
`${value/GradeValuSide*100}%`
} else if (value > GradeValuSide && value <= (GradeValuSide*2)) {
document.getElementById('top').style.width = `100%`
document.getElementById('right').style.height =
`${(value-GradeValuSide)/GradeValuSide*100}%`
} else if (value >= grade/2 && value < (grade/4)*3) {
document.getElementById('top').style.width = `100%`
document.getElementById('right').style.height = `100%`
document.getElementById('bottom').style.width =
`${((((value-(GradeValuSide*2)) / GradeValuSide) *100) / 100) *27}%`
} else if (value >= grade-(grade/4) /* && value < value + 1 */) {
document.getElementById('top').style.width = `100%`
document.getElementById('right').style.height = `100%`
document.getElementById('bottom').style.width = `100%`
document.getElementById('1').style.backgroundColor = `green`
document.getElementById("left").className = "left";
document.getElementById('left').style.height =
`${(40 - (40 * ((((value-(GradeValuSide*3)) * 100) / GradeValuSide)/ 100)))}%`
}
}
h1 {
font-size:20px;
position: absolute;
left: 40px;
display: block;
margin: 0 auto;
align-items: center;
padding-top:10%;
}
.container {
display:flex;
width: 150px;
height: 150px;
border: 1px solid black;
margin:0;
margin: -10px;
}
div.top {
display:block;
background-color: green;
height: 24px;
width: 0%; /* gorizontal top */
z-index:999;
}
div.right {
position:relative;
background-color: green;
height: 0%;/* right */
width: 32px;
z-index: 9999;
}
.box {
position: fixed;
top: 32.5px;
left: 32.5px;
background-color:white;
width: 100px;
height: 100px;
border: 1px solid black;
margin: auto;
z-index: 120;
margin: -10px -10px;
}
.wrap{
position: relative;
}
div.bottom {
position: absolute;
top: 123px;
background-color: green;
width: 0%; /* 27 = 100% */
height: 27px;
float: right;
right: 78vw;
z-index: 100;
}
div.left {
position: absolute;
background-color: white;
width: 23px;
height: 40%;
top: 23px;
bottom: 10px;
left: 0;
float: top;
}
div.noactive {
position: absolute;
background-color: white;
width: 23px;
height: 0%;
top: 23px;
bottom: 10px;
left: 0;
float: top;
}
.items {
margin-top: 50px;
text-align: center;
}
.grade,
.value {
height: 15px;
width: 50px;
align-items: center;
}
<div class='head'>
<div id='1' class='container'>
<div id='top' class='top'></div>
<div class='box'>
<h1 id='timer'>1</h1>
<div class='items'>
value<input id='grade' class='grade' type=number oninput="grade()"/>
range<input id='range' class='value' type=number oninput="grade()"/>
</div>
</div>
<div id='right' class='right'></div>
<div id='bottom' class='bottom'></div>
<div id='left' class='noactive'></div>
</div>
</div>
<script src='app.js'></script>
I have such structure:
<div class="body">
<div class="wrapper">
<div class="dialog">
<div class="content-0"></div>
<div class="content-1"></div>
<div class="content-2"></div>
</div>
</div>
</div>
Parent element .dialog holds three content items which are horizontally aligned. Visible is only active .content-*. Other content items are hidden. When user clicks button, active item is sliding to the left to the hidden area, and next item becomes active and visible
Here is fiddle to demonstrate the behaviour: https://jsfiddle.net/fmbn28xs/
My question here - how can I adjust parent (.dialog) height every time user clicks button according to visible content (.content-*) item height only with CSS, is that possible?
Update:
Height of content items is not known in advance.
You can do it with custom css properties(preview with full page):
var index = 0;
function slide() {
index++;
var current = index % 3;
var target = document.querySelector(`.dialog`);
target.style.setProperty('--index', current);
}
.body {
background-color: #fff;
width: 100%;
height: 100%;
position: relative;
}
.wrapper {
background-color: grey;
position: absolute;
top: 50%;
right: 50%;
transform: translate(50%, 20%);
overflow: hidden;
}
.dialog {
--index: 0;
width: 300px;
display: flex;
height: calc(200px + 50px * var(--index));
transition: transform 400ms, height 400ms;
transform: translateX(calc(var(--index) * -100%));
}
.content-0, .content-1, .content-2 {
width: 300px;
flex: 0 0 100%;
position: relative;
}
.content-0 {
background-color: tomato;
height: calc(200px + 50px * 0);
}
.content-1 {
background-color: yellow;
height: calc(200px + 50px * 1);
}
.content-2 {
background-color: green;
height: calc(200px + 50px * 2);
}
button {
position: relative;
}
<div class="body">
<div class="wrapper">
<div class="dialog">
<div class="content-0"></div>
<div class="content-1"></div>
<div class="content-2"></div>
</div>
<button onclick="slide()">Next</button>
</div>
</div>
But you have to assign the height for all the content manually.
If you're using a precompile css library(such as scss), you can also automate this:
.dialog > *{
#for $i from 1 through 3 {
&:nth-child(#{$i}) {
height: calc(200px + 50px * #{$i});
}
}
}
Update
If the height is dynamic, you can use tricks with animation associate with alternating position from relative to absolute to make the container height
adapts accordingly, but this way you can't animate the height change, since the height is determined by the height of its children.
var index = 0;
function slide() {
index++;
var current = index % 3;
var target = document.querySelector(`.dialog`);
target.style.setProperty('--index', current);
target.setAttribute('data-index', current);
}
.body {
background-color: #fff;
width: 100%;
height: 100%;
position: relative;
}
.wrapper {
background-color: grey;
position: absolute;
top: 50%;
right: 50%;
transform: translate(50%, 20%);
overflow: hidden;
}
.dialog {
--index: 0;
width: 300px;
position: relative;
}
.dialog > * {
width: 300px;
position: absolute;
z-index: 0;
animation: popout 400ms both;
top: 0;
}
.dialog[data-index='0'] > *:nth-child(1),
.dialog[data-index='1'] > *:nth-child(2),
.dialog[data-index='2'] > *:nth-child(3) {
position: relative;
z-index: 1;
animation: popin 400ms both;
}
.content-0 {
background-color: tomato;
height: 200px;
}
.content-1 {
background-color: yellow;
height: 250px;
}
.content-2 {
background-color: green;
height: 300px;
}
button {
position: relative;
}
#keyframes popin {
from {
transform: translateX(100%);
}
to {
transform: translateX(0);
}
}
#keyframes popout {
from {
transform: translateX(0);
}
to {
transform: translateX(-100%);
}
}
<div class="body">
<div class="wrapper">
<div class="dialog" data-index="0">
<div class="content-0"></div>
<div class="content-1"></div>
<div class="content-2"></div>
</div>
<button onclick="slide()">Next</button>
</div>
</div>
I have a website, and I want an element to spin around 360 degrees once when it is clicked. The only way I have heard of to rotate a div element is the CSS transform property. I have tried some different things, like
backward.classList.add("notrans");
backward.style.transform = "rotateZ(0deg)";
backward.classList.remove("notrans");
backward.style.transform = "rotateZ(-360deg)";
where the notrans class makes the element have a transition time of 0 seconds, and
backward.style.transition = "0s";
backward.style.transform = "rotateZ(0deg)";
backward.style.transition = transtime;
backward.style.transform = "rotateZ(360deg)";
Here is the source code I am using right now:
var backward = document.getElementById("backward");
var Backward = function() {bgm.currentTime -= 10;
backward.classList.add("notrans");
backward.style.transform = "rotateZ(0deg)";
backward.classList.remove("notrans");
backward.style.transform = "rotateZ(-360deg)";
}
:root {
--color: black;
--hovercolor: white;
--backcolor: white;
--hoverbackcolor: black;
--transtime: 0.5s;
}
#controls {
position: absolute;
left: 0;
top: 45%;
width: 100%;
height: 30%;
font-size: 250%;
border: 1px solid var(--color);
border-radius: 20px;
overflow: hidden;
padding: 0;
background-color: var(--color);
}
.cp {
height: 25%;
width: 0;
overflow: hidden;
background-color: black;
}
.controls {
position: absolute;
top: 0;
width: 25%;
height: 100%;
border: 1px solid var(--color);
background-color: var(--backcolor);
color: var(--color);
line-height: 75%;
transform: rotateZ(0deg);
border-radius: 0;
transition: color var(--transtime), background-color var(--transtime);
text-align: center;
padding: 5%;
}
.controls:hover {
background-color: var(--hoverbackcolor);
color: var(--hovercolor);
}
#pause {
left: 25%;
line-height: 100%;
}
#backward {
left: 0;
line-height: 100%;
}
#autoskip {
right: 0;
}
#forward {
right: 25%;
line-height: 100%;
}
#autoskip {
line-height: 150%;
}
#skipline {
position: absolute;
left: 0;
top: 47.5%;
background-color: red;
height: 5%;
width: 100%;
transform: rotateZ(-45deg);
transition: var(--transtime);
}
<!DOCTYPE html>
<html>
<body>
<div id="controls">
<div id="15" class="cp">
<div id="backward" class="controls"><span class="rot"><span class = "button">↺</span></span>
</div>
</div>
<div id="22" class="cp">
<div id="pause" class="controls"><span class="button">| |</span></span>
</div>
</div>
<div id="33" class="cp">
<div id="forward" class="controls"><span class="rot"><span class = "button">↻</span></span>
</div>
</div>
<div id="44" class="cp">
<div id="autoskip" class="controls"><span class="button">⏩</span>
<div id="skipline"></div>
</div>
</div>
</div>
</body>
</html>
As you can see, the Backward button is not spinning when you press it.
Any help?
FYI: There is a lot of extra stuff in the code snippet, like CSS variables, but those are necessary.
Do you want this behaviour?
var spinner = document.querySelector("#spinner");
document.querySelector("button").onclick = function() {
spinner.style.animationName = "example";
setTimeout(function() {
spinner.style.animationName = "";
}, 4000);
};
#spinner {
width: 100px;
height: 100px;
display: flex;
flex-wrap: wrap;
background-color: red;
border-radius: 50%;
overflow: hidden;
animation-duration: 4s;
position: relative;
justify-content: center;
align-items: center;
}
#spinner div {
width: 50%;
height: 50%;
}
#spinner button {
position: absolute;
cursor: pointer;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
.red {
background-color: red;
}
.yellow {
background-color: yellow;
}
#keyframes example {
0% {transform: rotate(0deg)}
100% {transform: rotate(360deg)}
}
<div id="spinner">
<div class="blue"></div>
<div class="red"></div>
<div class="green"></div>
<div class="yellow"></div>
<button>Spin</button>
</div>
Currently, I am building a style guide and I have a question about the transition of an element. Imagine you have a container with two elements besides each other. Both have 50% width. The left element should always be visible, but the right element slides from the right into its 50% width. How can I achieve something like this? I am a bit overwhelmed with the top, bottom, left, right, position:absolute properties.
The html would look like this:
<div class="module-container">
<div class="first-element">
<div class="second-element">
</div>
and the css like this:
.module-container {
display: flex;
}
.first-element {
width: 50%;
}
.second-element {
width: 50%;
}
which properties does the second Element need in the first place? And which should I add via JavaScript after pressing, for instance, a button?
try using jQuery and transitions
$('#btn').click(function() {
$('.secondElement').toggleClass("slide");
});
.moduleContainer {
display: flex;
height: 100px;
overflow: hidden;
}
.firstElement {
position: relative;
width: 50%;
border: 1px solid #000;
}
.secondElement {
position: relative;
width: 50%;
border: 1px solid #000;
left: 100%;
transition: left 1s;
}
.secondElement.slide {
left: 0;
}
#btn {
display: block;
margin-top: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="moduleContainer">
<div class="firstElement"></div>
<div class="secondElement"></div>
</div>
<button id="btn">Click Here</button>
.moduleContainer {
display: flex;
height:100px;
}
.moduleContainer > * {
border:1px solid red;
box-sizing:border-box;
overflow:hidden;
}
.firstElement {
height: 100%;
width: 50%;
}
.secondElement {
height: 100%;
width: 0%;
transition:width 0.3s ease;
}
.moduleContainer:hover .secondElement {
width:50%;
}
<div class="moduleContainer">
<div class="firstElement"></div>
<div class="secondElement"></div>
</div>
I have achieved it with pure CSS.I think it's good to have a bar, so the user can hover it and expand.I hope it will help you.
.moduleContainer{ display: flex;flex-flow: row nowrap; }
.firstElement{ background-color:blueviolet;flex:1;height:100px;position:relative;max-width: 50%; }
.secondElement{ background-color:aqua;height:100px;flex:1;max-width:1%;position:relative;transition:1s ease;left:48%; }
.secondElement:hover{ background-color: chartreuse;left:0px;max-width:50%; }
<div class="moduleContainer">
<div class="firstElement">First Element</div>
<div class="secondElement"></div>
</div>
You can use a negative value for margin-left of the .second-element.
.module-container {
display: flex;
height: 50px;
overflow: hidden;
}
.module-container:hover .second-element {
right: 0;
}
.first-element {
flex: 0 0 50%;
background: #f90;
}
.second-element {
flex: 0 0 50%;
background: #0f9;
right: -50%;
transition: all .6s ease;
position: relative;
}
<div class="module-container">
<div class="first-element"></div>
<div class="second-element"></div>
</div>
Or you can use position: absolute and animate the left property
.module-container {
position: relative;
height: 50px;
overflow: hidden;
}
.module-container:hover .second-element {
right: 0;
}
.first-element {
width: 50%;
background: #f90;
position: absolute;
left: 0;
top: 0;
bottom: 0;
}
.second-element {
background: #0f9;
width: 50%;
position: absolute;
right: -50%;
top: 0;
bottom: 0;
transition: all .6s ease;
}
<div class="module-container">
<div class="first-element"></div>
<div class="second-element"></div>
</div>
I am just playing around trying to get a simple 3 slide slider working but run into some issues with the javascript. All i want to happen is on click of the slider colour i would like the current slider to slide out and the selected one to slide in. I am trying to do it by adding an active class to the slider number that I have clicked to show. I just cant quite work out where I have gone wrong. I don't want to use jQuery as I am trying to learn vanilla javascript.
Thanks as always
window.onload = onPageLoad();
function onPageLoad() {
document.querySelector('.red').classList.add('active');
};
document.querySelector('.box').addEventListener('click', function() {
document.querySelector('.red').classList.toggle('active');
document.querySelector('.green').classList.toggle('active');
document.querySelector('.yellow').classList.toggle('active');
});
* {
padding: 0;
margin: 0;
}
.main__wrapper {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
.red,
.green,
.yellow {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2;
transform: translateX(-100%);
transition: transform 1.2s;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.yellow {
background-color: yellow;
}
.active {
transform: translateX(0) !important;
transition: transform 1s !important;
}
.slide__select {
position: absolute;
bottom: 0;
right: 0;
width: 60%;
height: 20%;
z-index: 10;
display: flex;
}
.box {
position: relative;
flex: 1 0 0;
color: $color-white;
display: flex;
align-items: center;
cursor: pointer;
background-color: #A68D71;
}
.box span {
display: block;
position: relative;
z-index: 11;
}
.box::after {
content: "";
position: absolute;
top: 0;
left: 0;
background-color: yellow;
width: 100%;
height: 0;
transition: height .3s;
}
.box:hover::after {
height: 100%;
transition: height .3s;
}
<div class="main__wrapper">
<section class="red">
</section>
<section class="green">
</section>
<section class="yellow">
</section>
<div class="slide__select">
<div class="box">
<span>red</span>
</div>
<div class="box">
<span>green</span>
</div>
<div class="box">
<span>yellow</span>
</div>
</div>
</div>
You're only adding an event listener to the first box and you're toggling every box's active class in order, and the last one is yellow, so you result with a yellow background.
querySelector returns the first DOM element it finds, which is the red box.
For the functionality that you want, you have to add event listeners to each box (querySelectorAll)
window.onload = onPageLoad();
function onPageLoad() {
document.querySelector('.red').classList.add('active');
};
document.querySelector('.redbox').addEventListener('click', function() {
document.querySelector('.red').classList.add('active');
document.querySelector('.green').classList.remove('active');
document.querySelector('.yellow').classList.remove('active');
});
document.querySelector('.greenbox').addEventListener('click', function() {
document.querySelector('.red').classList.remove('active');
document.querySelector('.green').classList.add('active');
document.querySelector('.yellow').classList.remove('active');
});
document.querySelector('.yellowbox').addEventListener('click', function() {
document.querySelector('.red').classList.remove('active');
document.querySelector('.green').classList.remove('active');
document.querySelector('.yellow').classList.add('active');
});
* {
padding: 0;
margin: 0;
}
.main__wrapper {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
.red,
.green,
.yellow {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2;
transform: translateX(-100%);
transition: transform 1.2s;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.yellow {
background-color: yellow;
}
.active {
transform: translateX(0) !important;
transition: transform 1s !important;
}
.slide__select {
position: absolute;
bottom: 0;
right: 0;
width: 60%;
height: 20%;
z-index: 10;
display: flex;
}
.box {
position: relative;
flex: 1 0 0;
color: $color-white;
display: flex;
align-items: center;
cursor: pointer;
background-color: #A68D71;
}
.box span {
display: block;
position: relative;
z-index: 11;
}
.box::after {
content: "";
position: absolute;
top: 0;
left: 0;
background-color: yellow;
width: 100%;
height: 0;
transition: height .3s;
}
.box:hover::after {
height: 100%;
transition: height .3s;
}
<div class="main__wrapper">
<section class="red">
</section>
<section class="green">
</section>
<section class="yellow">
</section>
<div class="slide__select">
<div class="redbox box">
<span>red</span>
</div>
<div class="greenbox box">
<span>green</span>
</div>
<div class="yellowbox box">
<span>yellow</span>
</div>
</div>
</div>
Here is a primitive example solution. It's overly verbose but shows you what is needed. This can be condensed.
To get an idea of how it can be condensed, all three listeners CAN be condensed into a single listener how you had it, listen just to the .box selector. But if you do that, you need a way to identify which box was clicked. This can be done via a data attribute or by looking at the html text. A data attribute would be my preferred method, as it separates the content from the logic a bit, but either would work.
Another less verbose solution:
window.onload = onPageLoad();
function onPageLoad() {
document.querySelector('.red').classList.add('active');
};
var boxes = document.querySelectorAll('.box');
for (var i = 0; i < boxes.length; i++) {
boxes[i].addEventListener('click', toggleSections);
}
var colors = ['red', 'green', 'yellow'];
function toggleSections(ev) {
var color = ev.currentTarget.innerText;
for (var c = 0; c < colors.length; c++) {
var colorElem = document.querySelector('.' + colors[c]);
if (colors[c] != color) {
colorElem.classList.remove('active');
} else {
colorElem.classList.add('active');
}
}
}
* {
padding: 0;
margin: 0;
}
.main__wrapper {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
.red,
.green,
.yellow {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2;
transform: translateX(-100%);
transition: transform 1.2s;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.yellow {
background-color: yellow;
}
.active {
transform: translateX(0) !important;
transition: transform 1s !important;
}
.slide__select {
position: absolute;
bottom: 0;
right: 0;
width: 60%;
height: 20%;
z-index: 10;
display: flex;
}
.box {
position: relative;
flex: 1 0 0;
color: $color-white;
display: flex;
align-items: center;
cursor: pointer;
background-color: #A68D71;
}
.box span {
display: block;
position: relative;
z-index: 11;
}
.box::after {
content: "";
position: absolute;
top: 0;
left: 0;
background-color: yellow;
width: 100%;
height: 0;
transition: height .3s;
}
.box:hover::after {
height: 100%;
transition: height .3s;
}
<div class="main__wrapper">
<section class="red">
</section>
<section class="green">
</section>
<section class="yellow">
</section>
<div class="slide__select">
<div class="box">
<span>red</span>
</div>
<div class="box">
<span>green</span>
</div>
<div class="box">
<span>yellow</span>
</div>
</div>
</div>
To achieve expected result, use below option
Use one section to avoid looping of section elements
Use querySelectorAll or elementsByClassName instead of querySelector to fetch all elements in array
Use forEach to loop through all elements of class- box and add addEventListener and run another loop with forEach for span elements
Use classList to add or remove
window.onload = onPageLoad();
function onPageLoad() {
document.querySelector('.red').classList.add('active');
};
// use querySelectorAll to get all elements of class-box and forEach to loop through
document.querySelectorAll('.box').forEach(function(ele){
//Add clici event through addEventListener
ele.addEventListener('click', function() {
// use another querySelectorAll to get all elements of tag span and forEach to loop through
document.querySelectorAll('span').forEach(function(e){
e.classList.remove('active');
//use querySelector for section element and empty classList to remove active and red/green/yellow class names
document.querySelector('section').className ='';
});
//toggle active class for clicked element
ele.children[0].classList.toggle("active");
//add active class for section
document.querySelector('section').classList.add('active');
//add class red/yellow/green using span innerHTML
document.querySelector('section').classList.add(ele.children[0].innerHTML);
});
});
* {
padding: 0;
margin: 0;
}
.main__wrapper {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
.red,
.green,
.yellow {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2;
transform: translateX(-100%);
transition: transform 1.2s;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.yellow {
background-color: yellow;
}
.active {
transform: translateX(0) !important;
transition: transform 1s !important;
}
.slide__select {
position: absolute;
bottom: 0;
right: 0;
width: 60%;
height: 20%;
z-index: 10;
display: flex;
}
.box {
position: relative;
flex: 1 0 0;
color: $color-white;
display: flex;
align-items: center;
cursor: pointer;
background-color: #A68D71;
}
.box span {
display: block;
position: relative;
z-index: 11;
}
.box::after {
content: "";
position: absolute;
top: 0;
left: 0;
background-color: yellow;
width: 100%;
height: 0;
transition: height .3s;
}
.box:hover::after {
height: 100%;
transition: height .3s;
}
<div class="main__wrapper">
<section class="red">
</section>
<div class="slide__select">
<div class="box">
<span>red</span>
</div>
<div class="box">
<span>green</span>
</div>
<div class="box">
<span>yellow</span>
</div>
</div>
</div>
code sample - https://codepen.io/nagasai/pen/vRoPwp