Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel is required to process package imports. If you need a different preprocessor remove all packages first.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <!--<img class="img01" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/265602/zoomanimaux03.jpg">-->

	<div class="enlarge_pane_contain">
		<div class="enlarge_pane">
			<div class="enlarge">
				<div class="enlarge_contain">
					<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/265602/zoomanimaux03.jpg" srcset="https://s3-us-west-2.amazonaws.com/s.cdpn.io/265602/zoomanimaux03.jpg 480w, https://s3-us-west-2.amazonaws.com/s.cdpn.io/265602/zoomanimaux03.jpg 1200w, https://s3-us-west-2.amazonaws.com/s.cdpn.io/265602/zoomanimaux03.jpg 2000w" sizes="100vw" alt="" id="test-img">
				</div>
				
				<a href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/265602/zoomanimaux03.jpg" class="enlarge_btn" title="Toggle Zoom">Toggle Zoom</a>
			</div>
		</div>
	</div>
              
            
!

CSS

              
                body {
		max-width: 600px;
		margin: 50px auto;
	background-color: #FAFAFA;
	cursor: cell;
}
.enlarge_btn {
	display: none;
}

img:active {
	transform: scale(10);
}

/*
 * enlarge plugin
 *
 * Copyright (c) 2016 Filament Group, Inc.
 * Licensed under MIT
*/
.enlarge_pane_contain,
.enlarge_pane {
	position: relative;
}
.enlarge_btn {
	position: absolute;
	top: 8px;
	left: 8px;
	font-size: 12px;
	overflow: hidden;
	background-color: rgba(255,255,255,.8);
	color: #000;
	text-decoration: none;
	padding: .5em;
}
.enlarge_btn:hover,
.enlarge_btn:focus {

}
.enlarge_btn:active {

}
.enlarge_disabled .enlarge_btn {
	display: none;
}
.zoom-out {

}
.enlarge-locked .enlarge_btn {
	background-color: #333;
	color: #fff;
	border-color: #333;
	background-image: url(/img/zoom-out-light.svg);
}
.enlarge-zoomed {
	overflow: hidden;
}
.enlarge_contain {
	overflow: hidden;
	-webkit-overflow-scrolling: touch;
	display: block;
	position: relative;
	height: 100%;
}
.enlarge_contain img {
	width: 100%;
	-webkit-touch-callout: none; /* image share menus get in the way of the interaction */
}
.enlarge-zoomed .enlarge_contain img,
.enlarge-zoomed.enlarge_flyout .enlarge_contain img {
	max-width: none;
}
.enlarge-locked .enlarge_contain {
	overflow: scroll;
}
.enlarge_loader {
	top: 0;
	left: 0;
	width: 100%;
	height: 5px;
	position: absolute;
	z-index: 30;
	background: #eee;
	opacity: 0;
	display: none;
}
.enlarge-delay .enlarge_loader {
	/* opacity: .4; disable loader for now */
}
.enlarge_loader * {
	width: 0;
	display: block;
	height: 5px;
	background: #4fa4c0;
	-webkit-transition: width .6s linear;
	transition: width .6s linear;
}

.enlarge_img-loading {
	position: absolute;
	left: -9999px;
	opacity: 0;
}
.enlarge_flyout {
	overflow: hidden;
	opacity: 0;
	transform: scale(0);
	transition: transform .3s;
	position: absolute;
	z-index: 9999;
}
.enlarge_flyout-flyoutloupe {
	border-radius: 100%;
	/*border: 5px solid #fff;*/
	box-shadow: 0 0 5px black;
	  pointer-events: none;
}
.enlarge_flyout-flyouttopleft,
.enlarge_flyout-flyouttopright {
	top: 0;
}
.enlarge_flyout-flyoutbottomleft,
.enlarge_flyout-flyoutbottomright {
	bottom: 0;
}
.enlarge_flyout-flyouttopright,
.enlarge_flyout-flyoutbottomright {
	transform-origin: left;
}
.enlarge_flyout-flyouttopleft,
.enlarge_flyout-flyoutbottomleft {
	transform-origin: right;
}
.enlarge-zoomed.enlarge_flyout {
	transform: scale(1);
	opacity: 1;
	overflow: hidden;
}
.enlarge-zoomed.enlarge_flyout .enlarge_contain {
	overflow: visible;
}
.enlarge-locked.enlarge_flyout {
	overflow: auto;
}

              
            
!

JS

              
                // DOM-ready auto-init of plugins.
