Keep resizable children within parent - javascript

I'd like to keep the resizable elements within the parent element.
What I did:
I gave already the minHeight : property and wile resizing I'm constraining the new height using Math.max to keep it at 30px height
Expected:
All resizable children elements should always be visible and minimally 30px in height.
Issue:
Somehow if you resize the lower elements, at some point vertical the big scrollbar appear and the resizable goes out of containment:"parent" (why?).
To recap - the page's vertical scrollbar should never appear an one should be always able to get to the "c" element.
$(".resiz").not(":last").resizable({
handles: 's',
minHeight : 30,
containment: "parent", /* seems not to work?! */
start:function(e,ui) {
this.other= $(this).next() || $(this).prev();
this.startingHeight = this.other.height();
},
resize:function(e,ui) {
var diffH = ui.size.height - ui.originalSize.height;
this.other.height( Math.max(30, this.startingHeight - diffH) );
}
});
*{box-sizing:border-box; margin:0;}
html, body{height:100%;}
#panel{
position:absolute;
height:100%;
width:200px;
}
.resiz{
height:33vh;
width:100%;
background:#eee;
}
.ui-resizable-s{
height:3px;
background:#08f;
}
<link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<div id="panel">
<div class='resiz'>a</div>
<div class='resiz'>b</div>
<div class='resiz'>c</div>
</div>
Edit: Seems related but the answer is not what I expected...

You are changing the height of the last div but never the actual div being resized. So the containment grows with the last div being pushed and since the containment is applied on the div being resized, it's never applied.
So to solve your problem I think you need to resize the last div until it's a maximum height, and when it's the case prevent anymore resizing. You could do it like this, although it seems there could be a more efficient way. Still it'll give you some ideas:
$(".resiz").not(":last").resizable({
handles: 's',
minHeight: 30,
containment: "parent",
/* seems not to work?! */
start: function(e, ui) {
this.maxHeight = undefined;
this.other = $(this).next();
this.startingHeight = this.other.height();
},
resize: function(e, ui) {
var diffH = ui.size.height - ui.originalSize.height;
//when next div is at max height, you prevent resizing of current div
if (Math.max(30, this.startingHeight - diffH) == 30) {
this.maxHeight = this.maxHeight || (this.prevHeight);
ui.size.height = this.maxHeight;
//until it's at max div you resize next div
} else {
this.other.height(this.startingHeight - diffH);
this.prevHeight = ui.size.height;
}
}
});
* {
box-sizing: border-box;
margin: 0;
}
html,
body {
height: 100%;
}
#panel {
position: absolute;
height: 100%;
width: 200px;
}
.resiz {
height: 33vh;
width: 100%;
background: #eee;
}
.ui-resizable-s {
height: 3px;
background: #08f;
}
<link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<div id="panel">
<div class='resiz'>a</div>
<div class='resiz'>b</div>
<div class='resiz'>c</div>
</div>

Related

How to control when a jQuery slideToggle(); which is position:absolute; is higher than viewport?

