Fixed row/column header with css and javascript - javascript

I need a layout with fixed column/row header. After some "trial and error" I came up with this solution (see jsfiddle). Only the lower right pane is scrollable, and the headers are moved using javascript.
Everything is fine in Chrome, but in IE/Edge the scrolling is laggy: the left and the right part are not scrolled on the same time but with a minimal delay (especially it the content is "big") which is annoying. Do you see any solution? I have to find another way to achieve the result (and in this case do you have any suggestion)?
$(function() {
init();
});
function init(){
var div1=$("#mainContainer");
var oldScrollTop = $(div1).scrollTop();
$(div1)
.scroll( function () {
if (oldScrollTop == $(div1).scrollTop()){
scrollRowTableHeader(); //horizontal scroll
}else {
oldScrollTop = $(div1).scrollTop();
scrollColumnTableHeader(); //vertical scroll
}
});
}
function scrollColumnTableHeader() {
var vScrollPanel = $("#mainContainer"),
headerPanelContent = $("#headerPanelContent"),
colHeaderPanelContent = $("#colHeaderPanelContent");
var colHeaderPanelContent2 = document.getElementById('headerContent');
colHeaderPanelContent2.style.top = (0 - vScrollPanel.scrollTop())+"px";
};
function scrollRowTableHeader() {
var vScrollPanel = $("#mainContainer"),
headerPanelContent = $("#headerPanelContent"),
colHeaderPanel = $("#colHeaderPanel");
var headerPanelContent2 = document.getElementById('headerPanelContent');
headerPanelContent2.style.left = (0 - vScrollPanel.scrollLeft())+"px";
};
#container {
/*background-color: green;*/
display: flex;
}
.item {
background-color: white;
border: 1px solid black;
flex-grow: 0;
}
.bigContent{
height: 1000px;
width: 1000px;
}
.scroll{
overflow: auto;
height: 300px;
width: 500px;
}
.colheader{
height: 300px;
width: 200px;
/*position: relative;*/
z-index: 1;
overflow:hidden;
display: inline;
border: solid 1px;
}
.headerContent{
background: lightgrey;
height: 1000px;
width: 200px;
position: relative;
border: solid 1px;
}
.rowHeaderContent{
background: whitesmoke;
height: 100px;
width: 200px;
position: relative;
}
.rowColHeaderContent{
background: lightyellow;
height: 100px;
width: 200px;
border: solid 1px;
}
.headerPanel{
overflow: hidden;
width: 500px;
border: solid 1px;
}
.tableProperties{
table-layout: fixed;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="container">
<div id="header" class="header">
<div class="rowColHeaderContent">
<table class="tableProperties">
<tr><td>Row/Col Header</td></tr>
</table>
</div>
</div>
<div id="headerPanel" class="headerPanel">
<div id="headerPanelContent" class="rowHeaderContent">
<table width="500px" class="tableProperties">
<colgroup><col width="50"><col width="40"><col width="40"><col width="40"><col width="45"><col width="40"></colgroup>
<tr><td>Some content (header)</td><td>Some content</td><td>Some content</td><td>Some content</td><td>Some content</td><td>Some content</td></tr>
</table>
</div>
</div>
</div>
<div id="container">
<div id="colheader" class="colheader">
<div id="headerContent" class="headerContent">
<table width="500px" class="tableProperties">
<tr><td>Column Header</td></tr>
<tr><td>Column Header</td></tr>
<tr><td>Column Header</td></tr>
<tr><td>Column Header</td></tr>
<tr><td>Column Header</td></tr>
<tr><td>Column Header</td></tr>
</table>
</div>
</div>
<div id="mainContainer" class="item scroll">
<div class="bigContent">
<table width="500px" class="tableProperties">
<colgroup><col width="50"><col width="40"><col width="40"><col width="40"><col width="45"><col width="40"></colgroup>
<tr><td>Some content</td><td>Some content</td><td>Some content</td><td>Some content</td><td>Some content</td><td>Some content</td></tr>
</table>
</div>
</div>
</div>

So, this is not a direct answer to your really complex issue, but here goes..
First of all looks like you are in the first steps of trying to create a fixed-column and fixed-row table. It might seem to be working at first, but, trust me, the way you are trying to achieve it is not going to work well and the reason is that since table-cell widths are set arbitrarily for each table, you won't be able to align the header table with the content table below it. So, you will either have to follow a different approach than the current way you are taking - tips imminent.
First things first, the problem with a lot of data in this kind of situation is more noticeable in IE11 - the lag is lighter in IE edge and there is no lag in other browsers. In your case you can use debouncing in order to reduce the js calls while scrolling.
setInterval(function(){
// Scroll stuff here
}, 2)
The interval doesn't have to be high, a light lag will be visible, but it will be a great improvement compared to how (I suppose) it currently works.
Also try using Javascript functions that work with minimum impact, eg use .attr instead of .style; also try using CSS3 transforms instead of normal transforms.
So concerning the different approach - you have to somehow the scrolling header and content be in the same table - ideally the fixed column as well. Here are some tips. It is necessary to remove word wrapping within the table cells by using white-space:nowrap for the following tips to work as intended. The concept might be difficult to grasp, but once you encounter each issue they will make sense.
First of all add some top padding to the table that will accommodate the header elements described next. Create both p and span elements inside the header cells and place the same header content in both of them. Absolutely position the span elements using CSS3 transforms towards the top.
The 'p' elements will remain static, but not visible - hide them using visibility, opacity and height:0. Paragraph elements will be used in case the th content exceeds the td content.
In order to scroll everything with decent performance you will HAVE to use CSS3 transforms to scroll the span elements (careful: the span elements!) after you cache them on page load.
Hope these tips help you out, for any questions feel free to ask - it will be difficult to digest at first but it will make sense.

If you want Only the lower right pane is scrollable?
I just used css like :-
.headerContent{
background: lightgrey;
height: 1000px;
width: 200px;
position: static;
border: solid 1px;
}
Changed position: relative into static...

Related

Scroll smoothly by 100px horizontally

Heyjo,
problem: I am looking for a javascript or jQuery code since a week to get an implemented scrollbutton on my website working. The moment I fail is when the button should work multiple times: his task is not so scroll to a dedicated element, it should scroll left by, for instance, 100px. Furthermore the scrolling is supposed to happen smoothly (in other words, animated) in a proper section.
what I tried: til now I tried to fulfill this task with $('#idofsection').animate({scrollLeft: 100}, 800) but obviously it didn't work. The Problem was, one couldn't use it multiple times, it just scrolled to a position in my section. Afterwards I used javascript's scrollBy(100, 0) or scrollLeft += 100px, but unfortunately didn't got it to scroll smoothly.
I hope someone can help me because I spent so much time on this issue without finding a solution. Thanks a lot, Sven
You can use scrollBy(100, 0) just like you tried and add this css property to the viewport where you want to scroll:
scroll-behavior: smooth;
.window{
width: 200px;
height: 100px;
border: 1px red solid;
overflow: hidden;
scroll-behavior: smooth;
}
.container{
width: 1000px;
height: 200px;
}
.buttons{
width: 200px;
display: flex;
flex-direction: row;
justify-content: space-between;
}
<div id="window" class="window">
<div class="container">
fjsdlf jslkd flsakj flksad jflkjsa dlfj slakd jflskad flksdaj lfk sadlkfj asldk fslkad fjlkasd flksa jdlf jsadlkfj slkda jflksadj flksa jdlkfj sadlk jflksadj flksjadflksadj flksdaj flksdaj flksdaflksjdflk sjdalkfj skdal fjlksadj flksa fklsjadfklj sadklfj salkdjf lksadj flksjad lfkj sadlkf jslakdjf lksdaj flkasj flkjsa dlfskal flsa jdas lkfjskad fj
</div>
</div>
<div class="buttons">
<button onclick="document.getElementById('window').scrollBy(-100,0)">
<-
</button>
<button onclick="document.getElementById('window').scrollBy(100,0)">
->
</button>
</div>
Solution also here: JSFiddle
So use the animation properties += to adjust it from current position.
$("#next").click(function(){
$('#foo').stop().animate({scrollLeft: "+=100"}, 800);
return false;
});
div {
width: 200px;
overflow: auto;
padding: 1em;
border: 1px solid black;
}
div p {
width: 1000px;
border: 2px dashed #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="foo">
<p>TEST</p>
</div>
<button id="next">Next</button>

Scroll a div when focused on an internal div

I need to make a scrollable div, scroll even if the mouse is upon the content (inside the scrollable div), and not just beside it (Where it is blank). This is what I have so far:
var main = document.getElementById('main-site');
var maxTop = main.parentNode.scrollHeight-main.offsetHeight;
main.parentNode.parentNode.onscroll = function() {
main.style.top = Math.min(this.scrollTop,maxTop) + "px";
}
In Chrome is ok
In IE8+ is ok (i know a hack)
In Safari the content shakes a lot when i scroll, can i fix that? (I want fix this)
Working fiddle -> https://jsfiddle.net/8oj0sge4/6/
var main = document.getElementById('main-site');
var maxTop = main.parentNode.scrollHeight - main.offsetHeight;
main.parentNode.parentNode.onscroll = function() {
main.style.top = Math.min(this.scrollTop, maxTop) + "px";
}
#wrapper {
width: 100%;
height: 1500px;
border: 1px solid red;
padding-top: 380px;
}
#wrapper .container {
border: 1px solid green;
width: 100%;
height: 500px;
overflow: scroll;
}
#wrapper .container-scroll {
height: 1500px;
width: 100%;
border: 1px solid yellow;
position: relative;
}
#wrapper .main {
width: 200px;
height: 500px;
background: black;
overflow: scroll;
position: absolute;
color: white;
left: 50%;
margin-left: -100px;
margin-top: 10px;
}
<div id="wrapper">
<div class="container">
<div class="container-scroll">
<div id="main-site" class="main">
My goals is to make the div container scroll also when the mouse is hover this div in safari, in Google and IE8 i already know how to make work, but safari is shaking a lot!
</div>
</div>
</div>
</div>
Thank you guys.
I hope this demo helps you out to make the div content scroll when mouse hover and when mouse out of the div.
<html>
</head>
<style>
.mydiv
{height: 50px;width: 100px; overflow-y: scroll; }
</style>
<script>
function loadpage()
{ document.getElementById('marquee1').stop(); }
function marqueenow()
{ document.getElementById('marquee1').start(); }
</script>
</head>
<body onload="loadpage()">
<marquee id="marquee1" class="mydiv" onmouseover="marqueenow()" onmouseout="loadpage()" behavior="scroll" direction="up" scrollamount="10">
This is my test content This is my test content This is my test content This is my test content This is my test content This is my test content This is my test
content This is my test content This is my test content This is my test content This is my test content This is my test content This is my test content This is my test content This is my test content This is my test content
</marquee>
</body>
</html>
you just add this js file to get a smooth scrolling effect.
https://github.com/nathco/jQuery.scrollSpeed
live deomo
http://code.nath.co/scrollSpeed
Not 100% sure what you are up to but you can get the fixed position with css "fixed". It will stay where you put it. The following css fixes to the bottom of the page.
.fixed {
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: auto;
}
There is already an answer on scroll position:
How to get scrollbar position with Javascript?
I don't know important is that content, and by this I mean if it needs to stay selectable.
If not a pretty good solution would be to use #wrapper .main{ pointer-events: none; }, meaning that the content will not get any events from mouse and it would go through it to the next element behind it - in your case the scroll would go dirrectly to #wrapper.
Safari does this because every browser has its own scrolling. If you have a fixed header on a phone it acts bouncy and if you do this on a PC it acts normal. Explorer scrolls smooth and Chrome scrolls right to the place without a smooth transition.
The reason why your #main-site is "jiggling" is because the browser keep "repaint" the position of this element.
One Trick to solve this is called Debounce Function, (you may also google it to see other variations.) The basic idea is to delay the scroll event handler to clear out those untriggered callbacks.
In your case, you may do something like this:
main.parentNode.parentNode.onscroll = function(event) {
debounce(offsetting, 10);
}
function offsetting() {
main.style.top = Math.min(main.parentNode.parentNode.scrollTop,maxTop) + "px";
}
function debounce(method, delay) {
clearTimeout(method._tId);
method._tId= setTimeout(function(){
method();
}, delay);
}
If you keep seeing the jiggling issue, you can simply edit the delay parameter (i.e, change 10 to 50). The downside for that is your #main-site element will be 'cut off the top` for a while, depending on your delay settings.
Since your code works perfectly on Chrome and IE, there might be a bug on scrollHeight or offsetHeight attribute on Safari. I recommend you to use getBoundingClientRect for calculating element position since this method is more reliable and accurate.
var maxTop = main.parentNode.getBoundingClientRect().height - main.getBoundingCLientRect().height;

