Giter VIP home page Giter VIP logo

fluidbox's Introduction

Fluidbox

Build Status Latest Github release Average issue resolution time

Replicating and improving the lightbox module seen on Medium with fluid transitions. View demo here. For users who are looking for a quick setup and/or troubleshooting process, refer to basic usage, but do not forget to read the usage precautions and frequently asked questions.

Although not thoroughly tested, Fluidbox should be working in IE ≥10 and all versions of Chrome, Firefox, Safari, iOS Safari and Android Chrome, with the exception of Opera Mini. However, I suggest disabling Fluidbox on mobile devices or at small screen resolutions.

Special thanks to the following stellar folks who has helped majorly in making Fluidbox better:

  • @hybernaut for refactoring the code and reorganizing functions
  • @maxee for implementation of a new feature that enables differential image ratios between thumbnails and linked image
  • @benwhilhelm for suggesting the immedate open option in Fluidbox. Ben has author a PR, but I have found some issues that I cannot resolve. However, I have adopted his idea and simplified the implementation in v1.4.3.
  • @jaechick for creating the LESS file for Fluidbox stylesheet.

In addition, a shoutout to:

  • Paul Irish for graciously allowing me to include a simple debouncing script in the plugin to handle viewport resize events
  • David Walsh and Jonathan Suh for their insight on listening to transitionend events

Introduction

Fluidbox was initially a simple personal challenge I set myself, with two simple aims—to replicate the distraction-free, fluid lightbox seen on Medium, and to improve on it such that it will allow linking to a larger-resolution image. The plugin deals with higher resolution, linked images elegantly, such that it only preloads them when users click on the thumbnails, therefore conserving bandwidth usage for your visitors and your server(s).

The plugin is relatively lightweight: 6.23kb (1.98kb after gzipped) for the minified JS file, and 1.91kb (728b after gzipped) for the minimal stylesheet.

You can read my article on Medium about how I got inspiration for this little project of mine, and the basic mechanisms behind the plugin. Some serious math is involved (nah, not really).

Moreover, you can visit the demo of this plugin on the project page hosted with GitHub. The plugin version 1.22 and onwards (uncompressed, minified and its associated CSS file) is hosted with CDNJS.

In the wild

Fluidbox is part of the vast collection of libraries proudly hosted by CDNJS. You can reference all versions of Fluidbox published hitherto from there.

Fluidbox has been implemented on other sites in the wild, too—check it out:

Some external resources that might help you:

To add your site that has implemented Fluidbox, or an article/tutorial you have written on Fluidbox use and/or application, feel free to write to me at @teddyrised.

Changelog

Version Comments
1.2.0 Official release
1.2.1 Minor bug fixes
1.2.2
  • Bug fix: Changed positioning of overlay, to ensure that it works in pages with absolutely- or relatively-positioned parent/wrapper elements with z-indexs specified
  • Update: Fluidbox is now available via CDNJS.
1.2.3
  • Bug fix: Fixed the iamge switching issue when Fluidbox is closed, which causes two flashes of white. This is done by listening to the transitionend property, with a tiny hack.
  • Update: JS is minifised using UglifyJS instead of the YUI compressor, saving a wee bit more bandwidth for you.
1.2.4α Warning: Buggy, alpha-build
  • Bug fix: Removed the white flash issue by rearranging how overlay is appended to the DOM tree. Users can change the z-index in the CSS file freely (to suit their layout needs), as the script will store the original assigned z-index in a HTML5 data- attribute for manipulation, in order to restore the original z-index
  • License notice: Switched from GNU to MIT.
1.2.5
  • Bug fix: Minimized white flash issue and fixed the stacking order bug introduced in v1.2.4α. A new option is now available, known as stackIndex. It is set to 999 by default, but if you have other absolutely positioned elements on the page that you want to overlay, you can change this option (alternatively, modify/lower the z-index of offending elements).
  • Update: Included the updated licenses in license.md and license.txt.
