<meta name="description" content="Responsive no-jQuery pure JS/CSS Lightbox for iframes, no dependencies, customizable aspect ratio, 4 kb unminified source code, with demo">
<h1 class="title">iframe-lightbox Demo</h1>
<p>Responsive no-jQuery pure JS/CSS Lightbox for iframes, no dependencies, customizable aspect ratio, 5kb unminified source code, with demo</p>
<h2>Demo</h2>
<p>
<a href="https://codepen.io/englishextra/full/jmjayV/">codepen</a>
<a href="https://fiddle.jshell.net/englishextra/8pzy6uhr/show/">jsfiddle</a>
<a href="https://output.jsbin.com/saqine">jsbin</a>
</p>
<h2>Features</h2>
<ul>
<li>Simple initialization</li>
<li>Nicely fits YouTube / Vimeo / SoundCloud / Audiomack or other URL via iframe</li>
<li>Customizable aspect ratio via <code>data-padding-bottom</code> attribute</li>
<li>Iframe content can be scrollable or not (default)</li>
<li>Debounced launch, default 500ms, custom rate can be set with <code>rate</code> property of options object</li>
<li>Preloading spinner that is unset after onload event succeeds</li>
<li>Pure CSS Retina Ready UI images, no external ones (prompted by github.com/jasomdotnet, thanks)</li>
<li>Custom event callbacks</li>
</ul>
<h2>CDN</h2>
<h4>jsDelivr</h4>
<p>
<code>https://cdn.jsdelivr.net/gh/englishextra/iframe-lightbox@latest/iframe-lightbox.min.js</code>
<br />
<code>https://cdn.jsdelivr.net/gh/englishextra/iframe-lightbox@latest/iframe-lightbox.min.css</code>
</p>
<h4>unpkg</h4>
<p>
<code>https://unpkg.com/iframe-lightbox@latest/iframe-lightbox.js</code>
<br />
<code>https://unpkg.com/iframe-lightbox@latest/iframe-lightbox.css</code>
</p>
<h2>Install</h2>
<h4>npm</h4>
<p>
<code>npm install iframe-lightbox</code>
</p>
<h4>bower</h4>
<p>
<code>bower install iframe-lightbox</code>
</p>
<h2>Setup</h2>
<p><code>class</code> is not required. They are used here to select elements. You may use some other method for elements selection.</p>
<p><code>data-src</code> is deprecated, but supported for compatibility.</p>
<p><code>href</code> is required, and contains URL of your content.</p>
<p><code>data-padding-bottom</code> is optional, and can be used to change default 16/9 Aspect Ratio to the one of yours with the formula: a percentage value of <code>height/width*100</code>.</p>
<p>For instance, HD would be: 9 / 16 * 100 + "%"</p>
<p>So, for YouTube or Vimeo, <code>data-padding-bottom="56.25%"</code> would be enough.</p>
<p>For SoundCloud embedded player via iframe, use: <code>data-padding-bottom="166px"</code></p>
<p>For Audiomack embedded player via iframe, use: <code>data-padding-bottom="252px"</code></p>
<p>For Scrollable content set <code>data-scrolling="true"</code>, or add <code>scrolling</code> option property with <code>true</code></p>
<p><code>data-scrolling</code> is optional, makes iframe content scrollable or not (default); this can be set with <code>scrolling</code> option property.</p>
<h2><a class="iframe-lightbox-link" href="https://www.youtube.com/embed/KK9bwTlAvgo?autoplay=0" data-padding-bottom="56.25%" aria-hidden="true" rel="lightbox">YouTube</a></h2>
<pre><code><a
class="iframe-lightbox-link"
href="https://www.youtube.com/embed/KK9bwTlAvgo?autoplay=0"
data-padding-bottom="56.25%">YouTube</a></code></pre>
<h2><a class="iframe-lightbox-link" href="https://player.vimeo.com/video/165424115?autoplay=false" data-padding-bottom="56.25%" aria-hidden="true" rel="lightbox">Vimeo</a></h2>
<pre><code><a
class="iframe-lightbox-link"
href="https://player.vimeo.com/video/165424115?autoplay=false"
data-padding-bottom="56.25%">Vimeo</a></code></pre>
<h2><a class="iframe-lightbox-link" href="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/317031598&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true" data-padding-bottom="166px">SoundCloud</a></h2>
<pre><code><a
class="iframe-lightbox-link"
href="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/317031598&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;visual=true"
data-padding-bottom="166px">SoundCloud</a></code></pre>
<h2><a class="iframe-lightbox-link" href="https://audiomack.com/embed/song/bottomfeedermusic/no-shame-explicit" data-padding-bottom="252px" aria-hidden="true" rel="lightbox">Audiomack</a></h2>
<pre><code><a
class="iframe-lightbox-link"
href="https://audiomack.com/embed/song/bottomfeedermusic/no-shame-explicit"
data-padding-bottom="252px">Audiomack</a></code></pre>
<h2><a class="iframe-lightbox-link" href="https://www.w3.org/" data-scrolling="true" aria-hidden="true" rel="lightbox">Scrollable content</a></h2>
<pre><code><a
class="iframe-lightbox-link"
href="https://www.w3.org/"
data-scrolling="true">Scrollable content</a></code></pre>
<h2>Initialize</h2>
<pre><code>[].forEach.call(document.getElementsByClassName("iframe-lightbox-link"), function(el) {
el.lightbox = new IframeLightbox(el);
});</code></pre>
<h2>Tips</h2>
<p>SPA / PWA developers don't need to bother: built-in class is added to a link.</p>
<p>That way you avoid multiple assignments to a single element.</p>
<h2>Examples of event handling</h2>
<pre><code>(function (root, document) {
"use strict";
[].forEach.call(document.getElementsByClassName("iframe-lightbox-link"), function (el) {
el.lightbox = new IframeLightbox(el, {
onCreated: function () {
/* show your preloader */
},
onLoaded: function () {
/* hide your preloader */
},
onError: function () {
/* hide your preloader */
},
onClosed: function () {
/* hide your preloader */
},
scrolling: false, /* default: false */
rate: 500 /* default: 500 */
});
});
})("undefined" !== typeof window ? window : this, document);</code></pre>
<h2>GitHub</h2>
<p>Inspired by <a href="https://github.com/squeral/lightbox">squeral/lightbox</a></p>
<p><a href="https://github.com/englishextra/iframe-lightbox">englishextra/iframe-lightbox</a></p>
<h2>License</h2>
<p>Available under <a href="https://opensource.org/licenses/MIT">MIT License</a></p>
/*!
* modified Simple lightbox effect in pure JS
* @see {@link https://github.com/squeral/lightbox}
* @see {@link https://github.com/squeral/lightbox/blob/master/lightbox.js}
* @params {Object} elem Node element
* @params {Object} [rate] debounce rate, default 500ms
* new IframeLightbox(elem)
* passes jshint
*/
(function(root,document){"use strict";var docBody=document.body||"";var appendChild="appendChild";var classList="classList";var createElement="createElement";var dataset="dataset";var getAttribute="getAttribute";var getElementById="getElementById";var getElementsByClassName="getElementsByClassName";var _addEventListener="addEventListener";var containerClass="iframe-lightbox";var iframeLightboxOpenClass="iframe-lightbox--open";var iframeLightboxLinkIsBindedClass="iframe-lightbox-link--is-binded";var isLoadedClass="is-loaded";var isOpenedClass="is-opened";var isShowingClass="is-showing";var IframeLightbox=function(elem,settings){var options=settings||{};this.trigger=elem;this.el=document[getElementsByClassName](containerClass)[0]||"";this.body=this.el?this.el[getElementsByClassName]("body")[0]:"";this.content=this.el?this.el[getElementsByClassName]("content")[0]:"";this.src=elem[dataset].src||"";this.href=elem[getAttribute]("href")||"";this.dataPaddingBottom=elem[dataset].paddingBottom||"";this.dataScrolling=elem[dataset].scrolling||"";this.rate=options.rate||500;this.scrolling=options.scrolling;this.onOpened=options.onOpened;this.onIframeLoaded=options.onIframeLoaded;this.onLoaded=options.onLoaded;this.onCreated=options.onCreated;this.onClosed=options.onClosed;this.init();};IframeLightbox.prototype.init=function(){var _this=this;if(!this.el){this.create();}
var debounce=function(func,wait){var timeout,args,context,timestamp;return function(){context=this;args=[].slice.call(arguments,0);timestamp=new Date();var later=function(){var last=(new Date())-timestamp;if(last<wait){timeout=setTimeout(later,wait-last);}else{timeout=null;func.apply(context,args);}};if(!timeout){timeout=setTimeout(later,wait);}};};var logic=function(){_this.open();};if(!this.trigger[classList].contains(iframeLightboxLinkIsBindedClass)){this.trigger[classList].add(iframeLightboxLinkIsBindedClass);this.trigger[_addEventListener]("click",function(e){e.stopPropagation();e.preventDefault();debounce(logic,this.rate).call();});}};IframeLightbox.prototype.create=function(){var _this=this,bd=document[createElement]("div");this.el=document[createElement]("div");this.content=document[createElement]("div");this.body=document[createElement]("div");this.el[classList].add(containerClass);bd[classList].add("backdrop");this.content[classList].add("content");this.body[classList].add("body");this.el[appendChild](bd);this.content[appendChild](this.body);this.contentHolder=document[createElement]("div");this.contentHolder[classList].add("content-holder");this.contentHolder[appendChild](this.content);this.el[appendChild](this.contentHolder);this.btnClose=document[createElement]("a");this.btnClose[classList].add("btn-close");this.btnClose.setAttribute("href","javascript:void(0);");this.el[appendChild](this.btnClose);docBody[appendChild](this.el);bd[_addEventListener]("click",function(){_this.close();});this.btnClose[_addEventListener]("click",function(){_this.close();});root[_addEventListener]("keyup",function(ev){if(27===(ev.which||ev.keyCode)){_this.close();}});var clearBody=function(){if(_this.isOpen()){return;}
_this.el[classList].remove(isShowingClass);_this.body.innerHTML="";};this.el[_addEventListener]("transitionend",clearBody,false);this.el[_addEventListener]("webkitTransitionEnd",clearBody,false);this.el[_addEventListener]("mozTransitionEnd",clearBody,false);this.el[_addEventListener]("msTransitionEnd",clearBody,false);this.callCallback(this.onCreated,this);};IframeLightbox.prototype.loadIframe=function(){var _this=this;this.iframeId=containerClass+Date.now();this.iframeSrc=this.src||this.href||"";var iframeHTML=[];iframeHTML.push('<iframe src="'+this.iframeSrc+'" name="'+this.iframeId+'" id="'+this.iframeId+'" onload="this.style.opacity=1;" style="opacity:0;border:none;" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen="true" height="166" frameborder="no"></iframe>');iframeHTML.push('<div class="half-circle-spinner"><div class="circle circle-1"></div><div class="circle circle-2"></div></div>');this.body.innerHTML=iframeHTML.join("");(function(iframeId,body){var iframe=document[getElementById](iframeId);iframe.onload=function(){this.style.opacity=1;body[classList].add(isLoadedClass);if(_this.scrolling||_this.dataScrolling){iframe.removeAttribute("scrolling");iframe.style.overflow="scroll";}else{iframe.setAttribute("scrolling","no");iframe.style.overflow="hidden";}
_this.callCallback(_this.onIframeLoaded,_this);_this.callCallback(_this.onLoaded,_this);};})(this.iframeId,this.body);};IframeLightbox.prototype.open=function(){this.loadIframe();if(this.dataPaddingBottom){this.content.style.paddingBottom=this.dataPaddingBottom;}else{this.content.removeAttribute("style");}
this.el[classList].add(isShowingClass);this.el[classList].add(isOpenedClass);docBody[classList].add(iframeLightboxOpenClass);this.callCallback(this.onOpened,this);};IframeLightbox.prototype.close=function(){this.el[classList].remove(isOpenedClass);this.body[classList].remove(isLoadedClass);docBody[classList].remove(iframeLightboxOpenClass);this.callCallback(this.onClosed,this);};IframeLightbox.prototype.isOpen=function(){return this.el[classList].contains(isOpenedClass);};IframeLightbox.prototype.callCallback=function(func,data){if(typeof func!=="function"){return;}
var caller=func.bind(this);caller(data);};root.IframeLightbox=IframeLightbox;})("undefined"!==typeof window?window:this,document);
(function(root, document) {
"use strict";
[].forEach.call(document.getElementsByClassName("iframe-lightbox-link"), function(el) {
el.lightbox = new IframeLightbox(el, {
onCreated: function() {
/* show your preloader */
},
onLoaded: function() {
/* hide your preloader */
},
onError: function() {
/* hide your preloader */
},
onClosed: function() {
/* hide your preloader */
},
scrolling: false,
/* default: false */
rate: 500 /* default: 500 */
});
});
})("undefined" !== typeof window ? window : this, document);
Output
300px
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |