20

So this is a bit of a strange question. Programming a web application with a resizable div. I'm using the CSS resize property at the moment as it seemed like it was the easiest way to do it. The problem is my box has a locked bottom and left position (which I want to maintain), but the resize corner chosen by default is the lower right one, which produces weird results for resizing the top. Looked around online but couldn't find a way to move that corner to the upper right instead of the bottom right. Any advice on how to produce this result? Also not opposed to using a different method of resizing. Here's the current style being applied to the box:

display: block; 
font-size: 9pt; 
position: absolute; 
bottom: 50px; 
left: 20px; 
padding: 10px; 
min-height: 0; 
min-width: 0; 
border: solid 1px black; 
width:400px; 
height:400px; 
resize: both; 
overflow-x: auto; 
overflow-y: hidden;

And here's a picture of the div in question with the corner that currently has the resize tool on it boxed. Any advice would be greatly appreciated. I'm more than happy to elaborate on things I might've missed as well. Thanks!

Box I want to resize in question

Gerold Broser
  • 14,080
  • 5
  • 48
  • 107
kklein623
  • 213
  • 1
  • 2
  • 5
  • See my answer to a similar question here: https://stackoverflow.com/a/62814513/1599699 – Andrew Jul 09 '20 at 12:12
  • Before you guys read the answers below - **You can't achieve this using only CSS, you have to use javascript(Read below)** – Sameer Oct 25 '21 at 05:38

7 Answers7

13

Here's one starting point. I essentially created a custom resize icon in the upper right corner. I then used 'mousedown', 'mousemove' and 'mouseup' events to track resizing activity. You might be able to do something similar using 'drag' and related events.

Note the 'mousedown' is on the resize icon, while 'mousemove' and 'mouseup' are on the document body (or some other larger element behind the resizable div).

I've hard-coded the width and height in the JavaScript for the sake of simplicity. That means those values exist in two different places which is not good. You should probably put them only in JavaScript or only in CSS, not in both as I have done.

I needed to put the resizable div into a container that filled the body. Otherwise 'mousemove' events outside of the resizable div were not registered. This might not be an issue if you already have other content "behind" your absolutely positioned resizable element.

For your information: I also initially tried using the native resize functionality. I used transform: rotate(-90deg) to move the resize corner to the upper right, then put in an inner div with transform: rotate(90deg) to make the inside content the right-way-up again. However, while this put the resize corner in the correct place, the resizing itself was completely messed up, as the mouse movements and the actually resizing itself were off by 90 degrees. It's a little hard to describe in words, but suffice it to say that, without some major re-working (or perhaps some brilliant code or hidden function) I couldn't get that strategy to work.

var
  doc = document,
  ht = 400,
  wd = 400,
  main = document.querySelector("#resizable"),
  x, y, dx, dy;

var startResize = function(evt) {
  x = evt.screenX;
  y = evt.screenY;
};

var resize = function(evt) {
  dx = evt.screenX - x;
  dy = evt.screenY - y;
  x = evt.screenX;
  y = evt.screenY;
  wd += dx;
  ht -= dy;
  main.style.width = wd + "px";
  main.style.height = ht + "px";
};

rsz.addEventListener("mousedown", function(evt) {
  startResize(evt);
  doc.body.addEventListener("mousemove", resize);
  doc.body.addEventListener("mouseup", function() {
    doc.body.removeEventListener("mousemove", resize);
  });
});
#container {
  position: absolute;
  border: solid red 1px;
  margin: 0;
  height: 100%;
  width: 100%;
}
#resizable {
  display: block;
  font-size: 9pt;
  position: absolute;
  bottom: 50px;
  left: 20px;
  padding: 10px;
  min-height: 0;
  min-width: 0;
  border: solid 1px black;
  width: 400px;
  height: 400px;
  overflow-x: auto;
  overflow-y: hidden;
}
#rsz {
  position: absolute;
  right: 0;
  top: 0;
  width: 20px;
  height: 20px;
  background-color: rgba(255, 0, 0, 0.5);
}
#original {}
<div id="container">
  <div id="resizable">
    <div id="rsz"></div>
    (some content)
  </div>