Make Div fixed bottom & scrollable

I want to have a long page, with a fixed top 100px div, and a fixed 50px bottom div. However, I want the bottom div to scroll as you scroll down the page.
Its hard to explain, but the best example of this is on the front page of PayPal.com
On the first page load, the bottom div looks like it is fixed, and as you adjust the height of the browser window, that div stays at the bottom. Yet as you scroll down the page it is not fixed.
Can anyone explain how they have done this? I am trying to re-create something similar, but cant see how they have managed it.
As far as I can see they have this html...
<div id="fixed-top">
<header class="table-row">
// header content
</header>
<div class="table-row table-row-two">
// Video content
</div>
<div class="table-row">
//bottom content
</div>
</div>
And this CSS...
#fixed-top {
height: 100%;
width: 100%;
display: table;
position: relative;
top: 0;
left: 0;
z-index: 1;
}
.table-row {
display: table-row;
}
But that alone doesn't do it. I also can't see any js thats getting window height and applying it to the main fixed div.
Help! :)
EDIT:
Have just found a way to do it with javascript, controlling the height of the middle row using the window height, minus the 150px for the header and third row.
jQuery(document).ready(function(){
$('div.table-row-two').css({'height':(($(window).height())-150)+'px'});
$(window).resize(function(){
$('div.table-row-two').css({'height':(($(window).height())-150)+'px'});
});
});
But saying that, Zwords CSS only method seems like a winner.
From what I understand, you are looking for something like a sticky footer. So basically if the content is not enough, the footer should go sit at the bottom like its fixed, but if content comes in, it should scroll down like other content.
Try this - http://css-tricks.com/snippets/css/sticky-footer/
First off, you'll need to set the height of the body and html tag, otherwise the table won't take the full screen. Then I altered your code, made it a bit easier.
HTML:
<div id="fixed-top">
<header>
// header content
</header>
<div>
// Video content
</div>
<div>
//bottom content
</div>
</div>
CSS:
html, body {
margin: 0;
padding: 0;
height: 100%;
min-height: 100%;
}
#fixed-top {
display: table;
width: 100%;
height: 100%;
}
#fixed-top > * { /* makes all the direct children of #fixed-top a table row*/
display: table-row;
background: lightblue;
}
#fixed-top > *:nth-child(1) {
background: lightgreen;
height: 40px;
}
#fixed-top > *:nth-child(3) {
background: lightgreen;
height: 25%;
}
You can either set the height to a fix height (in px) or percentages. If you only give two of the three rows a height, the third one will automaticly fill up the rest space.
Also, check this demo.
Check this fiddle / Fullscreen
Using display:table;,display:table-row;,min-height to adjust to screen
HTML
<div class="wrapper">
<div class="row">menu</div>
<div class="row">content</div>
<div class="row">footer</div>
</div>
<div class="wrapper">
<div class="row">content1</div>
<div class="row">content2</div>
<div class="row">content3</div>
</div>
CSS
html,body,.wrapper{
width:100%;
height:100%;
margin:0px auto;
padding:0px;
}
.wrapper{
display:table;
border:1px solid black;
}
.wrapper .row{
display:table-row;
background-color:rgb(220,220,220);
}
.wrapper .row:nth-of-type(1){
min-height:15px;
}
.wrapper .row:nth-of-type(2){
height:100%;
background-color:white;
}
.wrapper .row:nth-of-type(3){
min-height:15px
}
You can do this easily with jQuery using $(window).height() and subtracting your footer/header's heights. See Fiddle for an example.

Scrollbar on top of DIV and nowrap container

I'm familiar with this StackOverflow question & confirmed answer.
However, checking their fiddle here, I've noticed one thing I really really need. The container (aka div2 class element) doesn't have no-wrap property which I would really really need for my tables inside #container (nowrap for having tables in one row)
My code:
CSS:
.subnetTable {
width: 150px;
display: inline-table;
border:1px solid #E8E8E9;
margin: 2px;
padding: 2px;
white-space: normal;
}
#scroller_wrapper, #container_wrapper{
width: 98%; border: none 0px RED;
overflow-x: scroll; overflow-y:hidden;
}
#scroller_wrapper{height: 16px; }
#scroller { width: 500px; height: 16px; }
#container { width: 500px; overflow: auto;}
HTML:
<div id="scroller_wrapper">
<div id="scroller">
</div>
</div>
<div id="container_wrapper">
<div id="container">
<table class="subnetTable"><tr><td>12341234</td></tr></table>
<table class="subnetTable"><tr><td>12341234 123412341234 1234123412 34123412341 2341234123412 341234123 412341234</td></tr></table>
<table class="subnetTable"><tr><td>12341234</td></tr></table>
<table class="subnetTable"><tr><td>12341234 123412341 2341234123412 34123412341234 123412341 23412341234</td></tr></table>
<table class="subnetTable"><tr><td>12341234 1234123412 341234123412 34123412341234 123412341 23412341234</td></tr></table>
<table class="subnetTable"><tr><td>12341234 123412341 2341234123412 34123412341234 123412341 23412341234</td></tr></table>
</div>
</div>
JAVASCRIPT (jQuery):
// SCROLLBARS
$(function(){
$("#scroller_wrapper").scroll(function(){
$("#container_wrapper").scrollLeft($("#scroller_wrapper").scrollLeft());
});
$("#container_wrapper").scroll(function(){
$("#scroller_wrapper").scrollLeft($("#container_wrapper").scrollLeft());
});
});
// CONTAINER RESIZE
$(window).load(function () {
$('#scroller').css('width', ($(window).width() - 10) );
$('#container').css('width', ($(window).width() - 10) );
});
MY JsFiddle Code & the Problem:
click here.
The problem appears, when you add white-space: nowrap; to #container class. Instead of correct result, it creates another scrollbar at bottom which I wouldn't like. IT does move tables to one row but it doesn't create correct scrollbar at bottom or top anymore (replacing tables with only text doesn't work either).
Please help me out!
With you code as-is the solution is to put a <br> just before the fourth table or wrapping the first three and second three tables in a block level element such as a div.
Why?
Each table is inline - so setting #container to not wrap will make all the inline tables extend out to the right. Adding a break will force it to break as expected.
Note
Please consider using DIVs or some other semantic element rather than tables - your code does not appear to be tabular data.

