├── classicv2x.png:Zone.Identifier
├── README.md
├── classicv2.png
├── classicv2.png:Zone.Identifier
├── classicv2x.png
├── index.html
├── style.css
└── script.js
/classicv2x.png:Zone.Identifier:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # sliderparallaxcard
2 |
--------------------------------------------------------------------------------
/classicv2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/closeresty/sliderparallaxcard/HEAD/classicv2.png
--------------------------------------------------------------------------------
/classicv2.png:Zone.Identifier:
--------------------------------------------------------------------------------
1 | [ZoneTransfer]
2 | ZoneId=3
3 | HostUrl=about:internet
4 |
--------------------------------------------------------------------------------
/classicv2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/closeresty/sliderparallaxcard/HEAD/classicv2x.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | sliderparallaxcard
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
27 |
28 |
29 |

30 |
Wish List
31 |
32 |
Woman type
33 |
34 |
35 |
36 |
37 |
38 |
50 |
51 |
52 |

53 |
Wish List
54 |
55 |
Woman type
56 |
57 |
58 |
59 |
60 |
61 |
72 |
73 |
74 |

75 |
Wish List
76 |
77 |
Man type
78 |
79 |
80 |
81 |
82 |
83 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | width: 100%;
5 | margin: 0;
6 | padding: 0;
7 |
8 | font-family: "Roboto", "Helvetica", sans-serif;
9 |
10 | transition: background-color 0.2s;
11 | will-change: background-color;
12 | }
13 |
14 | .inspired-by {
15 | display: block;
16 | position: relative;
17 | margin-bottom: 15px;
18 | text-align: center;
19 | color: #fff;
20 | font-size: 14px;
21 | }
22 |
23 | .wrapper {
24 | position: relative;
25 | overflow-x: hidden;
26 | width: 100%;
27 | height: 100%;
28 | }
29 |
30 | .card {
31 | display: block;
32 | position: absolute;
33 | top: 50px;
34 | margin: 0 auto;
35 | width: 280px;
36 | background-color: #fff;
37 | border-radius: 15px;
38 |
39 | box-shadow: 0 30 50 rgba(0, 0, 0, 0.2);
40 |
41 | transform: translateX(-50%);
42 | transition: left 0.5s ease-out;
43 | will-change: left;
44 |
45 | -webkit-user-select: none;
46 | -moz-user-select: none;
47 | -ms-user-select: none;
48 | -o-user-select: none;
49 | user-select: none;
50 | }
51 |
52 | .card--19 {
53 | left: 50%;
54 | }
55 |
56 | .card--solstice,
57 | .card--huarache {
58 | left: 150%;
59 | }
60 |
61 | .card__header {
62 | position: relative;
63 | height: 170px;
64 | padding: 30px 30px 300px;
65 | border-top-right-radius: 15px;
66 | border-top-left-radius: 15px;
67 | color: #fff;
68 | }
69 |
70 | .card__header--19 {
71 | background-color: #F72648;
72 | background-image: linear-gradient(#F72648, #FCCB3C);
73 |
74 | background: #F72648;
75 | background: linear-gradient(#F72648, #FCCB3C);
76 | }
77 |
78 | .card__header--solstice {
79 | background-color: #3CA3FC;
80 | background-image: linear-gradient(#3CA3FC, #FFD300);
81 |
82 | background: #3CA3FC;
83 | background: linear-gradient(#3CA3FC, #FFD300);
84 | }
85 |
86 | .card__header--huarache {
87 | background-color: #26C9F7;
88 | background-image: linear-gradient(#26C9F7, #DFFC3C);
89 |
90 | background: #26C9F7;
91 | background: linear-gradient(#26C9F7, #DFFC3C);
92 | }
93 |
94 | .card__watermark {
95 | overflow: hidden;
96 | position: absolute;
97 | bottom: 10px;
98 | left: 0;
99 | width: 100%;
100 | }
101 |
102 | .card__watermark::after {
103 | content: attr(data-watermark);
104 | position: relative;
105 | left: -20px;
106 | color: rgba(0, 0, 0, .3);
107 | font-size: 240px;
108 | font-weight: 700;
109 | text-transform: uppercase;
110 | }
111 |
112 | .card__logo {
113 | width: 50px;
114 | height: auto;
115 | }
116 |
117 | .card__price {
118 | float: right;
119 | font-size: 16px;
120 | font-weight: 300;
121 | }
122 |
123 | .card__title {
124 | margin: 35px 0 20px;
125 | font-size: 15px;
126 | line-height: 1.1em;
127 | text-transform: uppercase;
128 | letter-spacing: 1.5px;
129 | }
130 |
131 | .card__subtitle {
132 | display: block;
133 | font-size: 13px;
134 | font-weight: 300;
135 | }
136 |
137 | .card__body {
138 | position: relative;
139 | padding: 40px 30px 20px;
140 | }
141 |
142 | .card__image {
143 | z-index: 1;
144 | position: absolute;
145 | top: -290px;
146 | left: -30px;
147 | width: 125%;
148 |
149 | user-select: none;
150 | -moz-user-select: none;
151 | -webkit-user-drag: none;
152 | -webkit-user-select: none;
153 | -ms-user-select: none;
154 | }
155 |
156 | .card__wish-list {
157 | display: block;
158 | width: 50%;
159 | margin: 0 auto 15px;
160 | padding: 15px;
161 | border: 2px solid #fff;
162 | border-radius: 20px;
163 | text-align: center;
164 | text-transform: uppercase;
165 | font-size: 14px;
166 | }
167 |
168 | .card__wish-list--19 {
169 | color: #8850FF;
170 | border-color: #8850FF;
171 | }
172 |
173 | .card__wish-list--solstice {
174 | color: #FFBA00;
175 | border-color: #FFBA00;
176 | }
177 |
178 | .card__wish-list--huarache {
179 | color: #26C9F7;
180 | border-color: #26C9F7;
181 | }
182 |
183 | .card__category {
184 | display: block;
185 | font-size: 12px;
186 | color: #AEAEAE;
187 | text-transform: uppercase;
188 | text-align: center;
189 | }
190 |
191 | .card__will-animate {
192 | will-change: transform;
193 | }
194 |
195 | .cards-placeholder {
196 | display: block;
197 | position: relative;
198 | margin-bottom: 15px;
199 | text-align: center;
200 | }
201 |
202 | .cards-placeholder__item {
203 | opacity: 0.3;
204 | display: inline-block;
205 | margin-right: 10px;
206 | background-color: #fff;
207 | width: 30px;
208 | height: 5px;
209 | border-radius: 5px;
210 |
211 | transition: opacity 0.2s;
212 | will-change: opacity;
213 | }
214 |
215 | .cards-placeholder__item--active {
216 | opacity: 1;
217 | }
--------------------------------------------------------------------------------
/script.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | var BODY_BACKGROUNDS = [
5 | '#8850FF',
6 | '#FFBA00',
7 | '#4054FF'
8 | ];
9 |
10 | function Slider() {
11 | this.cards = document.querySelectorAll('.card');
12 | this.currentIndex = 0;
13 |
14 | this.isDragging = false;
15 | this.startX = 0;
16 | this.currentX = 0;
17 |
18 | this.initEvents();
19 | this.setActivePlaceholder();
20 | }
21 |
22 | // initialize drag events
23 | Slider.prototype.initEvents = function () {
24 | document.addEventListener('touchstart', this.onStart.bind(this));
25 | document.addEventListener('touchmove', this.onMove.bind(this));
26 | document.addEventListener('touchend', this.onEnd.bind(this));
27 |
28 | document.addEventListener('mousedown', this.onStart.bind(this));
29 | document.addEventListener('mousemove', this.onMove.bind(this));
30 | document.addEventListener('mouseup', this.onEnd.bind(this));
31 |
32 | };
33 |
34 | // set active placeholder
35 | Slider.prototype.setActivePlaceholder = function () {
36 | var placeholders = document.querySelectorAll('.cards-placeholder__item');
37 | var activePlaceholder = document.querySelector('.cards-placeholder__item--active')
38 |
39 | if (activePlaceholder) {
40 | activePlaceholder.classList.remove('cards-placeholder__item--active');
41 | }
42 |
43 | placeholders[this.currentIndex].classList.add('cards-placeholder__item--active');
44 |
45 | var bodyEl = document.querySelector('body');
46 | bodyEl.style.backgroundColor = BODY_BACKGROUNDS[this.currentIndex];
47 | };
48 |
49 | // mousedown event
50 | Slider.prototype.onStart = function (evt) {
51 | this.isDragging = true;
52 |
53 | this.currentX = evt.pageX || evt.touches[0].pageX;
54 | this.startX = this.currentX;
55 |
56 | var card = this.cards[this.currentIndex];
57 |
58 | // calculate ration to use in parallax effect
59 | this.windowWidth = window.innerWidth;
60 | this.cardWidth = card.offsetWidth;
61 | this.ratio = this.windowWidth / (this.cardWidth / 4);
62 | };
63 |
64 | // mouseup event
65 | Slider.prototype.onEnd = function (evt) {
66 | this.isDragging = false;
67 |
68 | var diff = this.startX - this.currentX;
69 | var direction = (diff > 0) ? 'left' : 'right';
70 | this.startX = 0;
71 |
72 | if (Math.abs(diff) > this.windowWidth / 4) {
73 | if (direction === 'left') {
74 | this.slideLeft();
75 | } else if (direction === 'right') {
76 | this.slideRight();
77 | } else {
78 | this.cancelMoveCard();
79 | }
80 |
81 | } else {
82 | this.cancelMoveCard();
83 |
84 | }
85 |
86 | };
87 |
88 | // mousemove event
89 | Slider.prototype.onMove = function (evt) {
90 |
91 | if (!this.isDragging) return;
92 |
93 | this.currentX = evt.pageX || evt.touches[0].pageX;
94 | var diff = this.startX - this.currentX;
95 | diff *= -1;
96 |
97 | // don't let drag way from the center more than quarter of window
98 | if (Math.abs(diff) > this.windowWidth / 4) {
99 | if (diff > 0) {
100 | diff = this.windowWidth / 4;
101 | } else {
102 | diff = - this.windowWidth / 4;
103 | }
104 | }
105 |
106 | this.moveCard(diff);
107 | };
108 |
109 | // slide to left direction
110 | Slider.prototype.slideLeft = function () {
111 | // if last don't do nothing
112 | if (this.currentIndex === this.cards.length - 1) {
113 | this.cancelMoveCard();
114 | return;
115 | }
116 |
117 | var self = this;
118 | var card = this.cards[this.currentIndex];
119 | var cardWidth = this.windowWidth / 2;
120 |
121 | card.style.left = '-50%';
122 |
123 | this.resetCardElsPosition();
124 |
125 | this.currentIndex += 1;
126 | this.setActivePlaceholder();
127 | card = this.cards[this.currentIndex];
128 |
129 | card.style.left = '50%';
130 |
131 | this.moveCardEls(cardWidth * 3);
132 |
133 | // add delay to resetting position
134 | setTimeout(function () {
135 | self.resetCardElsPosition();
136 | }, 50);
137 | };
138 |
139 | // slide to right direction
140 | Slider.prototype.slideRight = function () {
141 | // if last don't do nothing
142 | if (this.currentIndex === 0) {
143 | this.cancelMoveCard();
144 | return;
145 | }
146 |
147 | var self = this;
148 | var card = this.cards[this.currentIndex];
149 | var cardWidth = this.windowWidth / 2;
150 |
151 | card.style.left = '150%';
152 |
153 | this.resetCardElsPosition();
154 |
155 | this.currentIndex -= 1;
156 | this.setActivePlaceholder();
157 | card = this.cards[this.currentIndex];
158 |
159 | card.style.left = '50%';
160 |
161 | this.moveCardEls(-cardWidth * 3);
162 |
163 | // add delay to resetting position
164 | setTimeout(function () {
165 | self.resetCardElsPosition();
166 | }, 50);
167 | };
168 |
169 | // put active card in original position (center)
170 | Slider.prototype.cancelMoveCard = function () {
171 | var self = this;
172 | var card = this.cards[this.currentIndex];
173 |
174 | card.style.transition = 'transform 0.5s ease-out';
175 | card.style.transform = '';
176 |
177 | this.resetCardElsPosition();
178 | };
179 |
180 | // reset to original position elements of card
181 | Slider.prototype.resetCardElsPosition = function () {
182 | var self = this;
183 | var card = this.cards[this.currentIndex];
184 |
185 | var cardLogo = card.querySelector('.card__logo');
186 | var cardPrice = card.querySelector('.card__price');
187 | var cardTitle = card.querySelector('.card__title');
188 | var cardSubtitle = card.querySelector('.card__subtitle');
189 | var cardImage = card.querySelector('.card__image');
190 | var cardWishList = card.querySelector('.card__wish-list');
191 | var cardCategory = card.querySelector('.card__category');
192 | var cardWillAnimate = card.querySelectorAll('.card__will-animate');
193 |
194 | // move card elements to original position
195 | cardWillAnimate.forEach(function (el) {
196 | el.style.transition = 'transform 0.5s ease-out';
197 | });
198 |
199 | cardLogo.style.transform = '';
200 | cardPrice.style.transform = '';
201 |
202 | cardTitle.style.transform = '';
203 | cardSubtitle.style.transform = '';
204 |
205 | cardImage.style.transform = '';
206 | cardWishList.style.transform = '';
207 | cardCategory.style.transform = '';
208 |
209 | // clear transitions
210 | setTimeout(function () {
211 | card.style.transform = '';
212 | card.style.transition = '';
213 |
214 | cardWillAnimate.forEach(function (el) {
215 | el.style.transition = '';
216 | });
217 | }, 500);
218 |
219 | };
220 |
221 | // slide card while dragging
222 | Slider.prototype.moveCard = function (diff) {
223 |
224 | var card = this.cards[this.currentIndex];
225 |
226 | card.style.transform = 'translateX(calc(' + diff + 'px - 50%))';
227 | diff *= -1;
228 |
229 | this.moveCardEls(diff);
230 | };
231 |
232 | // create parallax effect on card elements sliding them
233 | Slider.prototype.moveCardEls = function (diff) {
234 | var card = this.cards[this.currentIndex];
235 |
236 | var cardLogo = card.querySelector('.card__logo');
237 | var cardPrice = card.querySelector('.card__price');
238 | var cardTitle = card.querySelector('.card__title');
239 | var cardSubtitle = card.querySelector('.card__subtitle');
240 | var cardImage = card.querySelector('.card__image');
241 | var cardWishList = card.querySelector('.card__wish-list');
242 | var cardCategory = card.querySelector('.card__category');
243 | var cardWillAnimate = card.querySelectorAll('.card__will-animate');
244 |
245 | cardLogo.style.transform = 'translateX(' + (diff / this.ratio) + 'px)';
246 | cardPrice.style.transform = 'translateX(' + (diff / this.ratio) + 'px)';
247 |
248 | cardTitle.style.transform = 'translateX(' + (diff / (this.ratio * 0.90)) + 'px)';
249 | cardSubtitle.style.transform = 'translateX(' + (diff / (this.ratio * 0.85)) + 'px)';
250 |
251 | cardImage.style.transform = 'translateX(' + (diff / (this.ratio * 0.35)) + 'px)';
252 |
253 | cardWishList.style.transform = 'translateX(' + (diff / (this.ratio * 0.85)) + 'px)';
254 | cardCategory.style.transform = 'translateX(' + (diff / (this.ratio * 0.65)) + 'px)';
255 |
256 | };
257 |
258 |
259 | // create slider
260 | var slider = new Slider();
261 |
262 | })();
--------------------------------------------------------------------------------