aboutsummaryrefslogtreecommitdiffstats
path: root/src/js/utils/style.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/utils/style.js')
-rw-r--r--src/js/utils/style.js80
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];
+}