2

I have a page with a grid containing three div elements. Each one of this div has the size of the viewport so at any time just one of the divs if visible and the other two are outside. So the grid is three times big the viewport.

Resizing the window will cause the divs, hence the grid, to resize as well.

The html is pretty simple:

<div class="container">
  <div class="square square1">1</div>
  <div class="square square2">2</div>
  <div class="square square3">3</div>
</div>

Styled like this:

body {
  margin: 0;
  padding: 0;
}

.container {
  position: relative;
  height: 100vh;
  width: 300vw;
}

.square {
  height: 100vh;
  position: absolute;
  width: 100vw;
}
.square1 {
  background: red;
  left: 0;
}

.square2 {
  background: green;
    left: 100vw;
}

.square3 {
  background: yellow;
  left: 200vw;
}

The initial position, set via javascript, is on the middle div.

What happens is that resizing the window makes the whole document to move proportionally with the resizing. So, if at some point I'm seeing just the second div, resizing the window will make the third to appear more and more. I'm quite sure that with some javascript I could move the grid so that it appears fixed while resizing, but I can't figure out a formula.

I tried something like this:

var windowW = $(window).width();
$(window).resize(function() {
    var newWidth = $(window).width();
    var diff = windowW - newWidth;

    var windowLeftPos = $(window).scrollLeft();
    $(window).scrollLeft(windowLeftPos - diff / 2);
  });

But it's just a blind guess. I tried other formulas with multiplication and division and scale factors, but nothing worked. Any idea?

Here's a working example showing what I mean. Initially you see just the green div. Resizing the window, on of the two other divs will appear, instead I would like to see only the green one.


Edit: the question similar to mine is very interesting but it seems to me also very different. The main huge difference is that I'm resizing and moving DOM elements that stay outside the viewport. Besides, the answers are pretty focused on the image/background aspect ratio, which is part of the question, but it's not the case for me. I don't have a problem resizing elements, just compensating the movement due to the resizing


Update: I edited the pen and I think I'm getting closer to the desired result: http://codepen.io/anon/pen/vGeRgJ It seems to kind of work, but it doesn't especially when I'm closer to one of the extremes, like all on the left or on the right.

Asons
  • 84,923
  • 12
  • 110
  • 165
Carlo
  • 4,016
  • 7
  • 44
  • 65
  • Possible duplicate of [Scale element proportional to Background Cover with jQuery](http://stackoverflow.com/questions/35942014/scale-element-proportional-to-background-cover-with-jquery) – Asons Apr 02 '16 at 11:29
  • The dupe link has some really good (even CSS only) answers, though it might not be applicable in this case after all, so a retracted my vote-to-close-as-duplicate. – Asons Apr 02 '16 at 12:13
  • thanks, the thread seems to be full of useful information, but it also seems a bit beyond what I need. Anyway, I edited the pen and I'm getting closer to what I need. Still there's some issue – Carlo Apr 02 '16 at 15:11
  • May I ask how the user is going to move between the 3 squares? – Asons Apr 02 '16 at 15:20
  • I'm still not sure whether I'll leave the scrollbars or not, but (probably) there will be some click and drag involved. But this shouldn't affect the behavior, I think – Carlo Apr 02 '16 at 15:24
  • Well, the scroll bar seems, to me at least, to be a distraction, and if you consider a click( or a swipe on tough), which I think would be a much better solution, your problems would be gone, as then you can just animate the width of the 3 squares, having the one with "focus" full width and the other two 0. This way you don't need to mess with a resize script, as it feels to messy. – Asons Apr 02 '16 at 15:27
  • I understand what you mean, but that's not what I'm going for. I want to mantain the possibility to navigate the "scene", so scrolling, or dragging, and stopping in between two squares. So the squares must always have their size. I would like also for them to mantain the position on resizing – Carlo Apr 02 '16 at 15:32
  • @tyler indeed I'm not resizing via javascript. The resizing is happening exclusively in the css, on javascript I'm trying to controll the position of the elements (or of the viewport) when I manually resize the window – Carlo Apr 02 '16 at 17:24
  • @tyler can you point exactly where I'm resizing elements by javascript? – Carlo Apr 02 '16 at 18:55
  • 1
    @tyler What the OP wants can't be done using CSS alone, or at least I haven't been able to yet, but since you appear to know, please post an answer showing how this is done without script – Asons Apr 02 '16 at 19:10
  • 2
    Users don't go around resizing windows manually!! Unless of course, the website is poorly designed and they can't get to the content! – MilkyTech Apr 02 '16 at 23:18
  • @tyler You say: "_OP never even mentions what the goal is in terms of transitions and states,..._", I say he does, so if you read the question properly you'll find "_..., just compensating the movement due to the resizing_", and that **can't** be done without script, and that is also the only thing the OP ask for, so I don't understand why you bring up him using js for stuff he doesn't do, and tell to use CSS when he already used CSS as far as possible? – Asons Apr 02 '16 at 23:32
  • @ChrisM that's a fair point. I've already considered it and I think, for this reason, it will be ok even with these small issues. But, at the same time, I think it would be worth to find a way to do it just for the sake of experiment and of, well, doing it – Carlo Apr 03 '16 at 11:20
  • probably a waste of time, but I do think what you have already done is pretty cool and possibly useful. I am wondering why there is a vertical scroll bar if the content height is always the same as the viewport height? – MilkyTech Apr 03 '16 at 14:46
  • thanks! Yes, the vertical scrollbar is weird. I think it might be caused by the horizontal scrollbar. My guess is that it's calculating the height before it appears a horizontal scrollbar, so when this appears it takes vertical space. If you try and put overflow-x: hidden on the body, you will see both scrollbars disappearing. Maybe @LGSon knows better, though – Carlo Apr 03 '16 at 14:51
  • @Carlo You are correct, vert. scroll is caused by the hor. scroll, so by adding `overflow-y: hidden;` to the `container` it will go away, but then it will hide any content that reach beneath the scroll, so if you check my answer, I used `calc()` to make height not hit the scroll. Of course you could check the scroll bar's height with a script and withdraw that if you want to be sure ... some users might have set a custom size which can be bigger than the 22px I used ... or use the overflow and set a bottom padding to move content away from the edge. – Asons Apr 03 '16 at 15:13
  • @ChrisM Posted a comment explaining the vert. scroll – Asons Apr 03 '16 at 15:37
  • @Carlo I updated my answer ... just needed to see how close one can get :) – Asons Apr 03 '16 at 16:53

