当父可调整大小时,如何防止嵌套DIV的内容溢出父级?

Pol*_*hat 6 html javascript css draggable resizable

CORE ISSUE:我需要正确地确定<div>嵌套在可调整大小的父级中的子级的高度<div>.在调整父级的大小时,子级不应超出父级的范围.父本身应该受到限制,以免它缩小到超出孩子的最小可滚动范围.

DEAD ENDS:通过几个小时的研究,我了解到CSS即使具有该calc()功能,也无法<div>动态设置高度和宽度.此外,似乎为了防止子级<div>溢出其父级维度,父级本身必须具有固定大小.在后一种情况下,样式喜欢height: auto; height: inherit;height: 100%;可能都会产生相同的结果.

之前已经在这里提出了类似的问题,但我找到的都没有解决调整大小问题.例如,提供给以下问题的解决方案无法正确解决我的问题.

防止子div溢出父div

在我的情况下,我有一个<div>用户调整大小和/或拖动到屏幕的任何部分.<div>如有必要,它的内容应自动滚动.在任何情况下,它们都不应超过容器的尺寸,即可调整尺寸的容器<div>.我的情况要求我不使用jQuery,但欢迎使用JavaScript解决方案.(即使PERL可能也值得,因为我将提供页面并通过来自Perl平台的AJAX进行更新.)

下面包含一个完整工作的示例,其中显示了子项如何<div>超过其父项,即使启用了滚动也是如此,无论父项<div>的大小如何调整都会发生这种情况.(我在Firefox和Safari中测试过它.)

请注意,在我的实际应用程序中,<div>将通过<select>菜单中的每个用户选择通过AJAX提供内容,并且内容将具有不同的长度.无论返回的长度如何,容器/父级<div>应保持与用户自己调整的大小相同.

<!DOCTYPE html>
<HTML lang="utf8">
<head>
<title>Example of Resizable/Draggable Container Div with Nested (Overflowing) Contents</title>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">

<style type="text/css">
.nested {
  background-color: #ffffcc;
  overflow-y: auto;
  overflow-x: hidden;
  max-height: 720px;
  height: inherit;
  color: #000;
  text-align: left;
  font-weight: normal;
  } 
.resizable {
  background: white;
  min-width: 100px;
  min-height: 120px;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 80px;
  left: 60px;
display: -webkit-box;   /* OLD - iOS 6-, Safari 3.1-6, BB7 */
display: -ms-flexbox;  /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Safari 6.1+. iOS 7.1+, BB10 */
display: flex;         /* NEW, Spec - Firefox, Chrome, Opera */
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.resizable .resizers{
  width: 100%;
  height: 100%;
  border: 3px solid #4286f4;
  box-sizing: border-box;
}
.resizable .resizers .resizer{
  width: 3px;
  height: 5px;
  border-radius: 50%;  /*magic to turn square into circle*/
  background: black;
  border: 3px solid #4286f4;
  position: absolute;
  }
.resizable .resizers .resizer.top-left {
  left: -2px;
  top: -2px;
  cursor: nwse-resize; /*resizer cursor*/
}
.resizable .resizers .resizer.top-right {
  right: -2px;
  top: -2px;
  cursor: nesw-resize;
}
.resizable .resizers .resizer.bottom-left {
  left: -2px;
  bottom: -2px;
  cursor: nesw-resize;
}
.resizable .resizers .resizer.bottom-right {
  right: -2px;
  bottom: -2px;
  cursor: nwse-resize;
}  
#dragselection {
    position: absolute;
    top: 6px;
    left: 3%;
    z-index: 8;
    background-color: #f1f1f1;
    border: 1px solid #d3d3d3;
display: -webkit-box;   /* OLD - iOS 6-, Safari 3.1-6, BB7 */
display: -ms-flexbox;  /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Safari 6.1+. iOS 7.1+, BB10 */
display: flex;         /* NEW, Spec - Firefox, Chrome, Opera */
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.header {
    padding: 4px;
    margin-left: 2px;
    margin-right: 2px;
    margin-top: 4px;
    margin-bottom: 4px;
    text-align: center;
    cursor: move;
    z-index: 10;
    background-color: #2168a8;
    color: #fff;
    font-size: 14px;
    font-weight: bold;
    }
#CV1 {
    min-width:150px; 
    min-height:150px; 
    }    
.top-banner {
display: inline-block; 
margin-top: 0px; 
margin-right: 7px; 
margin-left: 5px; 
margin-bottom: 7px; 
background-color: #afb; 
border-radius: 12px; 
opacity: 0.9; 
box-shadow: 3px 3px #878087; 
max-width: 100%; 
height: auto;
align: auto;
text-align: center;
    }     
</style>


</head>
<body onload="dragElement('dragselection');">

<div class="top-banner">
<p style="margin-top: 30px; margin-right: 60px; margin-left: 60px; margin-bottom: 30px; text-align:center; font-size: 2.0em; color:#fff;text-shadow: 2px 1px 2px #050050;">&#9840; Easy Text Reference &#9840;</p>
</div>

<form id="myform" name="nmyform" method="POST" accept-charset="utf-8" action="URL_for_CGI" >
<article>

<h1>Example:</h1>

<div id="flex-box" name="nflex-box" class="flex-container">

<div class="container" id="mainscreen" ondrop="drop(event)" ondragover="allowDrop(event)">
<div class="header flex-container-head" id="header-box" name="nheader-box">  

       
<div class='resizable' id="dragselection" style="border: 1px solid gray; font-size:18px; height: 250px; ">
  <div class='resizers'>
    <div class='resizer top-left'></div>
    <div class='resizer top-right'></div>
    <div class='resizer bottom-left'></div>
    <div class='resizer bottom-right'></div>
    
    <div id="dragselectionheader" class='header'>
    Your Text Selection
 
  <select id="get_text" name="nget_text"  onchange="getAjaxResult(['selection_text','recordnum'], 'POST'); ">
<option value="">---- Selection Menu ----</option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>
   
   </div>
    
  <div id="CV1" class="nested">
  A sample text:
  
  In the annals of human history, the growth of nations, the rise and fall of empires, appear as if dependent on the will and prowess of man; the shaping of events seems, to a great degree, to be determined by his power, ambition, or caprice. But in the word of God the curtain is drawn aside, and we behold, above, behind, and through all the play and counterplay of human interest and power and passions, the agencies of the All-merciful One, silently, patiently working out the counsels of His own will.  (Prophets and Kings, p. 499)
  </div>
  </div>
</div>


</div>
</div>

</div>

</article>

</form>


<script type="text/javascript">

/* Make the DIV element draggable: */
dragElement(document.getElementById(("dragselection")));

function dragElement(elmnt) {
  var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  if (document.getElementById(elmnt.id + "header")) {
    /* if present, the header is where you move the DIV from: */
    document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
  } else {
    /* otherwise, move the DIV from anywhere inside the DIV: */
    elmnt.onmousedown = dragMouseDown;
  }

  function dragMouseDown(e) {
    e = e || window.event;
    /* get the mouse cursor position at startup: */
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    /* call a function whenever the cursor moves: */
    document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    /* calculate the new cursor position: */
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    /* set the element's new position: */
    if ((elmnt.offsetTop - pos2) < 0) { 
         elmnt.style.top = '0px'
    } else {     
         elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    }     
    if ((elmnt.offsetLeft - pos1) < 0) {
         elmnt.style.left = '0px'
    } else {
         elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
    }
  }

  function closeDragElement() {
    /* stop moving when mouse button is released:*/
    document.onmouseup = null;
    document.onmousemove = null;    
  }
}

/* Modeled after: 
https://medium.com/the-z/making-a-resizable-div-in-js-is-not-easy-as-you-think-bda19a1bc53d 
*/

function makeResizableDiv(div) {
  const element = document.querySelector(div);
  const resizers = document.querySelectorAll(div + ' .resizer')
  const minimum_size = 120;
  var original_width = 0;
  var original_height = 0;
  var original_x = 0;
  var original_y = 0;
  var original_mouse_x = 0;
  var original_mouse_y = 0;

  for (var i = 0;i < resizers.length; i++) {
    const currentResizer = resizers[i];
    currentResizer.addEventListener('mousedown', function(e) {
      e.preventDefault()
      original_width = parseFloat(getComputedStyle(element, null).getPropertyValue('width').replace('px', ''));
      original_height = parseFloat(getComputedStyle(element, null).getPropertyValue('height').replace('px', ''));
      original_x = element.getBoundingClientRect().left;
      original_y = element.getBoundingClientRect().top;
      original_mouse_x = e.pageX;
      original_mouse_y = e.pageY;
      window.addEventListener('mousemove', resize)
      window.addEventListener('mouseup', stopResize)
    })
    
    function resize(e) {
      if (currentResizer.classList.contains('bottom-right')) {
        const width = original_width + (e.pageX - original_mouse_x);     
        const height = original_height + (e.pageY - original_mouse_y)     
        if (width > minimum_size) {
          element.style.width = width + 'px'     
          element.style.left = original_x + 'px' 
        }
        if (height > minimum_size) {
          element.style.height = height + 'px'     
          element.style.top = original_y + 'px' 
        }
      }
      else if (currentResizer.classList.contains('bottom-left')) {
        const height = original_height + (e.pageY - original_mouse_y)     
        const width = original_width - (e.pageX - original_mouse_x)     
        if (height > minimum_size) {
          element.style.height = height + 'px'     
          element.style.top = original_y+'px' 
        }
        if (width > minimum_size) {
          element.style.width = width + 'px'     
          element.style.left = original_x+(e.pageX-original_mouse_x)+'px' 
        }
      }
      else if (currentResizer.classList.contains('top-right')) {
        const width = original_width + (e.pageX - original_mouse_x)     
        const height = original_height - (e.pageY - original_mouse_y)     
        if (width > minimum_size) {
          element.style.width = width + 'px'     
          element.style.left = original_x + 'px'
        }
        if (height > minimum_size) {
          if (original_y+(e.pageY-original_mouse_y) < 0 ) {
            element.style.top = '0px'
          } else {
            element.style.height = height + 'px'     
            element.style.top = original_y+(e.pageY-original_mouse_y)+'px' 
          }
        }
      }
      else {          /* top-left */
        const width = original_width - (e.pageX - original_mouse_x)     
        const height = original_height - (e.pageY - original_mouse_y)     
        if (width > minimum_size) {
          element.style.width = width + 'px'     
          element.style.left = original_x+(e.pageX-original_mouse_x)+'px' 
        }
        if (height > minimum_size) {
         if (original_y+(e.pageY-original_mouse_y) < 0 ) {
            element.style.top = '0px'
          } else {
            element.style.height = height + 'px'     
            element.style.top = original_y+(e.pageY-original_mouse_y)+'px' 
          }
        }
      }
    }
    
    function stopResize() {
      window.removeEventListener('mousemove', resize)
    }
  }
}
makeResizableDiv('.resizable')

</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

更新:我已经调整了上面的代码,以反映到目前为止提供的建议.不幸的是,使用此配置,我无法限制父级的宽度.然后,孩子继承任何小于100%(或自动)的东西,结果不利.但是,我不希望父母占据屏幕的整个宽度,所以这个解决方案是不够的.

我现在已经找到了可能与Firefox一起使用的解决方法.我的Safari似乎不接受flex选项,因此仍然没有跨浏览器解决方案.对于Firefox,以下JavaScript代码可以<div>在页面加载后设置位置,如下所示:

document.getElementById('dragselection').setAttribute("style","width:320px; height:240px; font-size:18px;");
Run Code Online (Sandbox Code Playgroud)

我现在已经了解到以下代码更兼容跨浏览器,并使Safari正确呈现它.

display: -webkit-box;   /* OLD - iOS 6-, Safari 3.1-6, BB7 */
display: -ms-flexbox;  /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Safari 6.1+. iOS 7.1+, BB10 */
display: flex;         /* NEW, Spec - Firefox, Chrome, Opera */
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
Run Code Online (Sandbox Code Playgroud)

我已在示例脚本中的两个位置更新了该代码.这可能是可行的.

Bis*_*yak 5

你可以在这里使用 flexbox css。其中 Parent DIV 将是 flex,flex-direction: 列。

并且对于最小可拖动屏幕,父高度为 120px,而子项最小高度为 150px,从#CV1 中删除样式。

你能更新这些样式并检查吗?

.resizable .resizers{
  width: 100%;
  height: 100%;
  border: 3px solid #4286f4;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
}

.nested {
  background-color: #ffffcc;
  overflow-y: auto;
  overflow-x: hidden;
  max-height: 720px;
  height: inherit;
  color: #000;
  text-align: left;
  font-weight: normal;
  }
Run Code Online (Sandbox Code Playgroud)