With Swiper.js, navigation via bullets sometimes doesn't go to correct slide - swiper.js

I'm using swiper.js in my project and sometimes (maybe 1 out of 10 times), navigation by clicking the associated bullet does not work - it instead goes to the previous slide. My swiper config object does contain clickable: true for the pagination.

Check this code. I think someone had the same problem here
HTML
<h1>Swipe 2</h1>
<div id='slider' style='max-width:500px;margin:0 auto' class='swipe'>
<div class='swipe-wrap'>
<div><b>1</b></div>
<div><b>2</b></div>
<div><b>3</b></div>
</div>
</div>
<div class="counter content" style='text-align:center;padding-top:20px;'>
<ul id='position'>
<li class="on"></li>
<li ></li>
<li ></li>
</ul>
</div>
<div style='text-align:center;padding-top:20px;'>
<button onclick='slider.prev()'>prev</button>
<button onclick='slider.next()'>next</button>
</div>
<script src='swipe.js'></script>
CSS
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, del, dfn, em, img, ins, kbd, q, samp, small, strong, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, table, tbody, tfoot, thead, tr, th, td, article, aside, footer, header, nav, section {
margin:0;
padding:0;
border:0;
outline:0;
font-size:100%;
vertical-align:baseline;
background:transparent;
}
body {
-webkit-text-size-adjust:none;
font-family:sans-serif;
min-height:416px;
}
h1 {
font-size:33px;
margin:50px 0 15px;
text-align:center;
color:#212121;
}
h2 {
font-size:14px;
font-weight:bold;
color:#3c3c3c;
margin:20px 10px 10px;
}
small {
margin:0 10px 30px;
display:block;
font-size:12px;
}
a {
margin:0 0 0 10px;
font-size:12px;
color:#3c3c3c;
}
html, body {
background: #f3f3f3;
}
#console {
font-size: 12px;
font-family:"Inconsolata", "Monaco", "Consolas", "Andale Mono", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
color: #999;
line-height: 18px;
margin-top: 20px;
max-height: 150px;
overflow: auto;
}
#slider div b {
display:block;
font-weight:bold;
color:#14ADE5;
font-size:20px;
text-align:center;
margin:10px;
padding:100px 10px;
box-shadow: 0 1px #EBEBEB;
background: #fff;
border-radius: 3px;
border: 1px solid;
border-color: #E5E5E5 #D3D3D3 #B9C1C6;
}
.swipe {
overflow: hidden;
visibility: hidden;
position: relative;
}
.swipe-wrap {
overflow: hidden;
position: relative;
}
.swipe-wrap > div {
float:left;
width:100%;
position: relative;
}
.counter {
height: 55px;
ul {
text-align: center;
li {
// padding: 5px;
display: inline-block;
height: 10px;
width: 10px;
border: solid 2px #404041;
border-radius: 10px;
margin: 2.5px;
&.on {
background: #404041;
}
}
}
}
JAVASCRIPT
var elem = document.getElementById('slider');
var slider =
Swipe(document.getElementById('slider'), {
auto: 10000,
continuous: true,
callback: function(pos) {
var i = bullets.length;
while (i--) {
bullets[i].className = ' ';
}
bullets[pos].className = 'on';
}
});
var bullets = document.getElementById('position').getElementsByTagName('li');
$('li').on('click', function(event){
event.preventDefault();
var index = $("li").index(event.currentTarget);
slider.slide(index);
});
// with jQuery
// window.mySwipe = $('#mySwipe').Swipe().data('Swipe');

Related

Cannot set Axios properly with Vue 2 and Nuxt

