I decided to give up trying to do it without JavaScript. I managed to get it to work smoothly by making sure it gets the position of the mouse cursor correctly, even when hovering over the iframe. It requires access to the domain in the iframe to use postMessage to get the mouse coordinates but no problem, I am only going to use this to create debug tools on my own website anyway. It can be resized in all directions by dragging an edge or corner.
<!DOCTYPE html>
<style>
iframe {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
border: none;
}
.frame_holder {
display: block;
top: 300px;
left: 200px;
height: 500px;
width: 350px;
position: absolute;
}
.resizer {
position: absolute;
width: 7px;
height: 7px;
z-index: 2;
}
.resizer.n {
top: -7px;
left: 0px;
width: 100%;
cursor: n-resize;
}
.resizer.s {
bottom: -7px;
left: 0px;
width: 100%;
cursor: s-resize;
}
.resizer.w {
top: 0px;
left: -7px;
height:100%;
cursor: w-resize;
}
.resizer.e {
top: 0px;
right: -7px;
height:100%;
cursor: e-resize;
}
.resizer.nw {
top: -7px;
left: -7px;
cursor: nw-resize;
}
.resizer.ne {
top: -7px;
right: -7px;
cursor: ne-resize;
}
.resizer.sw {
bottom: -7px;
left: -7px;
cursor: sw-resize;
}
.resizer.se {
bottom: -7px;
right: -7px;
cursor: se-resize;
}
</style>
<body>
<div class="frame_holder">
<div class="resizer n"></div>
<div class="resizer s"></div>
<div class="resizer w"></div>
<div class="resizer e"></div>
<div class="resizer ne"></div>
<div class="resizer nw"></div>
<div class="resizer sw"></div>
<div class="resizer se"></div>
<iframe class="frame" src="https://stackoverflow.com/questions/74724195/how-can-i-make-an-iframe-resizeable-without-javascript"></iframe>
</div>
</body>
<script>
$ = typeof $ == "undefined" ? [] : $;
$[window.location.pathname]=function()
{
window.addEventListener('contextmenu', (e) => {e.preventDefault()});
const el = document.querySelector(".frame_holder");
const iframe = document.querySelector(".frame");
const resizers = document.querySelectorAll(".resizer");
var currentResizer = 0;
var prevX;
var prevY;
function resize(el, size)
{
Object.keys(size).forEach((i) =>
{
el.style[i] = size[i] + "px";
});
}
window.onmessage = function(e)
{
try
{
var msg = JSON.parse(e.data);
}
catch (e)
{
return;
}
if (msg.type == "mouseUp")
{
el.isResizing=false;
//window.removeEventListener("mousemove", mousemove);
//window.removeEventListener("mouseup", mouseup);
return
}
if (!el.isResizing)
{
try
{
window.removeEventListener("mousemove", mousemove);
//window.removeEventListener("mouseup", mouseup);
}
catch (e)
{ }
return;
}
const rect = el.getBoundingClientRect();
let mouseX = msg.mouseX + rect.left;
let mouseY = msg.mouseY + rect.top;
//let top = Math.min(rect.top - (prevY - mouseY), 0);
//let left = Math.min(rect.left - (prevX - mouseX), 0);
let top = rect.top - (prevY - mouseY);
let left = rect.left - (prevX - mouseX);
let width = rect.width + (prevX - mouseX);
let width1 = rect.width - (prevX - mouseX);
let height= rect.height - (prevY - mouseY);
let height1 = rect.height + (prevY - mouseY);
//let vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0)
//let vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0)
let currentResizer = this.currentResizer;
if (currentResizer.classList.contains("n"))
resize(el, {top: top, height: height1});
else if (currentResizer.classList.contains("w"))
resize(el, {left: left, width: width});
else if (currentResizer.classList.contains("s"))
resize(el, {height: height});
else if (currentResizer.classList.contains("e"))
resize(el, {width: width1});
else if (currentResizer.classList.contains("sw"))
resize(el, {left: left, width: width, height: height});
else if (currentResizer.classList.contains("ne"))
resize(el, {top: top, width: width1, height: height1});
else if (currentResizer.classList.contains("nw"))
resize(el, {top: top, left: left, width: width, height: height1});
else if (currentResizer.classList.contains("se"))
resize(el, {width: width1, height: height});
else
resize(el, {left: left, top: top});
prevX = mouseX;
prevY = mouseY;
};
for (let resizer of resizers)
{
if (resizer.classList.contains("n"))
iframe.style.borderTop = "groove 2px";
else if (resizer.classList.contains("s"))
iframe.style.borderBottom = "groove 2px";
else if (resizer.classList.contains("w"))
iframe.style.borderLeft = "groove 2px";
else if (resizer.classList.contains("e"))
iframe.style.borderRight = "groove 2px";
resizer.addEventListener("mousedown", mousedown);
function mousedown(e)
{
currentResizer = e.target;
//window.currentResizer = e.target;
window.currentResizer = currentResizer;
el.isResizing = true;
prevX = e.clientX;
prevY = e.clientY;
window.addEventListener("mousemove", mousemove);
window.addEventListener("mouseup", mouseup);
//msg.mouseX=344, msg.mouseY=830
//e.clientX=551, e.clientY=800
function mousemove(e)
{
if (!el.isResizing)
{
window.removeEventListener("mousemove", mousemove);
window.removeEventListener("mouseup", mouseup);
return;
}
const rect = el.getBoundingClientRect();
//let top = Math.min(rect.top - (prevY - e.clientY), 0);
//let left = Math.min(rect.left - (prevX - e.clientX), 0);
let top = rect.top - (prevY - e.clientY);
let left = rect.left - (prevX - e.clientX);
let width = rect.width + (prevX - e.clientX);
let width1 = rect.width - (prevX - e.clientX);
let height= rect.height - (prevY - e.clientY);
let height1 = rect.height + (prevY - e.clientY);
if (currentResizer.classList.contains("n"))
resize(el, {top: top, height: height1});
else if (currentResizer.classList.contains("w"))
resize(el, {left: left, width: width});
else if (currentResizer.classList.contains("s"))
resize(el, {height: height});
else if (currentResizer.classList.contains("e"))
resize(el, {width: width1});
else if (currentResizer.classList.contains("sw"))
resize(el, {left: left, width: width, height: height});
else if (currentResizer.classList.contains("ne"))
resize(el, {top: top, width: width1, height: height1});
else if (currentResizer.classList.contains("nw"))
resize(el, {top: top, left: left, width: width, height: height1});
else if (currentResizer.classList.contains("se"))
resize(el, {width: width1, height: height});
else
resize(el, {left: left, top: top});
prevX = e.clientX;
prevY = e.clientY;
}
function mouseup()
{
el.isResizing = false;
console.log("mouseup");
window.removeEventListener("mousemove", mousemove);
//window.removeEventListener("mouseup", mouseup);
}
}
}
}
if (document.readyState!='loading') $[window.location.pathname](); else document.addEventListener('DOMContentLoaded', $[window.location.pathname]);
</script>
This code goes inside the iframe:
if (!window.isTop)
{
function mouseup(e)
{
window.top.postMessage(JSON.stringify({ type: "mouseUp" }), '*');
}
function mousemove(e)
{
window.top.postMessage(JSON.stringify({ type: "mouseMove", mouseX: e.clientX, mouseY: e.clientY }), '*');
}
window.addEventListener("mouseup", mouseup);
window.addEventListener("mousemove", mousemove);
}