Creating HTML table with sticky headers and columns using only CSS - css

I have a table in which I'm trying to make the header, and an arbitrary number of columns on its left "sticky". Sticky as in, as the table data is vertically scrolled, the headers stay stuck to the top. And if there's enough columns to scroll vertically, the data and headers are vertically scrollable, but some columns stick.
Here's a table that's vertically and horizontally scrollable with sticky headers.
http://jsfiddle.net/7b29Lkwy/5/
The important parts being
.sticky-table {
width: 100%;
height: 100%;
overflow-x: scroll;
}
.scroll {
float: left; /* Makes with total content width */
min-width: 100%; /* In case there isn't enough columns */
height: calc(100% - 35px); /* Assuming we know head height */
overflow: scroll;
}
But I'm not sure how I can do this while including a sticky column.

You need some js to make it work.
The scrollbars:
<button title="Up" onmousedown="upp();" onmouseup="upp(1);">Up</button>
<button title="Left" onmousedown="left();"
onmouseup="left(1);"><<</button>
<button title="Right" onmousedown="right();"
onmouseup="right(1);">>></button>
<button title="Down" onmousedown="down();" onmouseup="down(1);">Dn</button>
Replace t1 with your table ID
if(!myTable){myTable=document.getElementById("t1");
And of course the working js
var myRow=1;
var myCol=1;
var myTable;
var noRows;
var myCells,ID;
function setUp(){
if(!myTable){myTable=document.getElementById("t1");}
myCells = myTable.rows[0].cells.length;
noRows=myTable.rows.length;
for( var x = 0; x < myTable.rows[0].cells.length; x++ ) {
colWdth=myTable.rows[0].cells[x].offsetWidth;
myTable.rows[0].cells[x].setAttribute("width",colWdth-4);
}
}
function right(up){
if(up){window.clearTimeout(ID);return;}
if(!myTable){setUp();}
if(myCol<(myCells)){
for( var x = 0; x < noRows; x++ ) {
myTable.rows[x].cells[myCol].style.display="";
}
if(myCol >1){myCol--;}
ID = window.setTimeout('right()',100);
}
}
function left(up){
if(up){window.clearTimeout(ID);return;}
if(!myTable){setUp();}
if(myCol<(myCells-1)){
for( var x = 0; x < noRows; x++ ) {
myTable.rows[x].cells[myCol].style.display="none";
}
myCol++
ID = window.setTimeout('left()',100);
}
}
function down(up){
if(up){window.clearTimeout(ID);return;}
if(!myTable){setUp();}
if(myRow<(noRows-1)){
myTable.rows[myRow].style.display="none";
myRow++ ;
ID = window.setTimeout('down()',100);
}
}
function upp(up){
if(up){window.clearTimeout(ID);return;}
if(!myTable){setUp();}
if(myRow<=noRows){
myTable.rows[myRow].style.display="";
if(myRow >1){myRow--;}
ID = window.setTimeout('upp()',100);
}
}
Refer here for the detailed explanation
http://www.codeproject.com/Articles/20017/Freeze-Panes-like-Excel
Update:
Solution to problem is to use this jquery table plugin ->
jtable

Related

How to show the width of an element in the content of an ':after' pseudo-element?

I'm looking to show the width of an element within a pseudo element.
so my CSS would look like
:after {
content: "{width goes here}";
display:block;
}
but I have no idea if its even possible with just CSS.
If not, how would I do it with jQuery?
It's currently not possible to do this with CSS alone.
You could use JavaScript to iterate over the elements and set a custom data-width attribute based on the computed width of the element. In doing so, you can use the content value of attr(data-width) in order to display this attribute value as the pseudo element's content. The CSS attr() function allows you to retrieve the element's attribute and display the value.
For instance:
var elements = document.querySelectorAll('[data-width]');
for (var i = 0; i < elements.length; i++) {
elements[i].dataset.width = elements[i].offsetWidth;
}
[data-width]:after {
content: ' ' attr(data-width) 'px';
}
[data-width] {
border: 1px solid;
}
div {
width: 300px;
height: 30px;
}
<div data-width></div>
<p data-width>Paragraph element</p>
<span data-width>Span</span>
Since the data-width attribute is only set once, you would need to add a resize event listener in order to set the corresponding width values when they change.
For instance:
window.addEventListener('resize', setDataWidth, true);
setDataWidth();
function setDataWidth() {
var elements = document.querySelectorAll('[data-width]');
for (var i = 0; i < elements.length; i++) {
elements[i].dataset.width = elements[i].offsetWidth;
}
}
[data-width]:after {
content: ' ' attr(data-width)'px';
}
[data-width] {
border: 1px solid;
}
div {
width: 30%;
height: 30px;
}
<div data-width></div>
<p data-width>Paragraph element</p>
<span data-width>Span</span>

Semantic UI calendar, drop down menu overflow full width

I made a calendar where I can click on each day.
When I put my mouse on the last column div, it overflows the screen width.
<div class="menu">EEEEEEE</div>
https://jsfiddle.net/c0oh7kby/
You can apply transformation on last <td>, to pull tooltip to the left:
td.ui:last-child .ui.simple.dropdown:hover > .menu {
transform: translate(calc(-100% + 16px), 0);
}
Or put it to the right:
td.ui:last-child .ui.simple.dropdown:hover > .menu {
left: auto;
right: 0;
}
updated fiddle
Edit
Before that count all menu items, that overflows viewport:
$('.ui .menu').each(function(){
var $this = $(this);
if ($this.width() + $this.parent().position().left > $(window).width()) {
$this.addClass('transformed');
}
});
And then apply needed css:
.ui.simple.dropdown:hover > .menu.transformed {
left: auto;
right: 0;
}
fiddle
However it doesn't compensate if tooltip is overflowing in both sides. for that You can check twice:
$('.ui .menu').each(function(){
var $this = $(this);
if ($this.width() + $this.parent().position().left > $(window).width()) {
$this.addClass('transformed');
if ($this.parent().position().left - $this.width() < 0) {
$this.addClass('center');
}
}
});
And apply transformation:
.ui.simple.dropdown:hover > .menu.transformed.center {
transform: translate(50%, 0);
}
fiddle

Dynamic Div Layout

I know there are a lot of posts about div layouts but what I'm looking to do doesn't seem to be on here. I am creating div's that contain dynamic text. Therefore each div is of variable length. I want these div's placed alongside each other, 4 across the page. In other words, each div occupies 25% of the width. The number of div's is variable as well so if there are more than 4 div's, then the remaining would start be placed below in the same fashion. Below is a picture of what I am trying to depict, with the gray boxes being the div's I am creating. Any help is appreciated, thank you in advance!
The div's are created in my function addSuggestion(), which is as follows:
HTML:
addSuggestion = function (counter, company_name, contact_name, street_address_1, street_address_2, phone_number, email_address) {
var output = document.getElementById('container');
var div = document.createElement('div');
var company = document.createElement('p');
company.className = "companyClass";
var contact = document.createElement('p');
contact.className = "otherClass";
var address1 = document.createElement('p');
address1.className = "addressClass";
var address2 = document.createElement('p');
address2.className = "addressClass";
var phone = document.createElement('p');
phone.className = "otherClass";
var email = document.createElement('p');
email.className = "otherClass";
if(counter%4 == 0) {
div.className = "farleft";
}
else if(counter%4 == 1) {
div.className = "centerleft";
}
else if(counter%4 == 2) {
div.className = "centerright";
}
else {
div.className = "farright";
}
if(company_name) {
company.textContent = company_name;
div.appendChild(company);
}
else {
company.textContent = "*** COMPANY INFO ***";
div.appendChild(company);
}
if(contact_name) {
contact.textContent = contact_name;
div.appendChild(contact);
}
if(street_address_1) {
address1.textContent = street_address_1;
div.appendChild(address1);
}
if(street_address_2) {
address2.textContent = street_address_2;
div.appendChild(address2);
}
if(phone_number) {
phone.textContent = phone_number;
div.appendChild(phone);
}
if(email_address) {
email.textContent = email_address;
div.appendChild(email);
}
output.appendChild(div);
}
CSS:
#container {
width: 100%;
}
#farleft {
width: 25%;
position: absolute;
float:left;
}
#centerleft {
width: 25%;
position: relative;
float:left;
}
#centerright {
width: 25%;
position: relative;
float:right;
}
#farright {
width: 25%;
position: relative;
float:right;
}
Assigning width: 25% to each div will get your 4 divs on the same row (counting there are no borders and/or margin/padding on the exterior).
float: left will keep them to the left. In order to get your 'new row' to drop down a line, <br clear="both"> would do the trick:
JSFiddle
If its a row of div's you can store them in a containing div "row" that has a variable height.
Sorry of that doesn't make much sense but try this CSS on the row's div.
min-height: 100px; /*whatever you want the minimum height to be*/
height:auto !important; /*An IE fix for older versions */
height:100%;
The above css will ensure your div is never smaller than 100px but can grow based on its content.
The solution is quite simple:
#container>div {
width:25%;
margin:0;
border:0;
float:left;
}
#container>div.farleft {
clear:both;
}
jsfiddle

