From d369267c43aedb0b1e33af9bfbb487b307f8fcf3 Mon Sep 17 00:00:00 2001 From: Arek Mytych Date: Sat, 2 Mar 2019 12:10:28 +0100 Subject: [PATCH 1/2] Fix colWidth calculation issue There are sub-pixel differences between col widths returned by different browsers, when the width is not defined in absolute pixel values, e.g. a percentage. In Firefox, for example, it causes a three column layout to be rendered as a two column layout. See this fiddle forked from your example in the README: https://jsfiddle.net/avwgdurp/ When you resize the preview container you notice in Firefox the layout jumps between 2 and 3 columns, whereas in Chrome there are always 3 columns rendered. This change floors the col width value to the whole pixel, ensuring their combined width is never wider than the container. --- src/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index ad32cd2..3ffb140 100644 --- a/src/index.js +++ b/src/index.js @@ -74,7 +74,8 @@ class MagicGrid { * @private */ colWidth () { - return this.items[0].getBoundingClientRect().width + this.gutter; + const width = this.items[0].getBoundingClientRect().width + this.gutter; + return Math.floor(width); } /** From 78240419dbc8b72ba7918cb2e52d75827402b50a Mon Sep 17 00:00:00 2001 From: Arek Mytych Date: Mon, 4 Mar 2019 05:09:20 +0100 Subject: [PATCH 2/2] Replace Math.floor with more fine grained approach Instead of flooring col width down to the whole pixel, this approach tries to reduce the value by 0.0001 of a pixel, until we have proper layout. It happens in a short loop with limited iteration count. It also happens only in the case when there is sub pixel rounding issue. --- src/index.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 3ffb140..4693cb8 100644 --- a/src/index.js +++ b/src/index.js @@ -74,8 +74,27 @@ class MagicGrid { * @private */ colWidth () { - const width = this.items[0].getBoundingClientRect().width + this.gutter; - return Math.floor(width); + const width = this.container.getBoundingClientRect().width + let colWidth = this.items[0].getBoundingClientRect().width + this.gutter + let numCols = Math.floor(width / colWidth) || 1 + + // if we're dealing with subpixel rounding issue + // reduce the colWidth until we have a proper layout + // we know we should be able to fit one more column + // limit number of iterations to minimise overhead + // and to prevent any risk of infinite loop + if (Math.floor(colWidth) === Math.floor(width % colWidth)) { + const properNumCols = numCols + 1 + let iterationCount = 0 + const maxIterations = 20 + while (numCols !== properNumCols && iterationCount < maxIterations) { + iterationCount += 1 + colWidth -= 0.0001 + numCols = Math.floor(width / colWidth) + } + } + + return colWidth } /**