It is not entirely clear to me how CSS transforms affect the flow layout of the document and the positioning of an element. According to the documentation on MDN and W3C, CSS transforms do not interfere with the flow layout:
From MDN on CSS transforms (emphasis mine):
By modifying the coordinate space, CSS transforms change the shape and position of the affected content without disrupting the normal document flow.
Thus, if we translate an element, the original flow layout should remain intact and the result of the transformation should be purely visual. A trivial example of this is demonstrated below:
.container {
background: white;
margin: 0 auto;
border: 1px solid grey;
}
.block {
width: 100%;
height: 100px;
}
.blue {
background: blue;
}
.red {
background: yellow;
}
.transform {
transform: translateY(-200%);
}
<div class="container">
<div class="block red transform"></div>
<div class="block blue"></div>
</div>
In this example, there are two div
elements and the upper element was translated vertically so that it is not visible anymore. However, the flow layout remains unchanged and there is no overflow in the document. That is, the result of the transformation is purely visual.
Now, consider a page layout with a wrapper of fixed width, such that the width of the child elements is bounded by the wrapper element. Now add a positioned element that is wider than the wrapper and add an offset (e.g. left
). In "narrow enough" windows, the body overflows and we are able to scroll horizontally. However, if we translate the same element and re-center it, the overflow disappears, implying that the transformation is not purely visual.
A demonstration of this effect is shown in the example below. Initially, the offset element is not transformed. You may try resizing your window to see the overflow and then toggle the transformation with the button in the center.
document.getElementById('toggle').addEventListener('click', function(event) {
const blocks = document.querySelectorAll('.block.wide');
for(let i=0;i<blocks.length;i++) {
const block = blocks[i];
block.classList.toggle('transform');
}
});
html, body {
background: #ddd;
}
.container {
background: white;
max-width: 1152px;
margin: 0 auto;
}
.content {
border: 1px solid grey;
}
.block.wide {
background: yellow;
max-width: 1380px;
width: 100vw;
position: relative;
left: 50%;
}
.block.wide.transform {
transform: translateX(-50%);
}
<div class="container">
<div class="content">
<div class="block">
<h1>Lorem ipsum dolor sit amet</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p><strong>Click the button below to toggle the transform and see the overflow vanish</strong></p>
<button id="toggle">Toggle Transform</button>
</div>
<div class="block wide">
<h1>Lorem ipsum dolor sit amet</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
Is this the intended behavior according to the specifications? How do offsets and transformations interact?
In all my test cases, the CSS transform achieves the desired result. However, I feel that I am relying on luck rather than a technical specification.