// Many plugins bind to an "enhance" event to init themselves on dom ready, or when new markup is inserted into the DOM
(function( $ ){
	$( function(){
		$(".enlarge.inline-demo").data("options", {
			button: true,
			hoverZoomWithoutClick: true,
			delay: 300,
			flyout: {
				width: 300,
				height: 300
			},
			placement: "inline",
			magnification: 5
		});


		$( document ).bind( "enhance", function(){
			$( "body" ).addClass( "enhanced" );
		});

		$( document ).trigger( "enhance" );
	});
}( jQuery ));

/*
 * enlarge plugin
 *
 * Copyright (c) 2013 Filament Group, Inc.
 * Licensed under MIT
 */

/* global enlarge:true */
(function( $, window, undefined ) {

	var pluginName = "enlarge",
		initSelector = "." + pluginName;

	// auto-init on enhance (which is called on domready)
	$( document ).bind( "enhance", function( e ){
		$( initSelector, e.target ).each(function(){
			$(this)[ pluginName ]();
		});
	});

}( jQuery, this ));

/*
 * enlarge plugin
 *
 * Copyright (c) 2016 Filament Group, Inc.
 * Licensed under MIT
 */
;(function( w ){
	var enlarge = function(){
		var $ = w.jQuery;
		var pluginName = "enlarge";
		$.fn[ pluginName ] = function( options ){

			var pluginArgs = arguments;

			// options
			var o = $(this).data("options") || {
				button: true,
				hoverZoomWithoutClick: true,
				delay: 300,
				flyout: {
					width: 300,
					height: 300
				},
				placement: "flyoutloupe",
				magnification: 3
			};

			if( typeof options !== "string" ) {
				// extend with passed options
				o = $.extend( o, options );
				$(this).data("options", o);
			}

			var internalResult;

			var result = this.each(function(){
				var $element = $(this);

				var self = this;
				var testimg = w.document.createElement( "img" );
				var srcsetSupported = "srcset" in testimg;
				var srcsetSizesSupported = srcsetSupported && "sizes" in testimg;
				var $anchor = $( this ).find( "a" );

				if( !$anchor.length ){
					throw new Error(pluginName + ": requires an anchor element with `href` for the enlarged image source");
				}

				// find image within container
				var initialImg = $element.find( "img" )[ 0 ];
				var targetImg = initialImg;
				var imgOriginalSrc = targetImg.src;
				var srcset = $( targetImg ).attr( "srcset" );
				var imgOriginalSizes = $( targetImg ).attr( "sizes" );
				var imgZoomSrc = $anchor[ 0 ].href;
				var initialText = $anchor[ 0 ].innerText;
				var zoomClass = pluginName + "-zoomed";
				var delayClass = pluginName + "-delay";
				var $contain = $( targetImg ).closest( ".enlarge_contain" );
				var $zoomContain = $contain;
				var $parentPane = $( targetImg ).closest( ".enlarge_pane" ) || $element;

				var $zoomParent = $(this).data("zoomParent") || $parentPane;
				$(this).data("zoomParent", $zoomParent);

				var zoomed = $element.data("zoomed") || false;
				$element.data("zoomed", zoomed);

				$element.data("lockedZoom", $element.data("lockedZoom") || false);

				var lockZoomClass = pluginName + "-locked";

				if( !$contain.length ){
					throw new Error(pluginName + ": requires an element above the image marked with the class `enlarge_contain`");
				}

				// this allows for methods and changing options in subsequent calls to the plugin
				if( typeof options === "string" ) {
					var args = Array.prototype.slice.call(pluginArgs, 1);

					switch(options){
					case "in":
						if( !$element.data("zoomed") ){
							standardToggleZoom();
						}
						break;
					case "out":
						if( $element.data("zoomed") ){
							standardToggleZoom();
						}
						break;
					case "isZoomed":
						internalResult = $element.data("zoomed");
						break;
					case "updateOptions":
						$element.data( "updateOptions" )( args[ 0 ] );
						break;
					}
					return;
				}

				// to toggle between inline and flyout modes, we change the elements that
				// the targetImg, zoomParent, and zoomContain vars refer to
				function updatePlacement(){
					if( o.placement === "inline" ){
						targetImg = initialImg;
						$zoomParent = $parentPane;
						$element.data("zoomParent", $zoomParent);
						$zoomContain = $contain;
					} else {
						targetImg = $flyout.find( "img" )[ 0 ];
						$zoomParent = $zoomContain = $flyout;
						$element.data("zoomParent", $zoomParent);
					}
				}

				// this positions the loupe or side flyout element either according to mouse/touch coordinates
				// or the sides of the viewer specified
				function positionFlyout(){

					// set flyout width and height
					$flyout.css({
						"width": o.flyout.width + "px",
						"height": o.flyout.height + "px",
						top: "",
						left: "",
						"margin-left": "",
						"margin-top": ""
					});

					// set negative left or right value to match width
					var flyoutSide = o.placement.match( /left|right/ );

					if( flyoutSide ){
						$flyout.css( flyoutSide[ 0 ], -o.flyout.width + "px" );
					}
					// if loupe mode, center offset
					var loupe = o.placement.match( /loupe/ );

					if( loupe ) {
						// loupe
						$flyout.css({
							"margin-left": ( -o.flyout.width / 2 ) + "px",
							"margin-top": ( -o.flyout.height / 2 ) + "px"
						});
					}

					// add class to specify positioning spot for static css to apply
					$flyout[ 0 ].className = $flyout[ 0 ].className.replace( /enlarge_flyout\-[^$\s]+/, ' ' );
					$flyout.addClass( "enlarge_flyout-" +	 o.placement );
				}

				function disable(){
					if(o.disabled){
						$element.addClass("enlarge_disabled");
					} else {
						$element.removeClass("enlarge_disabled");
					}
				}

				disable();

				// this allows for subsequent calls to the plugin to pass an updateOptions method and object,
				// which will pass through to the existing viewer on that element
				$element.data( "updateOptions", function( opts ){
					o = $.extend( o, opts );
					$(this).data("options", o);

					updatePlacement();
					positionFlyout();
					hoverEnabled = o.hoverZoomWithoutClick;
					if( o.image && o.image.sizes ){
						imgOriginalSizes = o.image.sizes;
						toggleImgSrc();
					}

					disable();

					if( o.disabled && $element.data("zoomed") ) {
						standardToggleZoom();
					}
				});

				// loader div holds a new image while its new source is loading
				// we insert this into the dom so that srcset/sizes can calculate a best source
				function addLoader(){
					$contain.append( '<i class="enlarge_loader"><i></i></i>' );
				}

				// zoom state toggle boolean
				function toggleZoomState(){
					zoomed = !$element.data("zoomed");
					$element.data("zoomed", zoomed);
				}

				// toggle the image source bigger or smaller
				// ideally, this toggles the sizes attribute and allows the browser to select a new source from srcset
				// if srcset isn't supported or sizes attribute is not provided, the link href is used for the larger source
				function toggleImgSrc(after){
					after = after || function(){};

					if( !zoomed ){
						targetImg.sizes = imgOriginalSizes;
						if( !srcsetSizesSupported ){
							targetImg.src = imgOriginalSrc;
						}
						after();
					} else {
						// if the zooming is disabled do not replace with the larger source
						// NOTE we don't prevent switching to the original source because we
						// always want to allow the plugin to back out of the zoomed state
						// when disabled
						if( o.disabled ) { after(); return false; }

						var zoomimg = new Image();
						zoomimg.className = "enlarge_img-loading";
						zoomimg.onload = function(){
							targetImg.sizes = zoomimg.sizes;
							if( !srcsetSizesSupported || !srcset ){
								targetImg.src = imgZoomSrc;
							}
							$( zoomimg ).remove();

							after();
						};

						zoomimg.sizes = imgZoomWidth() + "px";

						if( !srcsetSizesSupported || !srcset ){
							zoomimg.src = imgZoomSrc;
						} else if (srcset) {
							zoomimg.srcset = srcset;
						}

						$( zoomimg ).insertBefore( targetImg );
					}
				}

				// scroll to the center of the zoomed image
				function scrollToCenter(){
					var pw = $zoomContain.width();
					var ph = $zoomContain.height();
					var w = targetImg.offsetWidth;
					var h = targetImg.offsetHeight;
					$zoomContain[ 0 ].scrollLeft = ( w / 2 ) - ( pw / 2 );
					$zoomContain[ 0 ].scrollTop = ( h / 2 ) - ( ph / 2 );
				}

				// lock zoom mode allows for scrolling around normally without a cursor-follow behavior
				function toggleLockZoom(){
					if( !$element.data("lockedZoom") ){
						// NOTE we allow the image to zoom out if functionality gets disabled
						// when it's in a zoomed state
						if(o.disabled) { return false; }

						$parentPane.add( $zoomParent ).addClass( lockZoomClass );
						$element.data("lockedZoom", lockedZoom = true);
						$zoomContain.attr( "tabindex", "0" );
						$zoomContain[ 0 ].focus();
					}
					else {
						$parentPane.add( $zoomParent ).removeClass( lockZoomClass );
						$element.data("lockedZoom", lockedZoom = false);
						$zoomContain.removeAttr( "tabindex" );
					}
				}

				function imgZoomWidth(){
					return $parentPane[0].offsetWidth * o.magnification;
				}

				// toggle magnification of image
				function toggleImgZoom(){
					if( $element.data("zoomed") ){
						// NOTE we allow the image to zoom out if functionality gets disabled
						// when it's in a zoomed state
						if(o.disabled) { return false; }

						if( o.placement === "inline" ){
							$contain.add( $parentPane ).css( { "width": $parentPane[0].offsetWidth + "px", "height": parseFloat( getComputedStyle( $parentPane[0] ).height ) + "px" } );
						}
						$zoomParent.addClass( zoomClass );
						$( targetImg ).css( "width", imgZoomWidth() + "px" );

						$(self).trigger( pluginName + ".after-zoom-in");
					}
					else{
						$zoomParent.removeClass( zoomClass );
						if( o.placement === "inline" ){
							$contain.add( $parentPane ).css( { "width": "", "height": "" } );
						}
						$( targetImg ).css( "width", "" );

						$(self).trigger( pluginName + ".after-zoom-out");
					}
				}

				function forceInlineMode(){
					var oldO = o.placement;
					if( oldO !== "inline" ){
						function resetPlacement(){
							o.placement = oldO;
							updatePlacement();
							$(self).unbind( pluginName + ".after-zoom-out", resetPlacement );
						}
						$(self).bind( pluginName + ".after-zoom-out", resetPlacement );
						o.placement = "inline";
						updatePlacement();
					}
				}

				// lock zoom mode toggle
				function standardToggleZoom(){
					// NOTE if the current is zoomed out and it's disabled prevent toggling
					if(o.disabled && !$element.data("zoomed")) { return false; }
					toggleZoomState();
					toggleImgSrc(function(){
						toggleLockZoom();
						toggleImgZoom();
						scrollToCenter();
					});
				}

				var trackingOn;
				var trackingTimer;
				var mouseEntered;
				var touchStarted;
				var hoverEnabled = o.hoverZoomWithoutClick;

				// mouseenter or touchstart handler for dragging image
				function startTrackingDelay(e){
					if( e.type === "touchstart" ){
						touchStarted = true;
					}
					if( touchStarted && e.type === "mouseenter" ||
							e.type === "mouseenter" && !touchStarted && !hoverEnabled ||
							$element.data("lockedZoom") ||
							mouseEntered ){
								return;
							}
					mouseEntered = true;
					$contain.addClass( delayClass );
					trackingTimer = setTimeout( function(){
						$contain.removeClass( delayClass );
						toggleZoomState();
						toggleImgSrc(function(){
							toggleImgZoom();
							trackingOn = true;
							scrollWithMouse(e);
						});
					}, o.delay );
				}

				// mouseleave or touchend after a drag
				function stopTrackingDelay( e ){
					$contain.removeClass( delayClass );
					clearTimeout( trackingTimer );
					trackingOn = false;
					if( o.hoverZoomWithoutClick === false && !touchStarted ){
						hoverEnabled = false;
					}
					if( touchStarted && e.type === "mouseleave" ){
						touchStarted = false;
					}
				}

				// mousemove or touch-drag image placement
				function scrollWithMouse( e ){
					// if tracking's not on yet, ignore. This allows the delay to work
					if( trackingOn ){
						// if the move was touch-started, and the event is mousemove, it can be ignored
						// (mouse events fire along with touch events and we just want the touch)
						if( touchStarted && e.type === "mousemove" ){
							return;
						}
						// normalize ev to touch or mouse
						var oe = e.originalEvent || e;
						var ev = oe.touches ? oe.touches[ 0 ] : oe;
						e.preventDefault();
						var x = ev.clientX - $contain[ 0 ].getBoundingClientRect().left;
						var y = ev.clientY - $contain[ 0 ].getBoundingClientRect().top;

						if( o.placement.match( /loupe/ ) ) {
							// offset the loupe a little differently for touch so that it's not directly beneath a finger
							var mLeft = ( oe.touches ? -o.flyout.width / 1.3 : -o.flyout.width / 2 ) + "px";
							var mTop = ( oe.touches ? -o.flyout.height / 1.3 : -o.flyout.height / 2 ) + "px";
							requestAnimationFrame(function(){
								$flyout.css( {
									top: y + "px",
									left: x + "px",
									"margin-left": mLeft,
									"margin-top": mTop
								} );
							});
						}

						var containWidth = $contain[ 0 ].offsetWidth;
						var containHeight = $contain[ 0 ].offsetHeight;
						var containScrollWidth =	targetImg.offsetWidth;
						var containScrollHeight = targetImg.offsetHeight;
						var zoomContainWidth = $zoomContain[ 0 ].offsetWidth;
						var zoomContainHeight = $zoomContain[ 0 ].offsetHeight;
						var widthFactor = containWidth / zoomContainWidth;
						var heightFactor = containWidth / zoomContainHeight;

						$zoomContain[ 0 ].scrollLeft = (( x / containWidth ) * ( containScrollWidth - zoomContainWidth ));
						$zoomContain[ 0 ].scrollTop = (( y / containHeight ) * ( containScrollHeight - zoomContainHeight )) ;
					}
				}

				// add flyout for flyout and loupe modes
				// flyout is always present, yet hidden when inline mode is active
				var $flyout = $( '<div class="enlarge_flyout"></div>' ).append( $contain.clone() );
				$flyout.insertAfter( $parentPane );

				// add loader div
				addLoader();
				updatePlacement();
				positionFlyout();

				// clicking the magnify anchor toggles lock-zoom mode
				$anchor
					.bind( "keydown", function(e){
						if( e.keyCode === 13 || e.keyCode === 32 ){
							forceInlineMode();
						}
						// spacebar triggers click too
						if( e.keyCode === 32 ){
							e.preventDefault(); // don't scroll the new focused area
							$( this ).trigger( "click" );
						}
					})
					.bind( "click", function( e ){
						e.preventDefault();
						standardToggleZoom();
					});

				// on resize, if in lock zoom mode, un zoom
				$( w )
					.bind( "resize", function( e ){
						if( $element.data("lockedZoom") ){
							standardToggleZoom();
						}
					});

				// on click-out on the page, if in locked zoom mode, zoom out
				$( w.document )
					.bind( "mouseup", function( e ){
						if( $element.data("lockedZoom") && !$( e.target ).closest( $parentPane ).length ){
							standardToggleZoom();
						}
					});

				// mouse hover and touch-drag gestures for a cursor-tracked zoom behavior
				$( initialImg )
					.bind( "mouseenter touchstart", startTrackingDelay )
					.bind( "mousemove touchmove", scrollWithMouse )
					.bind( "mouseleave touchend", function( e ){
						mouseEntered = false;
						if( zoomed && !$element.data("lockedZoom") ){
							toggleZoomState();
							toggleImgSrc(function(){
								toggleImgZoom();
							});
						}
						stopTrackingDelay( e );
					})
				// tapping the image should trigger a lock zoom
				// click will not fire after a touch-drag so it works as a tap for our needs here
					.bind( "click", function( e ){
						e.preventDefault();
						// if the click was started with a touchstart event,
						// and placement is inline
						// toggle the locked zoom mode
						if( touchStarted && o.placement === "inline" ){
							standardToggleZoom();
						}

						if( o.hoverZoomWithoutClick === false && !touchStarted ){
							hoverEnabled = !hoverEnabled;
							if( hoverEnabled ){
								$( this ).trigger( "mouseenter" );
							}
							else {
								$( this ).trigger( "mouseleave" );
							}
						}
					} );

				// keyboard handling for arrows in zoom mode
				$(this).bind( "keydown keyup", function( e ){
					if( e.keyCode === 37 ||
							e.keyCode === 38 ||
							e.keyCode === 39 ||
							e.keyCode === 40 ){
								e.stopImmediatePropagation();
								if( !$element.data("lockedZoom") ){
									e.preventDefault();
								}
							} else if( e.type === "keyup" && $(this).data("lockedZoom") && e.keyCode === 27 ){ //esc or backspace closes zoom
								standardToggleZoom();
								$anchor[0].focus();
								e.stopImmediatePropagation();
							}
				});

				// on scroll, zoom out
				$parentPane.bind( "scroll", function(){
					if( $element.data("zoomed") ){
						toggleZoomState();
						toggleImgSrc(function(){
							if( $element.data("lockedZoom") ){
								toggleLockZoom();
							}
							toggleImgZoom();
						});
					}
				});
			});

			return internalResult !== undefined ? internalResult : result;
		};
	};

	if( typeof module !== "undefined" ){
		module.exports = enlarge;
	} else {
		enlarge();
	}
}( typeof global !== "undefined" ? global : this ));

              
            
!
999px

Console