I need to adapt the width of a textarea (='#overlay') to its content. The minimum width should be 100px:
'input #overlay': function(e) {
var overlay = $('#overlay'),
element = document.getElementById('overlay'),
pos = overlay.position(),
width = 100;
if (element.scrollWidth > element.clientWidth) {
var diff = Math.ceil((element.scrollWidth - element.clientWidth)/20)*20,
left = pos.left - (diff/2);
width = element.scrollWidth + diff;
overlay.css({left: left, width: width});
}
This code works to expand the textarea if there is a long line. But it can't be used to make it smaller if you delete some characters of the line.
You have to set the minimum value before the if-part:
overlay.css({ width: 100 });
Then the height will always be adapted to the needed height.
Related
EDIT 3/Final: Th Computed Style problem/question is explained below but, for the benefit of others coming later, my real problem is solved with Flex Boxes and Vx measurements in conjunction with border-box. IMHO "display: flex;" is the answer to many questions and, although I'm struggling to get it to do what I want, stops you having to work against CSS!
EDIT 2: The following undoubtedly needs refactoring but if you can tell me that it does what I was asking for that'd be great. The change I had to make was to add clientTop in with offsetTop in the equation: -
function resizeContent()
{
var browserHeight = window.outerHeight;
var offesetHeight, offsetWidth;
var viewHeight = window.innerHeight;
var viewWidth = window.innerWidth;
var chromeFootPrint = browserHeight - viewHeight;
var tmpHeight = viewHeight;
if (window.matchMedia("(orientation: portrait)").matches) {
if (viewWidth > viewHeight) {
viewHeight = viewWidth - chromeFootPrint;
viewWidth = tmpHeight + chromeFootPrint;
}
} else {
if (viewWidth < viewHeight) {
viewHeight = viewWidth - chromeFootPrint;
viewWidth = tmpHeight + chromeFootPrint;
}
}
var dimTarget = logScroll;
var offsetTop = dimTarget.offsetTop + dimTarget.clientTop;
var offsetLeft = dimTarget.offsetLeft + dimTarget.clientLeft;
while (dimTarget = dimTarget.offsetParent) {
offsetTop += dimTarget.offsetTop + dimTarget.clientTop;
offsetLeft += dimTarget.offsetLeft + dimTarget.clientLeft;
}
logScrollHeight = viewHeight - (offsetTop + fireBreak);
logScroll.style.height = logScrollHeight + "px";
logScroll.style.width = getStyle(contentDiv).width;
logWindow.style.height = logScroll.style.height;
logWindow.style.width = logScroll.style.width;
logWindow.scrollTop = logWindow.scrollHeight - logScrollHeight;
contentDiv.style.visibility = "visible"; // Now we're presentable
}
and this is the fire-break calculation: -
var outerStyle = getStyle(wholeScreen);
fireBreak = Number(outerStyle.paddingBottom.match("[0-9.]*"))
+ Number(outerStyle.borderBottomWidth.match("[0-9.]*"))
;
resizeContent();
EDIT 1: Ok, let me re-phrase the question: - How to I find out the height of my DIVs content with: -
width: 250px;
border: 3px solid green;
padding: 0.5em;
box-sizing: border-box;
I am currently having to do this: -
logScrollHeight = viewHeight -
(offsetTop + Number(getStyle(headerDiv).paddingBottom.match("[0-9.]*")));
Original question: -
This is bound to be a duplicate but after nearly an hour of looking I have found many similar/identical questions but no real answer :-(
Why aren't the boundryWith and padding deducted from height?
Thankfully the boundryBottomWidth and PaddingBottom return have been converted to pixels (including the "px" string sadly) but doesn't the standard say that the usable height should be returned?
To get the height of an element, you don't use getComputedStyle.
getComputedStyle should only be used to get the parsed values that are currently applied from different style-sheets. In other words, you can see it as a live style-sheet, only targeted to a single element, with standardized units.
But in no way it should be used to get the current height or width of an element. Too many factors may interfere with the set value, and an element can even have an height without having any CSS height rule set.
So yes... when the height CSS rule is set to auto, you will get the computed value, which may coincide with the real height of the element, but it also may not be so.
So in order to get the displayed height of an element, without the border and padding, we will need to do some calculations ourself.
Element#getBoundingClientRect() will give us the real displayed dimensions of our element, transformations included. .offsetHeight will give us the untransformed height including the border-box, and .clientHeight will give us the untransformed height with the padding-box.
This means that we will first have to get all the border and padding computed values, then get the current scale of our element, and finally remove the scaled padding + border boxes from the values we get with getBoundingClientRect.
Here is an example, which will draw a new rectangle div atop the element's bounding-box without padding and border boxes.
let marker;
scale.onclick = e => {
element.classList.toggle('scaled');
drawRect();
}
boxSizing.onclick = e => {
element.classList.toggle('boxSized');
drawRect();
}
function drawRect() {
// remove previous marker if any
if (marker && marker.parentNode) {
marker.remove();
marker = null;
}
// first get the border and padding values
let computed = getComputedStyle(element);
let borderLeft = parseFloat(computed.borderLeftWidth);
let borderWidth = borderLeft + parseFloat(computed.borderRightWidth);
let borderTop = parseFloat(computed.borderTopWidth);
let borderHeight = borderTop + parseFloat(computed.borderBottomWidth);
let paddingLeft = parseFloat(computed.paddingLeft);
let paddingWidth = paddingLeft + parseFloat(computed.paddingRight)
let paddingTop = parseFloat(computed.paddingTop);
let paddingHeight = paddingTop + parseFloat(computed.paddingBottom);
// get the current bounding rect, including the border-box
let rect = element.getBoundingClientRect();
// we need to get the current scale since the computed values don't know about it...
let scale = 1 / (element.offsetHeight / rect.height);
// the real displayed height and width without border nor padding
let height = rect.height - ((borderHeight + paddingHeight) * scale);
let width = rect.width - ((borderWidth + paddingWidth) * scale);
// create our rectangle
marker = document.createElement('div');
marker.classList.add('marker');
marker.style.height = height + 'px';
marker.style.width = width + 'px';
// we need to scale border + padding again
marker.style.top = (rect.top + (borderTop + paddingTop) * scale) + 'px';
marker.style.left = (rect.left + (borderLeft + paddingLeft) * scale) + 'px';
document.body.append(marker);
}
#element {
width: 250px;
border: 0.5em solid green;
padding: 0.5em;
margin-top: 12px;
}
#element.scaled {
transform: scale(2);
transform-origin: top left;
}
#element.boxSized {
box-sizing: border-box;
}
.marker {
position: fixed;
width: 3px;
background: rgba(0, 0, 0, .3)
}
<label>scale
<input id="scale" type="checkbox">
</label>
<label>box-sizing
<input id="boxSizing" type="checkbox">
</label>
<div id="element">
Hello
<br> world
</div>
when you set box-sizing as border-box:
The width and height properties include the content, the padding and border, but not the margin
So when you use getComputedStyle to get a element's height, of course it includes the height of padding and border.
you can have a look at box-sizing property and css box model
I would like to add left margin and right margin to the body to hide the width change when I hide the vertical scrollbar.
I have this code that finds the width of the vertical scrollbar:
var $outer = $('<div>').css({visibility: 'hidden', width: 100, overflow: 'scroll'}).appendTo('body'),
widthWithScroll = $('<div>').css({width: '100%'}).appendTo($outer).outerWidth();
$outer.remove();
var scrollbarwidth = 100 - widthWithScroll;
It gives the value "17" (in pixels) for IE11, Chrome 45, and Firefox 39 (desktop).
When I hide the vertical scrollbar, all elements, such as images, jump exactly 17 pixels to the right, which I want to hide.
I have tried:
document.body.style.marginRight = scrollbarwidth + "px";
$('body').css('margin-right', scrollbarwidth);
$(body).css("marginRight", scrollbarwidth + "px");
The last one might be faulty in some way, since other parts of the function stops working when it's enabled. The two others don't seem to work either, as I don't see any margin changes.
EDIT 1: For easier understanding of how I am going to use it, I wanted to mention that it's supposed to trigger on a on scroll function, like this:
var check1 = false;
$(document).bind('scroll', function() {
if(check1 === false && $(window).scrollTop() >= $('#divscrolltester').offset().top + $('#divscrolltester').outerHeight() - window.innerHeight) {
check1 = true;
unloadScrollBars();
disableScroll();
var $outer = $('<div>').css({visibility: 'hidden', width: 100, overflow: 'scroll'}).appendTo('body'),
widthWithScroll = $('<div>').css({width: '100%'}).appendTo($outer).outerWidth();
$outer.remove();
var scrollbarwidth = 100 - widthWithScroll;
//document.body.style.paddingRight = scrollbarwidth + "px"; Temporary disabled.
//$('body').css('padding-right', scrollbarwidth); Temporary disabled.
//$(body).css("marginRight", scrollbarwidth + "px"); Temporary disabled.
setTimeout(function() {
enableScroll();
reloadScrollBars();
//document.body.style.paddingLeft = scrollbarwidth + "px"; Temporary disabled.
//$('body').css('padding-left', scrollbarwidth); Temporary disabled.
//$(body).css("marginLeft", scrollbarwidth + "px"); Temporary disabled.
}, 500);
}
});
EDIT 2:
Here is a Fiddle to show most of the js, html and css: https://jsfiddle.net/tfnwj7dj/10/.
I haven't added the change of css through code yet, as I'm still trying to solve the issue. Also, the scrolling and scrollbar are supposed to be re-enabled in a second, but there seems to be an error in there somewhere, sorry.
EDIT 3:
For your information at this moment, these lines work:
document.body.style.paddingLeft = (scrollbarwidth) + "px";
$('body').css('padding-left', scrollbarwidth);
document.body.style.paddingRight = (scrollbarwidth) + "px";
$('body').css('padding-right', scrollbarwidth);
document.body.style.marginLeft = (scrollbarwidth) + "px";
$('body').css('margin-left', scrollbarwidth);
document.body.style.marginRight = (scrollbarwidth) + "px";
$('body').css('margin-right', scrollbarwidth);
Maybe you have enough information to solve it, if you have the same issue, but unfortunately, this wasn't enough for me. It might be important info to know that I have my content centered with a width / max-width of just 500px, and that I don't actually have a body class. Maybe on designs with width="100%", or elements with absolute positioning, the lines might be enough.
Both javascript and jquery solutions are welcomed.
EDIT 4:
I finally solved it for my own circumstances - feel free to read the answer below. It works for preventing elements to jump when hiding the vertical scrollbar, and with some tinkering, it could probably do for a body class, or other situations.
Is your scrollbarwidth integer? Try this
var scrollbarwidth = 100;
$('body').css('margin-right', scrollbarwidth);
Maybe you have wrong value at scrollbarwidth ? In my ff this code works.
I managed to solve it - I'd like to clarify that my css actually don't contain a body class, and that I just centered all elements with a width / max-width of 500px and margin-left/right auto.
For my and other, similar cases, here is the answer:
/* First 5 lines for finding the scrollbar width. */
var $outer = $('<div>').css({visibility: 'hidden', width: 100, overflow: 'scroll'}).appendTo('body'),
widthWithScroll = $('<div>').css({width: '100%'}).appendTo($outer).outerWidth();
$outer.remove();
var scrollbarwidth = 100 - widthWithScroll;
var scrollbarwidthadjustment = scrollbarwidth / 2; /* For centered elements, divide the scrollbar width by 2. */
var element = document.getElementById('element');
element.style.right = (scrollbarwidthadjustment) + "px";
And when you re-enable the vertical scrollbar, simply add:
element.style.right = "0px";
Also, the element must have a css position stated, otherwise it won't trigger. Here is an example of a css style that works:
.examplestyle {
color: white;
position: relative;
margin-left: auto;
margin-right: auto;
max-width: 100%;
display: block;
}
EDIT 1:
To prevent some unsightly css errors on mobile devices, add these lines:
/* ... */
var scrollbarwidthadjustment = scrollbarwidth / 2;
var windowWidth = $(window).width(); /* Get current window width on click/scroll etc. */
var window1 = windowWidth + scrollbarwidth; /* Window width + scrollbar width. */
var element = document.getElementById('element');
if(window1 >= widthofelement) {element.style.right = (scrollbarwidthadjustment) + "px";}
else {}
EDIT 2:
Fix for image resized smaller than its original size:
var offsetwidth = element.offsetWidth;
var widthadjustment = offsetwidth - scrollbarwidth; /* Get full width of image when scrollbar hidden, and then remove the scrollbar width. */
if(window1 < widthofelement && scrollbarwidth > 0) {
element.style.width = widthadjustment + "px";
element.style.right = (scrollbarwidthadjustment) + "px";
}
And then this code when showing the Y-scrollbar again:
if(window1 < widthofelement && scrollbarwidth > 0) {
element.style.width = "OriginalSizepx";
element.style.right = "0px";
}
If you want to use every edit that I have added, here is the full code:
/* First 5 lines for finding the scrollbar width. */
var $outer = $('<div>').css({visibility: 'hidden', width: 100, overflow: 'scroll'}).appendTo('body'),
widthWithScroll = $('<div>').css({width: '100%'}).appendTo($outer).outerWidth();
$outer.remove();
var scrollbarwidth = 100 - widthWithScroll;
var scrollbarwidthadjustment = scrollbarwidth / 2; /* For centered elements, divide the scrollbar width by 2. */
var element = document.getElementById('element'); /* Put element ID into a variable for easier use, and consecutive uses without re-identifying it. */
var window1 = windowWidth + scrollbarwidth; /* Window width + scrollbar width. */
var offsetwidth = element.offsetWidth; /* Get exact element size in current window. Shows shown dimensions when the window is resized. */
var widthadjustment = offsetwidth - scrollbarwidth; /* Get full width of image when scrollbar hidden, and then remove the scrollbar width. */
if(window1 >= widthofelement) {element.style.right = (scrollbarwidthadjustment) + "px";} /* If current window is equal to or greater than element width... */
if(window1 < widthofelement && scrollbarwidth > 0) { /* If current windows is smaller than the element width, and the window has a scrollbar greater than 0 pixels in width. */
element.style.width = widthadjustment + "px";
element.style.right = (scrollbarwidthadjustment) + "px";
}
/* When re-enabling the Y-scrollbar again; */
if(window1 >= widthofelement) {element.style.right = "0px";}
if(window1 < widthofelement && scrollbarwidth > 0) {
element.style.width = "OriginalSizepx";
element.style.right = "0px";
}
For further clarification, this code will prevent elements from jumping to the right when you hide the vertical scrollbar.
padding is your answer, as Shikkediel said. Just change margin to that and it'll work.
The items move because you change the default margin body has, so the whole body moves to the left (in case we are modifying margin-right).
If you remove the scroll bar, the default margin will go right behind it, and then you need to "buffer" the rest, left of the margin, and that's what padding does.
I really enjoy working with the Inspecting tool Chrome supplies (Ctrl + Shift + I) and then in the Styles tab on the right scorll down until you see the measurements. It really helps understand the CSS box model.
Did you add 'px' here..
$('body').css('margin-right', scrollbarwidth+'px')??
Just nowI tried in w3schools. If you add 'px' to above syntax, it is working for me.
I'm looking to shrink a logo based on scroll
So far, I have something like this
logoSize = function(){
var headerOffset = $(window).height() - 650;
var maxScrollDistance = 1300;
$(window).scroll(function() {
var percentage = maxScrollDistance / $(document).scrollTop();
if (percentage <= headerOffset) {
$('.logo').css('width', percentage * 64);
}
console.log(percentage);
});
}
logoSize();
I'm close, but the image either starts too wide or it shrinks too quickly, I need it to happen for the first 650px of scroll as you can see - Any ideas? Perhaps a percentage width would be better?
I've re-written your code based on the assumption that you have a target size in mind , e.g. after scrolling 650px you want your image to be 250px wide.
It scrolls smoothly between the native size and the target size, and takes into account the fact that the window height could be less than your maximum scrolling distance:
logoSize = function () {
// Get the real width of the logo image
var theLogo = $("#thelogo");
var newImage = new Image();
newImage.src = theLogo.attr("src");
var imgWidth = newImage.width;
// distance over which zoom effect takes place
var maxScrollDistance = 650;
// set to window height if that is smaller
maxScrollDistance = Math.min(maxScrollDistance, $(window).height());
// width at maximum zoom out (i.e. when window has scrolled maxScrollDistance)
var widthAtMax = 500;
// calculate diff and how many pixels to zoom per pixel scrolled
var widthDiff = imgWidth - widthAtMax;
var pixelsPerScroll =(widthDiff / maxScrollDistance);
$(window).scroll(function () {
// the currently scrolled-to position - max-out at maxScrollDistance
var scrollTopPos = Math.min($(document).scrollTop(), maxScrollDistance);
// how many pixels to adjust by
var scrollChangePx = Math.floor(scrollTopPos * pixelsPerScroll);
// calculate the new width
var zoomedWidth = imgWidth - scrollChangePx;
// set the width
$('.logo').css('width', zoomedWidth);
});
}
logoSize();
See http://jsfiddle.net/raad/woun56vk/ for a working example.
Imagine I have the below element appended to the document :
<html>
<head>
<style>
#resizable {
position: absolute;
top: 30px;
left: 30px;
background: url(http://www.some243x350image.jpg) no-repeat;
height: 243px;
width: 350px;
background-size: contain;
}
</style>
</head>
<body>
<div id="resizable"></div>
</body>
</html>
I'd like to be able to resize the above div proportionally, without any max/min height/width limits.
Below is the code I've written (Working Example : http://jsfiddle.net/7wYAh/) but it has two main bugs :
1. The div's height and width do not change proportionally all the time (even though the image obviously does, given that I'm using background-size: contain;.
2. There are sudden increases/decreases in the height/width of the element the moment the element is "grabbed".
I'm not using an aspect ratio variable. What I'm doing is that I choose randomly whether to resize based on height or width every time. So if the height changes then I'll resize the width based on the height increase. And vice versa. Isn't that proportional as well? Meaning that if the height increases by 2px, I'll increase the width by 2px as well and vice versa.
Looking for an answer to my problem I found this post but I don't want to use width/height limits and I don't understand the use of the ratio.
So can you spot anything wrong with this code (assume that the elementCanBeResized is set to true whenever the mouse grabs the bottom right corner of the div) :
Working Example : http://jsfiddle.net/7wYAh/
var $element = $('#resizable');
var previousResizeX, previousResizeY, resizeDistanceX, resizeDistanceY;
$(window).mousemove(function (mouseCoordinates)
{
if (!elementCanBeResized)
{
return;
}
if (typeof previousResizeX === 'undefined')
{
previousResizeX = mouseCoordinates.pageX;
previousResizeX = mouseCoordinates.pageY;
}
else
{
var newResizeX = mouseCoordinates.pageX;
var newResizeY = mouseCoordinates.pageY;
// resizing proportionally based on width change
if (newResizeX !== previousResizeX)
{
resizeDistanceX = newResizeX - previousResizeX;
previousResizeX = newResizeX;
previousResizeY += resizeDistanceX;
newWidth = $element.width() + resizeDistanceX;
newHeight = $element.height() + resizeDistanceX;
}
// resizing proportionally based on height change
else if (newResizeY !== previousResizeY)
{
resizeDistanceY = newResizeY - previousResizeY;
previousResizeY = newResizeY;
previousResizeX += resizeDistanceY;
newHeight = $element.height() + resizeDistanceY;
newWidth = $element.width() + resizeDistanceY;
}
$element.css({
height: newHeight,
width: newWidth
});
}
});
I assume that you want to resize by clicking at some point and then 'dragging' de mouse. Okay.
To question 2: You are storing the point where you click in previousResizeX. But I don't see you cleaning its value after the release of the button. If you don't set previousResizeX to 'undefined' again, next time you click there will be a 'sudden change' of width/height because newResizeX will be the distance between the place where you pressed the mouse the first time and its current position.
To question 1: You are increasing the width/height the same number of pixels every time, that's why your div doesn't resize proportionally. I explain: if you start with a div that's 200 x 100, its width is the double of the height. When you duplicate its width, to be proportional you have to duplicate the height. But if you drag your mouse 100px, you'll end with a (200+100) x (100 + 100) div, which is 300 x 200. The image's width is no longer the double of its height. You need to calculate the ratio between width and height at the beginning:
var ratio = $element.height() / $element.width();
...
resizeDistanceX = newResizeX - previousResizeX;
resizeDistanceY = resizeDistanceX * ratio;
previousResizeX = newResizeX;
previousResizeY += resizeDistanceY;
newWidth = $element.width() + resizeDistanceX;
newHeight = $element.height() + resizeDistanceY;
...
//For Y
resizeDistanceY = newResizeY - previousResizeY;
resizeDistanceX = resizeDistanceY / ratio;
previousResizeY = newResizeY;
previousResizeX += resizeDistanceX;
newHeight = $element.height() + resizeDistanceY;
newWidth = $element.width() + resizeDistanceX;
And remember to set resizeDistanceX and resizeDistanceY once the mouse is released.
Hope this helps you.
I have a problem with a JavaScript I'm developing for my website. I have images which opens on hovering over them.
First my script calculates if the image should be displayed on the right or on the left of my window:
$("html,body").live("mousemove", function (e) {
//console.log("mousemove: "+e.pageX)
var width_window = $(window).width();
var center = width_window / 2;
if (e.pageX < center) {
side = 'left';
} else {
side = 'right';
}
});
Then, once we know on which side of the window the image will be displayed, I have another script to resize the image, depending of the height & width of my window, including the margins:
this.resizeImg = function (img, offset) {
var d = new Date();
//console.log(d, side);
var window_height = $(window).height();
var img_height = $(img).height();
var img_top = $(img).offset().top;
var window_width = $(window).width();
var img_width = $(img).width();
var img_left;
side == 'left' ? img_left = offset.left : img_left = window_width - offset.left;
console.log(window_width, img_left)
var image_resize_height = window_height - img_top - 20;
var image_resize_width = window_width - img_left - 20;
if (img_height + img_top > window_height && img_width + img_left > window_width) {
console.log("h w")
if (image_resize_width > image_resize_height) {
$(img).css('height', image_resize_height + 'px').css("width", "auto");
} else {
$(img).css('width', image_resize_width + 'px').css("height", "auto");
}
} else if (img_height + img_top > window_height) {
//console.log("h")
$(img).css('height', image_resize_height + 'px').css("width", "auto");
} else if (img_width + img_left > window_width) {
//console.log("w")
$(img).css('width', image_resize_width + 'px').css("height", "auto");
} else {
//console.log("non")
}
};
It almost works, but sometimes my images exceed the window width or height. I can't find the solution...
Here is my CSS:
.vignette {
max-height: 800px;
max-width : 800px;
z-index : 2;
top : 25px;
}
.info{
position : relative;
}
.info img {
position : absolute;
display : none;
cursor : pointer;
}
My full script in jsFiddle: http://jsfiddle.net/CrnNZ/
Here is the link to my website : http://olivierlellouche.com/
Thanks a lot for your help !
Are you taking care of the fact that you are moving the image down 25px in:
.vignette {
top : 25px;
}
The only height adjustment I see is 20px:
var image_resize_height = window_height - img_top - 20;
You may just need to subtract few more pixels to your calculations?
Or better yet:
var img_top = $(img).offset().top;
May be top of the offset area and not the raw top of the image. In which case, you still need to subtract 25px for that.
(From your website) The other thing that may be useful is to always enable, or always disable the vertical scroll-bar on the right. Or re-size the text area to be smaller than the available area when their isn't a scroll-bar. (Unfortunately, I could not get your jsfiddle to work at all and the only error from their I could view was vertical calculation errors. I could not see any horizontal errors.)
Does the problem continue if you subtract a few more pixels off the height?
I can't tell from your code but, does it place the image then re-size it? It may be better idea to calculate the size available before trying to place the image, that way it never changes sizes once it is placed.
EDIT:
After looking at your webpage with much smaller sized window I thought of something else. $(window).height() is not the same as $(document).height(). See: $(window).height() vs $(document).height You may need to calculate the remaining page differently if they are not the same.