</div>

If you run this code snippet from within Stack Overflow, you need to expand the running view area by clicking on "Full page" after clicking "Run code snippet".

Andrew Willems
  • 11,880
  • 10
  • 53
  • 70
9

Another dirty hack: set the direction of the container to rtl and the corner will be on the left

.resizable {
    resize: both;
    overflow: auto;
    direction: rtl
}

Remember that you will need to set the direction back to ltr in the inner div, so the text is displayed as you would expect it to:

.content {
    direction: ltr
}
frost
  • 1,003
  • 1
  • 12
  • 21
  • Unfortunately it seems it is not possible to get the resize corner to the top this way. Unless you use `transform: rotate(180deg);`. :-) – user14967413 Sep 12 '21 at 14:06
5

Here's a hack for you:

.outer-ne-resize {
  resize: both;
  overflow: auto;
}

.inner-ne-resize,
.outer-ne-resize {
  transform: rotateX(180deg);
  height: 100%;
  width: 100%;
}

.content {
  height: 100%;
  background-color: lightgray;
}
<div class="outer-ne-resize">
  <div class="inner-ne-resize">
    <div class="content">
      <p>Lorem ipsum content Lorem ipsum content Lorem ipsum content.<br>
      Lorem ipsum content Lorem ipsum content Lorem ipsum content.
      </p>
    </div>
  </div>

The problem with this hack, is that it still resizes in the same nwse direction, as indicated by the cursor. This means that when you pull down from the top it doesn't shrink, it expands from the bottom.

ADJenks
  • 2,973
  • 27
  • 38
4

Just a refactored solution from Andrew Willems to JS classes too keep your global scope clean and to be able apply it to several divs

If you run this code snippet from within Stack Overflow, you need to expand the running view area by clicking on "Full page" after clicking "Run code snippet".

class Resizehandler {
    constructor(targetDivID, pullTabID) {
        var d = document;
        var pullTab = d.getElementById(pullTabID);
        this.target = d.querySelector(targetDivID);

        this.ht = 400; this.wd = 400;
        this.x = 0; this.y = 0;
        this.dx = 0; this.dy = 0;

        var resizeFn = this.resize.bind(this);
        pullTab.addEventListener("mousedown", (evt) => {
            this.x = evt.screenX;
            this.y = evt.screenY;
            d.body.addEventListener("mousemove", resizeFn);
            d.body.addEventListener("mouseup", () => {
                d.body.removeEventListener("mousemove", resizeFn);
            });
        });
    }

    resize(evt) {
        this.dx = evt.screenX - this.x;
        this.dy = evt.screenY - this.y;
        this.x = evt.screenX;
        this.y = evt.screenY;
        this.wd += this.dx;
        this.ht -= this.dy;
        this.target.style.width = this.wd + "px";
        this.target.style.height = this.ht + "px";
    };
}
new Resizehandler("#resizable", "rsz");
#container {
  position: absolute;
  border: solid red 1px;
  margin: 0;
  height: 100%;
  width: 100%;
}
#resizable {
  display: block;
  font-size: 9pt;
  position: absolute;
  bottom: 50px;
  left: 20px;
  padding: 10px;
  min-height: 0;
  min-width: 0;
  border: solid 1px black;
  width: 400px;
  height: 400px;
  overflow-x: auto;
  overflow-y: hidden;
}
#rsz {
  position: absolute;
  right: 0;
  top: 0;
  width: 20px;
  height: 20px;
  background-color: rgba(255, 0, 0, 0.5);
}
#original {}
<div id="container">
  <div id="resizable">
    <div id="rsz"></div>
    (some content)
  </div>
</div>
2

A few years later, still looking for a way to do this.

I found a way now for resizing a bottom-right positioned element, with a top-left resize anchor.

It seems to work as expected in chrome, but it is depending on behaviour that is far from defined in any standards so it is probably best not to depend on it on any production environment, unless you have control over what clients/browsers use this code.

Full example with explanation found here: https://jsfiddle.net/ElMoonLite/zvok7p1f/