I have a slideToggle(); menu which is positioned absolutely on the bottom of the page. The slideToggle(); is going to show big content and sometimes this ends up being taller than the viewport.
My question is, how do I prevent the menu to:
1 - Not going on the top of the logo as they are both on the sidebar of my website
2 - When it reaches a height taller than the viewport, this will be scrollable
To explain myself better, I'd like the content of my menu, once is shown by slideToggle(); and whenever is taller than the viewport's height minus logo's height, to stop right below my logo and to continue expanding downwards if that's the case, and that I am able to scroll it down despite its position:absolute.
Does anyone have an idea on how I can achieve that? Please have a look at the snippet.
$( "#click" ).click(function() {
$( ".content" ).slideToggle();
});
.logo {
background: #11a1d6;
margin: 10px;
height: 100px;
width: 300px;
}
.list {
width: 200px;
position: absolute;
bottom: 20px;
}
.content {
background: #082965;
height: 10000px;
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="logo"></div>
<ul class="list">
<li id="click">
Click me
<div class="content"></div>
</li>
</ul>
You would need an additional wrapper for your .content that has overflow-y: hidden and height set to the max height available. To determine this height you need a function that runs after your DOM is loaded and adds this to your .content-wrapper:
function setContentMaxHeight() {
let containerHeight = $('.container').height()
let logoMargin = $('.logo').offset().top;
let logoHeight = $('.logo').height();
let listHeight = $('.list').height();
let listMargin = 20;
let maxHeight = containerHeight - ( 2 * logoMargin ) - logoHeight - ( 2 * listMargin) - listHeight;
$('.content-wrapper').css({
'height': maxHeight + 'px'
});
}
$(document).ready(function(){
setContentMaxHeight();
window.onresize = setContentMaxHeight; // detect the window resize and rerun the function
});
working fiddle

JQuery UI resizable grid, inconsistent behavior depending on grid value

I need a resizable bar that can go all the way to no bar. Depending on how what I set the grid to, sometimes I can, sometimes I can't. The values I try are multiples of the initial size of the bar.
Here are examples
Working:
https://jsfiddle.net/dg851voo/
$("#app-interactionAdjustingTheFractionBarsSTART-question-bar-5").resizable({
handles: 'n',
grid: [0, 60]
});
Not working:
https://jsfiddle.net/xmzj3x54/
$("#app-interactionAdjustingTheFractionBarsSTART-question-bar-5").resizable({
handles: 'n',
grid: [0, 20]
});
I need to be able to go all the way to no height for any multiple of the initial bar size.
I was able to get this working horizontally but not vertically. Possibly a bug with jQuery itself? Instead I came up with a slightly hacky solution that should get the job done.
Basically, if your grid size is 20 then the min height seems to be 20px - even if minHeight is set to 0. You put the resizable div in a wrap div, shift the resizable div down 20px, then you set the wrap to be overflow: hidden. Then if you want to retrieve the perceived height of the div you will have to subtract 20 from the actual height. Example below.
var gridY = 20;
$("#resizable").resizable({
handles: 'n',
grid: [0, gridY],
minHeight: gridY,
maxHeight: 120,
resize: function(e, ui){
var actualHeight = ui.size.height;
var perceivedHeight = actualHeight - gridY;
$("p").text(`${perceivedHeight}%`);
// because the height of my div is
// 100 I dont have to convert it to
// percentage, but if it was anything
// other than 100 you would have to
}
});
#resizable-wrap{
width: 100px;
height: 100px;
border: 1px solid #000;
position: relative;
overflow: hidden;
}
#resizable {
position: absolute;
top: 0;
left: 25px;
width: 50px;
height: 120px;
background-color: #F3EF7D;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div id="resizable-wrap">
<div id="resizable" class="resizableBox"></div>
</div>
<p>100%</p>

How to reload a div for equal height child on window resize

I wrote a script to give equal height to child elements of wrapper. It is working fine on page load, but when I resize or change the orientation of my iPad, the height remains the same as it was during page load.
$(window).on('load resize', function () {
$('.equal-height-wrapper').each(function () {
var heightArray = [];
var allbox = $(this).find(".equal-height-box");
$(allbox).each(function () {
heightArray.push($(this).height());
});
var maxBoxHeight = Math.max.apply(Math, heightArray);
$(this).find('.equal-height-box').css('height', maxBoxHeight);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="equal-height-wrapper">
<div class="inner-wrapper">
<div class="equal-height-box">
</div>
<div class="equal-height-box">
</div>
</div>
</div>
I want to update the height of the child elements when they change. As of now, I've added overflow hidden so that any text that overlaps gets hidden.
I tried placing this script on load resize, but it doesn't make any difference.
Wrapped code in a named function so you can call it in various ways. I'd replace window .load with $.ready. Also added orientationchange event. Then you get something like:
function setEqualHeight() {
$('.equal-height-wrapper').each(function() {
var heightArray = [];
var allbox = $(this).find(".equal-height-box");
$(allbox).each(function() {
$(this).height(""); // remove previously set heights
heightArray.push($(this).height());
});
var maxBoxHeight = Math.max.apply(Math, heightArray);
$(this).find('.equal-height-box').css('height', maxBoxHeight);
});
}
$(function() {
$(window).on('resize', setEqualHeight);
$(window).on('orientationchange', setEqualHeight);
setEqualHeight();
});
Why not using only CSS ?
Something like this could work...
(Updated to work with FIXED container height, and unknown container height)
/* For fixed container HEIGHT */
.container-1 {
display: block;
width:150px;
background-color:yellow;
height:200px;
}
.child-1 {
width: 30px;
background-color: red;
display: inline-block;
vertical-align: top;
top:0px;
bottom:0px;
height:100%;
}
/* FOR UNKNOWN CONTAINER HEIGHT */
.container-2 {
display: table;
width:150px;
background-color:yellow;
}
.child-2 {
width: 30px;
background-color: red;
display: table-cell;
vertical-align: top;
}
Demo: http://jsfiddle.net/bkG5A/740/
You could also, consider using CSS FLEX

CSS/JS: Animate Inline Element Upon Text Change

When an inline element's text changes, it is usually the case that its computed width or height changes as well.
Usually it's trivial to transition property changes with CSS, for example, adding a transition to change the background-color of an element upon hover.
However, inline element dimensions are really tricky. A simple transition property does not animate the change in computed width.
View example an by clicking here: https://jsfiddle.net/mz103/59s42ys4/ or viewing it below:
$("div").on("click", function() {
$(this).text("Although my width changes, it is not aniamted.");
});
div {
display: inline-block;
background-color: red;
padding: 8px 16px;
transition: width 0.3s; // Notice, this doesn't transition the width upon change.
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Click me.</div>
How, when the text of an inline element changes, can we animate those changes?
Here an Update: https://jsfiddle.net/ky3c5Lec/3/
$("div").on("click", function() {
//get the current Dimensions, as Start-value for the animation
var $this = $(this),
sw = $this.width(),
sh = $this.height();
$this.text("New text");
var tw = $this.width(),
th = $this.height();
$this.css({
//since jQuery.animate() doesn't have sth. like Tween.from()
//we have to reset the styles to the initial values
width: sw, height: sh
}).animate({
//and then animate
width: tw, height: th
}, function(){
//and when the animation is done, we clean up after ourselves
$this.css({
width: "", height: ""
});
})
});
You could try a little bit of jQuery animation:
function changeText(el) {
el.animate(
{
opacity: 0
},
{
duration: 'slow',
complete: function () {
$(this).text('New Text');
$(this).animate({opacity: 1}, 'slow');
}
});
}
Here is a fiddle.
I suppose that you will need two elements to achieve this elegantly:
$(".inner").on("click", function() {
var $this = $(this);
var $par = $this.parent();
$par.css({
width: $par.width()
});
$this.text("New text");
$par.css({
width: $this.outerWidth()
});
});
.inner {
display: inline-block;
padding: 8px 16px;
white-space: nowrap;
}
.outer {
display: inline-block;
transition: width 300ms ease-in-out;
background-color: red;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer">
<div class="inner">Here's some text.</div>
</div>

Switch div from fixed to absolute at bottom of browser

Im trying to add a footer at the bottom of this content that doesn't overlay the content but moves it up.
The only way I can see it working would be something like, when browser is at the bottom remove 'fixed' class on the left red '#work'.
js fiddle DEMO
Updated js fiddle DEMO
HTML
<div id="header-block">
Header-block, this sits here in the background
</div>
<div id="content">
<div id="work">
This content should be fixed when at the top
</div>
<div id="description">
This content should scroll -
</div>
</div><!-- end content -->
<div id="footer">
This should appear at the bottom
</div>
CSS
body {
margin: 0px;
padding: 0px;
}
#header-block {
background: green;
width: 100%;
position: fixed;
z-index: 1;
height: 300px;
top: 0;
}
#content {
margin-top: 300px;
width: 100%;
position: relative;
z-index: 2;
}
#work {
background: red;
width: 50%;
height: 100vh;
float: left;
position: absolute;
}
#description {
background: blue;
width: 50%;
height: 1200px;
float: right;
font-size: 30px;
}
#footer {
background: black;
width: 100%;
height: 100px;
position: absolute;
z-index: 3;
bottom: 0;
}
If I understand your question correct, this should do the trick (although it depends very much on JavaScript unfortunately).
// Fix work column on scroll
contentStart = $("#content").offset().top ;
contentSize = $("#content").height() ;
window.onscroll = function(){
if( window.XMLHttpRequest ) {
var position=window.pageYOffset;
// calculate the position of the footer and the actual seen window
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $("#footer").offset().top;
if ( position > 300 && !(docViewBottom >= elemTop)) {
$('#work').css({'position':'fixed', 'top':'0', 'height':'100vh'});
} else {
// if the footer is visible on the screen
if(docViewBottom >= elemTop) {
$('#work').css({ 'top': 0 - (docViewBottom - elemTop) }); // scroll the #main div relative to the footer
} else {
$('#work').css({'position':'relative', 'top': 'auto'}) ;
}
}
}
}
For further informations about the calculations, perhaps this question on stackoverflow is useful.
Edit: Andrew Haining posted his answer in between of my answer, perhaps give his link a try and maybe it's a better (more proper) solution. Unfortunately I haven't actualised this page when I was testing your code in JSFiddle and I didn't see his answer.
If you want to use my script, make sure you can test it with different resolutions. It works just fine for my resolution in JSFiddle, I didn't test any other.
I'm not 100% sure what you want, but if you remove the position: absolute and the bottom: 0 from the footer, and put a div with class='clearboth' above the footer, it seems to do what you need.
CSS
.clearboth {
clear: both;
}
This is a drawing of what I see on your fiddle;
Do you want the red and the blue to always be touching the black?
I don't see the red overlying the black
You should use jQuery to add a class containing the position:fixed value when the scroll position of the page is less than the inline position of the #work div. Once it scrolls past the position, remove the class and have the element fall back in line.
You can achieve this using the following jQuery methods.. .scrollTop() .offset().top() and $(window).height().
This tutorial will give you an understanding of what you need to do to achieve the necessary results, you will just have to change the calculation slightly using $(window).height(), $('#footer').height() and a few other changes to get what you desire.
Based on the question you asked i think this is what you mean. The red div should be fixed when it gets to the top but be absolute when it is below the top for scrolling and the black footer should be below the red while scrolling, check this code i have done for you. just add this jquery script and run it.
<script type="text/javascript" src="js/jquery.js"></script>
<script>
$(document).ready(function() {
$(window).scroll(function () {
console.log($(window).scrollTop());
if ($(window).scrollTop() >= 322) {
$('#footer').css("z-index","1");
$('#work').css(
{
"background": "red",
"width": '50%',
'height': '100vh',
'float': 'left',
'position': 'fixed',
'top': '0'
});
}
if ($(window).scrollTop() <= 322)
{
$('#work').css(
{
"background": "red",
"width": "50%",
"height": "100vh",
"float": "left",
"position": "absolute"
});
};
});
});
</script>
If not exactly a parallax, this is somewhat close to how parallax works, containers moving at different speeds, and some containers sitting fixed or scrolling when they attain a particular top/bottom offset in the viewport.
There's plugin that can do it. Skrollr
You can use Skrollr along with skrollrcss, and it'll make sure how the containers take position on screen based on scrolltop of the window and the container specifically.

Categories

Resources