Skip to content

Instantly share code, notes, and snippets.

@onizuka17
Created September 7, 2018 03:03
Show Gist options
  • Save onizuka17/efff70f10b1af55c6c5fe661a034878d to your computer and use it in GitHub Desktop.
Save onizuka17/efff70f10b1af55c6c5fe661a034878d to your computer and use it in GitHub Desktop.
Slider and Lightbox :: slider (swiper.js) & Lightbox gallery (photoswipe.js)
<h1>
<a title="swiper.js" href="http://idangero.us/swiper/" target="_blank">Swiper.js (4.3.5)</a>
&
<a title="photoswipe" href="http://photoswipe.com/" target="_blank">Photoswipe.js (4.1.1)</a>
- Mobile Native feel slider gallery
</h1>
<p>Combine two of the most powerfull JS plugins (Endless options / Great docs / Fast / Modern / Mobile freindly) - <a title="swiper.js" href="http://idangero.us/swiper/" target="_blank">SWIPER</a> IS PERFECT FOR THIS IDEA BEACUSE OF ITS unique <code>preventClicks</code> Parameter (Prevent accidental unwanted clicks on links during swiping) - <strong>Works like magic</strong>. Also its really <b>hard</b> to find - Code example of working photoswipe combination with any slider out there(slick, flickity, owl etc.) and in general slider & lightbox - so i hope this example be usefull for you.</p>
<!-- Slider main container -->
<div class="swiper-container">
<!-- Additional required wrapper -->
<ul class="swiper-wrapper my-gallery" itemscope itemtype="http://schema.org/ImageGallery">
<!-- Slides -->
<li class="swiper-slide" itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
<a title="click to zoom-in" href="http://placehold.it/1200x600/EC407A/ffffff?text=Zoom-image-1" itemprop="contentUrl" data-size="1200x600">
<img src="http://placehold.it/600x300/EC407A/ffffff?text=Thumbnail-image-1" itemprop="thumbnail" alt="Image description" />
</a> </li>
<li class="swiper-slide" itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
<a title="click to zoom-in" href="http://placehold.it/1200x600/AB47BC/ffffff?text=Zoom-image-2" itemprop="contentUrl" data-size="1200x600">
<img src="http://placehold.it/600x300/AB47BC/ffffff?text=Thumbnail-image-2" itemprop="thumbnail" alt="Image description" />
</a>
</li>
<li class="swiper-slide" itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
<a title="click to zoom-in" href="http://placehold.it/1200x600/EF5350/ffffff?text=Zoom-image-3" itemprop="contentUrl" data-size="1200x600">
<img src="http://placehold.it/600x300/EF5350/ffffff?text=Thumbnail-image-3" itemprop="thumbnail" alt="Image description" />
</a>
</li>
<li class="swiper-slide" itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
<a title="click to zoom-in" href="http://placehold.it/1200x600/1976D2/ffffff?text=Zoom-image-4" itemprop="contentUrl" data-size="1200x600">
<img src="http://placehold.it/600x300/1976D2/ffffff?text=Thumbnail-image-4" itemprop="thumbnail" alt="Image description" />
</a>
</li>
<li class="swiper-slide" itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
<a title="click to zoom-in" href="https://picsum.photos/1200/603" itemprop="contentUrl" data-size="1200x600">
<img src="https://picsum.photos/1200/603" itemprop="thumbnail" alt="Image description" />
</a>
</li>
</ul>
<!-- Add Pagination -->
<div class="swiper-pagination"></div>
<!-- If we need navigation buttons -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
<!-- Background of PhotoSwipe.
It's a separate element, as animating opacity is faster than rgba(). -->
<div class="pswp__bg"></div>
<!-- Slides wrapper with overflow:hidden. -->
<div class="pswp__scroll-wrap">
<!-- Container that holds slides. PhotoSwipe keeps only 3 slides in DOM to save memory. -->
<!-- don't modify these 3 pswp__item elements, data is added later on. -->
<div class="pswp__container">
<div class="pswp__item"></div>
<div class="pswp__item"></div>
<div class="pswp__item"></div>
</div>
<!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
<div class="pswp__ui pswp__ui--hidden">
<div class="pswp__top-bar">
<!-- Controls are self-explanatory. Order can be changed. -->
<div class="pswp__counter"></div>
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
<button class="pswp__button pswp__button--share" title="Share"></button>
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
<!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR -->
<!-- element will get class pswp__preloader--active when preloader is running -->
<div class="pswp__preloader">
<div class="pswp__preloader__icn">
<div class="pswp__preloader__cut">
<div class="pswp__preloader__donut"></div>
</div>
</div>
</div>
</div>
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
<div class="pswp__share-tooltip"></div>
</div>
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
</button>
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
</button>
<div class="pswp__caption">
<div class="pswp__caption__center"></div>
</div>
</div>
</div>
</div>
<!-- ////////////////////////
DOCS
////////////////////////////
-->
<section id="docs">
<br>
<br>
<br>
<hr>
<h2>Noted / Important</h2>
<ol>
<li>
<h3>Loop & Counter</h3>
<p>
<strong> Wont work well </strong> with swiper: <code>loop = true;</code> & photoswipe: <code>counterEl: true,</code>(What is counter? example: 1/5...2/5) - "loop" duplicate images - the photoswipe counter will be wrong. *** If you dont want a
loop - you can set photoswipe counter <code>counterEl: true,</code>
</p>
</li>
<li>
<h3>Markup</h3>
<p>
<a href="">Schema.org</a> markup + semantic HTML: use unordered (bulleted) list (If you want a div change JS - <strong>"(find) control+f-->"</strong> tagname value) . Copy-paste - this code to check: <a target="_blank" href="https://search.google.com/structured-data/testing-tool">Structured Data Testing Tool - Google</a>
</p>
</li>
<li>
<h3>Match index</h3>
<p>
<strong>
Extra CODE "match index"
</strong> - EXAMPLE: When you click(zoom) image1 -- goes to image 2 - close image2 (X) - also the swiper update is position (BETTER User Experience) (find(ctr +f)--> <code>mySwiper.slideTo(getCurrentIndex, false);</code>) - This idea miss
in most slider & lightbox examples/plugins mixed.
</p>
</li>
<li>
<h3>Photoswipe options</h3>
<p>
JS - line (find) -ctr +f --> the term:<code>// define options (if needed)</code>. You find endless options for <strong>photoswipe</strong> - This is the place to add/modify options. Full Options list her
<a href="http://photoswipe.com/documentation/options.html" target="_blank">PhotoSwipe
Options</a>
</p>
</li>
<li>
<h3>SWIPER options</h3>
<h4>slideperview</h4>
<p>
<code>slideperview</code> - option1: Set number (1,2,3 and so on) <a href="http://idangero.us/swiper/demos/110-slides-per-view.html" target="_blank"> - example </a> ||||| option2(<b>"Carousel Mode"</b> this example): Set to "<code>auto</code>"
than add CSS <a href="https://www.w3schools.com/cssref/pr_dim_width.asp" target="_blank">width Property</a></code> <code>.swiper-slide</code> (in thie case eash slide is 88% width) - <a href="http://idangero.us/swiper/demos/120-slides-per-view-auto.html"
target="_blank">example</a>.
</p>
<h4>spaceBetween & centeredSlides</h4>
<p>
Space Between slide by js option <code>spaceBetween</code> - and also usefull to change <code>centeredSlides</code>(true/flase). <br>
<a href="http://idangero.us/swiper/api/" target="_blank">Swiper API</a>
</p>
</li>
<li>
<h3>
A non-jQuery dependent
</h3>
</li>
</ol>
<hr>
<h3>Related Example</h3>
<p>
<a title="FancyBox3 & Flickity" href="https://codepen.io/ezra_siton/pen/OQmjoq" target="_blank">#FancyBox3 - lightbox & Flickity Slider</a>
</p>
</section>
/* 1 of 2 : SWIPER */
var mySwiper = new Swiper(".swiper-container", {
// If loop true set photoswipe - counterEl: false
loop: true,
/* slidesPerView || auto - if you want to set width by css like flickity.js layout - in this case width:80% by CSS */
slidesPerView: "auto",
spaceBetween: 7,
centeredSlides: true,
// If we need pagination
pagination: {
el: ".swiper-pagination",
clickable: true,
renderBullet: function(index, className) {
return '<span class="' + className + '">' + (index + 1) + "</span>";
}
},
// Navigation arrows
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
}
});
// 2 of 2 : PHOTOSWIPE
var initPhotoSwipeFromDOM = function(gallerySelector) {
// parse slide data (url, title, size ...) from DOM elements
// (children of gallerySelector)
var parseThumbnailElements = function(el) {
var thumbElements = el.childNodes,
numNodes = thumbElements.length,
items = [],
figureEl,
linkEl,
size,
item;
for (var i = 0; i < numNodes; i++) {
figureEl = thumbElements[i]; // <figure> element
// include only element nodes
if (figureEl.nodeType !== 1) {
continue;
}
linkEl = figureEl.children[0]; // <a> element
size = linkEl.getAttribute("data-size").split("x");
// create slide object
item = {
src: linkEl.getAttribute("href"),
w: parseInt(size[0], 10),
h: parseInt(size[1], 10)
};
if (figureEl.children.length > 1) {
// <figcaption> content
item.title = figureEl.children[1].innerHTML;
}
if (linkEl.children.length > 0) {
// <img> thumbnail element, retrieving thumbnail url
item.msrc = linkEl.children[0].getAttribute("src");
}
item.el = figureEl; // save link to element for getThumbBoundsFn
items.push(item);
}
return items;
};
// find nearest parent element
var closest = function closest(el, fn) {
return el && (fn(el) ? el : closest(el.parentNode, fn));
};
// triggers when user clicks on thumbnail
var onThumbnailsClick = function(e) {
e = e || window.event;
e.preventDefault ? e.preventDefault() : (e.returnValue = false);
var eTarget = e.target || e.srcElement;
// find root element of slide
var clickedListItem = closest(eTarget, function(el) {
return el.tagName && el.tagName.toUpperCase() === "LI";
});
if (!clickedListItem) {
return;
}
// find index of clicked item by looping through all child nodes
// alternatively, you may define index via data- attribute
var clickedGallery = clickedListItem.parentNode,
childNodes = clickedListItem.parentNode.childNodes,
numChildNodes = childNodes.length,
nodeIndex = 0,
index;
for (var i = 0; i < numChildNodes; i++) {
if (childNodes[i].nodeType !== 1) {
continue;
}
if (childNodes[i] === clickedListItem) {
index = nodeIndex;
break;
}
nodeIndex++;
}
if (index >= 0) {
// open PhotoSwipe if valid index found
openPhotoSwipe(index, clickedGallery);
}
return false;
};
// parse picture index and gallery index from URL (#&pid=1&gid=2)
var photoswipeParseHash = function() {
var hash = window.location.hash.substring(1),
params = {};
if (hash.length < 5) {
return params;
}
var vars = hash.split("&");
for (var i = 0; i < vars.length; i++) {
if (!vars[i]) {
continue;
}
var pair = vars[i].split("=");
if (pair.length < 2) {
continue;
}
params[pair[0]] = pair[1];
}
if (params.gid) {
params.gid = parseInt(params.gid, 10);
}
return params;
};
var openPhotoSwipe = function(
index,
galleryElement,
disableAnimation,
fromURL
) {
var pswpElement = document.querySelectorAll(".pswp")[0],
gallery,
options,
items;
items = parseThumbnailElements(galleryElement);
// define options (if needed)
options = {
/* "showHideOpacity" uncomment this If dimensions of your small thumbnail don't match dimensions of large image */
//showHideOpacity:true,
// Buttons/elements
closeEl: true,
captionEl: true,
fullscreenEl: true,
zoomEl: true,
shareEl: true,
counterEl: false,
arrowEl: true,
preloaderEl: true,
// define gallery index (for URL)
galleryUID: galleryElement.getAttribute("data-pswp-uid"),
getThumbBoundsFn: function(index) {
// See Options -> getThumbBoundsFn section of documentation for more info
var thumbnail = items[index].el.getElementsByTagName("img")[0], // find thumbnail
pageYScroll =
window.pageYOffset || document.documentElement.scrollTop,
rect = thumbnail.getBoundingClientRect();
return { x: rect.left, y: rect.top + pageYScroll, w: rect.width };
}
};
// PhotoSwipe opened from URL
if (fromURL) {
if (options.galleryPIDs) {
// parse real index when custom PIDs are used
// http://photoswipe.com/documentation/faq.html#custom-pid-in-url
for (var j = 0; j < items.length; j++) {
if (items[j].pid == index) {
options.index = j;
break;
}
}
} else {
// in URL indexes start from 1
options.index = parseInt(index, 10) - 1;
}
} else {
options.index = parseInt(index, 10);
}
// exit if index not found
if (isNaN(options.index)) {
return;
}
if (disableAnimation) {
options.showAnimationDuration = 0;
}
// Pass data to PhotoSwipe and initialize it
gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, options);
gallery.init();
/* EXTRA CODE (NOT FROM THE CORE) - UPDATE SWIPER POSITION TO THE CURRENT ZOOM_IN IMAGE (BETTER UI) */
// photoswipe event: Gallery unbinds events
// (triggers before closing animation)
gallery.listen("unbindEvents", function() {
// This is index of current photoswipe slide
var getCurrentIndex = gallery.getCurrentIndex();
// Update position of the slider
mySwiper.slideTo(getCurrentIndex, false);
});
};
// loop through all gallery elements and bind events
var galleryElements = document.querySelectorAll(gallerySelector);
for (var i = 0, l = galleryElements.length; i < l; i++) {
galleryElements[i].setAttribute("data-pswp-uid", i + 1);
galleryElements[i].onclick = onThumbnailsClick;
}
// Parse URL and open gallery if it contains #&pid=3&gid=1
var hashData = photoswipeParseHash();
if (hashData.pid && hashData.gid) {
openPhotoSwipe(hashData.pid, galleryElements[hashData.gid - 1], true, true);
}
};
// execute above function
initPhotoSwipeFromDOM(".my-gallery");
<script src="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.1/photoswipe.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.1/photoswipe-ui-default.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.3.5/js/swiper.min.js"></script>
/*==================================
SWIPER
===================================*/
/* remove bullet and space from the list */
ul.swiper-wrapper {
list-style-type: none;
margin: 0;
padding: 0;
}
/* Swiper styles */
.swiper-container {
max-width: 100%;
}
/* responive image */
.swiper-container img {
width: 100%;
height: auto;
}
.swiper-slide {
text-align: center;
/* Remove this if you want 1 slide perview - than change slidesPerView js-option to 1 -or- 2+ instead of 'auto' */
width: 80%;
}
/* Swiper custom pagination */
.swiper-pagination-bullet {
width: 34px;
height: 34px;
text-align: center;
line-height: 34px;
font-size: 14px;
color: #000;
opacity: 1;
background: rgba(0, 0, 0, 0.3);
}
.swiper-pagination-bullet-active {
color: #fff;
background: black;
}
/*======================================================
CODEPEN STYLES - Remove this from your code
=======================================================*/
.swiper-docs {
font-family: "Roboto", sans-serif;
}
.swiper-docs #docs h3 {
margin-bottom: 0px;
webkit-margin-after: 0em;
}
.swiper-docs #docs ol li:not(:first-of-type) {
border-top: thin solid rgba(203, 202, 204, 1);
}
.swiper-docs #docs p {
-webkit-margin-before: 1em;
line-height: 22px;
font-size: 0.9em;
}
.swiper-docs section #docs code {
padding: 0;
padding: 3px 5px;
margin: 0;
background: #f2f2f2;
border-radius: 2px;
}
.swiper-docs #docs ol li {
margin-bottom: 12px;
}
.swiper-docs {
max-width: 960px;
margin: 0px auto;
padding: 15px;
}
.swiper-docs a {
color: #4285f4;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.1/photoswipe.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.1/default-skin/default-skin.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.3.5/css/swiper.min.css" rel="stylesheet" />
@ofhope
Copy link

ofhope commented Mar 9, 2021

I moved these examples into Codepen to better explore this Gist https://codepen.io/bambii7/pen/mdOzame
Great work combining Swiper & Lightbox effect!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment