jQuery issue: body overflow vs body margin - javascript

Good day everyone!
When I click on a div I want overflow of body to become hidden and add a right margin to body of the scrollbar width. Here is my jQuery:
var getScrollbarWidth = function () {
var scrollElement = document.createElement("div"); // Create element
scrollElement.addClass("scrollbar-element"); // Apply predefined style
document.body.appendChild(scrollElement); // Add element to page
var scrollbarWidth = scrollElement.offsetWidth - scrollElement.clientWidth; // Subtract width without scrollbar from width with scrollbar
document.body.removeChild(scrollElement); // Remove element from page
return scrollbarWidth;
};
$(".thumbnail").on("click", function () {
$(".project-wrap").addClass("project-open");
$("body").attr("margin-right", getScrollbarWidth() + "px");
$(".project-button").attr("margin-right", getScrollbarWidth() + "px");
$("body").addClass("body-overflow");
}
And css:
.body-overflow
overflow: hidden !important
.project-open
display: block !important
The issue is that if "$("body").addClass("body-overflow");" is in the end, it doesn't work, but if it is on the first line of thimbnail click function, then body margin is not applied.

Try to store your scrollbar width in a variable before you add the body-overflow class.
Like:
$(".thumbnail").on("click", function () {
var scrollbarWidth = getScrollbarWidth();
$("body").addClass("body-overflow");
$("body").attr("margin-right", scrollbarWidth + "px");
$(".project-wrap").addClass("project-open");
$(".project-button").attr("margin-right", scrollbarWidth + "px");
});

Related

Calculating width of scrollbar and using result in calc() css

I want to calculate the width of the scrollbar so that I use the result in a CSS calc() declaration.
At the moment, I assume that the width of the scrollbar is always 17px, like this:
body {
width:calc(100vw - 17px);
}
.container {
max-width:calc(100vw - 17px);
}
The problem with this is when you choose a different browser zoom %, the width of the scrollbar changes. So I want to use the result of the calculation to do something along these lines:
body {
width:calc(100vw - CALCULATED SCROLL-BAR WIDTH);
}
.container {
max-width:calc(100vw - CALCULATED SCROLL-BAR WIDTH);
}
EDIT: I've now solved the problem with the help of this question
The JavaScript used to calculate the scrollbar width (though, I have found you require an interval to get it to autoupdate):
function getScrollbarWidth() {
var outer = document.createElement("div");
outer.style.visibility = "hidden";
outer.style.width = "100px";
outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
document.body.appendChild(outer);
var widthNoScroll = outer.offsetWidth;
// force scrollbars
outer.style.overflow = "scroll";
// add innerdiv
var inner = document.createElement("div");
inner.style.width = "100%";
outer.appendChild(inner);
var widthWithScroll = inner.offsetWidth;
// remove divs
outer.parentNode.removeChild(outer);
return widthNoScroll - widthWithScroll;
}
My code (which is used to embed the result of the function into a CSS calc() declaration).
$('body').css({
'width':'calc(100vw - ' + getScrollbarWidth() + 'px)'
});
$('.container').css({
'max-width':'calc(100vw - ' + getScrollbarWidth() + 'px)'
});
Actually, you can get the scrollbar width just with css and custom properties (and completely without javascript):
body {
--scrollbar-width: calc(100vw - 100%);
}
Then you can use this variable in a child element like this:
.container {
max-width: calc(100vw - var(--scrollbar-width));
}
This is because 100vw is always the inner width of the view, but the 100% of the body does not include the scrollbar.
Expanding jonas_jonas's answer, it can work but if .container must have the same width as the body.
If that's not the case, even so you can make it work with vanilla JS, defining a CSS property like this
document.body.style.setProperty(
"--scrollbar-width",
`${window.innerWidth - document.body.clientWidth}px`
);
And then you can use it in CSS
.container {
max-width: calc(100vw - var(--scrollbar-width));
}
Why you need so much code to do that?
The easy way with plain javascript it's:
$('body').css({
'width':'calc(100vw - ' + (window.innerWidth - document.body.clientWidth) + 'px)'
});

dynamic width of textarea with no-wrap

How can I make a textarea which does not force line wrapping and extends its size to match the contents instead of showing a scroll-bar?
I need a textarea with dynamic width. The width should be the widest line of the textarea. I mean there should be no wrapping and the width should be changed the long a line gets.
Assign an input listener function which compares the scroll width and height against the outer width and height of the element. If they are different then set them as necessary.
For CSS you need white-space:nowrap to stop the lines from wrapping and overflow:hidden to get rid of the scroll bars.
$('.demo').on('input', function(e){
this.style.width = '';
this.style.height = '';
if(this.scrollWidth > this.clientWidth) this.style.width = this.scrollWidth + 'px';
if(this.scrollHeight > this.clientHeight) this.style.height = this.scrollHeight + 'px';
})
.demo {
white-space: nowrap;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea class="demo"></textarea>

Keep a div visible when content would push it down

I want to have a div positioned in the bottom of another div. This i can solve with just
bottom: 0px;
postion: fixed;
But, if the containing div is larger than the window, i want to freeze the inner div to the bottom of the window.
If it's easier the first condition can be scrapped and the inner div can just be positioned under the content, the important part is that the content must always be visible.
The best solution would be to detect with JavaScript if the footer is visible inside the viewport. If not, you should change it's styles to stick to the bottom of the window instead of that of the containing div.
You could use this function to see if it's in the viewport:
function elementInViewport(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top >= window.pageYOffset &&
left >= window.pageXOffset &&
(top + height) <= (window.pageYOffset + window.innerHeight) &&
(left + width) <= (window.pageXOffset + window.innerWidth)
);
}
(taken from How to tell if a DOM element is visible in the current viewport?)
Now, every time you scroll or resize the page you can do a check that runs that function. Based on that, you can decide to set a class or change a CSS property that will do what you're looking for.
Since you didn't include any code (in the future, please do) I'm going to assume your code looks something like this:
<div class="wrapper">
(contents)
<div class="footer">footer</div>
</div>
To stick the .footer to the bottom of .wrapper, it has to have a 'positon: absolute' and the wrapper will need a position: relative. However, if you change it's position property to fixed and the wrapper to static (the default for all elements), the footer is going to stick to the bottom of the window instead.
View this example http://jsfiddle.net/GMYEh/
Now, using the script above you can tell which of the two it should be. You have to use a fake element at the same position of the footer, instead of the footer itself. That way, if you move the footer to the bottom of the window, you can still measure whether or not the bottom of the wrapper is in the viewport. (If you measure the footer itself and move it you'll get stuck).
The script that does this (in jQuery):
// add a fake footer after the wrapper
$('.wrapper').after($('<div class="fakefooter" />'));
$(document).on('resize scroll', function(e){
//measure if the fake footer is in viewport
if(elementInViewport($('.fakefooter')[0])) {
// If so, it should be in the bottom of the wrapper.
$('.wrapper').css('position', 'relative');
$('.footer').css('position', 'absolute');
} else {
// else it should be in the bottom of the window
$('.wrapper').css('position', 'static');
$('.footer').css('position', 'fixed');
}
});
Working example:
http://jsfiddle.net/GMYEh/4/
Try this:
HTML:
<div id="wrapper">
<div id="innerContent"></div>
</div>
CSS:
.fixedContent {
position: fixed;
bottom: 0;
}
and the javascript:
var wrapper = document.getElementById('wrapper');
var content = document.getElementById('innerContent');
function position() {
if (wrapper.offsetHeight + wrapper.offsetTop - content.offsetHeight - window.scrollY > window.innerHeight) {
content.className += ' fixedContent';
} else {
content.className = content.className.replace('fixedContent', '');
}
}
window.onload = position;
window.onresize = position;
If you're open to jQuery you can make the javascript more simple and compatible
var $wrapper = $('#wrapper');
var $content = $('#innerContent');
$(window).on('load resize', function() {
$content.toggleClass('fixedContent', $wrapper.outerHeight(true) $content.offset().top - $content.outerHeight(true) - $(document).scrollTop() > $(window).height());
});
EDIT:
I modified the conditions a bit adding the vertical scroll value and top offset.

set the width dynamically of element which create dynamically

I create one div#sresult_container dynamically and append no of div to that div. and all appended div have different text. so i can retrieve the width of div#sresult_container but i try to that increase the width of div#sresult_container 10px before it display on the view port. how can i do this plese help me?
my code is below:
var $sresult_container = $('<div id="sresult_container"></div>');
AND after that i append the some divs as children of div#sresult_container.
and append to body.
$('body').append($sresult_container);
var Setwidth = $('#sresult_container').outerWidth() + 10;
$('#sresult_container').css('width',Setwidth + 'px');
so here first load original width after that load the modified width. so how can do directly load the modified width.
First of all #sresult_container must have a pre-defined width.
#sresult_container {
width: 100px;
}
$('<div id="sresult_container">text</div>').appendTo('body');
$('#sresult_container').css('width', function () {
return ($(this).outerWidth(true) + 10) + 'px';
});​
http://jsfiddle.net/xBZT7/14/
http://jsfiddle.net/xBZT7/15/

how to re-calculate variables in javascript

function scrollContent(){
var div = $('#scrolling-content'),
ul = $('ul.image'),
// unordered list's left margin
ulPadding = 0;
//Get menu width
var divWidth = div.width();
//Remove scrollbars
div.css({overflow: 'hidden'});
//Find last image container
var lastLi = ul.find('li:last-child');
//When user move mouse over menu
div.mousemove(function(e){
//As images are loaded ul width increases,
//so we recalculate it each time
var ulWidth = lastLi[0].offsetLeft + lastLi.outerWidth() + ulPadding;
var left = (e.pageX - div.offset().left) * (ulWidth-divWidth) / divWidth;
div.scrollLeft(left);
});
}
This is how I scroll my image list. The problem is that #scrolling-content element's size is dynamic. It changes on window resize. Here;
$(window).resize(function() {
$("#scrolling-content").css("width",$(window).width() + "px");
$("#scrolling-content").css("height",($(window).height()-400) + "px");
});
So it has to recalculate the left value when user changes windows size. How sould I change script to do that? Recalling scrollContent() function with window.resize function is a noob solution I guess. And it creates conflict for IE.
You could set the width on resize and make your function call the variable like so. This method turns your function into a js object and the window update resets the width var inside that object. Course now you call the function like this: scrollContent.scroll();
var scrollContent = {
width: 0,
scroll:function(){
var div = $('#scrolling-content'),
ul = $('ul.image'),
// unordered list's left margin
ulPadding = 0;
//Get menu width
scrollContent.width = div.width();
//Remove scrollbars
div.css({overflow: 'hidden'});
//Find last image container
var lastLi = ul.find('li:last-child');
//When user move mouse over menu
div.mousemove(function(e){
//As images are loaded ul width increases,
//so we recalculate it each time
var left = (e.pageX - div.offset().left) * (ulWidth-scrollContent.width) / scrollContent.width;
div.scrollLeft(left);
});
}
};
$(window).resize(function() {
$("#scrolling-content").css("width",$(window).width() + "px");
$("#scrolling-content").css("height",($(window).height()-400) + "px");
scrollContent.width = $(window).width();
});
You can also just declare a standard js var and use that to keep things simple. I just prefer working with js objects to eliminate possible var interference.

Categories

Resources