I have table with multiple rows, showing items for sale. When the user clicks on a row, a Javascript inserts / shows a new row right beneath it with details about the item. The issue is when the description is long, it forces the column widths to readjust / resize. This shifts the columns positions and is really annoying, especially for the user. Right now, I have my table.style.tableLayout: auto. I actually prefer it this way, because the columns are adjusted to the content.
My question is: how do I dynamically "lock" the widths of the columns in my table so that when I insert / show the new row, the columns do not readjust / resize?
I've tried:
dynamically setting the table to temporarily "tableLayout: fixed"
inserting / showing my new row
changing the table back to "tableLayout: auto"
Actions 1 & 2 works in in FireFox, but not in Safari and IE (6 & 7). However, doing all three seems to prevent the columns from shifting too much.
The frustration is unbearable ... loosing lots of sleep ... please help!
Thanks.
For those looking for the code (this is done in jQuery). This also assumes the first row has the proper widths for each cell. Pretty easy changes if needed.
$('table.class_of_table_to_fix tr:first td').each(function() {
$(this).css({'width': $(this).width()+"px"});
});
I would set a percent width on each column simply as a guide. Set it just once on the TH of each column. The browser will still adjust the columns to content if necessary, but the columns will stay in place more consistently.
Next, I would never put css "white-space:nowrap" anywhere on that table. A long description should not break the table layout, it should wrap around properly on multiple lines, and be readable if you set the widths on each column to suit the type of data. Similarly I would keep the use of (non breakable spaces) to dates, times and numbers and allow the text to wrap.
Other than that, I do this at my job on a dialy basis, and there's a time when you need to stop ulling hairs asking the browser to do something it's not designed to do. Content should flow and adapt. Locking column widths to pixels is 99.99999% of the time a bad idea.
PS: If you really, reeally, REALLY need to lock columns, the only solution I'm aware of that works with CSS2 and accross all browsers is to use images. You could insert a 1px high transparent gif image in each column, and counting in the padding of the cells (TD), set a pixel width on each image (IMG), instead of on the columns (TH/TD). You could hide those in the TH for example. You can leave the images at 1 pixel wide and set percent widths on TDs, and when you open a new row, you would get each column width minus TD Padding, and set that to the corresponding IMG. I haven't tried! I just know that in many projects I've worked on, I've used small gif images to lock a minimum vertical spacing between columns, for example.
I had a similar problem when I was implementing a table with groups that could be toggled. I wanted the initial ratio between the columns to stay the same without fixing the widths of the columns. By default the browser would change the widths depending on the visibility of the table's rows, which was undesirable.
I went ahead and followed #faB's suggestion of applying percentages, but doing so using a small script that would calculate the percentages of the th elements and apply them after the initial render. This made my columns stay the same width, even with all rows hidden.
Here's the script, which uses jQuery:
(function($){
var lock_widths = function() {
var total_width = $('table').innerWidth();
var headers = $('table th');
var leftover = 100;
$.each(headers, function(ix, el) {
var header = $(el), width;
// on the last call use the leftover percentage
if (ix == headers.length - 1) {
width = leftover;
} else {
leftover -= width = header.outerWidth() / total_width * 100;
}
header.css({'width': width + '%'});
});
};
$(document).ready(lock_widths);
})(jQuery);
Tested in IE7+, Firefox and Chrome. This works for my special case because I have header columns as a reference, but it could be rewritten to measure some other columns.
You can display the details of the row beneath the clicked one in DIV and set its
style="overflow:auto";
so that details will wrap and scrollbar will be available to display entire text.
I don´t know if you´re familiar with jquery, but that´s what I would use - in combination with a separate class for the column that´s causing resizing in the new row - to:
Calculate / get the with of the column
Set the with of the afore mentioned class
Add the row
I haven´t tried it, but that should do it.
By the way, there are probably other ways to do it, I´m just more familiar with jquery (for point 1. and 2.).
Related
I've a requirement where I have 3 panels(Chats, Groups, Channels) in the left side panel and I need to adjust their heights based on the resolutions and also the items in that panels.
I will make api calls and get the items for that panels and bind them through angular bindings.
Please check the JSFiddle I've prepared for a clear understanding.In this, I've also wrote some additional media queries and adjusted the max-heights for the resolutions.
Now, My actual requirement is :
1) If there are no items at all in all the 3 panels, then all panels should collapse which is already working.
2) If all the 3 panels has items more than its size, then scroll should appear as the output screen which is already working.
3) If only one panel has items, then it should automatically expand its size like shown in the image in the
and same should apply to other panels as well.
4) Finally, if only few items are available in the 2 panels and more items are present in the 3rd panel, then it should show in the following way.
Actually, I thought of writing some jquery after the api calls based on the items count but that's kind of getting hard because I need to check the resolutions as well and also the items count in all the panels.
Is there any css way of achieving this?
at least, is there any article or something where I can follow and do this?
is jquery, the only way of doing this?
You could standardise it at 33.33333vh height then modify it using jQuery after the fact. It could get a little complex depending on how many exceptions you want to cater for but this unit will take care of the resolution differences and is supported by modern browsers.
In your jQuery you could work out the number of items in each panel as a percentage of the total and give each panel an appropriate height in vh - the label.
$(function() {
var totalNumItems = $('.panel div').length;
$('.panel').each(function() {
setPanelHeight($(this));
});
function setPanelHeight(panel) {
var numItems = panel.find('div').length,
heightPercentage = (numItems / totalNumItems) * 100;
/* calc -1.5em takes the label height into account */
panel.css('height', 'calc(' + heightPercentage + 'vh - 1.5em)');
panel.niceScroll();
}
});
If there were no items in a panel, it would calculate its vh as 0 and as such collapse it.
Edit: jsfiddle: https://jsfiddle.net/mattBBP/8vvcub3c/
This doesn't quite work because the area it's being displayed is not 100% of the viewport but this could be modified/offset / would not be a problem out of the fiddle.
I have a layout of boxes that are all floated left and when you click on their headings, they slide open revealing content. The issue is that the way floats work, when you click to expand one of them, it messes with the row underneath.
http://jsfiddle.net/FCCye/ <-- click on one of the headings to see the issue.
I've solved this by separating them into columns like so:
http://jsfiddle.net/caW4M/
That works fine, however, the layout needs to be responsive, so when the window is 480 or lower, it needs to be 1 column. Between 480 and 768 it needs to be 2 columns. Anything above 768, 3 columns. (obviously, the jsfiddles don't show the breakpoints I have set up.)
This is the code I've come up with to solve this, however it is not working at all. I was wondering if someone could tell me what I'm doing wrong.
// Create all three portfolio columns
var one = $('<div/>').addClass('column').addClass('one');
var two = $('<div/>').addClass('column').addClass('two');
var three = $('<div/>').addClass('column').addClass('three');
// Store all portfolio elements into variables once they're in columns
var colElems = $('.column .project');
// Now append the columns
var winWidth = $(window).width();
if ( winWidth > 480 && winWidth <= 768 ) {
// Remove everything from columns and delete existing columns
$(colElems).appendTo('#portfolio .content');
$('#portfolio .content').remove(one,two,three);
// Store portfolio elements into variables for safe-keeping
var c1Elems = $('.project:nth-child(2n+1)');
var c2Elems = $('.project:nth-child(2n+2)');
// Perform appends into portfolio columns
c1Elems.appendTo(one);
c2Elems.appendTo(two);
// Append portfolio elements to columns
$('#portfolio .content').append(one,two);
}else{
// Remove everything from columns and delete existing columns
$(colElems).appendTo('#portfolio .content');
$('#portfolio .content').remove(one,two,three);
// Store portfolio elements into variables for safe-keeping
var c1Elems = $('.project:nth-child(3n+1)');
var c2Elems = $('.project:nth-child(3n+2)');
var c3Elems = $('.project:nth-child(3n+3)');
// Perform appends into portfolio columns
c1Elems.appendTo(one);
c2Elems.appendTo(two);
c3Elems.appendTo(three);
$('#portfolio .content').append(one,two,three);
}
So, what I'm trying to do is append the normal 3 columns when it's not between 480 and 768 (because on mobile size, the columns would stack on top of each other anyway) and when between 480 and 768, only append two columns. So my thought is that at the different sizes, I would have to pull all of the boxes out of the columns, delete the columns, and reappend the columns in different numbers based on the window width. This has proved to be a failed attempt, so if anyone can explain to me what I'm doing wrong I would be very appreciative!
Thanks!
Not an answer to your question, but if you will follow the advice then your question will no longer be of interest. ;-)
First of all why don't you use CSS3 Media Queries for your different layouts? That is what they are for.
Secondly it is "bad practice" to use pixel values (or any other kind of absolute units) for defining breakpoints, even if a lot of authors actually do! It is best to only use relative units like 'em'.
The new Flexbox module could also be an option for you, depending on the supported Browser versions (especially IE 8).
And why don't you let the expanded box not simply overlap the other content by using 'position: absolute'?
Well, doing things with Javascript which should be done with pure CSS isn't a good idea. What happens, when JS is deactivated? And also from a performance point of view, on resizing the viewport ... - all bad.
So my advice would be to completely rethink your approach.
I have a list of tags that are in a box that I've specified as having multiple columns:
#tags {
-webkit-columns: 140px 5;
}
Result:
The content of this list is dynamically generated.
When I resize the browser window, the number of columns collapses. e.g.:
Using jQuery / JS / CSS / etc., how can I determine how many columns are being displayed at any given time?
Unless you specified all column width-related properties browsers will try to fit whole number of columns in content area (between left and right padding of element). So (contentWidth + columnGap)/(columnWidth + columnGap) rounded down will give you result.
Note that right padding may be set so high that whole column will be able to fit there - you may need to adjust computations.
You can also directly get size of column if you have an element with 100% width inside columns text.
You can get the value like this:
$('#tags').css('-webkit-column-count');
Try alerting this:
alert($('#tags').css('-webkit-column-count'));
Similar to Alexei's answer, I figured out a solution to get the column count:
var $tags = $("#tags"),
column_width = $tags.children(':first').width(),
container_width = $tags.width(),
column_count = Math.floor(container_width / column_width); // in my case, sum of column gaps is less than the width of a column, so I can round down.
I am trying to implement a table structure in which the header remains fixed when i scroll down. I have used 2 tables for this purpose. The first table has the header values and the second table have the corresponding data(length of data in each column might vary as the data is populated dynamically). The problem is that the header width and data column width are not matching exactly.
I have written some code like shown below to dynamically alter the column width
$('#tdCheckAllBody').width($('#tdCheckAllHead').width());
$('#tdLoginBody').width($('#tdLoginHead').width());
$('#tdStatusBody').width($('#tdStatusHead').width());
$('#tdFNameBody').width($('#tdFNameHead').width());
$('#tdLNameBody').width($('#tdLNameHead').width());
$('#tdCompBody').width($('#tdCompHead').width());
But it doesnt seem to work properly. Any help appreciated.
Use this method
$(window).scroll(function(){
$("#id of the table header").offset({top:$("#id of the control which u placed the scrolling").scrollTop()});
});
Created a working fiddle for this:
http://jsfiddle.net/terjeto/dx7H5/
Offcourse if your case is different, you might need to tweak a litle. In my opinion the problematic areas are if the table use dynamic or % width and coping with the "auto" scrollbar which takes up approx 18px, and offcourse if the table needs horizontal scrollbars it complicates things a litle needing the onscroll event.
Could it be that your exmple is not accurate because of lacking reset-css code?
I use this: http://developer.yahoo.com/yui/reset/
Has anyone been able to implement a scrollable table in HTML where the TOP row and LEFT columns are frozen, but the rest of the table is scrollable? A perfect example of this is:
Google Squared
I tried to reverse engineer the code for the google squared table, but I have been unsuccessful so far.
Note: I need the ability to FREEZE the TOP ROW and the LEFT COLUMN at the same time.
There's a working example at http://ajaxian.com/archives/freeze-pane-functionality that should be easy to duplicate. Be sure to note the comments -- many of the users have made helpful suggestions for improving the script.
Per #Nirk's request, a direct link to the active demo is at http://www.disconova.com/open_source/files/freezepanes.htm.
Go with a basic structure like this-
table
row
column (blank)
column
table (1 row high, column headers)
row
column
table (1 column wide, row headers)
column
div (fixed height & width, overflow auto)
table (actual data)
Set a fixed table-layout and specify column widths in pixels explicitly. You should be able to achieve the same effect.
i have a version of this in use (for a Gantt-chart style display).
it uses 3 tables: 1 for left column (the rows), 1 for top (columns), and then the data.
you need to work hard to get the cells to match sizes with the ones they match up to (
table layout-fixed can help achieve this).
The tables then are placed in some divs; the left and top divs have (as suggested above) height & width and overflow-auto in their css.
You then hook up some javascript to sync the scrolling of the left / top divs with the inner one...
As I recall there was a fair bit of 'curse-and-try-again', but it can be done with minimal js.
hth
If you use jQuery there's a lot of plugins for tables with fixed head.
You need Scrollable (jQuery plugin)
Demo is here