I am quite new to vue.js, using vue 2 and nuxt.js. I am trying to build an authentication in a website. There is a backend api running in local.
I have a form that receives my user's data. The data is then stored in the store using vuex. I want to make a POST Api call using axios, which retrieves the data stored from the store to the API running localy.
Unfortunately, I cannot get axios to run this properly...
It seems that the sendData function cant have access to the store. I tried many things : this.$store.user, this.user, $store...
Thanks a lot for your help!
4th Component
<template>
<form class="form-horizontal" >
<!-- firstname input-->
<div class="field">
<label class="label" for="contact_first_name">Prénom</label>
<div class="control">
<input id="contact_first_name" name="contact_first_name" type="contact_first_name" placeholder="Prénom" class="input " required="" v-model="companycontact.contact_first_name">
</div>
</div>
<!-- name input-->
<div class="field">
<label class="label" for="contact_last_name">Nom</label>
<div class="control">
<input id="contact_last_name" name="contact_last_name" type="contact_last_name" placeholder="Nom" class="input " required="" v-model="companycontact.contact_last_name">
</div>
</div>
<!-- service choice -->
<div class="field">
<label class="label" for="Service">Service</label>
<div class="control">
<div class="formfield-select">
<select id="service-choice" name="service-choice" class="input" v-model="companycontact.contact_service">
<option v-for="(service, index) in services" :key="index" :value="service.value">
{{ service.text }}
</option>
</select>
</div>
</div>
<div class="next-back-button">
<nuxt-link to="/SignUpCompanyOnline" class="button is-rounded back-button" #click.native="saveStore()">Retour</nuxt-link>
<nuxt-link to="/SignUpCompanyIg" class="button is-rounded next-button" #click.native="saveStore(); sendData()">Suivant</nuxt-link>
</div>
</div>
</form>
</template>
<script>
export default {
name: 'SignUpCompanyContact',
data () {
return {
companycontact: {
contact_first_name: this.contact_first_name,
contact_last_name: this.contact_last_name,
services: this.services,
},
services: [
{ text: 'Communication', value: 'COM' },
{ text: 'Direction', value: 'DIR' },
{ text: 'Marketing', value: 'MAR' },
{ text: 'Autre', value: 'OTH' },
],
}
},
methods: {
saveStore() {
this.$store.commit('signUp/setContactServiceInsta', { companycontact: this.companycontact })
},
async sendData () {
// console.log(this.user.email)
// console.log(this.$store.user.email)
// console.log(user.email)
// console.log($store)
/* let data = {
email: this.user.email,
password: this.password,
nb_employees: this.numberemployee,
name: this.name,
insta_account: this.insta_account,
sale_type: this.option,
sector_type: this.sector,
website_url: this.website_url,
contact_first_name: this.contact_first_name,
contact_last_name: this.contact_last_name,
contact_service: this.contact_service
}
// console.log(data);
this.$axios.post('http://localhost:8000/api/companies/', data )
.then(response => console.log(response))
.catch(error => console.log(error.response)) */
}
}
}
</script>
<style>
.form-example {
padding-bottom: 20px;
}
.form-logo{
width: 30px;
height: 30px;
border-bottom:2px solid #D8D8D8;
}
input {
width: 300px;
}
input[placeholder] {
width: 300px;
}
/* contact firstname lastname */
input[type=contact_last_name] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
box-sizing: border-box;
border: none;
border-bottom: 2px solid #D8D8D8;
background-image: url(../../assets/icons/user-lightgrey.svg);
background-size: 30px;
background-position-y: 4px;
background-repeat: no-repeat;
text-indent: 20px;
}
input[type=contact_last_name]:focus {
border-bottom: 2px solid #7F7F7F;
outline: none;
background-image: url(../../assets/icons/user-darkgrey.svg);
-webkit-box-shadow: 0px 14px 8px -8px rgba(0,0,0,0.40);
-moz-box-shadow: 0px 14px 8px -8px rgba(0,0,0,0.40);
box-shadow: 0px 14px 8px -8px rgba(0,0,0,0.40);
transition-duration: .3s;
border-radius: 1px;
}
input[type=contact_first_name] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
box-sizing: border-box;
border: none;
border-bottom: 2px solid #D8D8D8;
background-image: url(../../assets/icons/user-lightgrey.svg);
background-size: 30px;
background-position-y: 4px;
background-repeat: no-repeat;
text-indent: 20px;
}
input[type=contact_first_name]:focus {
border-bottom: 2px solid #7F7F7F;
outline: none;
background-image: url(../../assets/icons/user-darkgrey.svg);
-webkit-box-shadow: 0px 14px 8px -8px rgba(0,0,0,0.40);
-moz-box-shadow: 0px 14px 8px -8px rgba(0,0,0,0.40);
box-shadow: 0px 14px 8px -8px rgba(0,0,0,0.40);
transition-duration: .3s;
border-radius: 1px;
}
/* service */
#service-choice {
padding-left: 20px !important;
margin: 8px 0;
box-sizing: border-box;
color: #4A4A4A !important;
border: 1px solid #fff !important;
border-bottom: 2px solid #D8D8D8 !important;
background-image: url(../../assets/icons/sector-lightgrey.svg);
background-size: 30px;
background-repeat: no-repeat;
text-indent: 20px;
outline: none !important;
}
#service-choice:focus {
border-bottom: 2px solid #7F7F7F;
outline: none;
color: #4A4A4A !important;
background-image: url(../../assets/icons/sector-darkgrey.svg);
border-radius: 1px;
}
/* submit button */
.submit-button {
text-decoration: none;
outline: none;
background-color: #00CC99;
border: 1px solid #00CC99;
font-size: 20px;
color: #fff;
font-weight: normal;
padding: 10px 20px;
margin-top: 40px;
font-family: 'Montserrat', sans-serif;
-webkit-box-shadow: 0px 0px 44px -9px rgba(0,0,0,0.40);
-moz-box-shadow: 0px 0px 44px -9px rgba(0,0,0,0.40);
box-shadow: 0px 0px 44px -9px rgba(0,0,0,0.40);
}
.submit-button:hover {
background-color: #fff;
border: 1px solid #00CC99;
color: #00CC99;
transition: background-color .3s;
}
/* next button / back button */
.next-back-button {
display: flex;
justify-content: space-evenly;
flex-direction: row;
width: 50%;
}
.next-button {
text-decoration: none;
outline: none;
background-color: #00CC99;
border: 1px solid #00CC99;
font-size: 20px;
color: #fff;
font-weight: normal;
padding: 10px 20px;
margin-top: 40px;
font-family: 'Montserrat', sans-serif;
}
.next-button:hover {
background-color: #fff;
border: 1px solid #00CC99;
color: #00CC99;
transition: background-color .3s;
}
.back-button {
text-decoration: none;
outline: none;
background-color: #ffffff;
border: 1px solid #D8D8D8;
font-size: 20px;
color: #D8D8D8;
font-weight: normal;
padding: 10px 20px;
margin-top: 40px;
font-family: 'Montserrat', sans-serif;
outline: none;
}
.back-button:hover {
background-color: #fff;
border: 1px solid #999999;
color: #999999;
transition: background-color .3s;
}
</style>
VUEX store :
export const state = () => ({
user: {},
company: {},
companydetails: {},
companycontact: {},
validationcode: {},
})
export const mutations = {
setEmailPassword(state, { user }) {
console.log(user)
state.user.email = user.email
state.user.password = user.password
},
setCompanyEmployeeInsta(state, { company }) {
console.log(company)
state.company.name = company.name
state.company.insta_account = company.insta_account
state.company.selected = company.selected
},
setWebsiteCanalSector(state, { companydetails }) {
console.log(companydetails)
state.companydetails.website_url = companydetails.website_url
state.companydetails.option = companydetails.option
state.companydetails.sector = companydetails.sector
},
setContactServiceInsta(state, { companycontact }) {
console.log(companycontact)
state.companycontact.contact_first_name = companycontact.contact_first_name
state.companycontact.contact_last_name = companycontact.contact_last_name
state.companycontact.contact_service = companycontact.contact_service
},
setValidationCode(state, { validationcode }) {
console.log(validationcode)
state.validationcode.contact_first_name = validationcode.contact_first_name
},
}

