mindriot
mindriot

Reputation: 3

Make child element full horizontal width of scrolling parent

I'm trying to tweak an existing app so would prefer to not change the dom structure. But I can't seem to get it how I need.

here is the example of where I am now.

https://codepen.io/m1nd/pen/QYLMeJ

<div class="canvas">
  <div class="node node-1">node 1</div>
  <div class="node node-2">node 2</div>
  <div class="node node-3">node 3</div>
  <div class="wrapper">
    <div class="right-target"></div>
  </div>
</div>
html, body {
  height:100%;
  background: yellow;
  padding:0;
  margin:0;
}

.canvas {
  position:relative;
  background: red;
  height:100%;
  overflow:auto;
}

.node {
  position:absolute;
  background: grey;
  width: 200px;
  height: 20px;
}

.node-1 {
  top: 2px;
  left: 2000px;
}

.wrapper {
  position:relative;
  height:100%;
  background:pink;
}

.right-target {
  position:absolute;
  right:0px;
  top:0px;
  width:20px;
  height: 100%;
  background:green;
}

I want the .wrapper div to expand to the full width of the .canvas (scrolling) div, so the green .right-target should be to the far far right.But no matter what I try I can't seem to get the .wrapper div to expand past the viewport width.

I've seen examples that address this vertically (http://bennadel.github.io/JavaScript-Demos/demos/css-position-overflow/) but I can't seem to get the same principle to work in my case.

Upvotes: 0

Views: 59

Answers (1)

cantuket
cantuket

Reputation: 1592

You have 2 options...

  1. Make the .wrapper overflow the viewport by the exact width of its child element, which is what you actually want to out of the viewport, but this will be near impossible to do precisely (without some extremely new CSS features) becaaus you will have make that .wrapped element 100% + 20px wide (this is actually on the future specs I believe)
  2. A better solution, if it works for your use case, would be having the green .right-target overlap is container (.wrapper) by its exact width...

    .right-target { ... right: -20px; ... }

Sorry, misunderstood question. Revised answer below...

To do this you will need to use Javascript since the .canvas element is overflowing the viewport. You'll need to...

  1. Calculate initial viewport width
  2. Imperatively set the .canvas width to the viewport width + the offset of the element creating the overflow, .node-1 and 2000px respectively
    1. On resize of the viewport you will have to re-calculate the new viewport.
    2. reset the .canvas to the new viewport width + the same .node-1 offset

$(document).ready(function () {
var viewportStartWidth = window.outerWidth,
    $target = $('.wrapper'),
    $offsetElems = $('.canvas .node'),
    offsetRight = (function () {
       var largestOffset = 0;
       $offsetElems.each(function(){
            var pos = $(this).offset().left;
            if (pos > largestOffset) {
             largestOffset = pos; 
            }
       });
       return largestOffset;
    })();
  
$target.width(viewportStartWidth + offsetRight)

$(window).on('resize', function(){
  var viewportNewWidth= $(this).outerWidth;
  $target.width(viewportNewWidth + offsetRight)
});

})

This makes you code very brittle though (if 2000px offset ever changes) and also has a significant performance cost (calculating and resetting width) every browser resize. You can improve this by debouncing/rate-limiting these calculations, but I would suggest a solution that does reorganize the DOM instead, even if you have to do it with JS on initial page load.

Full working example: https://codepen.io/anon/pen/QYWwKq

This is the only way you're able to do it with pure CSS, but take a look at the browser support to make sure it is acceptable for you...

.canvas {
    ...
    width: calc(100% + 2000px);   
    ...
}

Working example: https://codepen.io/anon/pen/GzRgeE

Upvotes: 1

Related Questions