Motla
Motla

Reputation: 1232

Set space/margin all around an absolute <div> which is inside a scrollable <div>

I'd like to set a margin all around a <div> with a position:absolute inside a scrollable <div> to let some free space between the inside div and the scrollable area boundaries (right and bottom).

I tried something like this but with no luck:

<div style="overflow:scroll">
  <div style="position:absolute; margin-right:100px; margin-bottom:100px">DRAG ME</div>
</div>

Demo here: https://jsfiddle.net/ayft01x0/

Only the margin-bottom works, and only in Chrome.

You can also imagine that there are other elements inside the scollable div and that they should stay clickable even if they are masked by the margin of the "drag me" element (which should be the case when using CSS margins).

I'm looking preferably for a CSS-only solution that works in Webkit browsers.
Any ideas?

Upvotes: 0

Views: 677

Answers (3)

Motla
Motla

Reputation: 1232

The easiest way to achieve this is to create an invisible CSS ::before pseudo-element that covers the box plus a padding, and to make it transparent to the mouse interactions using the pointer-events property:

div.box::before{
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    padding-right: 100px;
    padding-bottom: 100px;
    pointer-events: none;
    /* background-color: rgba(255,0,0,0.2); // to understand what is going on */
}

Demo here: https://jsfiddle.net/rmxwwyno/

Be warned that it's not working when the box has an overflow property that is not set to visible.

Upvotes: 0

Motla
Motla

Reputation: 1232

There is a workaround by using an encapsulating div with inner padding and make it transparent to the mouse interactions using the pointer-events property.

<div style="overflow:scroll">
  <div style="position:absolute; padding-right:100px; padding-bottom:100px; pointer-events:none">
    <div style="pointer-events:all">DRAG ME</div>
  </div>
</div>

Demo here: https://jsfiddle.net/1axtonez/

Upvotes: 0

henry
henry

Reputation: 4385

Absolute positioning changes the way margins work, but you can get the effect you're after with borders:

We add a border to the left and the right. This interferes with the border you already had on the draggable element, so we add a pseudoelement to take care of the design. The pseudoelement covers up the "drag me" text, so we add a wrapper around that content and fix the z indices

Here's an update to your fiddle, and here's a snippet of the essential css

#container {
  position: relative;
  width: 200px;
  height: 200px;
  border: solid 1px black;
  background-color: white;
}
#box {
  position: absolute;
  border-right: 100px solid transparent; /* changed this */
  border-bottom: 100px solid transparent; /* changed this */
  outline: 1px solid red; /* just for demo purposes */
  width: 80px;
  height: 80px;
  left: 50px;
  top: 50px;
  /* dropped the border and background styles */
}
#box span { /* added this element */
  position: relative;
  z-index: 1;
}
#box:before { /* added this element */
  content: '';
  position: absolute;
  z-index: 0;
  width: 80px;
  height: 80px;

  /* placement adjusted to take the border into account */
  left: -2px;
  top: -2px;

  /* border and background styles moved from #box to here */
  border: solid 2px #666;
  border-radius: 10px;
  background: #ccc; /* shaved off a couple bytes by dropping the -color */
}
<div id="container" style="overflow:scroll">
  <div id="box">
    <span>DRAG ME</span><!-- added this wrapping element so that it can get a z-index -->
  </div>
</div>

Note that I've kept your initial positions for the draggable box, but I would probably actually do it like this. The negative margins are just half the element's dimensions. This way if you tweak the size of #container you don't have to recalculate #box's starting position

#box {
    ...
    width: 80px;
    height: 80px;
    left: 50%;
    top: 50%;
    margin-left: -40px;
    margin-top: -40px;
}

Upvotes: 1

Related Questions