26 | ├── preview.png ├── assets ├── img │ ├── img1.png │ ├── img2.png │ ├── img3.png │ ├── img4.png │ └── img5.png ├── scss │ ├── styles.scss │ ├── base │ │ └── _base.scss │ ├── components │ │ ├── _breakpoints.scss │ │ └── _gallery.scss │ └── config │ │ └── _variables.scss ├── js │ ├── main.js │ └── swiper-bundle.min.js └── css │ ├── styles.css │ └── swiper-bundle.min.css ├── README.md ├── LICENSE └── index.html /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bedimcode/responsive-image-gallery-slider/HEAD/preview.png -------------------------------------------------------------------------------- /assets/img/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bedimcode/responsive-image-gallery-slider/HEAD/assets/img/img1.png -------------------------------------------------------------------------------- /assets/img/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bedimcode/responsive-image-gallery-slider/HEAD/assets/img/img2.png -------------------------------------------------------------------------------- /assets/img/img3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bedimcode/responsive-image-gallery-slider/HEAD/assets/img/img3.png -------------------------------------------------------------------------------- /assets/img/img4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bedimcode/responsive-image-gallery-slider/HEAD/assets/img/img4.png -------------------------------------------------------------------------------- /assets/img/img5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bedimcode/responsive-image-gallery-slider/HEAD/assets/img/img5.png -------------------------------------------------------------------------------- /assets/scss/styles.scss: -------------------------------------------------------------------------------- 1 | @import 'config/variables'; 2 | @import 'base/base'; 3 | @import 'components/gallery'; 4 | @import 'components/breakpoints'; -------------------------------------------------------------------------------- /assets/scss/base/_base.scss: -------------------------------------------------------------------------------- 1 | /*=============== BASE ===============*/ 2 | *{ 3 | box-sizing: border-box; 4 | padding: 0; 5 | margin: 0; 6 | } 7 | 8 | body{ 9 | font-family: var(--body-font); 10 | background-color: var(--body-color); 11 | } 12 | 13 | img{ 14 | max-width: 100%; 15 | height: auto; 16 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🖼️ Responsive Image Gallery Slider 2 | ## [Watch it on youtube](https://youtu.be/h_R7A0CfUbo) 3 | ### 🖼️ Responsive Image Gallery Slider 4 | 5 | - Responsive Image Gallery Slider Using HTML CSS & JavaScript (SwiperJs) 6 | - Includes image thumbnails. 7 | - With CSS effects on swipe. 8 | - Developed first with the Mobile First methodology, then for desktop. 9 | - Compatible with all mobile devices and with a beautiful and pleasant user interface. 10 | 11 | 💙 Join the channel to see more videos like this. [Bedimcode](https://www.youtube.com/c/Bedimcode) 12 | 13 |  14 | -------------------------------------------------------------------------------- /assets/scss/components/_breakpoints.scss: -------------------------------------------------------------------------------- 1 | /*=============== BREAKPOINTS ===============*/ 2 | /* For small devices */ 3 | @media screen and (max-width: 320px){ 4 | .swiper-button-next, 5 | .swiper-button-prev{ 6 | display: none; 7 | } 8 | } 9 | 10 | /* For medium devices */ 11 | @media screen and (min-width: 1024px){ 12 | .gallery{ 13 | &__card{ 14 | width: 220px; 15 | height: 290px; 16 | } 17 | &__thumbnail{ 18 | width: 65px; 19 | height: 65px; 20 | } 21 | } 22 | 23 | .gallery-cards, 24 | .gallery-thumbs{ 25 | width: 280px; 26 | } 27 | } -------------------------------------------------------------------------------- /assets/js/main.js: -------------------------------------------------------------------------------- 1 | /*=============== SWIPER JS GALLERY ===============*/ 2 | let swiperCards = new Swiper(".gallery-cards", { 3 | loop: true, 4 | loopedSlides: 5, 5 | cssMode: true, 6 | effect: 'fade', 7 | }); 8 | 9 | let swiperThumbs = new Swiper(".gallery-thumbs", { 10 | loop: true, 11 | loopedSlides: 5, 12 | slidesPerView: 3, 13 | centeredSlides: true, 14 | slideToClickedSlide: true, 15 | 16 | pagination: { 17 | el: ".swiper-pagination", 18 | type: "fraction", 19 | }, 20 | navigation: { 21 | nextEl: ".swiper-button-next", 22 | prevEl: ".swiper-button-prev", 23 | }, 24 | }); 25 | 26 | swiperThumbs.controller.control = swiperCards; -------------------------------------------------------------------------------- /assets/scss/config/_variables.scss: -------------------------------------------------------------------------------- 1 | /*=============== GOOGLE FONTS ===============*/ 2 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap'); 3 | 4 | /*=============== VARIABLES CSS ===============*/ 5 | :root{ 6 | /*========== Colors ==========*/ 7 | --first-color: hsl(30, 16%, 50%); 8 | --text-color: #fff; 9 | --text-color-black: hsl(30, 8%, 15%); 10 | --body-color: hsl(30, 100%, 98%); 11 | 12 | /*========== Font and typography ==========*/ 13 | --body-font: 'Poppins', sans-serif; 14 | 15 | --h3-font-size: 1rem; 16 | --small-font-size: .813rem; 17 | --smaller-font-size: .75rem; 18 | 19 | // Responsive typography 20 | @media screen and (min-width: 1024px){ 21 | --h3-font-size: 1.125rem; 22 | --small-font-size: .875rem; 23 | --smaller-font-size: .813rem; 24 | } 25 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Bedimcode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/scss/components/_gallery.scss: -------------------------------------------------------------------------------- 1 | /*=============== GALLERY ===============*/ 2 | .gallery{ 3 | height: 100vh; 4 | display: grid; 5 | align-content: center; 6 | justify-content: center; 7 | 8 | &__card{ 9 | position: relative; 10 | width: 208px; 11 | height: 268px; 12 | border-radius: 3rem; 13 | margin-left: auto; 14 | margin-right: auto; 15 | overflow: hidden; 16 | } 17 | &__img, 18 | &__card::after, 19 | &__data{ 20 | position: absolute; 21 | } 22 | &__img{ 23 | inset: 0; 24 | margin: auto; 25 | transition: transform .3s; 26 | } 27 | &__card::after{ 28 | content: ''; 29 | width: 100%; 30 | height: 100%; 31 | background: linear-gradient(180deg, 32 | hsla(0, 0%, 100%, 0) 32%, 33 | hsla(0, 0%, 0%, .3) 100%); 34 | top: 0; 35 | z-index: 1; 36 | } 37 | &__data{ 38 | bottom: 1.5rem; 39 | left: 1.75rem; 40 | z-index: 10; 41 | } 42 | &__title, 43 | &__subtitle{ 44 | color: var(--text-color); 45 | font-weight: 500; 46 | } 47 | &__title{ 48 | font-size: var(--h3-font-size); 49 | } 50 | &__subtitle{ 51 | font-size: var(--smaller-font-size); 52 | } 53 | &__overflow{ 54 | position: relative; 55 | } 56 | &__thumbnail{ 57 | position: relative; 58 | width: 60px; 59 | height: 60px; 60 | border-radius: 1.5rem; 61 | overflow: hidden; 62 | cursor: pointer; 63 | margin-left: auto; 64 | margin-right: auto; 65 | transition: transform .3s; 66 | 67 | &-img{ 68 | position: absolute; 69 | inset: 0; 70 | margin: auto; 71 | } 72 | } 73 | } 74 | 75 | /* Swiper class */ 76 | .gallery-cards, 77 | .gallery-thumbs{ 78 | width: 260px; 79 | } 80 | 81 | .gallery-cards:hover .gallery__img{ 82 | transform: scale(1.1); 83 | } 84 | 85 | .gallery .swiper-wrapper{ 86 | padding: 2.5rem 0; 87 | } 88 | 89 | .gallery-thumbs{ 90 | height: 132px; 91 | } 92 | 93 | /* Active thumbnail */ 94 | .swiper-slide-active .gallery__thumbnail{ 95 | transform: translateY(-1.25rem) scale(1.2); 96 | } 97 | 98 | /* Rotate thumbnail */ 99 | .swiper-slide-next .gallery__thumbnail{ 100 | transform: rotate(15deg); 101 | } 102 | 103 | .swiper-slide-prev .gallery__thumbnail{ 104 | transform: rotate(-15deg); 105 | } 106 | 107 | /* Sliding numbers */ 108 | .swiper-pagination-fraction{ 109 | font-size: var(--small-font-size); 110 | letter-spacing: -1px; 111 | font-weight: 500; 112 | color: var(--first-color); 113 | bottom: 0; 114 | } 115 | 116 | /* Arrow buttons */ 117 | .swiper-button-next::after, 118 | .swiper-button-prev::after{ 119 | content: ''; 120 | } 121 | 122 | .swiper-button-next, 123 | .swiper-button-prev{ 124 | font-size: 1.5rem; 125 | color: var(--text-color-black); 126 | top: 5.5rem; 127 | } 128 | 129 | .swiper-button-next{ 130 | right: -1.5rem; 131 | transform: rotate(15deg); 132 | } 133 | 134 | .swiper-button-prev{ 135 | left: -1.5rem; 136 | transform: rotate(-15deg); 137 | } 138 | 139 | /* Other swiper settings */ 140 | .gallery-cards::after{ 141 | content: ''; 142 | width: 100%; 143 | height: 100%; 144 | position: absolute; 145 | top: 0; 146 | left: 0; 147 | z-index: 10; 148 | } 149 | 150 | .swiper-horizontal.swiper-css-mode>.swiper-wrapper{ 151 | scroll-snap-type: initial; 152 | } -------------------------------------------------------------------------------- /assets/css/styles.css: -------------------------------------------------------------------------------- 1 | /*=============== GOOGLE FONTS ===============*/ 2 | @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap"); 3 | 4 | /*=============== VARIABLES CSS ===============*/ 5 | :root { 6 | /*========== Colors ==========*/ 7 | --first-color: hsl(30, 16%, 50%); 8 | --text-color: #fff; 9 | --text-color-black: hsl(30, 8%, 15%); 10 | --body-color: hsl(30, 100%, 98%); 11 | 12 | /*========== Font and typography ==========*/ 13 | --body-font: 'Poppins', sans-serif; 14 | --h3-font-size: 1rem; 15 | --small-font-size: .813rem; 16 | --smaller-font-size: .75rem; 17 | } 18 | 19 | /* Responsive typography */ 20 | @media screen and (min-width: 1024px) { 21 | :root { 22 | --h3-font-size: 1.125rem; 23 | --small-font-size: .875rem; 24 | --smaller-font-size: .813rem; 25 | } 26 | } 27 | 28 | /*=============== BASE ===============*/ 29 | * { 30 | box-sizing: border-box; 31 | padding: 0; 32 | margin: 0; 33 | } 34 | 35 | body { 36 | font-family: var(--body-font); 37 | background-color: var(--body-color); 38 | } 39 | 40 | img { 41 | max-width: 100%; 42 | height: auto; 43 | } 44 | 45 | /*=============== GALLERY ===============*/ 46 | .gallery { 47 | height: 100vh; 48 | display: grid; 49 | align-content: center; 50 | justify-content: center; 51 | } 52 | 53 | .gallery__card { 54 | position: relative; 55 | width: 208px; 56 | height: 268px; 57 | border-radius: 3rem; 58 | margin-left: auto; 59 | margin-right: auto; 60 | overflow: hidden; 61 | } 62 | 63 | .gallery__img, 64 | .gallery__card::after, 65 | .gallery__data { 66 | position: absolute; 67 | } 68 | 69 | .gallery__img { 70 | inset: 0; 71 | margin: auto; 72 | transition: transform .3s; 73 | } 74 | 75 | .gallery__card::after { 76 | content: ''; 77 | width: 100%; 78 | height: 100%; 79 | background: linear-gradient(180deg, 80 | hsla(0, 0%, 100%, 0) 32%, 81 | hsla(0, 0%, 0%, .3) 100%); 82 | top: 0; 83 | z-index: 1; 84 | } 85 | 86 | .gallery__data { 87 | bottom: 1.5rem; 88 | left: 1.75rem; 89 | z-index: 10; 90 | } 91 | 92 | .gallery__title, 93 | .gallery__subtitle { 94 | color: var(--text-color); 95 | font-weight: 500; 96 | } 97 | 98 | .gallery__title { 99 | font-size: var(--h3-font-size); 100 | } 101 | 102 | .gallery__subtitle { 103 | font-size: var(--smaller-font-size); 104 | } 105 | 106 | .gallery__overflow { 107 | position: relative; 108 | } 109 | 110 | .gallery__thumbnail { 111 | position: relative; 112 | width: 60px; 113 | height: 60px; 114 | border-radius: 1.5rem; 115 | overflow: hidden; 116 | cursor: pointer; 117 | margin-left: auto; 118 | margin-right: auto; 119 | transition: transform .3s; 120 | } 121 | 122 | .gallery__thumbnail-img { 123 | position: absolute; 124 | inset: 0; 125 | margin: auto; 126 | } 127 | 128 | /* Swiper class */ 129 | .gallery-cards, 130 | .gallery-thumbs { 131 | width: 260px; 132 | } 133 | 134 | .gallery-cards:hover .gallery__img { 135 | transform: scale(1.1); 136 | } 137 | 138 | .gallery .swiper-wrapper { 139 | padding: 2.5rem 0; 140 | } 141 | 142 | .gallery-thumbs { 143 | height: 132px; 144 | } 145 | 146 | /* Active thumbnail */ 147 | .swiper-slide-active .gallery__thumbnail { 148 | transform: translateY(-1.25rem) scale(1.2); 149 | } 150 | 151 | /* Rotate thumbnail */ 152 | .swiper-slide-next .gallery__thumbnail { 153 | transform: rotate(15deg); 154 | } 155 | 156 | .swiper-slide-prev .gallery__thumbnail { 157 | transform: rotate(-15deg); 158 | } 159 | 160 | /* Sliding numbers */ 161 | .swiper-pagination-fraction { 162 | font-size: var(--small-font-size); 163 | letter-spacing: -1px; 164 | font-weight: 500; 165 | color: var(--first-color); 166 | bottom: 0; 167 | } 168 | 169 | /* Arrow buttons */ 170 | .swiper-button-next::after, 171 | .swiper-button-prev::after { 172 | content: ''; 173 | } 174 | 175 | .swiper-button-next, 176 | .swiper-button-prev { 177 | font-size: 1.5rem; 178 | color: var(--text-color-black); 179 | top: 5.5rem; 180 | } 181 | 182 | .swiper-button-next { 183 | right: -1.5rem; 184 | transform: rotate(15deg); 185 | } 186 | 187 | .swiper-button-prev { 188 | left: -1.5rem; 189 | transform: rotate(-15deg); 190 | } 191 | 192 | /* Other swiper settings */ 193 | .gallery-cards::after { 194 | content: ''; 195 | width: 100%; 196 | height: 100%; 197 | position: absolute; 198 | top: 0; 199 | left: 0; 200 | z-index: 10; 201 | } 202 | 203 | .swiper-horizontal.swiper-css-mode > .swiper-wrapper { 204 | scroll-snap-type: initial; 205 | } 206 | 207 | /*=============== BREAKPOINTS ===============*/ 208 | /* For small devices */ 209 | @media screen and (max-width: 320px) { 210 | .swiper-button-next, 211 | .swiper-button-prev { 212 | display: none; 213 | } 214 | } 215 | 216 | /* For medium devices */ 217 | @media screen and (min-width: 1024px) { 218 | .gallery__card { 219 | width: 220px; 220 | height: 290px; 221 | } 222 | .gallery__thumbnail { 223 | width: 65px; 224 | height: 65px; 225 | } 226 | .gallery-cards, 227 | .gallery-thumbs { 228 | width: 280px; 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |1&&u.push(e.virtualSize-r)}if(0===u.length&&(u=[0]),0!==a.spaceBetween){const s=e.isHorizontal()&&n?"marginLeft":t("marginRight");c.filter(((e,t)=>!a.cssMode||t!==c.length-1)).css({[s]:`${x}px`})}if(a.centeredSlides&&a.centeredSlidesBounds){let e=0;m.forEach((t=>{e+=t+(a.spaceBetween?a.spaceBetween:0)})),e-=a.spaceBetween;const t=e-r;u=u.map((e=>e<0?-f:e>t?t+g:e))}if(a.centerInsufficientSlides){let e=0;if(m.forEach((t=>{e+=t+(a.spaceBetween?a.spaceBetween:0)})),e-=a.spaceBetween,e {r.wrapperEl.style.scrollSnapType="",r._swiperImmediateVirtual=!1}))}else{if(!r.support.smoothScroll)return w({swiper:r,targetPosition:s,side:e?"left":"top"}),!0;h.scrollTo({[e?"left":"top"]:s,behavior:"smooth"})}return!0}return r.setTransition(t),r.setTranslate(v),r.updateActiveIndex(n),r.updateSlidesClasses(),r.emit("beforeTransitionStart",t,a),r.transitionStart(s,b),0===t?r.transitionEnd(s,b):r.animating||(r.animating=!0,r.onSlideToWrapperTransitionEnd||(r.onSlideToWrapperTransitionEnd=function(e){r&&!r.destroyed&&e.target===this&&(r.$wrapperEl[0].removeEventListener("transitionend",r.onSlideToWrapperTransitionEnd),r.$wrapperEl[0].removeEventListener("webkitTransitionEnd",r.onSlideToWrapperTransitionEnd),r.onSlideToWrapperTransitionEnd=null,delete r.onSlideToWrapperTransitionEnd,r.transitionEnd(s,b))}),r.$wrapperEl[0].addEventListener("transitionend",r.onSlideToWrapperTransitionEnd),r.$wrapperEl[0].addEventListener("webkitTransitionEnd",r.onSlideToWrapperTransitionEnd)),!0},slideToLoop:function(e,t,s,a){if(void 0===e&&(e=0),void 0===t&&(t=this.params.speed),void 0===s&&(s=!0),"string"==typeof e){const t=parseInt(e,10);if(!isFinite(t))throw new Error(`The passed-in 'index' (string) couldn't be converted to 'number'. [${e}] given.`);e=t}const i=this;let r=e;return i.params.loop&&(r+=i.loopedSlides),i.slideTo(r,t,s,a)},slideNext:function(e,t,s){void 0===e&&(e=this.params.speed),void 0===t&&(t=!0);const a=this,{animating:i,enabled:r,params:n}=a;if(!r)return a;let l=n.slidesPerGroup;"auto"===n.slidesPerView&&1===n.slidesPerGroup&&n.slidesPerGroupAuto&&(l=Math.max(a.slidesPerViewDynamic("current",!0),1));const o=a.activeIndex0&&o(u(t));const a=e.children(`.${s.slidePrevClass}`);a.length>0&&o(u(a))}}function p(){const e=r();if(!t||t.destroyed)return;const s=t.params.lazy.scrollingElement?d(t.params.lazy.scrollingElement):d(e),a=s[0]===e,i=a?e.innerWidth:s[0].offsetWidth,l=a?e.innerHeight:s[0].offsetHeight,o=t.$el.offset(),{rtlTranslate:u}=t;let h=!1;u&&(o.left-=t.$el[0].scrollLeft);const m=[[o.left,o.top],[o.left+t.width,o.top],[o.left,o.top+t.height],[o.left+t.width,o.top+t.height]];for(let e=0;e