vue.js, vuetify scroll event not firing when using css scroll snap

UPDATE dropped this approach and went with vue-awesome-swiper script
I"m been stuck on this for days. Basically I want to use css scroll snap and I want to monitor scroll also.
In this basic example with just javascript it works fine scroll event fires and div snaps with css. The other pen below with vue.js does not and that is my problem. Losing hair about this... any help appreciated!
https://codepen.io/travis-pancakes/pen/pGYOZK?editors=0011
var i = 0;
function Onscrollfnction(event) { document.getElementById("demo").innerHTML = i;
i = i + 1;
};
/* setup */
html, body, .holster {
height: 100%;
}
.holster {
display: flex;
align-items: center;
justify-content: space-between;
flex-flow: column nowrap;
font-family: monospace;
}
.container {
display: flex;
overflow: auto;
outline: 1px dashed lightgray;
flex: none;
}
.container.x {
width: 100%;
height: 128px;
flex-flow: row nowrap;
}
.container.y {
width: 256px;
height: 256px;
flex-flow: column nowrap;
}
/* scroll-snap */
.x.mandatory-scroll-snapping {
scroll-snap-type: x mandatory;
}
.y.mandatory-scroll-snapping {
scroll-snap-type: y mandatory;
}
.x.proximity-scroll-snapping {
scroll-snap-type: x proximity;
}
.y.proximity-scroll-snapping {
scroll-snap-type: y proximity;
}
.container > div {
text-align: center;
scroll-snap-align: center;
flex: none;
}
.x.container > div {
line-height: 128px;
font-size: 64px;
width: 100%;
height: 128px;
}
.y.container > div {
line-height: 256px;
font-size: 128px;
width: 256px;
height: 256px;
}
/* appearance fixes */
.y.container > div:first-child {
line-height: 1.3;
font-size: 64px;
}
/* coloration */
.container > div:nth-child(even) {
background-color: #87EA87;
}
.container > div:nth-child(odd) {
background-color: #87CCEA;
}
<div><p>Scrolled <span id="demo">0</span> times.</p></div>
<div class="container y mandatory-scroll-snapping" onscroll="Onscrollfnction();" dir="ltr">
<div>Y Mand. LTR</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
The vue.js, vuetify version does not
https://codepen.io/travis-pancakes/pen/BMbqPq?editors=1111
new Vue({
el: '#app',
data: function(){
return {
i: 0
}
},
created () {
},
methods: {
Onscrollfnction (event) {
document.getElementById("demo").innerHTML = this.i;
this.i = this.i + 1;
console.log('i ', i)
}
}
});
/* setup */
html, body, .holster {
height: 100%;
}
.holster {
display: flex;
align-items: center;
justify-content: space-between;
flex-flow: column nowrap;
font-family: monospace;
}
.container {
display: flex;
overflow: auto;
outline: 1px dashed lightgray;
flex: none;
}
.container.x {
width: 100%;
height: 128px;
flex-flow: row nowrap;
}
.container.y {
width: 256px;
height: 256px;
flex-flow: column nowrap;
}
/* scroll-snap */
.x.mandatory-scroll-snapping {
scroll-snap-type: x mandatory;
}
.y.mandatory-scroll-snapping {
scroll-snap-type: y mandatory;
}
.x.proximity-scroll-snapping {
scroll-snap-type: x proximity;
}
.y.proximity-scroll-snapping {
scroll-snap-type: y proximity;
}
.container > div {
text-align: center;
scroll-snap-align: center;
flex: none;
}
.x.container > div {
line-height: 128px;
font-size: 64px;
width: 100%;
height: 128px;
}
.y.container > div {
line-height: 256px;
font-size: 128px;
width: 256px;
height: 256px;
}
/* appearance fixes */
.y.container > div:first-child {
line-height: 1.3;
font-size: 64px;
}
/* coloration */
.container > div:nth-child(even) {
background-color: #87EA87;
}
.container > div:nth-child(odd) {
background-color: #87CCEA;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<!-- could use v-scroll="Onscrollfnction" with vuetify" --->
<div class="container y mandatory-scroll-snapping"
v-on:scroll.native="Onscrollfnction" dir="ltr">
<div>Y Mand. LTR</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
<p>Scrolled <span id="demo">0</span> times.</p>
</div>
</div>
vue-awesome-swiper does the functionality I'm going for

How to get VueJS transitioning Divs beside eachother?

When using Vue transitions with a slide left/right animation, how can I get the Divs beside eachother?
Take a look at this pen;
https://codepen.io/anon/pen/jeBBaB
HTML
<div class="heading">
<h1>Transition demo</h1>
<h4>Why this no work?</h4>
</div>
<div class="container" id="app">
<transition :enter-active-class="enterAnimation" :leave-active-class="leaveAnimation" mode="">
<div key="one" v-if="currentStep == 1">
This is Step One
<button class="btn btn-primary" #click="currentStep = 2; previousStep=1">Next</button>
</div>
<div key="two" v-else>
This is Step Two
<button class="btn btn-primary" #click="currentStep = 1; previousStep=2">Back</button>
</div>
</transition>
</div>
CSS
$purple: #5c4084;
body {
background-color: $purple;
padding: 50px;
}
.container {
padding: 40px 80px 15px 80px;
background-color: #fff;
border-radius: 8px;
max-width: 800px;
}
.heading {
text-align: center;
h1 {
background: -webkit-linear-gradient(#fff, #999);
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
text-align: center;
margin: 0 0 5px 0;
font-weight: 900;
font-size: 4rem;
color: #fff;
}
h4 {
color: lighten(#5c3d86,30%);
text-align: center;
margin: 0 0 35px 0;
font-weight: 400;
font-size: 24px;
}
}
.btn{
outline: none !important;
}
.btn.btn-primary {
background-color: $purple;
border-color: $purple;
outline: none;
&:hover {
background-color: darken($purple, 10%);
border-color: darken($purple, 10%);
}
&:active, &:focus {
background-color: lighten($purple, 5%);
border-color: lighten($purple, 5%);
}
& .fa {
padding-right: 4px;
}
}
.form-group {
margin-bottom: 25px;
}
JS
new Vue({
el: '#app',
data: {
currentStep: 1,
previousStep: 0
},
computed:{
enterAnimation() {
if (this.currentStep < this.previousStep) {
return "animated slower fadeInLeft";
} else {
return "animated slower fadeInRight";
}
},
leaveAnimation() {
if (this.currentStep > this.previousStep) {
return "animated slower fadeOutLeft";
} else {
return "animated slower fadeOutRight";
}
}
}
});
When using no mode, the "entering" div appears on the line below the "leaving" div until then end, then it pops upwards.
I can use mode="out-in" but then there's a noticable gap between the Divs. I'd like to just have one sliding in, right next to the one sliding out. Any way to achieve this?
You could make use of absolute positioning on the div elements, you need to adjust your css a bit though.
But as a starting point, change your .container rules to this (adding position: relative;):
.container {
padding: 40px 80px 15px 80px;
background-color: #fff;
border-radius: 8px;
max-width: 800px;
position:relative;
}
and add this as a new rule below it:
.container div {position:absolute;top:0;left:0;}
The flexbox way:
Change your container rules to this:
.container {
padding: 40px 80px 15px 80px;
background-color: #fff;
border-radius: 8px;
max-width: 800px;
display:flex;
}
After this you can use a css translate rule to position the content. You can see a working example here:
Vue transitions

CSS TranslationX of container not working in Safari

Today I have noticed a weird behavior of Safari (9.0) when I applied a transition to an element that was translating on the X axis while the width was also increasing.
I have reproduced the behavior in this JsFiddle. Here is an embed code for those who like it better. In Firefox and Chrome it looks pretty smooth but not in Safari, does anyone have a solution or a best way to achieve the same effect?
var button = document.getElementsByTagName('button')[0],
container = document.getElementsByTagName('div')[0];
button.addEventListener('click', function() { container.classList.toggle('open'); });
.container {
width: 100%;
overflow: hidden;
}
ul {
display: block;
width: 100%;
padding: 0;
margin: 0;
transition: width 1s, transform 1s;
}
.open ul {
width: 200%;
transform: translateX(-50%);
}
li {
/* Just some style first */
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
background-color: red;
padding: 1em 0;
display: inline-block;
width: calc(50% - 4px);
}
li:first-child {
background-color: green;
}
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
Re-posting as an answer.
Here is the jsFiddle result and snippet as below:
var button = document.getElementsByTagName('button')[0];
var container = document.getElementsByTagName('div')[0];
var timeline = new TimelineMax({ paused: true });
timeline.to('ul', 1, { width: '200%', xPercent: -50, ease: Power2.easeInOut });
button.addEventListener('click', function() {
timeline.progress() > 0 ? timeline.reverse() : timeline.play();
});
.container {
width: 100%;
overflow: hidden;
}
ul {
display: block;
width: 100%;
padding: 0;
margin: 0;
}
li {
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
background-color: red;
display: inline-block;
padding: 1em 0;
width: calc(50% - 4px);
}
li:first-child {
background-color: green;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/TweenMax.min.js"></script>
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
Hope this is helpful.
P.S. I have been using GSAP for quite a while now and I don't remember getting stuck on any browser-specific issues unless a browser would do something differently. A little research into GSAP and it would tell you that browser compatibility is one of their main selling points.
By animating margin-left instead of translateX the result is acceptable in Safari:
var button = document.getElementsByTagName('button')[0],
container = document.getElementsByTagName('div')[0];
button.addEventListener('click', function() {
container.classList.toggle('open');
});
.container {
width: 100%;
overflow: hidden;
}
ul {
display: block;
width: 100%;
padding: 0;
margin: 0;
transition: width 1s, margin-left 1s;
}
.open ul {
width: 200%;
margin-left:-100%;
}
li {
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
background-color: red;
display: inline-block;
padding: 1em 0;
width: calc(50% - 4px);
}
li:first-child {
background-color: green;
}
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
Using scaleX instead of animating width is smoother, but probably not what you want.
var button = document.getElementsByTagName('button')[0],
container = document.getElementsByTagName('div')[0];
button.addEventListener('click', function() {
container.classList.toggle('open');
});
.container {
width: 100%;
overflow: hidden;
}
ul {
display: block;
width: 100%;
padding: 0;
margin: 0;
transition: transform 1s;
}
.open ul {
transform: translateX(-50%) scaleX(2);
}
li {
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
background-color: red;
display: inline-block;
padding: 1em 0;
width: calc(50% - 4px);
}
li:first-child {
background-color: green;
}
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
So, I will try to sum up the two best solutions here : one with CSS transform and the other with Javascript animation (GSAP).
CSS TRANSFORM
In terms of performance, it is recommended to only animate transforms (translate, scale, rotate) and opacity. If you are interested in more optimisation details you can have a look at this article by Anna Migas.
So, as #Meiko suggested, the best solution is to only animate scale and translate properties. Here is a code sample (and the JSFiddle)
var button = document.getElementsByTagName('button')[0],
container = document.getElementsByTagName('div')[0];
button.addEventListener('click', function() {
container.classList.toggle('open');
})
.container,
ul {
width: 100%;
}
ul {
overflow: hidden;
/* reset default browser styles */
padding: 0;
margin: 0;
}
li {
display: inline-block;
width: calc(50% - 2px);
position: relative;
transition: transform 1s;
/* Just some style */
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
padding: 1em 0;
}
li::before {
content: '';
position: absolute;
top: 0;
left: 0;
display: block;
width: 100%;
height: 100%;
background-color: red;
z-index: -1;
transition: transform 1s;
}
li:first-child::before {
background-color: green;
}
.open li:first-child {
transform: translateX(-100%);
}
.open li:nth-of-type(2) {
transform: translateX(-50%);
}
.open li:nth-of-type(2)::before {
transform: scaleX(2);
}
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
PROS:
Only use a tiny bit of Javascript to toggle class,
The browser support is quite good (needs vendor-specific properties and some testing),
Really fast and light on GPU memory.
CONS:
Pretty limited in terms of usage (the actual width of the second cell stays the same),
Needs more lines of CSS.
JS ANIMATION (WITH GSAP)
This solution has been suggested by #Tahir Ahmed and use the GSAP library. As a side note, I really think that this is the best js library out there for this kind of animation. Here is a snippet of how it works (and the JSFiddle):
var button = document.getElementsByTagName('button')[0],
timeline = new TimelineMax({ paused: true });
timeline.to('ul', 1, { width: '200%', xPercent: -50 });
button.addEventListener('click', function() {
timeline.progress() > 0 ? timeline.reverse() : timeline.play();
})
.container {
width: 100%;
overflow: hidden;
}
ul {
width: 100%;
/* reset default browser styles */
padding: 0;
margin: 0;
}
li {
display: inline-block;
width: calc(50% - 2px);
background-color: red;
/* Just some style */
font-family: sans-serif;
color: #fff;
text-align: center;
text-transform: uppercase;
padding: 1em 0;
}
li:first-child {
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/TweenMax.min.js"></script>
<div class="container">
<ul>
<li>Test</li>
<li>Test</li>
</ul>
</div>
<button type="button">Toggle translation</button>
PROS:
Really flexible, sky is the limit!
You can animate properties such as display (you can't in CSS),
Compatible with every browser out there (down to IE6).
CONS:
Require a third party library (about 30kb),
Seems a bit harder for the GPU (although it needs more testing to be sure).
In the end it really depends on the animation you need but if it get's a little bit more complex than moving a container around then I will choose GSAP.

Simple Gallery Slider

I'm trying to create a simple slider using divs and javascript. I set up a div with six images and an arrow that movies the containder holding the images 528px (the width of each image) every time it's clicked. When I reach the begining or end of the gallery, I want the respective arrow button to fade out so that the user won't keep pressing next/prev.
Any help is appreciated.
JAVASCRIPT
$("#btn-gallery-next").click(function(){
$("div#gallery li").not(this).removeClass('clicked');
$("div#gallery-slide").animate({left:"-=528px"});
if($("div#gallery-slide").position().left < -3168)
{
$("#btn-gallery-next").fadeOut();
}
else {
$("#btn-gallery-next").fadeIn();
}
});
$("#btn-gallery-prev").click(function(){
$("div#gallery li").not(this).removeClass('clicked');
$("div#gallery-slide").animate({left:"+=528px"});
if($("div#gallery-slide").position().left > 0)
{
$("#btn-gallery-prev").fadeOut();
}
else {
$("#btn-gallery-prev").fadeIn();
}
});
HTML
<div id="gallery-slide">
<img class="gallery-img" src="_/img/gallery/img1.jpg" alt="" />
<img class="gallery-img" src="_/img/gallery/img2.jpg" alt="" />
<img class="gallery-img" src="_/img/gallery/img3.jpg" alt="" />
<img class="gallery-img" src="_/img/gallery/img4.jpg" alt="" />
<img class="gallery-img" src="_/img/gallery/img5.jpg" alt="" />
<img class="gallery-img" src="_/img/gallery/img6.jpg" alt="" />
</div>
Try flex slider from woothemes, it have all ur needs.
Why not use a slider library like Owl Slider? It comes with lots of options and configurations. It is super simple to integrate into any project.
Example #1 www.midwestgathering.com/#galleries
Example #2 www.owlgraphic.com/owlcarousel/demos/images.html
Another option is jcarousel. The basic slider is shown with an example that makes the left next button inactive until the user slides to the right, then once the user gets to the end of the gallery the right next button becomes inactive:
JS
(function($) {
$(function() {
$('.jcarousel').jcarousel();
$('.jcarousel-control-prev')
.on('jcarouselcontrol:active', function() {
$(this).removeClass('inactive');
})
.on('jcarouselcontrol:inactive', function() {
$(this).addClass('inactive');
})
.jcarouselControl({
target: '-=1'
});
$('.jcarousel-control-next')
.on('jcarouselcontrol:active', function() {
$(this).removeClass('inactive');
})
.on('jcarouselcontrol:inactive', function() {
$(this).addClass('inactive');
})
.jcarouselControl({
target: '+=1'
});
$('.jcarousel-pagination')
.on('jcarouselpagination:active', 'a', function() {
$(this).addClass('active');
})
.on('jcarouselpagination:inactive', 'a', function() {
$(this).removeClass('active');
})
.jcarouselPagination();
});
})(jQuery);
CSS
.jcarousel-wrapper {
margin: 20px auto;
position: relative;
border: 10px solid #fff;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
-webkit-box-shadow: 0 0 2px #999;
-moz-box-shadow: 0 0 2px #999;
box-shadow: 0 0 2px #999;
}
.jcarousel-wrapper .photo-credits {
position: absolute;
right: 15px;
bottom: 0;
font-size: 13px;
color: #fff;
text-shadow: 0 0 1px rgba(0, 0, 0, 0.85);
opacity: .66;
}
.jcarousel-wrapper .photo-credits a {
color: #fff;
}
/** Carousel **/
.jcarousel {
position: relative;
overflow: hidden;
width: 600px;
height: 400px;
}
.jcarousel ul {
width: 20000em;
position: relative;
list-style: none;
margin: 0;
padding: 0;
}
.jcarousel li {
float: left;
}
/** Carousel Controls **/
.jcarousel-control-prev,
.jcarousel-control-next {
position: absolute;
top: 200px;
width: 30px;
height: 30px;
text-align: center;
background: #4E443C;
color: #fff;
text-decoration: none;
text-shadow: 0 0 1px #000;
font: 24px/27px Arial, sans-serif;
-webkit-border-radius: 30px;
-moz-border-radius: 30px;
border-radius: 30px;
-webkit-box-shadow: 0 0 2px #999;
-moz-box-shadow: 0 0 2px #999;
box-shadow: 0 0 2px #999;
}
.jcarousel-control-prev {
left: -50px;
}
.jcarousel-control-next {
right: -50px;
}
.jcarousel-control-prev:hover span,
.jcarousel-control-next:hover span {
display: block;
}
.jcarousel-control-prev.inactive,
.jcarousel-control-next.inactive {
opacity: .5;
cursor: default;
}
/** Carousel Pagination **/
.jcarousel-pagination {
position: absolute;
bottom: 0;
left: 15px;
}
.jcarousel-pagination a {
text-decoration: none;
display: inline-block;
font-size: 11px;
line-height: 14px;
min-width: 14px;
background: #fff;
color: #4E443C;
border-radius: 14px;
padding: 3px;
text-align: center;
margin-right: 2px;
opacity: .75;
}
.jcarousel-pagination a.active {
background: #4E443C;
color: #fff;
opacity: 1;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.75);
}
You can find documentation for jcarousel at www.sorgalla.com/jcarousel/docs/.
see demo - http://codepen.io/vsync/pen/waKju?editors=011
javascript
/**
* Slider - loops over images
* SEP 2014
* By - Yair Even-Or
*/
var Slider = function(elm, prev, next){
var that = this;
this.locked = false;
this.slider = elm;
this.children = this.slider.children;
this.itemWidth = this.children[0].clientWidth;
this.preloadImages();
next && next.addEventListener('click', function(){ that.move('next') });
prev && prev.addEventListener('click', function(){ that.move('prev') });
}
Slider.prototype = {
move : function(dir){
var that = this,
itemToMove;
if( this.locked ){
this.locked.removeAttribute('style');
this.slider.appendChild(this.locked);
clearTimeout(this.timer);
moveToEnd();
}
// do nothing if there are no items
if( this.children.length < 2 )
return false;
itemToMove = this.children[0];
this.locked = itemToMove;
if( dir == 'next' )
itemToMove.style.marginLeft = -this.itemWidth + 'px';
else{
itemToMove = this.children[this.children.length-1];
itemToMove.style.marginLeft = -this.itemWidth + 'px';
this.slider.insertBefore(itemToMove, this.children[0]);
setTimeout(function(){
itemToMove.removeAttribute('style');
},50);
this.preloadImages();
this.locked = false;
}
// move the child to the end of the items' list
if( dir == 'next' )
this.timer = setTimeout(moveToEnd, 420);
function moveToEnd(el){
itemToMove = el || itemToMove;
if( !itemToMove ) return;
itemToMove.removeAttribute('style');
that.slider.appendChild(itemToMove);
that.locked = false;
that.preloadImages();
}
},
preloadImages : function(){
this.lazyload(this.children[1].getElementsByTagName('img')[0] );
this.lazyload(this.children[this.children.length-1].getElementsByTagName('img')[0] );
},
// lazy load image
lazyload : function(img){
var lazy = img.getAttribute('data-src');
if( lazy ){
img.src = lazy;
img.removeAttribute('data-src');
}
}
}
// HOW TO USE /////////////////
var sliderElm = document.querySelector('.content'),
next = document.querySelector('.next'),
prev = document.querySelector('.prev'),
slider = new Slider(sliderElm, prev, next);
HTML (JADE syntax)
.slider
a.arrow.next
a.arrow.prev
ul.content
li
img(src='image1.jpg')
li
img(src='image2.jpg')
li
img(src='image3.jpg')
li
img(src='image4.jpg')