1.2.6
  • Bug fix: Replaced the use of transitionend event detection for timing effects, due to the fact that the event lacks cross-browser support and standardization. This issue is particularly bad for Firefox, which showed that the transitionend is not triggered properly, causing parts of the plugin to break. I have chosen to fall back to the native JS' setTimeout and clearTimeout functions.
1.2.7
  • Bug fix: Fixed issues when the .one() event is not propery unbound, especially after rapid, successive clicking.
  • Update: Added a new option called stackIndexDelta, where you can dictate how much the z-index should change when Fluidbox is toggled. The default is set to 10. If you have a lot of absolutely positioned elements on the page, you might want to increase this delta value.
1.3.0
  • Update: Authored by @hybernaut. Removes dependency on imagesLoaded for a speedier performance—instead, listens to .load() event on each individual Fluidbox thumbnail separately when triggering Fluidbox. Click handler has been migrated to a separate function to aid clarity.
  • Bug fix: The resize function used to check for the presence of a[data-fluidbox], which might not be present if users choose other ways to identify Fluidbox thumbnails. Selector has been updated to the universal a.fluidbox.fluidbox-opened.
1.3.1
  • Update & bug fix: Removed timer in JS, and rely on CSS3's very own transition-delay instead. This fixes the issue of rapid clicking causing the enlarged image not showing up.
1.3.2
  • Update: Added support for borders and paddings on Fluidbox images.
1.3.3
  • Bug fix: Added transition delay to thumbnail.
1.3.4
  • Update: Upon popular request, I have added a new feature such that Fluidbox does not enlarge excessively images that lack the necessary resolution to fill the viewport. Also updated readme to clarify basic usage details.
  • Bug fix: Fluidbox not working with elements that are hidden. Now Fluidbox only binds to visible elements on the page. If you are revealing images later (by user interaction, AJAX requests and the likes), please bind .fluidbox() to newly visible elements.
1.3.5
  • Update: Removed overlayColor settings for Fluidbox. The option is now delegated to the stylesheet, which allows for easy customization of overlays for different Fluidbox instances. It is therefore possible to specify custom overlay colours, background gradients and even images for Fluidbox.
1.4.0
  • Update: Authored by @maxee. Now supports differential aspect ratios of thumbnails and linked images.
  • Bug fix: Fixed namespace clash issue that leads to crashing of IE8.
1.4.1
  • Update: Added custom event handlers to allow for addition of application-specific callbacks. For more information, refer to the custom events section for usage instructions.
