diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..b1f7ef2 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/.prettierrc b/.prettierrc new file mode 100755 index 0000000..51727a1 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "printWidth": 80, + "singleQuote": true, + "quote-props": "consistent", + "trailingComma": "es5", + "arrowParens": "always" +} diff --git a/README.md b/README.md index 59b0b41..3195e8d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # object-fit-polyfill + A polyfill for browsers that don't support the `object-fit` CSS property. Unsure of what the `object-fit` does? Essentially `object-fit` is to `` tags what `background-size` is to `background-image`. You can check out the [MDN page](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) for more details. ## Features @@ -38,20 +39,25 @@ Initialization: ```html
- +
@@ -61,15 +67,33 @@ Customized object-fit/object-position: ```html
- +
- +
- +
``` @@ -77,7 +101,12 @@ If you're only interested in using the basic polyfill (which assumes `object-fit ```html
- +
diff --git a/demo/style.css b/demo/style.css index 84a3914..4f3d7d7 100644 --- a/demo/style.css +++ b/demo/style.css @@ -1,7 +1,9 @@ -html, body { +html, +body { margin: 0; height: 100%; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, + Arial, sans-serif; line-height: 1.5; background-color: #111; color: #fff; @@ -9,7 +11,8 @@ html, body { a { color: inherit; } -h1, h2 { +h1, +h2 { margin: 0; } @@ -20,7 +23,7 @@ h1, h2 { .heading-intro { position: relative; top: 50%; - background-color: rgba(0,0,0, 0.8); + background-color: rgba(0, 0, 0, 0.8); -webkit-transform: translateY(-50%); -ms-transform: translateY(-50%); transform: translateY(-50%); @@ -31,7 +34,7 @@ h1, h2 { */ .clearfix::after { - content: ""; + content: ''; display: table; clear: both; } diff --git a/dist/objectFitPolyfill.basic.min.js b/dist/objectFitPolyfill.basic.min.js index d47e597..37aa0c8 100644 --- a/dist/objectFitPolyfill.basic.min.js +++ b/dist/objectFitPolyfill.basic.min.js @@ -1 +1 @@ -!function(){"use strict";if("undefined"!=typeof window){var t=window.navigator.userAgent.match(/Edge\/(\d{2})\./),n=!!t&&16<=parseInt(t[1],10);if("objectFit"in document.documentElement.style==!1||n){var o=function(t){var e=t.parentNode;!function(t){var e=window.getComputedStyle(t,null),i=e.getPropertyValue("position"),n=e.getPropertyValue("overflow"),o=e.getPropertyValue("display");i&&"static"!==i||(t.style.position="relative"),"hidden"!==n&&(t.style.overflow="hidden"),o&&"inline"!==o||(t.style.display="block"),0===t.clientHeight&&(t.style.height="100%"),-1===t.className.indexOf("object-fit-polyfill")&&(t.className=t.className+" object-fit-polyfill")}(e),function(t){var e=window.getComputedStyle(t,null),i={"max-width":"none","max-height":"none","min-width":"0px","min-height":"0px",top:"auto",right:"auto",bottom:"auto",left:"auto","margin-top":"0px","margin-right":"0px","margin-bottom":"0px","margin-left":"0px"};for(var n in i)e.getPropertyValue(n)!==i[n]&&(t.style[n]=i[n])}(t),t.style.position="absolute",t.style.height="100%",t.style.width="auto",t.clientWidth>e.clientWidth?(t.style.top="0",t.style.marginTop="0",t.style.left="50%",t.style.marginLeft=t.clientWidth/-2+"px"):(t.style.width="100%",t.style.height="auto",t.style.left="0",t.style.marginLeft="0",t.style.top="50%",t.style.marginTop=t.clientHeight/-2+"px")},e=function(t){if(void 0===t)t=document.querySelectorAll("[data-object-fit]");else if(t&&t.nodeName)t=[t];else{if("object"!=typeof t||!t.length||!t[0].nodeName)return!1;t=t}for(var e=0;ee.clientWidth?(t.style.top="0",t.style.marginTop="0",t.style.left="50%",t.style.marginLeft=t.clientWidth/-2+"px"):(t.style.width="100%",t.style.height="auto",t.style.left="0",t.style.marginLeft="0",t.style.top="50%",t.style.marginTop=t.clientHeight/-2+"px")},e=function(t){if(void 0===t)t=document.querySelectorAll("[data-object-fit]");else if(t&&t.nodeName)t=[t];else{if("object"!=typeof t||!t.length||!t[0].nodeName)return!1;t=t}for(var e=0;en.clientWidth||"contain"===e&&t.clientWidthn.clientWidth||"contain"===e&&t.clientWidth tags // TODO: Keep an eye on Edge to determine which version has full final support var edgeVersion = window.navigator.userAgent.match(/Edge\/(\d{2})\./); - var edgePartialSupport = (edgeVersion) ? (parseInt(edgeVersion[1], 10) >= 16) : false; + var edgePartialSupport = edgeVersion + ? parseInt(edgeVersion[1], 10) >= 16 + : false; // If the browser does support object-fit, we don't need to continue - if ("objectFit" in document.documentElement.style !== false && !edgePartialSupport) { - window.objectFitPolyfill = function() { return false }; + var hasSupport = 'objectFit' in document.documentElement.style !== false; + if (hasSupport && !edgePartialSupport) { + window.objectFitPolyfill = function() { + return false; + }; return; } @@ -37,28 +40,28 @@ */ var checkParentContainer = function($container) { var styles = window.getComputedStyle($container, null); - var position = styles.getPropertyValue("position"); - var overflow = styles.getPropertyValue("overflow"); - var display = styles.getPropertyValue("display"); + var position = styles.getPropertyValue('position'); + var overflow = styles.getPropertyValue('overflow'); + var display = styles.getPropertyValue('display'); - if (!position || position === "static") { - $container.style.position = "relative"; + if (!position || position === 'static') { + $container.style.position = 'relative'; } - if (overflow !== "hidden") { - $container.style.overflow = "hidden"; + if (overflow !== 'hidden') { + $container.style.overflow = 'hidden'; } // Guesstimating that people want the parent to act like full width/height wrapper here. // Mostly attempts to target elements, which default to inline. - if (!display || display === "inline") { - $container.style.display = "block"; + if (!display || display === 'inline') { + $container.style.display = 'block'; } if ($container.clientHeight === 0) { - $container.style.height = "100%"; + $container.style.height = '100%'; } // Add a CSS class hook, in case people need to override styles for any reason. - if ($container.className.indexOf("object-fit-polyfill") === -1) { - $container.className = $container.className + " object-fit-polyfill"; + if ($container.className.indexOf('object-fit-polyfill') === -1) { + $container.className = $container.className + ' object-fit-polyfill'; } }; @@ -71,18 +74,18 @@ var checkMediaProperties = function($media) { var styles = window.getComputedStyle($media, null); var constraints = { - "max-width": "none", - "max-height": "none", - "min-width": "0px", - "min-height": "0px", - "top": "auto", - "right": "auto", - "bottom": "auto", - "left": "auto", - "margin-top": "0px", - "margin-right": "0px", - "margin-bottom": "0px", - "margin-left": "0px", + 'max-width': 'none', + 'max-height': 'none', + 'min-width': '0px', + 'min-height': '0px', + top: 'auto', + right: 'auto', + bottom: 'auto', + left: 'auto', + 'margin-top': '0px', + 'margin-right': '0px', + 'margin-bottom': '0px', + 'margin-left': '0px', }; for (var property in constraints) { @@ -108,25 +111,22 @@ checkMediaProperties($media); // Mathematically figure out which side needs covering, and add CSS positioning & centering - $media.style.position = "absolute"; - $media.style.height = "100%"; - $media.style.width = "auto"; - - if ( - $media.clientWidth > $container.clientWidth - ) { - $media.style.top = "0"; - $media.style.marginTop = "0"; - $media.style.left = "50%"; - $media.style.marginLeft = ($media.clientWidth / -2) + "px"; - } - else { - $media.style.width = "100%"; - $media.style.height = "auto"; - $media.style.left = "0"; - $media.style.marginLeft = "0"; - $media.style.top = "50%"; - $media.style.marginTop = ($media.clientHeight / -2) + "px"; + $media.style.position = 'absolute'; + $media.style.height = '100%'; + $media.style.width = 'auto'; + + if ($media.clientWidth > $container.clientWidth) { + $media.style.top = '0'; + $media.style.marginTop = '0'; + $media.style.left = '50%'; + $media.style.marginLeft = $media.clientWidth / -2 + 'px'; + } else { + $media.style.width = '100%'; + $media.style.height = 'auto'; + $media.style.left = '0'; + $media.style.marginLeft = '0'; + $media.style.top = '50%'; + $media.style.marginTop = $media.clientHeight / -2 + 'px'; } }; @@ -136,13 +136,13 @@ * @param {node} media - Optional specific DOM node(s) to be polyfilled */ var objectFitPolyfill = function(media) { - if (typeof media === "undefined") { + if (typeof media === 'undefined') { // If left blank, all media on the page will be polyfilled. - media = document.querySelectorAll("[data-object-fit]"); + media = document.querySelectorAll('[data-object-fit]'); } else if (media && media.nodeName) { // If it's a single node, wrap it in an array so it works. media = [media]; - } else if (typeof media === "object" && media.length && media[0].nodeName) { + } else if (typeof media === 'object' && media.length && media[0].nodeName) { // If it's an array of DOM nodes (e.g. a jQuery selector), it's fine as-is. media = media; } else { @@ -151,30 +151,27 @@ } for (var i = 0; i < media.length; i++) { - if (!media[i].nodeName) { continue; } + if (!media[i].nodeName) continue; + var mediaType = media[i].nodeName.toLowerCase(); - if (mediaType === "img" && !edgePartialSupport) { + if (mediaType === 'img' && !edgePartialSupport) { if (media[i].complete) { objectFit(media[i]); - } - else { - media[i].addEventListener("load", function() { + } else { + media[i].addEventListener('load', function() { objectFit(this); }); } - } - else if (mediaType === "video") { + } else if (mediaType === 'video') { if (media[i].readyState > 0) { objectFit(media[i]); - } - else { - media[i].addEventListener("loadedmetadata", function() { + } else { + media[i].addEventListener('loadedmetadata', function() { objectFit(this); }); } - } - else { + } else { objectFit(media[i]); } } @@ -182,13 +179,12 @@ return true; }; - document.addEventListener("DOMContentLoaded", function() { + document.addEventListener('DOMContentLoaded', function() { objectFitPolyfill(); }); - window.addEventListener("resize", function() { + window.addEventListener('resize', function() { objectFitPolyfill(); }); window.objectFitPolyfill = objectFitPolyfill; - })(); diff --git a/src/objectFitPolyfill.js b/src/objectFitPolyfill.js index fa0e56b..ad1327a 100644 --- a/src/objectFitPolyfill.js +++ b/src/objectFitPolyfill.js @@ -7,22 +7,25 @@ * https://github.com/constancecchen/object-fit-polyfill *--------------------------------------*/ -(function(){ - "use strict"; +(function() { + 'use strict'; // if the page is being rendered on the server, don't continue - if (typeof window === "undefined") { - return; - } + if (typeof window === 'undefined') return; // Workaround for Edge 16+, which only implemented object-fit for tags // TODO: Keep an eye on Edge to determine which version has full final support var edgeVersion = window.navigator.userAgent.match(/Edge\/(\d{2})\./); - var edgePartialSupport = (edgeVersion) ? (parseInt(edgeVersion[1], 10) >= 16) : false; + var edgePartialSupport = edgeVersion + ? parseInt(edgeVersion[1], 10) >= 16 + : false; // If the browser does support object-fit, we don't need to continue - if ("objectFit" in document.documentElement.style !== false && !edgePartialSupport) { - window.objectFitPolyfill = function() { return false }; + var hasSupport = 'objectFit' in document.documentElement.style !== false; + if (hasSupport && !edgePartialSupport) { + window.objectFitPolyfill = function() { + return false; + }; return; } @@ -34,28 +37,28 @@ */ var checkParentContainer = function($container) { var styles = window.getComputedStyle($container, null); - var position = styles.getPropertyValue("position"); - var overflow = styles.getPropertyValue("overflow"); - var display = styles.getPropertyValue("display"); + var position = styles.getPropertyValue('position'); + var overflow = styles.getPropertyValue('overflow'); + var display = styles.getPropertyValue('display'); - if (!position || position === "static") { - $container.style.position = "relative"; + if (!position || position === 'static') { + $container.style.position = 'relative'; } - if (overflow !== "hidden") { - $container.style.overflow = "hidden"; + if (overflow !== 'hidden') { + $container.style.overflow = 'hidden'; } // Guesstimating that people want the parent to act like full width/height wrapper here. // Mostly attempts to target elements, which default to inline. - if (!display || display === "inline") { - $container.style.display = "block"; + if (!display || display === 'inline') { + $container.style.display = 'block'; } if ($container.clientHeight === 0) { - $container.style.height = "100%"; + $container.style.height = '100%'; } // Add a CSS class hook, in case people need to override styles for any reason. - if ($container.className.indexOf("object-fit-polyfill") === -1) { - $container.className = $container.className + " object-fit-polyfill"; + if ($container.className.indexOf('object-fit-polyfill') === -1) { + $container.className = $container.className + ' object-fit-polyfill'; } }; @@ -68,18 +71,18 @@ var checkMediaProperties = function($media) { var styles = window.getComputedStyle($media, null); var constraints = { - "max-width": "none", - "max-height": "none", - "min-width": "0px", - "min-height": "0px", - "top": "auto", - "right": "auto", - "bottom": "auto", - "left": "auto", - "margin-top": "0px", - "margin-right": "0px", - "margin-bottom": "0px", - "margin-left": "0px", + 'max-width': 'none', + 'max-height': 'none', + 'min-width': '0px', + 'min-height': '0px', + top: 'auto', + right: 'auto', + bottom: 'auto', + left: 'auto', + 'margin-top': '0px', + 'margin-right': '0px', + 'margin-bottom': '0px', + 'margin-left': '0px', }; for (var property in constraints) { @@ -100,58 +103,55 @@ */ var setPosition = function(axis, $media, objectPosition) { var position, other, start, end, side; - objectPosition = objectPosition.split(" "); + objectPosition = objectPosition.split(' '); if (objectPosition.length < 2) { objectPosition[1] = objectPosition[0]; } - if (axis === "x") { + if (axis === 'x') { position = objectPosition[0]; other = objectPosition[1]; - start = "left"; - end = "right"; + start = 'left'; + end = 'right'; side = $media.clientWidth; - } - else if (axis === "y") { + } else if (axis === 'y') { position = objectPosition[1]; other = objectPosition[0]; - start = "top"; - end = "bottom"; + start = 'top'; + end = 'bottom'; side = $media.clientHeight; - } - else { + } else { return; // Neither x or y axis specified } if (position === start || other === start) { - $media.style[start] = "0"; + $media.style[start] = '0'; return; } if (position === end || other === end) { - $media.style[end] = "0"; + $media.style[end] = '0'; return; } - if (position === "center" || position === "50%") { - $media.style[start] = "50%"; - $media.style["margin-" + start] = (side / -2) + "px"; + if (position === 'center' || position === '50%') { + $media.style[start] = '50%'; + $media.style['margin-' + start] = side / -2 + 'px'; return; } // Percentage values (e.g., 30% 10%) - if (position.indexOf("%") >= 0) { + if (position.indexOf('%') >= 0) { position = parseInt(position); if (position < 50) { - $media.style[start] = position + "%"; - $media.style["margin-" + start] = side * (position / -100) + "px"; - } - else { + $media.style[start] = position + '%'; + $media.style['margin-' + start] = side * (position / -100) + 'px'; + } else { position = 100 - position; - $media.style[end] = position + "%"; - $media.style["margin-" + end] = side * (position / -100) + "px"; + $media.style[end] = position + '%'; + $media.style['margin-' + end] = side * (position / -100) + 'px'; } return; @@ -160,7 +160,6 @@ else { $media.style[start] = position; } - }; /** @@ -169,11 +168,17 @@ * @param {node} $media - img/video/picture element */ var objectFit = function($media) { - // Fallbacks, IE 10- data - var fit = ($media.dataset) ? $media.dataset.objectFit : $media.getAttribute("data-object-fit"); - var position = ($media.dataset) ? $media.dataset.objectPosition : $media.getAttribute("data-object-position"); - fit = fit || "cover"; - position = position || "50% 50%"; + // IE 10- data polyfill + var fit = $media.dataset + ? $media.dataset.objectFit + : $media.getAttribute('data-object-fit'); + var position = $media.dataset + ? $media.dataset.objectPosition + : $media.getAttribute('data-object-position'); + + // Default fallbacks + fit = fit || 'cover'; + position = position || '50% 50%'; // If necessary, make the parent container work with absolutely positioned elements var $container = $media.parentNode; @@ -183,55 +188,53 @@ checkMediaProperties($media); // Reset any pre-set width/height CSS and handle fit positioning - $media.style.position = "absolute"; - $media.style.width = "auto"; - $media.style.height = "auto"; + $media.style.position = 'absolute'; + $media.style.width = 'auto'; + $media.style.height = 'auto'; // `scale-down` chooses either `none` or `contain`, whichever is smaller - if (fit === "scale-down") { + if (fit === 'scale-down') { if ( $media.clientWidth < $container.clientWidth && $media.clientHeight < $container.clientHeight ) { - fit = "none"; - } - else { - fit = "contain"; + fit = 'none'; + } else { + fit = 'contain'; } } // `none` (width/height auto) and `fill` (100%) and are straightforward - if (fit === "none") { - setPosition("x", $media, position); - setPosition("y", $media, position); + if (fit === 'none') { + setPosition('x', $media, position); + setPosition('y', $media, position); return; } - if (fit === "fill") { - $media.style.width = "100%"; - $media.style.height = "100%"; - setPosition("x", $media, position); - setPosition("y", $media, position); + if (fit === 'fill') { + $media.style.width = '100%'; + $media.style.height = '100%'; + setPosition('x', $media, position); + setPosition('y', $media, position); return; } // `cover` and `contain` must figure out which side needs covering, and add CSS positioning & centering - $media.style.height = "100%"; + $media.style.height = '100%'; if ( - fit === "cover" && $media.clientWidth > $container.clientWidth || - fit === "contain" && $media.clientWidth < $container.clientWidth + (fit === 'cover' && $media.clientWidth > $container.clientWidth) || + (fit === 'contain' && $media.clientWidth < $container.clientWidth) ) { - $media.style.top = "0"; - $media.style.marginTop = "0"; - setPosition("x", $media, position); - } - else { - $media.style.width = "100%"; - $media.style.height = "auto"; - $media.style.left = "0"; - $media.style.marginLeft = "0"; - setPosition("y", $media, position); + $media.style.top = '0'; + $media.style.marginTop = '0'; + setPosition('x', $media, position); + } else { + $media.style.width = '100%'; + $media.style.height = 'auto'; + $media.style.left = '0'; + $media.style.marginLeft = '0'; + setPosition('y', $media, position); } }; @@ -241,13 +244,13 @@ * @param {node} media - Optional specific DOM node(s) to be polyfilled */ var objectFitPolyfill = function(media) { - if (typeof media === "undefined") { + if (typeof media === 'undefined') { // If left blank, all media on the page will be polyfilled. - media = document.querySelectorAll("[data-object-fit]"); + media = document.querySelectorAll('[data-object-fit]'); } else if (media && media.nodeName) { // If it's a single node, wrap it in an array so it works. media = [media]; - } else if (typeof media === "object" && media.length && media[0].nodeName) { + } else if (typeof media === 'object' && media.length && media[0].nodeName) { // If it's an array of DOM nodes (e.g. a jQuery selector), it's fine as-is. media = media; } else { @@ -256,31 +259,27 @@ } for (var i = 0; i < media.length; i++) { - if (!media[i].nodeName) { continue; } + if (!media[i].nodeName) continue; var mediaType = media[i].nodeName.toLowerCase(); - if (mediaType === "img" && !edgePartialSupport) { + if (mediaType === 'img' && !edgePartialSupport) { if (media[i].complete) { objectFit(media[i]); - } - else { - media[i].addEventListener("load", function() { + } else { + media[i].addEventListener('load', function() { objectFit(this); }); } - } - else if (mediaType === "video") { + } else if (mediaType === 'video') { if (media[i].readyState > 0) { objectFit(media[i]); - } - else { - media[i].addEventListener("loadedmetadata", function() { + } else { + media[i].addEventListener('loadedmetadata', function() { objectFit(this); }); } - } - else { + } else { objectFit(media[i]); } } @@ -288,13 +287,12 @@ return true; }; - document.addEventListener("DOMContentLoaded", function() { + document.addEventListener('DOMContentLoaded', function() { objectFitPolyfill(); }); - window.addEventListener("resize", function() { + window.addEventListener('resize', function() { objectFitPolyfill(); }); window.objectFitPolyfill = objectFitPolyfill; - })();