1 Answers1

1

Here is an updated version for you, from where you can easily make your own adjustments.

Since jQuery doesn't throttle the resize event by default, I made this one in plain javascript.

To get rid of the vertical scroll, and I also added a getScrollbarSize function as a bonus :)

function getWidth() { return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; }
function getLeft() { return document.body.scrollLeft; }
function setLeft(v) { document.body.scrollLeft = v; }
function getScrollbarSize() {
  var div, width;
  div = document.createElement('div');
  div.innerHTML = '<div style="width:50px;height:50px;position:absolute;left:-50px;top:-50px;overflow:auto;"><div style="width:1px;height:100px;"></div></div>';
  div = div.firstChild;
  document.body.appendChild(div);
  width = div.offsetWidth - div.clientWidth;
  document.body.removeChild(div);
  return width;
};

(function(t,w,l,l2) {
  
  document.querySelector('.container').style.height = 'calc(100vh - ' + getScrollbarSize() + 'px)';
  
  w = getWidth(), l = w, l2 = l / w, setLeft(w);
  
  window.addEventListener("resize", function(e) {
    if ( !t ) {
      t = setTimeout(function() {
        t = null;
        resizeHandler(e);
      }, 66);                  /*  throttle timeout  */
    }
  }, false);
  
  function resizeHandler(e) {
    w = getWidth();
    l = getLeft();
    setLeft(w * l2);
  }

  window.addEventListener("scroll", function(e) {
    if ( !t ) {
      l2 = getLeft() / w;
    }
  }, false);
  
}());
body {
  margin: 0;
  padding: 0;
}

.container {
  position: relative;
  height: 100vh;
  width: 100vw;
}

.square {
  height: 100%;
  position: absolute;
  width: 100vw;
}
.square1 {
  background: red;
  left: 0;
}

.square2 {
  background: green;
  left: 100%;
}

.square3 {
  background: yellow;
  left: 200%;
}
<div class="container">
  <div class="square square1">1</div>
  <div class="square square2">2</div>
  <div class="square square3">3</div>
</div>
Asons
  • 84,923
  • 12
  • 110
  • 165
  • thanks, this can be helpful, but it's not what I'm going for. If the viewport is between two squares I would like to keep them where they are. I think I almost got it working in my pen, but still something is a bit off – Carlo Apr 02 '16 at 18:58
  • 1
    @Carlo I have been testing this a bit more and you need to throttle the resize event/handler, and possibly the need of a bypass variable, so you can distinct between when the scroll events fires based on a user scroll and when you set the `scrollLeft` ... and that is likely why it's still is a bit off, as jQuery doesn't throttle by default. – Asons Apr 02 '16 at 23:43
  • @Carlo Also, and as pointed out by Chris M, users normally doesn't sit and resize their browser just to see if your web app manage to keep all page items in an exact position, so I think a little bit off is good enough. – Asons Apr 02 '16 at 23:46
  • thanks for all these inputs, I'll try experimenting with throttling. As for Chris' point, well, he's right, of course, but I'm quite sure you understand that at some point you just want to do something – Carlo Apr 03 '16 at 11:39
  • thank you very much. I think that throttling might be of great help in this case. Now I just need some time to test all this things out. So, even though this doesn't exactly answer my question, I think it's only fair to mark as accepted for the help and info you provided. Do you agree? – Carlo Apr 09 '16 at 09:45
  • @Carlo I do :) .. thanks .. and if you run into something that can improve, feel free to adjust my answer (or drop me a comment so I can) – Asons Apr 09 '16 at 09:48