1.4.2
  • Update: Added custom event triggers to allow for manual triggering of Fluidbox recomputation/recalculation upon layout changes that are independent of viewport resizes (therefore not triggering the $(window).resize() event. For more information, refer to the custom triggers section for usage instructions.
  • Bug fix: A hitherto undiscovered bug that causes the closeTrigger settings to propagate to all instances of Fluidboxes on the same page, even though it was only specified for a subset of instances, has been fixed. This bug has been present since the first release—so if you are intending to use custom events to close Fluidbox instances, it is strongly recommended that you upgrade to v1.4.2 and later.
1.4.3
  • Post-release note: v1.4.3 came with a bug that only occurs in Safari, involving the browser's refusal to scale and re-render the background image properly when a super-imposing element (e.g. the loader) is present. This will be fixed in v1.4.4, and the fix has been implemented as of commit 2aad89d2bd.
  • Update: Enabled the option to trigger immediate opening of Fluidbox. This has to be turned on manually, by setting immediateOpen to true during initialization.
  • Added five new custom events that are triggered.
  • Rearranged some code with regards to opening and closing of Fluidbox instances for better readability, fixed indentation inconsistencies in original JS file.
  • Added an animated CSS loader to Fluidbox instances, exceptionally important for delayed opening setups (default setup) as users are often unaware if Fluidbox has failed, or simply waiting for target image to be preloaded. The appearance of the loader is purely controlled by a CSS pseudo-element, activated upon the addition of .fluidbox-loading class.
  • The stylesheet of Fluidbox has been ported over to LESS, in addition to SCSS.

Installation

To install Fluidbox, you will have to include the following resources in your page. The JS files should be loaded in the order stipulated below. For the CSS file, you can either incorporate it with your site's stylesheet, or load it externally through the <link> element in <head>.

Type File Name Description
JS jQuery 1.x External Dependency: The latest verson of jQuery 1.x library is needed for Fluidbox functionality. Minimum version requirement: v1.7
JS jquery.fluidbox.js Confers the main functionality of Fluidbox. Alternatively, you can load the minified version, jquery.fluidbox.min.js
CSS css/fluidbox.css Offers styles that are crucial for the correct display of Fluidbox. The appearance will break if this is not included.

In order to support CSS animation and transformation applied by fluidbox.css in browsers that require vendor prefixes, you should consider using prefixfree.js as a dependency.

Usage

Basic

It is rather straightforward to use Fluidbox—simply chain the .fluidbox() method to a selector of your choice. The plugin will automatically check if the selector is:

  1. An anchor element with an href to the correct image url
  2. Contains one and only one child
  3. The only children is an <img> element
  4. Is visible upon DOM ready (v1.3.4 onwards)

In the event that the element that satisfies the selector criteria but failed any one of the above criteria, the element will be ignored and the plugin moves on to the next available element. Therefore, it is important that your Fluidbox element(s) follow the following format. The title and alt attributes of the <img> element is not used by the plugin, but the alt attribute has to be present for it to be semantically valid.

<a href="path/to/image">
    <img src="path/to/image" alt="" />
</a>

In your JS file, you can simply chain the .fluidbox() method to your selector on DOM ready:

$(function () {
    $('a').fluidbox();
})

The selector can be anything of your choice. Let's say you want to target the <a> elements specifically in a certain section on your page:

<section id="gallery">
    <h1>Title</h1>
    <p>Introductory text with an <a href="#">unrelated link</a></p>
    <a href="..." rel="lightbox">
        <img src="..." alt="" />
    </a>
</section>

Then, you can use, for example:

$(function () {
    $('#gallery a[rel="lightbox"]').fluidbox();
})

Custom triggers

As of v1.4.2, Fluidbox allows users to trigger manual recomputing of the dimensions of the overlay and that of the active Fluidbox instance. This functionality is extremely useful when you make layout changes that repaints the canvas and alters the dimensions of linked Fluidbox images. In order to do so, you will have to trigger the event manually, after the changes in the DOM, or element dimensions has been applied.

An example would be changing the size of the Fluidbox thumbnail:

$('button').click(function() {
    $(selector)
    .css('width', '200px')
    .trigger('recompute'); 
});

Custom events

As of v1.4.1, Fluidbox will trigger several distinct events depending on the state of the current (and only) instance of Fluidbox. You should use .on() to listen to the event being triggered, and can add your own custom callbacks if necessary, for example:

$(selector)
.fluidbox()
.on('openstart', doSomething)
.on('closeend', doSomethingElse);

The list of custom events supported by Fluidbox is as follow:

Event Version Description
openstart 1.4.1 Fired when a click event is registered from a Fluidbox instance that triggers its opening. This is called after the linked image has been successfully loaded.
openend 1.4.1 Fired when the transitionend event is fired (with appropriate vendors supported). This happens when Fluidbox has been scaled to its final size (determined by viewportScale, see configuration). The timing between openstart and openend are dictated by the transition-duration settings in fluidbox.css, or any overrides that you have implemented that targets the class .fluidbox-ghost.
resizeend 1.4.1 Fired when the positioning and scale of an opened Fluidbox instance is recalculated and has been transitioned to completion.
closestart 1.4.1 Fired when a click event is registered from a Fluidbox instance that triggers its closing.
closeend 1.4.1 Fired when the transitionend event is fired (with appropriate vendors supported). This happens when Fluidbox has been scaled back to its original thumbnail size on the page. The timing between closestart and closeend are dictated by the transition-duration settings in fluidbox.css, or any overrides that you have implemented that targets the class .fluidbox-ghost.
recomputeend 1.4.2 Fired when the Fluidbox ghost element, or the active Fluidbox on display, is recomputed due to layout changes not dependent on the $(window).resize() event. This is triggered manually by the custom trigger recompute (see usage instructions).
delayedloaddone 1.4.3 Fired only when the immediateOpen option is set to true (see configuration). Indicates that the target/linked image has been successfully loaded.
delayedreposdone 1.4.3 Fired only when the immediateOpen option is set to true (see configuration). Indicates that the ghost image has been transformed successfully after retrieving the natural dimensions of the newly loaded image.
imageloaddone 1.4.3 Fired when the target/linked image is successfully loaded. Synonymous with delayloaddone if immediateOpen option is set to true.
imageloadfail 1.4.3 Fired when the target/linked image fails to load.
thumbloaddone 1.4.3 Fired when the thumbnail has been loaded. Will only happen once, when .fluidbox() is first applied to the element.
thumbloadfail 1.4.3 Fired when the thumbnail fails to load. Will only happen once, when .fluidbox() is first applied to the element.

Previously hidden elements

As of v1.3.4, Fluidbox will only work with elements that are visible, i.e. not display: none, on the page upon DOM ready. This is because dimensions of hidden images (or images in parents who are hidden) are inaccesible to Fluidbox, resulting in an error. You will have to rebind Fluidbox to the newly revealted elements. Given the example below:

// Apply Fluidbox to elements of interest
$('.gallery a').fluidbox();

// User-triggered event to display gallery
$('#show-gallery').click(function () {
    $(this).next().show();
});
<button type="button" id="show-gallery">Show Gallery</button>
<div class="gallery" style="display: none">
    <a href="...">
        <img src="..." alt="" />
    </a>
</div>

You will realize that, even after revealing the element, the Fluidbox method is not working for it. That is because non-visible elements, despite satisfying the selector, will not be bound. So, use the following code instead:

// Apply Fluidbox to elements of interest
$('.gallery a').fluidbox();

// User-triggered event to display gallery
$('#show-gallery').click(function () {
    $(this)
        .next()
        .show()             // Show gallery
        .find('a')          // Fluidbox to all elements in gallery
            .fluidbox();
});

Dynamically-added elements

In order to enable Fluidbox functionality to dynamically-added content, you will have to apply .fluidbox() to the element of interest after appending it to the DOM. For example, let's say clicking a <button> triggers the addition of a new image:

$(function() {
    $('button').click(function(e) {
        e.preventDefault();
        
        // Construct new image
        var $newContent = $('<div><p>This is a new image that is dynamically-added to the page.</p><a href="http://placehold.it/500x500" title="" data-fluidbox><img src="http://placehold.it/200x200" alt="Alternate Text" title="Image Title" /></a></div>');
        
        // Insert new content object into DOM, and then apply .fluidbox to it
        $(this).after($newContent).next().find('a[data-fluidbox]').fluidbox();
    });
));

You are of course welcome to use other ways to manipulate and/or transverse the DOM, but you will have to adjust the search/filter function (using .find() or other similar jQuery methods) to retrieve the newly inserted content and search for the element of interest where you want Fluidbox to work with.

Configuration

Fluidbox can be configured according to your needs. The following options are available:

Variable/Option Type Default value Description
viewportFill Numerical 0.95 Dictates how much the longest axis of the image should fill the viewport. The default value will make the image fill 95% of the viewport dimension along its longest axis
overlayColor String rgba(255,255,255,.85)

Warning: Deprecated from v1.3.5. The overlay color is now dictated in the stylesheet, allowing custom overlays for each Fluidbox instance.

Legacy description: Sets the background-color property of Fluidbox overlay. Defaults to white with an opacity of 0.85.

debounceResize Boolean true Dictates if the $(window).resize() event should be debounced for performance reason. This feature leverages the small snippet kindly provided by Paul Irish.
closeTrigger Array see below Dictates what event triggers closing of an opened Fluidbox. The default setup binds the click handler to the overlay.
stackIndex Integer 999 Determines how high up the z-index will all Fluildbox elements be. Leave this option as default, unless you have other relatively or absolutely positioned elements on the page that is messing with Fluidbox appearance.
immediateOpen Boolean false Launches the Fluidbox instance immediately when a click event is triggered, regardless of whether the target/linked image has been preloaded. When this value is set to true, the custom events delayedloaddone and delayedreposdone will be fired when the target/linked image is subsequently loaded and the ghost image dimensions being recomputed.

User-defined settings have to be passed as the aforementioned variables/options to the .fluidbox() method, i.e.:

$('a').fluidbox({
	viewportFill: 0.8,
	debounceResize: false
});

Note on closeTrigger option

The default setup will have the effect of binding the click event to the overlay, so that when user click on the overlay, the Fluidbox instance that is opened will be closed:

// Default option
closeTrigger: [
    {
        selector: '#fluidbox-overlay',
        event: 'click'
    },
    {
        selector: 'document',
        event: 'keyup',
        keyCode: 27
    }
]

It is also possible to bind other events to trigger the same effect. For example, if you would want to close the Fluidbox when the viewport is resized, you can do the following:

$(function () {
    $('a').fluidbox({
        closeTrigger: [
            { selector: '#fluidbox-overlay', event: 'click'  },
            { selector: 'window',            event: 'resize' }
        ]
    });
});

This will have the effect of doing so (where closeFb is the internal function in the plugin needed to close any opened Fluidbox):

$(document).on('click', '#fluidbox-overlay', closeFb);
$(window).on('resize', closeFb);

You can even bind event to multiple selectors, and vice versa. The syntax of dictating so is similar to constructing event handler binding using the .on() method, so if you are familiar with its use, dictating your own closeTrigger should not be too difficult:

$(function () {
    $('a').fluidbox({
        closeTrigger: [
            { selector: '#fluidbox-overlay', event: 'click'         },
            { selector: 'window',            event: 'resize scroll' },
            { selector: '#ele1, #ele2',      event: 'hover'         }
        ]
    });
});

This will have the effect of doing so:

$(document).on('click', '#fluidbox-overlay', closeFb);
$(window).on('resize scroll', closeFb);
$(document).on('hover', '#ele1, #ele2', closeFb)

Dependencies

Fluidbox require the following dependencies in order to function properly—you will have to include them in your page, if you want Fluidbox to work:

  • The latest release of jQuery 1.x (minimum requirement: jQuery ≥1.7), available from Google's jQuery API at http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js

Note that the imagesloaded jQuery plugin is no longer required as of v1.2.8 and above.

Fluidbox allows you to throttle the $(window).resize() event, and this is only possible with Paul Irish's debounced resize function. The small script has been included in the plugin by default, but I would like to extend my gratitude to Paul for making it available, and for allowing me to include it in this plugin.

Known Issues

Transition of CSS3 transform in Safari

For inexplicable reason(s), Safari no longer transition CSS transformations (the scale component especially) after the first time the Fluidbox has been opened. A simple workaround would be enabling the immediateOpen option (i.e. immediateOpen: true) when initializing Fluidbox.

Precautions

Overflowing content

Fluidbox may not work properly in the event that you have set your parent container, or content wrapping elements, such as <div id="#content"> and the likes, to hide their overflowing content, i.e. overflow: hidden. This is because the enlarged image is positioned relatively to its hyperlink, and not absolutely or fixed within the viewport.

Interaction with other positioned elements on the same page

When you want an absolutely/fixed-positioned element on the page to not be obscured by the dynamically-generated wrapping element, you should use a z-index of between 1000 to 1010. 1000 is set as the default stackIndex of Fluidbox, while 10 is set as the default stackIndexDelta, which is toggled on/off depending on the state of the Fluidbox. These settings can be individually tuned, see Configuration below.

Binding Fluidbox to previously hidden images

As Fluidbox requires access to the final calculation dimensions of the image in question in order to (1) position the ghost element correctly and (2) calculate the correct scale factor and transform values, it will only bind to images that are visible upon DOM ready. If you are relying on dynamic events (e.g. user-triggered, AJAX-loaded and etc.) to trigger a later appearance of an image, rebind Fluidbox to freshly revealed elements. This also applies to dynamically-loaded content, see demo for a working example.

Derped ghost element calculations in flexbox layouts

In some cases—which I have also experienced myself—the ghost element that overlays the thumbnail might have incorrect dimensions being calculated. This is because its dimensions are calculation on DOM ready by retrieving the computed dimensions of the underlying image. When the flexbox layout is active, the browser might change the dimensions of the image when flex-grow and/or flex-shrink are enabled (i.e. set to a non-zero integer). The cause is likely to be that the browser receives information on the image dimensions after DOM ready and then resizes the flex containers, which happens after the computed widths are fed to Fluidbox calculations.

In this case, I strongly recommend triggering the recomputer custom trigger (see above) after all images in the flexbox container has loaded. You can do this upon $(window).load(), but you can also use jQuery deferred objects and promises to do so. Let's say we have a flexbox container with the class of .flex:

// Do this AFTER Fluidbox has been initialized
$('.flex').each(function() {
    var images = [],
        $fb = $(this).find('a.fluidbox');

    $f.find('img').each(function() {
        var image = $.Deferred();
        $(this).load(image.resolve).error(image.resolve);
        images.push(image);
    });

    $.when.apply(null, images).done(function() {
        $fb.trigger('recompute');
    });
});

Accidental creation of new stacking contexts

There are a few CSS properties, when applied to the wrapping parent of elements meant for the .fluidbox() method, causes a new stacking context to be created—this leads to an issue where an opened Fluidbox instance will fail to cover its neighbouring elements.

They are, in alphabetical order but not exhaustively so:

  • CSS3 regions1
  • filter1, 2
  • flex3
  • isolation3
  • mix-blend-mode3
  • opacity1
  • position1, 3
  • paged media1
  • transform1
  • will-change3

Sources:

  1. What No One Told You About Z-Index by Philip Walton
  2. Why does stacking order change on webkit filter hover? on StackOverflow
  3. The stacking context on MDN

Frequently Asked Questions

  1. Fluidbox is not working in my installation. Where should I start?
    Start by checking your browser's console log. What error messages do you see? Also, make sure that you are using the latest version of jQuery 1.x (minimum requirement: v1.8 or above) and that the dependencies have been loaded successfully. Also, did you remember reading the usage precautions? You might have encountered a scenario where Fluidbox is not designed to handle.

  2. Do you plan to implement [insert feature]?
    Fluidbox is conceived as a means to simplify lightboxes. Therefore, I plan to keep Fluidbox as simple as it is, without additional features, such as captioning (there are other limitations to this, too) and gallery features. However, you can always fork and modify Fluidbox to your personal liking. Manual captioning is possible, refer to the [advanced demo].

  3. The image url isn't being interpretted correctly.
    Fluidbox fetches the larger image based on the URL specified in the href attribute if the wrapping anchor (<a>) tag.

  4. I have a application-specific problem that I need help troubleshooting. Can you help me?
    Of course! I am more than happy to help, but it really depends if you have a clear problem statement and a minimal, complete and verifiable example (MCVE) that I can play around with—I strongly encourage you to host your reduced test case(s) with either JSFiddle, CodePen or the likes. Then, create a new issue. I promise I will get back to you when I have time.

  5. Do you provide private support by email / phone call / Skype call / (insert any other forms of communication)?
    Since Fluidbox is provided as-is and free-of-charge, I am sorry to inform you that it is so far not possible for me to dedicate so much effort. However, you can follow what is described in step #4.

Licensing: MIT License

This plugin is licensed under the MIT License.

fluidbox's People

Contributors

terrymun avatar hybernaut avatar benwilhelm avatar maxee avatar zorker avatar jeffpersonified avatar joshuapinter avatar marcstoecker avatar m19c avatar toddmoy avatar jchck avatar

Watchers

javy_liu avatar James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.