Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overflow scroll on scaled child: different behavior on X and Y axis

Here is a code showing my issue

.container {
  width: 200px;
  height: 200px;
  overflow: auto;
}

.child {
  width: 400px;
  height: 400px;
  /* When scaling down, no more X scrolling because size is 200px, but still Y scrolling :( */
  transform: scale(0.5);
  /* Both axis working the same (no more scrolling) when absolutely positioned */
  /* position: absolute; */
}

/* Irrelevant styling */
.container {
  border: 2px solid palevioletred;
  position: relative;
}

.child {
  background-color: pink;
  transform-origin: top left;
}
<div class="container">
  <div class="child">
    Child
  </div>
</div>

Try to scroll down or right within the box.
  • There is a container with a fixed size, containing a child also with a fixed size.
  • There is overflow scrolling.
  • Then I scale down the child with a transformation, halving its size.

    • The X scroll disappears because child's width is 200px (more specifically, container's scrollWidth property has shrinked accordingly)
    • The Y scroll is still there and the container's scrollHeight property is still the same.

I can somewhat understand the behavior of each axis, but not why they're acting differently.

Ideally I'd like the Y axis to act like the X axis.

If I set position:absolute on the child, then the Y axis acts as the X axis (Both scrolls disappears).

.container {
  width: 200px;
  height: 200px;
  overflow: auto;
}

.child {
  width: 400px;
  height: 400px;
  position:absolute;
  transform: scale(0.5);
}

/* Irrelevant styling */
.container {
  border: 2px solid palevioletred;
  position: relative;
}

.child {
  background-color: pink;
  transform-origin: top left;
}
<div class="container">
  <div class="child">
    Child
  </div>
</div>

Try to scroll down or right within the box.

Same thing when I set display:inline-block. Both axis behave the sames (Both scrolls aren't affected by scale)

.container {
  width: 200px;
  height: 200px;
  overflow: auto;
}

.child {
  width: 400px;
  height: 400px;
  display:inline-block;
  transform: scale(0.5);
}

/* Irrelevant styling */
.container {
  border: 2px solid palevioletred;
  position: relative;
}

.child {
  background-color: pink;
  transform-origin: top left;
}
<div class="container">
  <div class="child">
    Child
  </div>
</div>

Try to scroll down or right within the box.

Why in the initial case, we have a different behavior? And why in some cases, the scale change the scroll (when we used position:absolute) and in other cases it doesn't (when we used display:inline-block).


As a side note, transform is a visual effect that doesn't affect the layout so logically the scroll shouldn't change in all the cases.

like image 984
Renaud Avatar asked Sep 03 '18 00:09

Renaud


Video Answer


2 Answers

I've found a few confusing statements in w3.org website about scollable overflow that might explain why the implementation is inconsistent. They look more like TODO marks, since it's a draft:

ISSUE 1:

There’s disagreement on the scrolling model. 2.1 apparently defined that you scrolled the content area; the content would overflow the content-box, and you would union that overflow with the content box to find the scrollable area. In particular, this means that the content would be offset by the start-sides padding, but if it overflowed, it would go right to the edge on the end sides. This is what Firefox and IE do. At least some authors (and spec authors) instead have the mental model that the padding box is what’s scrollable, so when you scroll to the end of the overflow, there’s the right/bottom padding. Chrome/WebKit do this for the block axis, at least. They’re somewhat inconsistent for the inline axis; there’s something weird about how they handle lineboxes.

It seems that the block-axis padding is probably web-compatible to honor. It’s unclear that the inline-axis padding will be. Further experimentation is needed.

ISSUE 2:

Is this description of handling transforms sufficiently accurate?

Note:

The scrollable overflow rectangle is always a rectangle in the box’s own coordinate system, but might be non-rectangular in other coordinate systems due to transforms [CSS3-TRANSFORMS]. This means scrollbars can sometimes appear when not actually necessary.

Anyway, it seems that we need to rely on "position:absolute" as a workaround for Chrome. Or transform the container instead of the child. Or even create an extra cointainer level.

Hope it helps!

like image 168
Fabio Manzano Avatar answered Oct 16 '22 12:10

Fabio Manzano


I believe the discrepancy in behaviour is linked to the transform-origin. When the origin is adjusted so that the child is placed to the right rather than the left (and the inline-block display removed), the horizontal scroll reappears and the child is only visible on scroll-over (see code snippet). As the child's default 'static' position (even without being transformed) would display from the top of the container, this is why it doesn't affect the vertical scroll in the same manner as I understand it.

As others have pointed out, there are outstanding tasks regarding CSS transforms. I would't regard it as a bug (although I see your point). Perhaps better explanations/more clarity will become available in future from the w3c.

.container {
  width: 200px;
  height: 200px;
  overflow: auto;
  border: 2px solid palevioletred;
  position: relative;
}

.child {
  width: 400px;
  height: 400px;
  transform: scale(0.5);
  background-color: pink;
  transform-origin: top right;
}
<div class="container">
  <div class="child">
    Child
  </div>
</div>

Transform-origin changed to top right (as opposed to top left)
like image 33
Rachel Gallen Avatar answered Oct 16 '22 11:10

Rachel Gallen