How to stack divs beside each other to create a carousel

I am trying to create a carousel, where clicking on any element will slide it leftwards, simultaneously sliding the right element into viewport. For that, I need to have the divs stacked side by side. I am trying it out as a float based layout (see Fiddle ).
Problem is that here clicking the red colored div slides it leftward alright, but not the green element leftwards. This is probably due to the fact that they are actually lying below another, as visible when the overflow: hidden is removed from #cont's style. How elese to stack them side by side so that sliding one leftward automatically slides the next one leftwards as well? (Creating the to-be-next element on the fly while clicking and animating it into viewport is a no-no, the element should be present in the DOM!)
I'd suggest you use a plugin, as there is more to this than you may realize. There are many plugins out there for this, here's a list to get you started: http://www.tripwiremagazine.com/2012/12/jquery-carousel.html
I modified your Javascript, HTML, and CSS to get you pointed in the right direction:
http://jsfiddle.net/nf5Dh/2/
You need a container contContent, positioned absolutely, and that container gets moved within the container div. You just float the elements in contContent to get them next to each other.
HTML:
<div id='cont'>
<div id="contContent">
<div id='i1'></div>
<div id='i2'></div>
<div id='i3'></div>
</div>
</div>
CSS:
#cont {
width: 50px;
padding-top: 10px;
background: blue;
height: 50px;
overflow: hidden;
position: relative;
}
#contContent {
height: 50px;
width: 150px;
position: absolute;
top: 0;
left: 0;
}
#contContent > div {
float: left;
display: inline-block;
height: 50px;
width: 50px;
}
#i1 { background: red; }
#i2 { background: green; }
#i3 { background: yellow; }
And the JS:
$("#contContent > div").click(function(){
$("#contContent").animate({left: "-=50px"},1000);
});
You'd probably be better off using an ul instead of all divs, this is at least more semantically correct, though not technically necessary.
<div id="carousel">
<ul id="carouselContent">
<li id="slide1"></li>
<li id="slide2"></li>
<li id="slide3"></li>
</ul>
</div>
This:
#cont {
white-space:nowrap;
overflow: hidden;
}
.pane { // or whatever the slide divs are called. get rid of the float.
float: none;
display: inline-block;
*zoom:1;
*display:inline;
}
You can use that carousel where you can generate javascript for the carousel http://caroufredsel.dev7studios.com/configuration-robot.php
I've used http://sorgalla.com/jcarousel/ for things like this in the past, that's based on postion: relative and left/right offsets. Probably easier than messing with floats.
You can try using a list item instead, and display them inline.

Categories