Is it possible, with the following Fiddle, to allow a user to create flash cards dynamically by inputting data into an <input> field?
Fiddle
If it's possible, it would be very much appreciated if a new fiddle could be provided, as I am new to coding.
Thank You!
$(function(){
var maxCards = $('.card').length;
// turn card
for (var i = 1; i <= maxCards; ++i) {
$('._' + i).click(function(){
$(this).addClass('flipped');
$(this).find('.front').addClass('showingBack');
$(this).find('.front').css("z-index", 0);
$(this).css("z-index", i);
});
}
// reset stack
$('#reset button').click(function(){
$('.card').removeClass('flipped');
$('.card').find('.front').removeClass('showingBack');
$('.card').find('.front').css("z-index", 2);
for (var j = 0; j < maxCards; ++j) {
$('.card:eq(' + j + ')').css("z-index", maxCards - j);
}
});
});
$(document).ready(function() {
var max_fields = 20; //maximum input boxes allowed
var wrapper = $(".input_fields_wrap"); //Fields wrapper
var add_button = $(".add_field_button"); //Add button ID
var x = 1; //initlal text box count
$(add_button).click(function(e){ //on add input button click
e.preventDefault();
if(x < max_fields){ //max input box allowed
x++; //text box increment
$(wrapper).append('<div><input placeholder="Question" type="text" name="mytext[]"/><input placeholder="Answer" type="text" name="mytext[]"/>Remove</div>'); //add input box
}
});
$(wrapper).on("click",".remove_field", function(e){ //user click on remove text
e.preventDefault(); $(this).parent('div').remove(); x--;
})
});
body {
background: #ccc;
font-family: Indie Flower, sans-serif;
}
#reset {
text-align: center;
}
#reset button {
background: rgba(0, 0, 0, 0.4);
border: 0;
color: white;
font-size: 12pt;
margin: auto;
width: 120px;
height: 30px;
}
#reset button:active {
background: rgba(0, 0, 0, 0.8);
}
#stack {
margin: auto;
position: relative;
width: 300px;
}
.card {
border: 1px solid #888;
position: absolute;
width: 300px;
height: 180px;
transform-origin: 0% 0%;
}
.card .front {
background: white;
font-size: 24pt;
position: absolute;
width: 300px;
height: 180px;
z-index: 2;
}
.card .front p {
line-height: 3em;
text-align: center;
}
.card .back {
background: white linear-gradient(transparent, transparent 20%, hotpink 20%, hotpink 21%, transparent 21%, transparent 31%, lightblue 31%, lightblue 32%, transparent 32%, transparent 42%, lightblue 42%, lightblue 43%, transparent 43%, transparent 53%, lightblue 53%, lightblue 54%, transparent 54%, transparent 64%, lightblue 64%, lightblue 65%, transparent 65%, transparent 75%, lightblue 75%, lightblue 76%, transparent 76%, transparent 86%, lightblue 86%, lightblue 87%, transparent 87%, transparent 97%);
font-size: 11pt;
position: absolute;
width: 300px;
height: 180px;
transform: rotateY(180deg);
z-index: 1;
}
.card .back p {
margin: 40px 5px 5px 5px;
}
._1 {
top: 0px;
right: 0px;
z-index: 3;
}
._2 {
top: 3px;
right: 2px;
z-index: 2;
}
._3 {
top: 6px;
right: 4px;
z-index: 1;
}
._4 {
top: 9px;
right: 6px;
z-index: 0;
}
.flipped {
transform: rotateY(180deg) translateX(30px);
animation: flip 1s;
}
.showingBack {
animation: showBack 1s;
}
#keyframes flip {
from {
transform: rotateY(0deg) translateX(0px);
}
to {
transform: rotateY(180deg) translateX(30px);
}
}
#keyframes showBack {
0% {
z-index: 2;
}
25% {
z-index: 2;
}
50% {
z-index: 0;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>
Import FlashCard Text Below:
</h2>
<div class="input_fields_wrap">
<button class="add_field_button">Add More Flash Cards</button>
<button>
Create Flash Cards
</button>
<div><input placeholder="Question" type="text" name="mytext[]"><input placeholder="Answer" type="text" name="mytext[]"/></div>
</div>
<hr>
<p id='reset'>
<button align="center">Reset stack</button>
</p>
<div id='stack'>
<div class='card _1'>
<div class='front'>
<p>What is 1+3?</p>
</div>
<div class='back'>
<p>4</p>
</div>
</div>
<div class='card _2'>
<div class='front'>
<p>What is 2-1?</p>
</div>
<div class='back'>
<p>1</p>
</div>
</div>
<div class='card _3'>
<div class='front'>
<p>What is Pi?</p>
</div>
<div class='back'>
<p>3.14...</p>
</div>
</div>
<div class='card _4'>
<div class='front'>
<p>What is 1/2?</p>
</div>
<div class='back'>
<p>0.5</p>
</div>
</div>
</div>
Here's a totally different way to create flash cards.
Flash card content goes into google drive sheets. Easy to use, easy to update. Then use Google's API to download the data in JSON format.
The code is as simple as putting this code in the body of your html file.
<script src="https://spreadsheets.google.com/feeds/list/XXXXXXXX/od6/public/full?alt=json-in-script&callback=useJSONdata"></script>
In the script portion of your site you would have:
function useJSONdata(root) {
console.log(JSON.stringify(root, null, 4));
// Understanding the object root is a great way to understand what is going on with JSON
var entries = root.feed.entry || []; .. etc.
Analyse the data you need, run a for loop, create a string of content to be pasted back into the Document Object Model / HTML / body.
Finally use jQuery mobile tools to create a mobile ready application. I used both their js and css files. Very nice. I made use of three mobile events “swipeleft” “swiperight” and “taphold”. Swipe left to go to next slide. Swipe right to go to previous slide. Long touch and hold to reveal answer to question.
I realize this wasn't exactly what you were asking for, and although an active input is nice, I'm thinking a spreadsheet format for a series of flash cards with data persistence (and the ability to do edits) is a pretty good way to go.
Related
I was trying to get started on one of my personal projects and I wanted to generate hexagons in a particular Pattern and each new row is generated depending on user input. I went through all the stackoverflow answers and everyone seems to make an entire grid or just svg pattern on the website directly. The problem for me is I want to animate each hexagon and need to access to each hexagon element. Is there a way to do this in CSS/HTML/JS or in general using some other language.
You can store the pattern into an array and then create the elements dynamically looping through that array.
Just create a container div and than create rows dynamically and put hexagons into rows and than append the row into container.
const container = document.querySelector('.container');
const hexagonPattern = [1, 2, 3, 4];
for (let i = 0; i < hexagonPattern.length; i++) {
const row = document.createElement('div');
row.classList.add('row');
for (let j = 0; j < hexagonPattern[i]; j++) {
const hexagon = document.createElement('div');
hexagon.classList.add('hexagon');
row.appendChild(hexagon);
}
container.appendChild(row);
}
.container {
display: flex;
flex-direction: column;
align-items: center;
}
.row {
margin-bottom: -30px;
}
.hexagon {
display: inline-block;
box-shadow: 10px 10px 5px #000;
width: 100px;
height: 100px;
background: grey;
-webkit-clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
transition: .7s;
margin: 2px;
}
.hexagon:hover {
background: red;
transform: rotateY(-180deg);
transition: .7s;
}
<div class="container">
</div>
Here is a demo from the article I wrote: https://css-tricks.com/hexagons-and-beyond-flexible-responsive-grid-patterns-sans-media-queries/
It's responsive Octagon grid. Run it on full screen to see the pyramidal grid that will fallback to a normal one on small screen. I invite you to read the above article to understand the technical detail behind this technique.
All you have to do is to adjust the variables to get your hexagon grid:
let inputs = document.querySelectorAll('input[type=range]')
let elem = document.querySelector('.main')
inputs.forEach(input => {
input.addEventListener('change', function(e) {
var p = e.target.getAttribute('name');
if(p=="s" || p=="mv") {
elem.style.setProperty("--"+p, this.value+"px");
e.target.previousElementSibling.innerHTML = this.value+"px";
} else {
elem.style.setProperty("--"+p, this.value);
e.target.previousElementSibling.innerHTML = this.value;
}
});
});
.main {
display:flex;
--s: 100px; /* size */
--r: 1; /* ratio */
/* clip-path */
--h: 0.25;
--v: 0.35;
--hc:calc(clamp(0,var(--h),0.5) * var(--s)) ;
--vc:calc(clamp(0,var(--v),0.5) * var(--s) * var(--r));
/*margin */
--mv: 4px; /* vertical */
--mh: calc(var(--mv) + (var(--s) - 2*var(--hc))/2); /* horizontal */
/* for the float*/
--f: calc(2*var(--s)*var(--r) + 4*var(--mv) - 2*var(--vc) - 2px);
--nr:6;
--lw:calc(var(--nr)*(var(--s) + 2*var(--mh)));
}
.container {
font-size: 0; /*disable white space between inline block element */
max-width:var(--lw);
margin:0 auto;
}
.container div {
width: var(--s);
margin: var(--mv) var(--mh);
height: calc(var(--s)*var(--r));
display: inline-block;
font-size:initial;
clip-path: polygon(var(--hc) 0, calc(100% - var(--hc)) 0,100% var(--vc),100% calc(100% - var(--vc)), calc(100% - var(--hc)) 100%,var(--hc) 100%,0 calc(100% - var(--vc)),0 var(--vc));
background: red;
margin-bottom: calc(var(--mv) - var(--vc));
}
.container div:nth-child(odd) {
background:green;
}
.container::before {
content: "";
width: clamp(0px, (var(--lw) - 100%)*1000,calc(var(--s)/2 + var(--mh)));
float: left;
height: 120%;
shape-outside: repeating-linear-gradient(#0000 0 calc(var(--f) - 3px),#000 0 var(--f));
}
.container i::before ,
.container i::after{
content: "";
width: clamp(0px, (100% - var(--lw) + 1px)*1000,calc(50% - var(--mh) - var(--s)/2));
float: left;
height: calc(var(--f)*(var(--nr) - 1)/2);
shape-outside: linear-gradient(to bottom right,#000 50.5%,#0000 0);
}
.container i::after {
float:right;
shape-outside: linear-gradient(to bottom left,#000 49%,#0000 0);
}
.panel {position: fixed;top: 20px;right: 20px;padding: 10px;border: 1px solid;border-radius: 10px;background: #fff;font-family: sans-serif;opacity:.5}
.panel:hover {opacity:1}
.panel > div:not(:last-child) {border-bottom: 1px solid;padding-bottom: 10px;margin-bottom: 10px;}
*,*::before {transition:0.5s linear}
<div class="main">
<div class="container">
<i></i>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
<div class="panel">
<div>Size: [<span>100px</span>] <input type="range" min="20" max="200" step="10" value="100" name="s"></div>
<div>Ratio: [<span>1</span>] <input type="range" min="0" max="2" step="0.05" value="1" name="r"></div>
<div>Spacing: [<span>4px</span>]<input type="range" min="0" max="10" step="1" value="4" name="mv"></div>
<div>Clip-path<br>
hc: [<span>0.25</span>]<input type="range" min="0" max=".5" step=".05" value=".25" name="h"><br>
vc: [<span>0.35</span>]<input type="range" min="0" max=".5" step=".05" value=".35" name="v"></div></div>
You can use a combination of CSS clip paths and a basic understanding of geometry to get the position right. Assuming that you want to define the width of an individual hexagon, then the ratio of height to width is 1.157... (2 / Math.sqrt(3) to be precise), but we round it to 1.2 for ease of calculation.
The CSS clip path for a hexagon (with the long diagonal being vertical) is:
clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
Then it's a matter of applying these calculations to get the right layout. I have used CSS custom properties in the example below, so you can adjust the placement when necessary.
.stage {
--cell-width: 100px;
--cell-height: calc(var(--cell-width) * 1.2);
--cell-spacing: 4px;
padding-top: calc(var(--cell-width) * 0.25);
padding-bottom: calc(var(--cell-width) * 0.25);
background-color: #ddd;
}
.row {
display: flex;
justify-content: center;
margin-top: calc(var(--cell-width) * -0.27 + var(--cell-spacing));
margin-bottom: calc(var(--cell-width) * -0.27 + var(--cell-spacing));
}
.cell {
clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
background-color: steelblue;
width: var(--cell-width);
height: var(--cell-height);
margin-left: var(--cell-spacing);
margin-right: var(--cell-spacing);
}
<div class="stage">
<div class="row">
<div class="cell"></div>
</div>
<div class="row">
<div class="cell"></div>
<div class="cell"></div>
</div>
<div class="row">
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
</div>
<div class="row">
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
</div>
</div>
You can make an element into a hexagon shape by using clip-path polygon.
Then on user input you can create however many hexagons you want and lay them side by side in a new row.
This snippet is a simplified version, it creates a hexagon on a click and puts it in a row.
It uses CSS variable to define the length of the side of the hexagon so it is easy for you to change.
const row = document.querySelector('.row');
function createHexagon() {
const hexagon = document.createElement('div');
hexagon.classList.add('hexagon');
return hexagon;
}
.hexagon {
--sin30: 0.5;
--side: 10vmin;
--x: calc(var(--side) * var(--sin30));
background-color: gray;
clip-path: polygon(var(--x) 0, calc(100% - var(--x)) 0, 100% 50%, calc(100% - var(--x)) 100%, var(--x) 100%, 0% 50%);
width: calc(2 * var(--side));
height: calc(2 * var(--side));
display: inline-block;
margin: 1vmin;
}
<div class="row"></div>
<button onclick="row.appendChild(createHexagon());">Click to add a hexagon</button>
Hello StackOverFlowers!
I found this really awesome animation on jsfiddle.net and would really love to use it in my project.
I'f you follow the link the author, 'internoma', states that it can be used as a page transition if a little Ajax is added.
My question is: What Ajax code do I add in order to make this work?!
I'm extremely lost, any suggestions will be greatly appreciated.
If you happen to know how to make this working using Barba.js or smoothState.js that would be awesome also since those are to plugins I'd like to dive deeper in learning.
Thanks in advance!
Link: Material Design Ripple Transition
JavaScript:
$(document).ready(function() {var ripple_wrap = $('.ripple-wrap'),
rippler = $('.ripple'),
finish = false,
monitor = function(el) {
var computed = window.getComputedStyle(el, null),
borderwidth = parseFloat(computed.getPropertyValue('border-left-width'));
if (!finish && borderwidth >= 1500) {
el.style.WebkitAnimationPlayState = "paused";
el.style.animationPlayState = "paused";
swapContent();
}
if (finish) {
el.style.WebkitAnimationPlayState = "running";
el.style.animationPlayState = "running";
return;
} else {
window.requestAnimationFrame(function() {monitor(el)});
}
};
storedcontent = $('#content-2').html();
$('#content-2').remove();
rippler.bind("webkitAnimationEnd oAnimationEnd msAnimationEnd
mozAnimationEnd animationend", function(e){
ripple_wrap.removeClass('goripple');
});
$('body').on('click', 'a', function(e) {
rippler.css('left', e.clientX + 'px');
rippler.css('top', e.clientY + 'px');
e.preventDefault();
finish = false;
ripple_wrap.addClass('goripple');
window.requestAnimationFrame(function() {monitor(rippler[0])});
});
function swapContent() {
var newcontent = $('#content-area').html();
$('#content-area').html(storedcontent);
storedcontent = newcontent;
// do some Ajax, put it in the DOM and then set this to true
setTimeout(function() {
finish = true;
},10);
}
});
CSS
.ripple-wrap {
display: none;
overflow: hidden;
position: fixed;
font-size: 0;
z-index: 1000;
top: 0; left: 0; right: 0; bottom: 0;
}
#-webkit-keyframes RIPPLER {
0% { border-width: 0; }
40% {
height: 0;
width: 0;
border-width: 1500px;
margin-top: -1500px;
margin-left:-1500px;
border-color: #009688;
}
41% {
height: 0;
width: 0;
border-width: 1500px;
margin-top: -1500px;
margin-left:-1500px;
border-color: #009688;
}
100% {
border-width: 1500px;
height: 2000px;
width: 2000px;
margin-top: -2500px;
margin-left:-2500px;
border-color: #009688;
}
}
#keyframes RIPPLER {
0% { border-width: 0; }
40% {
height: 0;
width: 0;
order-width: 1500px;
margin-top: -1500px;
margin-left:-1500px;
border-color: #009688;
}
41% {
height: 0;
width: 0;
border-width: 1500px;
margin-top: -1500px;
margin-left:-1500px;
border-color: #009688;
}
100% {
border-width: 1500px;
height: 2000px;
width: 2000px;
margin-top: -2500px;
margin-left:-2500px;
border-color: #009688;
}
}
.ripple {
display: block;
height: 0;
width: 0;
border-width: 0px;
border-style: solid;
border-color: #00796b;
border-radius: 100%;
position: absolute;
top: 300px;
left: 300px;
-webkit-animation: none;
animation: none;
}
.ripple-wrap.goripple {
display: block;
}
.ripple-wrap.goripple .ripple {
-webkit-animation-name: RIPPLER;
-webkit-animation-duration: 1.5s;
-webkit-animation-fill-mode: forwards;
animation-name: RIPPLER;
animation-duration: 1.5s;
animation-fill-mode: forwards;
}
HTML
<div class="wrap" id="content-area">
<h1>Material Design Ripple Transition</h1>
<p>Just playing around to see if I can recreate the Material Design
ripple as a page transition in CSS. Click any link in
this block of text to load another set of text. The links don't go anywhere yet. They are just hooks to allow you to click somewhere</p>
<p>The style and animation is entirely CSS so it is smooth. JavaScript
is used to add classes at the right time. It also pauses to wait for the
content to be replaced, and calculates where to centre the hole. There
are two stages to the animation. When a link is clicked
the border-width grows very large.</p>
<p>That's enough reading on this slide. Click a link to
load the second slide</p>
</div>
<div id="content-2" style="display:none">
<h2>Slide Two</h2>
<p>This is the second slide. If you want you can <a href="#">go back to
the first slide</a>. The second part of the animation is increasing the
size of the element itself in order to create a hole.</p>
<p>This transition could be used for presentation slides. Using
pushState then this could be used as a transition between webpages.</p>
</div>
<div class="ripple-wrap"><div class="ripple"></div></div>
i want to make it so that when you hover over an element, it's always darker or lighter than it initially was. regardless of the color
something like this but universal
.darker{
Background:red;
width:100px;
height:100px
}
.darker:hover{
Background:#b20000
}
.lighter {
Background:blue;
width:100px;
height:100px
}
.lighter:hover{
Background:#adccff
}
<div class='darker'></div>
<div class='lighter'></div>
You're looking for the brightness CSS filter:
The brightness() CSS function applies a linear multiplier to the input image, making it appear brighter or darker
div {
width: 50px;
height: 50px;
background: red;
filter: brightness(1);
}
.light-on-hover:hover {
filter: brightness(5.00);
}
.dark-on-hover:hover {
filter: brightness(0.5);
}
<h5> Darker on hover </h5>
<div class="dark-on-hover"></div>
<h5> Lighter on hover </h5>
<div class="light-on-hover"></div>
There is one way to do it by adding a pseudo element as an overlay
See code snippet
div {
position: relative;
display: inline-block;
color: white;
font-size: 18px;
padding: 50px;
}
div > * {
position: relative;
z-index: 2;
}
div.red {
background: red;
}
div.green {
background: green;
}
div.blue {
background: blue;
}
div:after {
content: '';
display: inline-block;
background: black;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
z-index: 1;
}
div:hover::after {
opacity: .3;
}
<div class="red"><span>text</span></div>
<div class="green">link</div>
<div class="blue"><button>button</button></div>
You can consider multiple background and some CSS variable like below. The idea is to either add some white or black color on the top by adjusting background-size
.color {
background:
linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)),
linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.5)),
linear-gradient(var(--c, red), var(--c, red));
background-size: 0 0, 0 0, auto;
width: 100px;
height: 100px;
display:inline-block;
}
.darker:hover {
background-size:auto,0 0,auto;
}
.lighter:hover {
background-size:0 0,auto,auto;
}
.blue {
--c:blue;
}
.green {
--c:green;
}
.yellow {
--c:yellow;
}
.pink{
--c:pink;
}
<div class='color darker blue'></div>
<div class='color lighter blue'></div>
<div class='color lighter red'></div>
<div class='color darker red'></div>
<div class='color darker green'></div>
<div class='color lighter yellow'></div>
<div class='color darker pink'></div>
Hmmm, I can imagine two options
1) use an element inside the button and set a background for that element with some opacity like this https://codepen.io/anon/pen/WLNbPG (it's a bit hacky though)
<button id='button1'><span>Darker</span></button>
<button id='button2'><span>Lighter</span></button>
and the CSS
button {
border: 0;
background-color: red;
padding: 0;
}
button span {
display: block;
padding: 1em
}
#button1:hover span {
background-color: rgba(0,0,0,.4);
}
#button2:hover span {
background-color: rgba(255,255,255,.4);
}
That way the span background with it's opacity can make the effect of makign the background of the button darker or lighter.
2) use an image as the button background and, on hover, add a color with alpha values and use background-blend-mode: darken/lighten https://developer.mozilla.org/en-US/docs/Web/CSS/background-blend-mode but it doesn't have good support for Edge or Android's webviews.
I don't think you're explaining what you want to do clearly. My solution below answers the question you posed in this sentence:
"I wanna assign some background to the button element...and I want to make it so that when you add class names get-darker or get-lighter and hover over the button, it changes its color to the darker/lighter one."
<!DOCTYPE html>
<html lang="en-us">
<head>
<style>
button {
background-color: red;
padding: 20px;
margin: 20px;
}
button:hover.get-darker {
background-color: darkslategray;
}
button:hover.get-lighter {
background-color: gray;
}
</style>
</head>
<body>
<button class="get-darker">
this button will get darker
</button>
<button class="get-lighter">
this button will get lighter
</button>
</body>
</html>
You can use opacity to make it like:-
div{
Background:rgba(255, 0, 0, 0.8);
width:200px;
height:200px
}
div:hover{
Background:rgba(255, 0, 0, 1)
}
<div></div>
I've been trying to create the following animation:
(1) I have a button consisting of a white 100x100 box on top of a black 100x100 box.
(2) Clicking on the button makes the white box disappear into the black box.
(see the result here)
// html
<div class="button">
<div class="white u-on-top"></div>
<div class="black"></div>
</div>
// css
.button {
width: 100px;
height: 100px;
margin: 10px;
position: relative;
display: inline-block;
.white {
width: 100%;
height: 100%;
background: #fff;
border: 1px solid #000;
position: absolute;
transition: .5s;
}
.black {
width: 100%;
height: 100%;
background: #000;
border: 1px solid #000;
}
}
.u-on-top {
z-index: 1;
}
.u-at-bottom {
z-index: -1;
}
// javascript
var btn = document.querySelector(".button");
var btnState = false;
btn.addEventListener("click", () => {
var btnw = btn.querySelector(".white");
if (!btnState) {
btnw.style.transform = "scale(0)";
btnState = true;
} else {
btnw.style.transform = "scale(1)";
btnState = false;
}
})
(3) What I've unsuccessfully been trying to do is to also make the black box disappear into the white box when clicked on.
So:
clicking on the white box makes it disappear into the black box
clicking on the black box makes it disappear into the white box
clicking on the white box makes it disappear into the black box
And so on...
My idea was to obtain the effect by modifying the z-index of the boxes when clicked on, using the utility classes u-on-top and u-at-bottom (eg the black box is brought to the top after the white box disappears), but I got some weird results.
You can try to adjust some transition, the trick is to add a delay to z-index so it changes after the scale effect. I have also change the JS code and reduced the CSS:
var btnW = document.querySelector(".white");
var btnB = document.querySelector(".black");
var btnState = false;
btnW.addEventListener("click", () => {
btnB.classList.remove('hide');
btnW.classList.add('hide');
btnW.classList.remove('u-on-top');
btnB.classList.add('u-on-top');
})
btnB.addEventListener("click", () => {
btnW.classList.remove('hide');
btnB.classList.add('hide');
btnB.classList.remove('u-on-top');
btnW.classList.add('u-on-top');
})
.button {
width: 100px;
height: 100px;
margin: 10px;
position: relative;
display: inline-block;
cursor: pointer;
}
.button>div {
width: 100%;
height: 100%;
border: 1px solid #000;
position: absolute;
transition: transform 0s, z-index 0s 0.5s;
z-index:0;
}
.button .white {
background: #fff;
}
.button .black {
background: #000;
}
.button>div.hide {
transform:scale(0);
transition: transform .5s, z-index 0s 0.5s;
}
.button>div.u-on-top {
z-index:1;
}
<div class="button">
<div class="white u-on-top"></div>
<div class="black"></div>
</div>
I am a beginner and I'd like to know if it's possible to create a responsive slider with autoplay(fade or slide effect, no matters) and next and previous arrows for navigation without affecting the autoplay, just to change from one slide to another.
I've already tried with multiple js solutions I found on the net like "setinterval" function with javascript, but I have always the same problem, one effect works and not the other.
Actually I've done a slider in html and css but I can't get this done by adding a javascript function.
I am open to all the solutions, even if it is possible only with js.
I'm following a course right now and that is part of a project.
could it be done??
Thank you in advance!
/*progress bar effect*/
#keyframes loading {
0% {
transform: scaleX(0);
}
100% {
transform: scaleX(100%);
}
}
/*autoplay effect*/
#keyframes fade {
0% {
opacity: 1
}
45% {
opacity: 1
}
50% {
opacity: 0
}
95% {
opacity: 0
}
100% {
opacity: 1
}
}
#keyframes fade2 {
0% {
opacity: 0
}
45% {
opacity: 0
}
50% {
opacity: 1
}
95% {
opacity: 1
}
100% {
opacity: 0
}
}
/*Section slider*/
.slider {
width: 100%;
height: 550px;
margin: 20px auto;
position: relative;
}
.slide1,
.slide2 {
position: absolute;
width: 100%;
height: 100%;
}
.slide1 {
background: url('images/bg1.jpg') no-repeat center;
background-size: cover;
animation: fade 30000s infinite linear;
-webkit-animation: fade 30000s infinite linear;
}
.slide2 {
background: url('images/bg2.jpg') no-repeat center;
background-size: cover;
animation: fade2 30000ms infinite linear;
-webkit-animation: fade2 30000ms infinite linear;
}
/*progress bar*/
.progress-bar {
position: absolute;
bottom: -76px;
left: 0px;
height: 80px;
width: 100%;
background: color: rgba(192, 194, 192, 0.8);
border-radius: 0 0 1px 1px;
box-shadow: inset 0px 11px 14px -10px #737373, inset 0px -11px 8px -10px #CCC;
}
.loaded {
height: 4px;
width: 100%;
background: #5cadd3;
animation: 15000ms infinite linear loading normal;
transform-origin: 0%;
}
/*Slider buttons left or right*/
.slider #button_left {
position: absolute;
top: 45%;
left: 0px;
background-color: rgba(70, 70, 70, 0.6);
width: 35px;
height: 70px;
border-radius: 0px 50px 50px 0px;
}
.slider #button_right {
position: absolute;
top: 45%;
right: 0px;
background-color: rgba(70, 70, 70, 0.6);
width: 35px;
height: 70px;
border-radius: 50px 0px 0px 50px;
}
#button_left:hover,
#button_right:hover {
transition: .3s;
background-color: rgba(99, 99, 99, 1);
color: #ffffff;
}
/*left and right arrows for slider with font-awesome*/
.fas.fa-chevron-left {
position: absolute;
left: 0;
top: 30%;
margin-left: 5px;
color: #fff;
font-size: 25px;
}
.fas.fa-chevron-right {
position: absolute;
right: 0;
top: 30%;
margin-right: 5px;
color: white;
font-size: 25px;
}
<section id="slideshow">
<div class='slider'>
<div class='slide1'>
<div class="text-slider">
<h1><span class="textblue">WEBAGENCY</span>: lorem ipsum <br> lorem ipsum</h1>
<p> lorem ipsum</p>
lorem ipsum
</div>
</div>
<div class='slide2'>
<div class="text-slider">
<h1><span class="textblue">WEBAGENCY</span>: lorem ipsum <br> lorem ipsum</h1>
<p> lorem ipsum</p>
lorem ipsum
</div>
</div>
<!--<div class="progress-bar"></div>-->
<div class="progress-bar">
<div class="loaded"></div>
</div>
<i class="fas fa-chevron-left"></i>
<i class="fas fa-chevron-right"></i>
</div>
</section>
No need for a lib or framework to do that.
So, i already have to do this, it's not as complicated as it seems.
First, i used css pseudo class :checked and input type radio to choose which slide to display:
<div id="slider">
<input type="radio" name="slider" checked> <!-- The first slide is displayed by default -->
<div class="slide">...</div>
<input type="radio" name="slider">
<div class="slide">...</div>
...
<div class="prev-button">prev</div>
<div class="next-button">next</div>
</div>
And a bit of css :
#slider > .slide,
#slider > input[type="radio"]{
display:none;
}
#slider > input[type="radio"]:checked + .slide{display:block;}
Then, it should be simpler with js:
window.addEventListener("load",function(){
let timer; let delay = 4000;
let loader = document.querySelector("#slider .loader");
let inputs = Array.from(document.querySelectorAll('#slider > input[type="radio"]'));
//first, the go function that choose which input to check
let go = (prev=false)=>{
let checked = document.querySelector('#slider > input[type="radio"]:checked');
let index = inputs.indexOf(checked);
let next = ((prev) ? index -1 : index + 1);
if(next >= inputs.length) next = 0; //restart from beginning
else if(next < 0 ) next = inputs.length -1; //go to the last slide
//restart the progress bar
loader.classList.remove("loader");
loader.classList.add("loader");
inputs[next].checked = true;
};
//Allow you to define some sort of recursive timeout, otherwise it works only once
let defineTimer = (callback)=>{
timer = setTimeout(()=>{
callback();
defineTimer(callback);
},delay);
};
//next, autoplay :
defineTimer(go);
//next, buttons:
let next = document.querySelector("#slider > .next-button");
let prev = document.querySelector("#slider > .prev-button");
//clear the timer with `clearTimeout` each time you click on a button, if you don't
//and the user click on a button 3900ms after the autoplay call, the next/prev slide will only be displayed
//for 100ms and then switch to the next, which can be disturbing for the user.
next.addEventListener("click",()=>{
go();
clearTimeout(timer);
defineTimer(go);
});
prev.addEventListener("click",()=>{
go(true);
clearTimeout(timer);
defineTimer(go);
});
});
Why it should works :
Every time the go function is called, it will select the next or previous input to check, accordingly to the currently checked one. So you can call it from the timer or not, it doesn't makes any difference.
Hope it answer your question :)