The core code:

<div class="bottomright-with-nw-resize-outer">
    <div class="bottomright-with-nw-resize-inner">
        Lorem ipsum content Lorem ipsum content Lorem ipsum content.<br>
        Lorem ipsum content Lorem ipsum content Lorem ipsum content.
    </div>
</div>
.bottomright-with-nw-resize-outer {
    transform: rotateZ(180deg);
    resize: both;
    overflow: auto;
    padding: 0 8px 8px 0;
    position: fixed;
    bottom: 10px;
    right: 10px;
    height: 100px;
    width: 100px;
}

.bottomright-with-nw-resize-inner {
    transform: rotateZ(180deg);
    width: 100%;
    height: 100%;
    overflow: auto;
}
MoonLite
  • 4,981
  • 2
  • 21
  • 13
1

This is an inline version that works like I would expect a right drag anchor to. note it has two handles one on the top right that I wanted and an extra on the bottom for the vertical axis.

note about the vertical scroll

.vertical-scroll { //can also be used as a wrap for multiple x-flip and x-flipback elements
min-height:20px; //this prevents overlapping to negatives
resize:vertical;
overflow:auto; //this is undefined until user input if no height attribute is set
}

alternatively to the snippet I have used the vertical-scroll class on the outside of the element. maybe if there are more than one child flip and flip back elements that would look better with one vertical scroll point aligning at the bottom.

or even take the vertical-scroll class out.

.resize-x-handle-flip {
transform: rotateX(180deg);
resize: horizontal;
overflow: auto;
width: 200px;
background:lightcyan;
}
.x-text-flip-back {
transform: rotateX(180deg);
}
.vertical-scroll { 
min-height:20px;  
resize:vertical;
overflow:auto;
}
<div class="resize-x-handle-flip">
 <div class="x-text-flip-back">
  <div class="vertical-scroll">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et.<br> dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.
  </div>
 </div>
</div>
1

The following solution uses the 'move object' technique, but keeps the bottom right corner in place. A standard html arrow in the top left accepts the cursor down and you can now 'drag' the box around while the bottom left stays in place, effectively re-sizing the box but from the top-left. This code works stand-alone:

<html>
<head>
<script>
document.onmousedown=myMouseDown;
document.onmouseup=myMouseUp;
var can_drag=false;
var moving;

function obj_move(e) {
    if (can_drag) {
         moving.style.left =(e.clientX)+'px';
         moving.style.top =(e.clientY)+'px';
        return true;
    }
}
function myMouseUp(e) {
    can_drag=false;
}
function myMouseDown(e) {
    var selected_item=event.srcElement;
    if(selected_item.className=="drag")  {
        moving=document.getElementById('test');
        can_drag=true;
        document.onmousemove=obj_move;
    }
    return true;
}
</script>
</head>
<body>
<div style='position:absolute;top:50px; left:200px;right:600px;bottom:300px; border:1px solid black;overflow:scroll' id='test'>

<span class='drag' style='cursor:pointer'>&#8689;</span>

<br>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis vel velit blandit, convallis est vel, feugiat 
lorem. Suspendisse aliquam turpis eu posuere fermentum. Proin ullamcorper, purus vitae pulvinar congue, 
odio augue cursus diam, et semper mauris eros et odio. Nam vestibulum est scelerisque, accumsan ligula sed, 
pulvinar justo. Duis scelerisque ligula eget facilisis molestie. Suspendisse et consequat nunc, at ultrices risus.
 Duis varius nisl in nibh convallis fermentum. Mauris posuere neque placerat posuere ultrices. 
 Suspendisse eget massa ligula. Vestibulum quis elit justo. Maecenas sed augue fringilla, luctus leo eget, 
 tincidunt dui. Aliquam ligula enim, condimentum vitae vestibulum vitae, rutrum sed turpis. Vivamus vitae nibh erat. 
 Duis laoreet quis turpis eu eleifend. Suspendisse nec ultrices augue, vel suscipit sem.
<br>
</div>

user3211098
  • 51
  • 1
  • 10