Is it possible to put DIV's Vertical Scroll bar on left of the div with css? what about jscript?
I had a simple use case so opted for a simple css solution:
<div style="direction: rtl; height: 250px; overflow: scroll;">
<div style="direction: ltr; padding: 3px;">
Content goes here
</div>
</div>
You can add a pseudo-scrollbar anywhere you want with JQuery and this plug-in: JScrollPane
Okay, so, I wrote a jQuery plugin to give you a completely-native-looking left scroll bar.
Left Scrollbar Hack Demo
Here's how it works:
Inject an inner div inside the pane to allow calculation of the content width (content_width). Then, using this, the native scrollbar width can be calculated: scrollbar_width = parent_width - content_width - horizontal_padding .
Make two different divs inside the pane, both filled with the content.
One's purpose is being a "poser". It's used solely for the scrollbar. Using a negative left margin, the plugin pulls it left so that only the scrollbar is in view (the content of this div is clipped off at the edge).
The other div is used to actually house the visible scrolling content.
Now, it's time to bind the two together. Every 50ms (window.setInterval), the scrollTop offset from the "poser" div is applied to the visible, scrolling content div. So, when you scroll up or down with the scrollbar on the left, the scroll offset gets applied back on the div with the visible content.
This explanation probably sucks and there's actually a quite a bit more to it that I didn't describe, but, without further ado, here it is:
$.fn.leftScrollbar = function(){
var items = $(this);
$(function(){
items.each(function(){
var e = $(this);
var content = e.html();
var ie = !jQuery.support.boxModel;
var w = e[ie?'innerWidth':'width'](), h = e[ie?'innerHeight':'height']();
//calculate paddings
var pad = {};
$(['top', 'right', 'bottom', 'left']).each(function(i, side){
pad[side] = parseInt(e.css('padding-' + side).replace('px',''));
});
//detect scrollbar width
var xfill = $('<div>').css({margin:0, padding:0, height:'1px'});
e.append(xfill);
var contentWidth = xfill.width();
var scrollerWidth = e.innerWidth() - contentWidth - pad.left - pad.right;
e.html('').css({overflow:'hidden'});
e.css('padding', '0');
var poserHeight = h - pad.top - pad.bottom;
var poser = $('<div>')
.html('<div style="visibility:hidden">'+content+'</div>')
.css({
marginLeft: -w+scrollerWidth-(ie?0:pad.left*2),
overflow: 'auto'
})
.height(poserHeight+(ie?pad.top+pad.bottom:0))
.width(w);
var pane = $('<div>').html(content).css({
width: w-scrollerWidth-(ie?0:pad.right+pad.left),
height: h-(ie?0:pad.bottom+pad.top),
overflow: 'hidden',
marginTop: -poserHeight-pad.top*2,
marginLeft: scrollerWidth
});
$(['top', 'right', 'bottom', 'left']).each(function(i, side){
poser.css('padding-'+side, pad[side]);
pane.css('padding-'+side, pad[side]);
});
e.append(poser).append(pane);
var hRatio = (pane.innerHeight()+pad.bottom) / poser.innerHeight();
window.setInterval(function(){
pane.scrollTop(poser.scrollTop()*hRatio);
}, 50);
});
});
};
Once you've included jQuery and this plugin in the page, apply the left scroll bar:
$('#scrollme').leftScrollbar();
Replace #scrollme with the CSS selector to the element(s) you wish to apply left scrollbars to.
(and, obviously, this degrades nicely)
Related
I'm looking for a way in jQuery or pure JS to get the amount of pixels scrolled, not from the top of the page, but from the bottom of a div.
In other words I need to turn the amount scrolled beyond a div's height + its pixel distance from the top of the page into a variable.
I want to append this parallax code below so instead of calculating from the top of the page, calculates from a target div's distance from the top + its height.
/* Parallax Once Threshold is Reached */
var triggerOne = $('#trigger-01').offset().top;
$(window).scroll(function(e){
if ($(window).scrollTop() >= triggerOne) {
function parallaxTriggerOne(){
var scrolled = $(window).scrollTop();
$('#test').css('top',+(scrolled*0.2)+'px');
}
parallaxTriggerOne();
} else {
$('#test').css('top','initial');
}
});
I realize I didn't phrase this quite clear enough, I'm looking to only get the value of the amount of pixels scrolled since passing a div, so for example if I had a 200px tall div at the very top of the page and I scrolled 20 pixels beyond it, that variable I need would equal 20, not 220.
You can get a div's position by using div.offsetTop,
adding div.offsetHeight into div's distance from top of page will give you bottom of div, then you can subtract from window's scroll to get your desired value.
Feel free to ask if you have any doubts.
var div = document.getElementById('foo');
let div_bottom = div.offsetTop + div.offsetHeight;
var doc = document.documentElement;
var left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
var scroll_top, scroll_after_div;
setInterval(function(){
scroll_top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
scroll_after_div = scroll_top - div_bottom;
console.log(scroll_after_div);
}, 1000);
body { margin: 0; }
<div id="foo" style="position:relative; top: 100px; height: 30px; width: 100%; background-color: #000;"></div>
<div id="bar" style="position:relative; top: 700px; height: 30px; width: 100%; background-color: #000;"></div>
In this snippet setInterval method is printing the scroll value each second, you can scroll and see the change in value.
To work out the distance from the top of the page to the bottom of an element, you can add an elements outerHeight() with its offset().top.
Example: https://jsfiddle.net/dw2jwLpw/
console.log(
$('.target').outerHeight() + $('.target').offset().top
);
In pure JS you can get the bottom of the div directly with document.getElementById("my-element").getBoundingClientRect().bottom.
In jQuery you can use $('#my-element').offset().top + $('#my-element').height()
My situation is this:
I have a large container the size of the screen which is static and has overflow:hidden. Inside is a very large div that is jqueryui-draggable. Inside that are many many small divs.
The small divs are all hidden by default, I'd like them to appear when they move into the viewport(top parent container) and disappear when moved out. Keep in mind all the moving is done by dragging the very large middle div.
Most of the solutions I've found only work on page scroll. Is there some sort of event I could bind to the draggable?
Disclaimer
I haven't tested this, but hopefully it at least gives you a direction.
The biggest concept to grasp is to check each child to determine whether it is fully within the viewport every time the .drag() method is called on your draggable container. You can modify the logic to fade your elements in / out as needed or to allow the child to be considered visible even before it is fully within view.
CSS
.parent {
position: absolute;
overflow: hidden;
height: 5000px; /* example */
width: 5000px; /* example */
}
.child {
position: absolute;
height: 50px;
width: 50px;
}
HTML
<body>
<div class='parent'>
<div class='child'></div>
<div class='child'></div>
<div class='child'></div>
<!-- ... -->
</div>
</body>
JQUERY
$( ".parent" ).draggable({
drag: function( event, ui ) {
var parentTop = ui.position.top;
var parentLeft = ui.position.left;
var windowHeight = $(window).height();
var windowWidth = $(window).width();
$('.child').each(function(index) {
var childTop = $(this).position().top;
var childLeft = $(this).position().left;
var childWidth = $(this).width();
var childHeight = $(this).height();
// check whether the object is fully within the viewport
// if so - show, if not - hide (you can wire up fade)
((childLeft >= -(parentLeft) && childTop <= -(parentTop) &&
(childLeft + childWidth) <= (-(parentLeft) + windowWidth) &&
(childTop + childHeight) <= (-(parentTop) + windowHeight)))
? $(this).show()
: $(this).hide();
});
}
});
I have a scrollable div that I zoom/scale the content of using css3 transform. It works fine if I'm zooming in (scaling up the content) but I've noticed that when scaling down, below 100%, the amount that you can scroll vertically of the container div does not reduce.
I've made a jsfiddle to illustrate this
CSS:
.scrollable
{
height: 250px;
width: 250px;
overflow: auto;
background-color: green;
}
.content
{
height :500px;
width : 500px;
background: linear-gradient(red, blue);
...
}
JS/jquery:
function scaleContent(newScale){
var $content = $("#content");
var scaleString = "scale("+newScale+")";
//var height = (newScale<1)? $("#content").height()/scale*newScale : originalHeight;
$content.css({
'-webkit-transform' : scaleString,
'-webkit-transform-origin' : '0 0',
...
//'height' : height +'px'
});
scale=newScale;
}
The actual scaling and the amount that you can scroll horizontally works perfectly, but the amount you can scroll vertically doesn't change below 100%.
Note: the amount you can scroll vertically appears to change on the first scaledown/zoomout, but this is simply because the horizontal scrollbar is removed.
I tried to manually change the height of the content, but this just messed with the content dimensions (duh). That's the commented-out height code.
The ellipses are where I've repeated things for other browsers.
I've managed to come up with one solution, though it's probably not the best. I introduced another div around the content, which I call the view wrapper. I set its overflow to "hidden" and manually set its width and height to match what the scaled content should be.
CSS:
.viewwrapper{
height :500px;
width : 500px;
overflow: hidden
}
JS:
function scaleContent(newScale){
var $content = $("#content");
var scaleString = "scale("+newScale+")";
var $viewwrapper = $("#viewwrapper");
var height = $content.height()/newScale;
var width = $content.width()/newScale;
$viewwrapper.height(height);
$viewwrapper.width(width);
$content.css({
'-webkit-transform' : scaleString,
'-webkit-transform-origin' : '0 0',
...
});
}
JS Fiddle
Update:
This won't work if you're using jQuery 3.0 or 3.1. The read behaviour of the height and width functions has changed, so they return the scaled values. To fix the above code for those versions you can just say.
function scaleContent(newScale){
var $content = $("#content");
var scaleString = "scale("+newScale+")";
var $viewwrapper = $("#viewwrapper");
$viewwrapper.height($content.height());
$viewwrapper.width($content.width());
$content.css({
'-webkit-transform' : scaleString,
'-webkit-transform-origin' : '0 0',
...
});
}
JSFiddle using jQuery 3.0
However this probably won't make it into future versions of jQuery.
Update 2:
You might see unnecessary scrollbars in Chrome when you zoom out of the content. This is down to a Chrome bug.
you're applying transformations to your #content div, but the outside div, #scrollable has also a fixed height and is not reducing. You have to apply transformations to it too.
Because if you're zooming in, the outside div adapts to the inside content, whereas if you're reducing it does not.
The site in question is this one:
http://www.pickmixmagazine.com/wordpress/
When you click on one of the posts (any of the boxes) an iframe will slide down from the top with the content in it. Once the "Home" button in the top left hand corner of the iframe is clicked, the iframe slides back up. This works perfectly the first 2 times, on the 3rd click on of a post, the content will slide down, but when the home button is clicked, the content slides back up normally but once it has slid all the way up to the position it should be in, the iframe drops straight back down to where it was before the home button was clicked, I click it again and then it works.
Here is the code I've used for both sliding up and sliding down functions:
/* slide down function */
var $div = $('iframe.primary');
var height = $div.height();
var width = parseInt($div.width());
$div.css({ height : height });
$div.css('top', -($div.width()));
$('.post').click(function () {
$('iframe.primary').load(function(){
$div.animate({ top: 0 }, { duration: 1000 });
})
return false;
});
/* slide Up function */
var elm = parent.document.getElementsByTagName('iframe')[0];
var jelm = $(elm);//convert to jQuery Element
var htmlElm = jelm[0];//convert to HTML Element
$('.homebtn').click(function(){
$(elm).animate({ top: -height }, { duration: 1000 });
return false;
})
Have you considered using Ajax, like load(), ready() in jquery to control them better?
I am also not sure what you are trying to do with this.
var height = $div.height();
$div.css({ height : height });
may be you want to get the height of the current window? Where you can get it this way
var $dDiv = $('iframe.primary');
var innerH = window.innerHeight;
$dDiv.height(innerH);
Also try avoiding naming your custom var with default names like height, width, div, etc... You will confuse yourself and make debugging a pain.
I have something vaguely like the following:
<div id="body">
surrounding text
<div id="pane" style="overflow: auto; height: 500px; width: 500px;">
lots and lots of text here
<span id="some_bit">tooltip appears below-right of here</span>
</div>
more surrounding text (should be overlapped by tooltip)
</div>
and:
<div id="tooltip" style="width: 100px; height: 100px;">Whee</div>
What I want to do is insert the tooltip such that it is positioned above the pane it's in. If it's attached to an element that's next to the pane boundary (like above), then it should be visible above the pane, and above the text surrounding the pane.
It should NOT a) extend the pane, such that you have to scroll down to see the tooltip (like in http://saizai.com/css_overlap.png), or b) be cut off, so you can't see all of the tooltip.
I'm inserting this with JS, so I can add a wrapper position:relative div or the like if needed, calculate offsets and make it position:absolute, etc. I would prefer to not assume anything about the pane's position property - the tooltip should be insertable with minimal assumptions of possible page layout. (This is just one example case.)
It's for a prototype tooltip library I'm writing that will be open source.
ETA: http://jsfiddle.net/vCb2y/5/ behaves visually like I want (if you keep re-hovering the trigger text), but would require me to update the position of the tooltip on all DOM changes and scrolling behavior. I would rather the tooltip be positioned with pure CSS/HTML so that it has the same visual behavior (i.e. it overlaps all other elements) but stays in its position relative to the target under DOM changes, scrolling, etc.
ETA 2: http://tjkdesign.com/articles/z-index/teach_yourself_how_elements_stack.asp (keep defaults except set cyan div 'a' to position:relative; imagine 'A' is the pane and 'a' the tooltip) seems to more closely behave as I want, but I've not been able to get it to work elsewhere. Note that if you make 'A' overflow: auto, it breaks the overlapping behavior of 'a'.
I can't think of a pure HTML/CSS solution for this.
The overflow declaration is the issue here. If the tooltip is in #pane:
you establish a positioning context within #pane, then the tooltip shows next to #some_bit (regardless of scrolling, etc.) but it gets cut-off.
you do not establish a positioning context, then the tooltip is not clipped but it has no clue where #some_bit is on the page.
I'm afraid you'll need JS to monitor where #some_bit is on the page and position the tooltip accordingly. You'd also need to kill that tooltip as soon as #some_bit is outside of the viewing area (not an issue if the trigger is mouseover).
Actually, if the trigger is mouseover then you may want to use the cursor coordinates to position the tooltip (versus calculating the position of #some_bit).
I would just put the tooltip outside of the #pane div and position it absolutely using JavaScript since you're using JS anyway.
I don't use Prototype so I don't know how it's done in Prototype, but in jQuery, you'd use $(element).position() to get the element position. If you have to do it manually, it's a little more complicated.
And you'll probably want to add a little extra logic to prevent the tooltip from extending outside of the document.
Edit: CSS used
#tooltip {
z-index: 9999;
display: none;
position: absolute;
}
JS used
Note: in jQuery, but it should be easy to change it to Prototype syntax.
$('#some_bit').hover(function() {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
// hovered element
var offset = $(this).offset();
var top = offset.top + docViewTop;
var left = offset.left;
var width = $(this).width();
var height = $(this).height();
var right = left + width;
var bottom = top + height;
// pane
var poffset = $('#pane').offset();
var ptop = poffset.top + docViewTop;
var pleft = poffset.left;
var pwidth = $('#pane').width();
var pheight = $('#pane').height();
var pright = pleft + pwidth;
var pbottom = ptop + pheight;
// tooltip
var ttop = bottom;
var tleft = right;
var twidth = $('#tooltip').width();
var theight = $('#tooltip').height();
var tright = tleft + twidth;
var tbottom = ttop + theight;
if (tright > pright)
tleft = pright - twidth;
if (tbottom > pbottom)
ttop = pbottom - theight;
if (tbottom > docViewBottom)
ttop = docViewBottom - theight;
$('#tooltip').offset({top: ttop, left: tleft});
$('#tooltip').css('display', 'block');
}, function() {
$('#tooltip').hide();
});
Edit: See it here.