Firefox/Safari/Chrome all latest stable releases on macOS as of 12 May.
jQuery v3.1.0
I've a jquery
script that dynamically resizes images (specifically, a container div
which has an img
element filling it 100%) inside a collection container div
to give a masonry wall-like effect. The logic, heavily summarized, is that I calculate images at their preferred size for the current window width and add them up (including gutters) until they exceed that window width. I then subtract the last element and scale the remainder up to fit.
This works fine in Chrome and Safari. Firefox works on most rows but on occasion the last element gets bumped to the next row and throws the whole composition off. The culprit, on inspection, of the guilty rows appears to be that the sum of all the row elements exceeds the collection container by 1 pixel at most, never more. It's usually a fraction of a pixel. My hunch is that it's a rounding or decimal place issue; or an issue related to the floating point that I've seen come up in my research, like here.
Code:
Forgive me if I leave out anything pertinent here in the following code. I feel as though the relevance is in the calculations of the various elements widths through jquery
(particularly, my scaleFactor result) so that should be enough and leaves this a bit more legible:
Calculations made in the script:
// Once it's been determined that a row has the required number of elements to fill it:
var windowwidth = $(window).width();
var gutter = 23;
var scaleFactor = (windowWidth - (sum of total gutters in row)) / (sum of total element widths in row);
// Looping through each element, resize them as such:
var w = $(this).width();
var h = $(this).height();
// Set new width and height
$(this).css({'width': (w * scaleFactor) + 'px'});
$(this).css({'height': (h * scaleFactor) + 'px'});
Result:
Chrome and Safari produce a row where the sum of all gutters and elements is consistently just under the window width by a fraction, giving visually perfect spacing, like so:
(23) + 936.094 + (23) + 415.859 + (23) // gives a sum of 1,420.953 for a window width of 1,421
Firefox, on inspecting a row where the last element was bumped off to the next row, gives the same example as follows:
(23) + 938.9 + (23) + 417.117 + (23) // gives a sum of 1,425.017 for a window width of 1,425
Additional Info:
I've given the
img
elements, their containerdivs
and the content containerdiv
box-sizing
values ofborder-box
in css to try and rule out any styling discrepencies in the width values on each browser. None had any padding or borders, regardless.The content container
div
I mention here holds all the elements being arranged into rows. It is the width of the window less one gutter, which it uses as a margin. I've accounted for it in all calculations and am pretty confident I've done so appropriately as the sums would be out by a lot more than a fraction of a pixel if I've overlooked something more. I deliberately scale the elements to the window width, not the content container (its main purpose is to provide an opposing margin to the side each element has to give consistent and equal gutters around each element) but have tested with scaling to the content container and it gives the same outcome.I've also confirmed that the
width
values I'm using here:(sum of total element widths in row)
is consistent across all browsers and was sourced fromjquery's
width()
function for each element. The value for the window size on all browsers differs slightly - I imagine due to scrollbar differences - but I can only assume it's accurate. I've used other methods to get the window width without scrollbars and they confirmed (to the best of my knowledge) that the value being used is correct.I've attempted rounding various parts and this confirmed my presumption that it would not fix the problem when the sum of widths exceeds the container by more than 0.5.
The measurements taken are done after all content is finished loading and scrollbars are in place and accounted for, using the
$( window ).on( "load", function()
function.
Optimal Solution:
Ideally, I'm hoping I've overlooked an aspect of the calculation in the code, above, that can be adjusted to ensure that the same variables would produce the same results across browsers.
It's likely wishful thinking so my plan b would be an elegant means of compensating for this. Currently I could compare the window width with the sum total after the calculation and scale it back. Or I could forego precise gutters and aim to scale to the window width, less one pixel.
The problem with the first idea is that it seems like a poor design to patch a simple calculation that should work. It wastes lines of code and overhead and I avoid bloat as best as I can. The second solution annoys the perfectionist in me and could have long-term complications if I scale the project in a manner that's reliant on certain believed truths, such as even gutters throughout the layout.
Update:
I hadn't ruled out rounding various floats in the calculation just yet but was doing it mostly by guessing. My main lead was attempting to do on the widthBefore
var as it was sometimes a float, whereas all the other vars in scaleFactor
were integers. Round
, as before, didn't work. To my surprise, floor
didn't work. I thought it would leave minutely visible edge differences in spacing but it still left rows exceeding the window width. To my further surprise ceiling
worked. I can't actually explain why Firefox needed me to round this value with ceiling
to work but it's doing well with everything I throw at it so far. I still have to see what the repercussions are for gutter sizes now.