Alvaro Alvaro - 8 days ago 6
CSS Question

Change position top/left of children independently of the parent scrollTop position

I have several divs positioned absolutely within its parent.
The parent overflows the screen and can be scrolled.

On click those divs are supposed to be positioned occupying the height of the screen (as if they had position fixed). So each div is assigned a certain width and height and a top value. The problem is this only works as expected if the parent is not scrolled (scrollTop = 0).

I want this to be done smoothly with CSS transitions. I could assign a top value related to the scroll position of the parent in the click moment. But I am looking for a CSS way to do this. I thought of changing position fixed to the divs but this doesn't transition.

Is there any way I could make it work using CSS?

Edit: I am asking if anyone has some suggestion on how to achieve this using CSS, or some thought on how to approach it differently.

gif

Edit2: This GIF includes just the position change (the width or height is no changing) as it is where I am having the issue. This is the desired solution:

enter image description here

JSFiddle.



var $container = $('#container');
var $elements = $container.find('.element');
$container

.height(function() {

return ($elements.eq(-1).position().top - $elements.eq(0).position().top + $elements.eq(0).outerHeight());

})
.on('click', function() {

$elements.add($container).toggleClass('on');

});

#container {
width: 100%;
background: grey;
position: absolute;
}

.element {
border: 1px solid black;
position: absolute;
width: 100px;
height: 100px;
background: white;
left: 100px;
transition: all 1s ease;
}

.element:nth-child(2) {
top: 130px;
}

.element:nth-child(3) {
top: 340px;
}

.element:nth-child(4) {
top: 550px;
}

.element:nth-child(5) {
top: 660px;
}

.on.element {
left: 0;
height: 20vh;
width: 20vh;
}

.on.element:nth-child(2) {
top: 20vh;
}

.on.element:nth-child(3) {
top: 40vh;
}

.on.element:nth-child(4) {
top: 60vh;
}

.on.element:nth-child(5) {
top: 80vh;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>




Answer

Adding a margin-top value equivalent to the scrollTop position, and transitioning it with the same duration and ease as the children did the trick:

JSFiddle

var $container = $('#container');
var $elements = $container.find('.element');
$container

  .height(function() {

    return ($elements.eq(-1).position().top - $elements.eq(0).position().top + $elements.eq(0).outerHeight());

  })
  .on('click', function() {

    $elements.add($container).toggleClass('on');
    $container.css('margin-top', $('body').scrollTop());

  });
#container {
  width: 100%;
  background: grey;
  position: absolute;
  transition: all 1s ease;
}

.element {
  border: 1px solid black;
  position: absolute;
  width: 100px;
  height: 100px;
  background: white;
  left: 100px;
  transition: all 1s ease;
}

.element:nth-child(2) {
  top: 130px;
}

.element:nth-child(3) {
  top: 340px;
}

.element:nth-child(4) {
  top: 550px;
}

.element:nth-child(5) {
  top: 660px;
}

.on.element {
  left: 0;
  height: 20vh;
  width: 20vh;
}

.on.element:nth-child(2) {
  top: 20vh;
}

.on.element:nth-child(3) {
  top: 40vh;
}

.on.element:nth-child(4) {
  top: 60vh;
}

.on.element:nth-child(5) {
  top: 80vh;
}

.on.element:nth-child(6) {
  top: 25vh;
}
body {
  margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div id="container">
  <div class="element"></div>
  <div class="element"></div>
  <div class="element"></div>
  <div class="element"></div>
  <div class="element"></div>
</div>

Comments