Center absolute positioned div with translateX and overflow: auto without margins

I'm trying a very easy way to center and preserve the full size of a div without success, look at this snippet:

* {
  box-sizing: border-box;
}

.body {
  width: 400px;
  height: 100px;
  
  float: left;
  
  margin-right: 20px;

  position: relative;
}

.body.smaller {
  width: 200px;
}

.container {
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  
  position: absolute;
  
  overflow: auto;
  
  border: 2px solid blue;
}

.child {
  width: 300px;
  height: 1000px;
  
  position: absolute;
  
  left: 50%;
  transform: translateX(-50%);
  
  border: 2px solid green;
}
<div class="body">
  <div class="container">
    <div class="child"></div>
  </div>
</div>

<div class="body smaller">
  <div class="container">
    <div class="child"></div>
  </div>
</div>

As can be noticed in this snippet, the first sample is correctly rendered and centered but the smaller one is not, the green left border is cropped someway.

How I can show the entire content of the div using the translateX transform option and without tricks like margin: 0 auto; or similar statements?

I would achieve this in combination of a scaled container div with the possibility to scroll the child div, I tried all possible combinations without luck.

Update: please not that all sizes are not prefixed, these are just sample width and height, so no forced calculation should be done to achieve the expected result.

Update 2: I cannot use the margin: 0 auto; way to center the div because I'm trying to achieve a particular result. Look at this JSFiddle: https://jsfiddle.net/Emulator000/79c5L6o8/12/

function scale() {
    let children = document.getElementsByClassName('child');
  for (let i = 0; i < children.length; i++) {
    children[i].style.transform = 'scale(3)';  
  }
}
* {
  box-sizing: border-box;
}

.body {
  width: 400px;
  height: 100px;
  
  float: left;
  
  margin-right: 20px;

  position: relative;
}

.body.smaller {
  width: 200px;
}

.container {
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  
  position: absolute;
  
  overflow: auto;
  
  border: 2px solid blue;
}

.child {
  display: block;
  
  width: 300px;
  height: 1000px;
  
  margin: 0 auto;
  
  border: 2px solid green;

  transform-origin: 0 0;
}
<div class="body">
  <div class="container">
    <div class="child"></div>
  </div>
</div>

<div class="body smaller">
  <div class="container">
    <div class="child"></div>
  </div>
</div>

<button onclick="scale()">Scale</button>

As you can see, if you press the "Scale" button, the smaller one is scaled correctly and you can scroll the div as expected, the bigger one instead, shows a space as starts the scaling with a prefixed and computed margin, this issue is noticeable also with similar techniques like "justify", "box", centered text with "display: inline-block" or similar.

2 answers

  • answered 2020-10-27 22:38 AziMez

    Try this one:

    * {
      box-sizing: border-box;
    }
    
    .body {
      width: 400px;
      height: 100px;
      
      float: left;
      
      margin-right: 20px;
    
      position: relative;
    }
    
    .body.smaller {
      width: 200px;
    }
    
    .container {
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      
      position: absolute;
      
      overflow: auto;
      
      border: 2px solid blue;
    }
    
    .child {
    //width: 300px;
    
      width: 80%;
      height: 1000px;
      
      position: absolute;
      
    //left: 50%;  
      left: 10%;
      
    //transform: translateX(-50%);   
      border: 2px solid green;
    }
    <div class="body">
      <div class="container">
        <div class="child"></div>
      </div>
    </div>
    
    <div class="body smaller">
      <div class="container">
        <div class="child"></div>
      </div>
    </div>

  • answered 2020-10-27 23:10 Mohamed_Hafez

    The scroll bar can't display the right margin so you can remove it after the scale

        <head>
        </head>
        <style>
         * {
          box-sizing: border-box;
        }
    
        .body {
          width: 400px;
          height: 100px;
          
          float: left;
          
          margin-right: 20px;
    
          position: relative;
        }
    
        .body.smaller {
          width: 200px;
        }
    
        .container {
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          
          position: absolute;
          
          overflow: auto;
    
          
          border: 2px solid blue;
        }
    
        .child {
          display: block;
          
          width: 300px;
          height: 1000px;
          
          margin: 0 auto;
          
          border: 2px solid green;
    
          transform-origin: 0 0;
        }
        </style>
    
        <body>
        <div class="body">
          <div class="container">
            <div class="child">Lorem, ipsum dolor sit amet consectetur, adipisicing elit. Optio sequi quos amet, doloremque earum assumenda sapiente recusandae explicabo fuga, sed provident! Aspernatur ex neque maiores voluptatibus reprehenderit! At, quasi laboriosam.</div>
          </div>
        </div>
    
        <div class="body smaller">
          <div class="container">
            <div class="child">Lorem ipsum dolor sit amet consectetur adipisicing elit. Eius iusto numquam, autem eligendi voluptas ab qui id soluta voluptatum molestias sapiente dignissimos enim illo, impedit omnis tempore, corporis, ipsam accusantium.</div>
          </div>
        </div>
    
        <button onclick="scale()">Scale</button>
        <script type="text/javascript">
            
            function scale() {
            let children = document.getElementsByClassName('child');
          for (let i = 0; i < children.length; i++) {
            children[i].style.transform = 'scale(3)';
            // Remove the margin 
            children[i].style.margin = '0';  
          }
        }
        </script>
        </body>
    
        </html>