Margin, position and padding not working when display:inline is set. also weird behaviour from relative position

I have two CSS classes:
.class1 {
height: 100%;
width: 300px;
border: 1px none #B0B0B0;
position: relative;
display: inline;
left: 10px;
}
.class2 {
height: 100%;
width: 200px;
position: relative;
display: inline;
margin-left: 15px;
background-color: #00CCCC;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-style: solid;
border-right-style: solid;
border-bottom-style: solid;
border-left-style: solid;
}
Now, as you can see, they're both set to display in a line (no line breaks in between elements). Which works correctly. But for some reason, ever since I set the display to inline, the Padding, the Positioning and the Margin CSS have all just stopped working. I can add a margin-left 10inches and nothing will happen. Same with padding and positioning.
Can anyone explain how to fix this?
Also, I have the relative position set on both classes, yet when viewing the page in a browser, .class2 over laps .class1 when its supposed to be just after .class1.
Any ideas?
EDIT:
Okay, so I've done a JSFiddle, but it seems to be playing up even more there....
Looks like the Width is not working....
here it is:
http://jsfiddle.net/zYbwh/1/
You need to use
display: inline-block;
instead. margin doesn't work with display: inline elements, however with inline-block it does. You can then have an inline element with margins and explicit widths/heights.
To make this work in IE7, add these two lines:
*display: inline;
zoom: 1;
It's horrible, but it works.
I know this is quite a late answer but I wrote a jQuery plugin which support padding on inline elements (with word breaking) see this JSfiddle:
http://jsfiddle.net/RxKek/
Plugin Code:
$.fn.outerHTML = function () {
// IE, Chrome & Safari will comply with the non-standard outerHTML, all others (FF) will have a fall-back for cloning
return (!this.length) ? this : (this[0].outerHTML || (
function (el) {
var div = document.createElement('div');
div.appendChild(el.cloneNode(true));
var contents = div.innerHTML;
div = null;
return contents;
})(this[0]));
};
/*
Requirements:
1. The container must NOT have a width!
2. The element needs to be formatted like this:
<div>text</div>
in stead of this:
<div>
text
</div>
*/
$.fn.fixInlineText = function (opt) {
return this.each(function () {
//First get the container width
var maxWidth = opt.width;
//Then get the width of the inline element
//To calculate the correct width the element needs to
//be 100% visible that's why we make it absolute first.
//We also do this to the container.
$(this).css("position", "absolute");
$(this).parent().css("position", "absolute").css("width", "200%");
var width = $(this).width();
$(this).css("position", "");
$(this).parent().css("position", "").css("width", "");
//Don't do anything if it fits
if (width < maxWidth) {
return;
}
//Check how many times the container fits within the box
var times = Math.ceil(width / maxWidth);
//Function for cleaning chunks
var cleanChunk = function (chunk) {
var thisChunkLength = chunk.length - 1;
if (chunk[0] == " ") chunk = chunk.substring(1);
if (chunk[thisChunkLength] == " ") chunk = chunk.substring(0, thisChunkLength);
return chunk;
};
//Divide the text into chunks
var text = $(this).html();
var textArr = text.split(" ");
var chunkLength = Math.ceil((textArr.length - 1) / times);
var chunks = [];
var curChunk = "";
var curChunkCount = 0;
var isParsingHtml = false;
//Loop through the text array and split it into chunks
for (var i in textArr) {
//When we are parsing HTML we don't want to count the
//spaces since the user doesn't see it.
if (isParsingHtml) {
//Check for a HTML end tag
if (/<\/[a-zA-Z]*>/.test(textArr[i]) || /[a-zA-Z]*>/.test(textArr[i])) {
isParsingHtml = false;
}
} else {
//Check for a HTML begin tag
if (/<[a-zA-Z]*/.test(textArr[i])) {
isParsingHtml = true;
}
}
//Calculate chunks
if (curChunkCount == (chunkLength - 1) && !isParsingHtml) {
curChunk += textArr[i] + " ";
chunks.push(cleanChunk(curChunk));
curChunk = "";
curChunkCount = -1;
} else if ((i == (textArr.length - 1))) {
curChunk += textArr[i];
chunks.push(cleanChunk(curChunk));
break;
} else {
curChunk += textArr[i] + " ";
}
if (!isParsingHtml) {
curChunkCount++;
}
}
//Convert chunks to new elements
var el = $($(this).html("").outerHTML());
for (var x in chunks) {
var new_el = el.clone().html(chunks[x]).addClass("text-render-el");
var new_el_container = $("<div/>").addClass("text-render-container");
new_el_container.append(new_el);
$(this).before(new_el_container);
}
//Finally remove the current element
$(this).remove();
});
};
Thats the problem you get when using templates, ive programmed a site in php, but the design is killing me.
So i try'd some rocket fuel for webdesigners.
And this is the problems i keep getting every step of the way...
Inline-block does not work for me, nothing works, becouse it is not my design and i dont know the setup.
Ive tryd doing the design myself, but i am out of time, i need a design yesterday.
I suggest you take what u need from the templates and delete everything else, that will schrink your problem, and save you time.

Position fixed menu to top

I know how to use position:fixed; but I want, if the page scrolls over it, that it's on the top and on normal state lower.
.menu {
height: 30px;
width: 100%;
border-bottom: 1px solid black;
position: fixed;
top: 0px;
}
If I understand correctly, you want to make a menu fixed after it's scrolled past? If that's the case, see this question.
If that doesn't work for you, consider using code like this, assuming jQuery (actually Sprint but it's about the same for both):
var navigation = $('nav').item(0);
var navigationY = navigation.element.offsetTop;
var navClone = navigation.clone();
$(window).bind('scroll', function() {
var scrollY = (window.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop) >>> 0;
if(scrollY > navigationY) {
if(!navClone.element.parentNode || navClone.element.parentNode.nodeType !== 1) {
navigation.after(navClone);
navigation.addClass('fixed');
}
} else if(navClone.element.parentNode) {
navClone.remove();
navigation.removeClass('fixed');
}
});
which I used in a recent project, so just change $('nav') at the top to whatever you need to select your element, e.g. $('.menu').

Resources