I'm not sure if "sticky" is the term for this, but is there a way to make the scrollbar from overflow:auto stay visible?
I have a rather large table that I want to be scrollable horizontally; however, the table is fairly tall as well, so when the page loads the horizontal scrollbar is not within the viewport of the browser, so it's rather hard to tell that the table is scrollable at all.
<div style = 'width:900px;overflow:auto'>
<table>
<!-- Very large table here -->
</table>
</div>
The scroll bar appears below the table, but unfortunately the table is so tall you can't see it unless you scroll down.
I'd like to have the horizontal scrollbar stay visible even if the table goes off the screen, maybe fixed to the bottom of the viewport. Ideally I'd like to do it using only CSS or a minimal amount of javascript.
Here is a script for that http://jsfiddle.net/TBnqw/2288/
$(function($){
var scrollbar = $('<div id="fixed-scrollbar"><div></div></div>').appendTo($(document.body));
scrollbar.hide().css({
overflowX:'auto',
position:'fixed',
width:'100%',
bottom:0
});
var fakecontent = scrollbar.find('div');
function top(e) {
return e.offset().top;
}
function bottom(e) {
return e.offset().top + e.height();
}
var active = $([]);
function find_active() {
scrollbar.show();
var active = $([]);
$('.fixed-scrollbar').each(function() {
if (top($(this)) < top(scrollbar) && bottom($(this)) > bottom(scrollbar)) {
fakecontent.width($(this).get(0).scrollWidth);
fakecontent.height(1);
active = $(this);
}
});
fit(active);
return active;
}
function fit(active) {
if (!active.length) return scrollbar.hide();
scrollbar.css({left: active.offset().left, width:active.width()});
fakecontent.width($(this).get(0).scrollWidth);
fakecontent.height(1);
delete lastScroll;
}
function onscroll(){
var oldactive = active;
active = find_active();
if (oldactive.not(active).length) {
oldactive.unbind('scroll', update);
}
if (active.not(oldactive).length) {
active.scroll(update);
}
update();
}
var lastScroll;
function scroll() {
if (!active.length) return;
if (scrollbar.scrollLeft() === lastScroll) return;
lastScroll = scrollbar.scrollLeft();
active.scrollLeft(lastScroll);
}
function update() {
if (!active.length) return;
if (active.scrollLeft() === lastScroll) return;
lastScroll = active.scrollLeft();
scrollbar.scrollLeft(lastScroll);
}
scrollbar.scroll(scroll);
onscroll();
$(window).scroll(onscroll);
$(window).resize(onscroll);
});
It is a quick test rather than a complete generic plugin, but is a good start, I think
Here's my take, #user2451227's is almost perfect, but didn't work with nested overflowed elements and had a number of performance issues, so I rewrote it:
$(function($){
var fixedBarTemplate = '<div class="fixed-scrollbar"><div></div></div>';
var fixedBarCSS = { display: 'none', overflowX: 'scroll', position: 'fixed', width: '100%', bottom: 0 };
$('.fixed-scrollbar-container').each(function() {
var $container = $(this);
var $bar = $(fixedBarTemplate).appendTo($container).css(fixedBarCSS);
$bar.scroll(function() {
$container.scrollLeft($bar.scrollLeft());
});
$bar.data("status", "off");
});
var fixSize = function() {
$('.fixed-scrollbar').each(function() {
var $bar = $(this);
var $container = $bar.parent();
$bar.children('div').height(1).width($container[0].scrollWidth);
$bar.width($container.width()).scrollLeft($container.scrollLeft());
});
$(window).trigger("scroll.fixedbar");
};
$(window).on("load.fixedbar resize.fixedbar", function() {
fixSize();
});
var scrollTimeout = null;
$(window).on("scroll.fixedbar", function() {
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(function() {
$('.fixed-scrollbar-container').each(function() {
var $container = $(this);
var $bar = $container.children('.fixed-scrollbar');
if($bar.length && ($container[0].scrollWidth > $container.width())) {
var containerOffset = {top: $container.offset().top, bottom: $container.offset().top + $container.height() };
var windowOffset = {top: $(window).scrollTop(), bottom: $(window).scrollTop() + $(window).height() };
if((containerOffset.top > windowOffset.bottom) || (windowOffset.bottom > containerOffset.bottom)) {
if($bar.data("status") == "on") {
$bar.hide().data("status", "off");
}
} else {
if($bar.data("status") == "off") {
$bar.show().data("status", "on");
$bar.scrollLeft($container.scrollLeft());
}
}
} else {
if($bar.data("status") == "on") {
$bar.hide().data("status", "off");
}
}
});
}, 50);
});
$(window).trigger("scroll.fixedbar");
});
Usage: Add the class fixed-scrollbar-container to your horizontally overflowed element, then include this code. If the container is updated or changes in size, run $(window).trigger("resize.fixedbar"); to update the bar.
Demo: http://jsfiddle.net/8zoks7wz/1/
#Mahn - I made a small update to the following function:
$('.fixed-scrollbar-container').each(function() {
var container = jQuery(this);
if (container[0].offsetWidth < container[0].scrollWidth) {
var bar = jQuery(fixedBarTemplate).appendTo(container).css(fixedBarCSS);
bar.scroll(function() {
container.scrollLeft(bar.scrollLeft());
});
bar.data("status", "off");
}
});
The if statement looks if the container offsetWidth is smaller than the scrollWidth. Else you will also get a fixed scrollbar if the content happens to be smaller than the container. I did not like having a disfunctional scrollbar, hence this edit.
How about restricting the height of the containing div so it stays within the body? You could then have the table scroll within that div.
Working jsfiddle here: http://jsfiddle.net/fybLK/
html, body {height: 100%; margin: 0; padding: 0;}
div {
width:500px;
max-height: 100%;
overflow:auto;
background: steelblue;}
table {
width: 1000px;
height: 1000px;
color: #fff;}
Here, I've set the html and body to 100% height so that the containing div can be sized.
Related
Using the canvas, the image changes when scrolling.
I wrote the code for animation.
If css gives you the same value as positio:absolute top:4000px,
Even if I scroll, the animation doesn't work.
It works if you lower the top value. I have to operate at the top 4000px position.
I'm curious about the solution
var canvas = document.getElementById('macbook');
var ctx = canvas.getContext('2d');
var scrollYPos = 1000;
var img = new Image();
img.src = "img/AirPods Max/large0.jpg";
window.addEventListener('scroll', function(e) {
scrollYPos = Math.round (window.scrollY/5);
console.log(scrollYPos);
if (scrollYPos> 52) {
scrollYPos = 52;
}
player(scrollYPos);
});
function player(num) {
img.src = `img/AirPods Max/large${num}.jpg`;
}
img.addEventListener('load', function(e) {
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
ctx.drawImage(img, 0,0);
})
canvas {
position: absolute;
top: 4000px;
}
<div id="img-sequence">
<canvas width="1004" height="1214" id="macbook"></canvas>
</div>
I want to ask if it is possible to make the embedded airnbnb listing responsive? I am using this code for the sharing of listing:
<div class="airbnb-embed-frame" data-id="133213" data-view="home" data-hide-price="true" style="max-width:450px;width:100%;min-height:300px;height:100%;margin:auto;"><span>View On Airbnb</span>1 BR APT + 1 LIVING RM # SKYWALK CONDO (24th)<script async="" src="https://www.airbnb.com/embeddable/airbnb_jssdk"></script></div>
The container was responsive but the content of iframe is not. It only shows horizontal and vertical scroll.
I've found a workaround, not sure how well it holds up though.
Here's a codepen.
Basically, what I've done is calculate the scale by doing client width - 10 (for some margin on the right site) divided by the embedded div's width, then used that to transform it to the fitting size and set the origin to left in order to center it.
CSS:
.room-container {
display: flex;
flex-flow: row wrap;
}
.room {
width: 450px;
height: 300px;
margin: auto;
}
#media all and (max-width: 500px) {
.room-container {
flex-direction: column;
}
.room {
transform-origin: left;
}
}
JS:
(function () {
const resize = () => {
let rooms = document.getElementsByClassName('room');
for (let room of rooms) {
let scale = (window.innerWidth - 15) / room.offsetWidth;
room.style.transform = 'scale(' + scale + ')';
}
}
window.onload = () => resize();
window.onresize = () => resize();
})();
Thanks #AesopChris. I had some problems with responsiveness on Andoid devices, so I made few changes and it worked perfectly in WordPress and Elementor Page builder.
JS in Footer:
<script>
(function () {
const resize = () => {
let rooms = document.getElementsByClassName('airbnb-embed-frame');
for (let room of rooms) {
if ( window.innerWidth < 500 ) {
let scale = (screen.width - 20) / room.offsetWidth;
room.style.transform = 'scale(' + scale + ')';
} else {
room.style.transform = 'scale(1)';
}
}
}
window.onload = () => resize();
window.onresize = () => resize();
})();
</script>
when it comes to wrap point how can we add animation?
maybe this can help:
we have a header and inside of that header we have container with flex attr and the direction is column when we resize our browser from bottom to top or when we changing height of browser those items suddenly reshape , I just want to add animation to this event.thx
<header>
<div class="container">
<div class="item1 item"></div>
<div class="item2 item"></div>
<div class="item3 item"></div></div></header>
header {
width: 200vw;
max-height: 100vh ;
}
.container{
display: flex;
max-height:100vh;
flex-direction: column;
flex-wrap: wrap;
align-content:flex-start;
}
.item1 {
background-color: red;
height: 200px;
flex: 1 0 150px;
}
.item2 {
background-color: blue;
height: 200px;
flex: 1 0 150px;
}
.item3 {
background-color: orange;
height: 200px;
flex: 1 0 150px;
}
I had a similar need and created a simple utility to achieve it.
- Demo at CodePen: https://codepen.io/hideya/pen/Jamabx
- GH gist: https://gist.github.com/hideya/16ed168a42f74eb5d2162b4e743940ff
The implementation is a bit wild and pretty much assumes no change in flex items except xy coords. You may need to adjust z-index, as it switches item's 'position' to 'absolute'.
Hope this helps.
window.addEventListener('load', function(event) {
var targetClassName = 'flex-wrap-anim';
var defaultDuration = '0.3s';
var dummyList = [];
function addDummy(item, duration) {
var top = item.offsetTop;
var left = item.offsetLeft;
setTimeout(function() {
item.style.position = 'absolute';
item.style.top = top + 'px';
item.style.left = left + 'px';
var dummyDiv = document.createElement('div');
dummyDiv.classList.add(targetClassName + '-dummy');
var rect = item.getBoundingClientRect();
dummyDiv.style.width = rect.width + 'px';
dummyDiv.style.height = rect.height + 'px';
dummyDiv.style.visibility = 'hidden';
dummyDiv['__' + targetClassName + '_pair'] = item;
dummyDiv['__' + targetClassName + '_duration'] = duration;
item.parentNode.appendChild(dummyDiv);
dummyList.push(dummyDiv);
}, 0);
}
var conts = document.getElementsByClassName(targetClassName);
for (var i = 0, max = conts.length; i < max; i++) {
var cont = conts[i];
cont.style.positoin = 'relative';
var duration = cont.getAttribute('data-duration')
|| defaultDuration;
var items = cont.getElementsByTagName('div');
for (var i = 0, max = items.length; i < max; i++) {
addDummy(items[i], duration);
}
}
window.addEventListener('resize', function(event) {
dummyList.forEach(function(dummyDiv) {
var item = dummyDiv['__' + targetClassName + '_pair'];
var duration = dummyDiv['__' + targetClassName + '_duration'];
if (item.offsetTop != dummyDiv.offsetTop) {
item.style.transition = 'all ' + duration;
item.style.top = dummyDiv.offsetTop + 'px';
item.style.left = dummyDiv.offsetLeft + 'px';
} else {
item.style.transition = '';
item.style.left = dummyDiv.offsetLeft + 'px';
}
});
});
});
While this cannot be done with CSS alone, you can accomplish this using JQuery. When looking at a flexbox using rows, the flexbox will change height if a new row is created or removed. Knowing this, we can add a .resize() function to the page to test if a window resize has altered the height of the flexbox. If it has, you can then execute an animation. I have created an example JFiddle here.
Here is the code that makes this work:
$(document).ready(function() {
var height = $('.container').css('height');
var id;
$(window).resize(function() {
clearTimeout(id);
id = setTimeout(doneResizing, 500);
});
function doneResizing() {
var newheight = $('.container').css('height');
if (newheight != height) {
$('.item').fadeOut();
$('.item').fadeIn();
height = newheight;
}
}
});
Now with a flexbox using columns, we need to detect when a change in width occurs. This is slightly more difficult as the flexbox width will take up the maximum allotted width as it is a block style element by default. So to accomplish this, you either need to set it as an inline flexbox using display: inline-flex, or set a maximum width for the flexbox equal to the width of its contents at its largest. Once you have set one of those, you can use the same code as above, except tweaking it to detect changes in width as opposed to height.
These changes applied an animation to all elements on resize. What if you want to only apply it to the element whose row/column changes? This would take more effort but is do-able. You would need to write many if-statements in your javascript/jquery code to catch which flex-item to apply the animation to based on width/height.
ext js 3.2: How can the css & js be coded so the tab panel scroller menu (currently it is the 2 down carets in top right) will display all the time on the LEFT side ?
See working example in jsfiddle:
http://jsfiddle.net/remy/hNhjR/3/
<style>
.x-tab-scroller-right-over {
background-position: -18px 0;
}
.x-tab-tabmenu-right {
background: transparent url(http://dev.sencha.com/deploy/ext-3.4.0/examples/tabs/tab-scroller-menu.gif) no-repeat 0 0;
border-bottom: 1px solid #8db2e3;
width:18px;
position:absolute;
right:0;
top:0;
z-index:10;
cursor:pointer;
}
.x-tab-tabmenu-over {
background-position: -18px 0;
}
.x-tab-tabmenu-disabled {
background-position: 0 0;
opacity:.5;
-moz-opacity:.5;
filter:alpha(opacity=50);
cursor:default;
}
</style>
Ext.ux.TabScrollerMenuPmve = Ext.extend(Object, {
pageSize: 10,
maxText: 15,
menuPrefixText: 'Items',
menuItemIds: 'None',
constructor: function (config) {
config = config || {};
Ext.apply(this, config);
},
init: function (tabPanel) {
Ext.apply(tabPanel, this.parentOverrides);
tabPanel.TabScrollerMenuPmve = this;
var thisRef = this;
tabPanel.on({
render: {
scope: tabPanel,
single: true,
fn: function () {
var newFn = tabPanel.createScrollers.createSequence(thisRef.createPanelsMenu, this);
tabPanel.createScrollers = newFn;
}
}
});
},
// private && sequeneced
createPanelsMenu: function () {
var h = this.stripWrap.dom.offsetHeight;
//move the right menu item to the left 18px
var rtScrBtn = this.header.dom.firstChild;
Ext.fly(rtScrBtn).applyStyles({
right: '18px'
});
var stripWrap = Ext.get(this.strip.dom.parentNode);
stripWrap.applyStyles({
'margin-right': '36px'
});
// Add the new righthand menu
var scrollMenu = this.header.insertFirst({
cls: 'x-tab-tabmenu-right'
});
scrollMenu.setHeight(h);
scrollMenu.addClassOnOver('x-tab-tabmenu-over');
scrollMenu.on('click', this.showTabsMenu, this);
this.scrollLeft.show = this.scrollLeft.show.createSequence(function () {
scrollMenu.show();
});
this.scrollLeft.hide = this.scrollLeft.hide.createSequence(function () {
scrollMenu.hide();
});
}
/**
* Returns the current menu prefix text String.;
* #return {String} this.menuPrefixText The current menu prefix text.
*/
getmenuItemIds: function () {
return this.menuItemIds;
},
/**
* Sets the menu item ids array.
* #param {String} t The menu item ids array text.
*/
setmenuItemIds: function (t) {
this.menuItemIds = t;
},
See working example in jsfiddle:
http://jsfiddle.net/remy/hNhjR/3/
Here what you have to change:
CSS:
.x-tab-scroller-right-over {
background-position: 0 0;
}
Javascript
var rtScrBtn = this.header.dom.firstChild;
Ext.fly(rtScrBtn).applyStyles({
right: 0 //'18px',
});
var stripWrap = Ext.get(this.strip.dom.parentNode);
stripWrap.applyStyles({
'margin-right': '18px',
'margin-left': '36px'
});
// Add the new righthand menu
var scrollMenu = this.header.insertFirst({
cls: 'x-tab-tabmenu-right'
});
scrollMenu.setHeight(h);
scrollMenu.addClassOnOver('x-tab-tabmenu-over');
scrollMenu.on('click', this.showTabsMenu, this);
this.scrollLeft.applyStyles({
'left': '18px'
});
and the updated jsfiddle.
Code below works good on local computer, but on remote server pop-up window doesn't consider scroll width and appears on the top of the page even when i scrolled the page up to the bottom. Problem appears only in IE and only on remote server. Files are the same. What should I check?
HTML
<div style="position:absolute;">
<div id="a_div">
123
</div>
</div>
CSS
#a_div {
display:none;
position:fixed;
width:850px;
top:35px;
border:1px solid #B1B8C7;
background:white;
z-index:3000;
}
JS
function showaDiv() {
var div = document.getElementById('a_div');
var width = document.body.clientWidth;
if (div) {
div.style.left = Math.round((width-850)/2)+'px';
div.style.display = 'block';
document.getElementById('a_bgdiv').style.display = 'block';
}
}
Try this fiddle if you want to center it vertically
function showaDiv() {
var div = document.getElementById('a_div');
var width = document.body.clientWidth;
var height = getDocHeight();
if (div) {
div.style.left = Math.round((width-850)/2)+'px';
div.style.display = 'block';
div.style.top = Math.round((height-div.clientHeight)/2)+'px';
//document.getElementById('a_bgdiv').style.display = 'block';
}
}
function getDocHeight() {
var D = document;
return Math.max(
Math.max(D.body.scrollHeight, D.documentElement.scrollHeight),
Math.max(D.body.offsetHeight, D.documentElement.offsetHeight),
Math.max(D.body.clientHeight, D.documentElement.clientHeight)
);
}
Just added the top.