diff options
Diffstat (limited to 'src/js/utils/style.js')
-rw-r--r-- | src/js/utils/style.js | 80 |
1 files changed, 71 insertions, 9 deletions
diff --git a/src/js/utils/style.js b/src/js/utils/style.js index f02b0ba5..e05e058f 100644 --- a/src/js/utils/style.js +++ b/src/js/utils/style.js @@ -2,9 +2,39 @@ // Style utils // ========================================================================== +import { closest } from './arrays'; import is from './is'; -export function validateRatio(input) { +// Check support for a CSS declaration +export function supportsCSS(declaration) { + if (!window || !window.CSS) { + return false; + } + + return window.CSS.supports(declaration); +} + +// Standard/common aspect ratios +const standardRatios = [ + [1, 1], + [4, 3], + [3, 4], + [5, 4], + [4, 5], + [3, 2], + [2, 3], + [16, 10], + [10, 16], + [16, 9], + [9, 16], + [21, 9], + [9, 21], + [32, 9], + [9, 32], +].reduce((out, [x, y]) => ({ ...out, [x / y]: [x, y] }), {}); + +// Validate an aspect ratio +export function validateAspectRatio(input) { if (!is.array(input) && (!is.string(input) || !input.includes(':'))) { return false; } @@ -14,6 +44,7 @@ export function validateRatio(input) { return ratio.map(Number).every(is.number); } +// Reduce an aspect ratio to it's lowest form export function reduceAspectRatio(ratio) { if (!is.array(ratio) || !ratio.every(is.number)) { return null; @@ -26,8 +57,9 @@ export function reduceAspectRatio(ratio) { return [width / divider, height / divider]; } +// Calculate an aspect ratio export function getAspectRatio(input) { - const parse = (ratio) => (validateRatio(ratio) ? ratio.split(':').map(Number) : null); + const parse = (ratio) => (validateAspectRatio(ratio) ? ratio.split(':').map(Number) : null); // Try provided ratio let ratio = parse(input); @@ -44,10 +76,10 @@ export function getAspectRatio(input) { // Get from HTML5 video if (ratio === null && this.isHTML5) { const { videoWidth, videoHeight } = this.media; - ratio = reduceAspectRatio([videoWidth, videoHeight]); + ratio = [videoWidth, videoHeight]; } - return ratio; + return reduceAspectRatio(ratio); } // Set aspect ratio for responsive container @@ -58,10 +90,20 @@ export function setAspectRatio(input) { const { wrapper } = this.elements; const ratio = getAspectRatio.call(this, input); - const [w, h] = is.array(ratio) ? ratio : [0, 0]; - const padding = (100 / w) * h; - wrapper.style.paddingBottom = `${padding}%`; + if (!is.array(ratio)) { + return {}; + } + + const [x, y] = reduceAspectRatio(ratio); + const useNative = supportsCSS(`aspect-ratio: ${x}/${y}`); + const padding = (100 / x) * y; + + if (useNative) { + wrapper.style.aspectRatio = `${x}/${y}`; + } else { + wrapper.style.paddingBottom = `${padding}%`; + } // For Vimeo we have an extra <div> to hide the standard controls and UI if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) { @@ -74,10 +116,30 @@ export function setAspectRatio(input) { this.media.style.transform = `translateY(-${offset}%)`; } } else if (this.isHTML5) { - wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null); + wrapper.classList.add(this.config.classNames.videoFixedRatio); } return { padding, ratio }; } -export default { setAspectRatio }; +// Round an aspect ratio to closest standard ratio +export function roundAspectRatio(x, y, tolerance = 0.05) { + const ratio = x / y; + const closestRatio = closest(Object.keys(standardRatios), ratio); + + // Check match is within tolerance + if (Math.abs(closestRatio - ratio) <= tolerance) { + return standardRatios[closestRatio]; + } + + // No match + return [x, y]; +} + +// Get the size of the viewport +// https://stackoverflow.com/questions/1248081/how-to-get-the-browser-viewport-dimensions +export function getViewportSize() { + const width = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0); + const height = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0); + return [width, height]; +} |