I have a div, max width 80% of page. Inside is a table, width 100%. The table will have at least 5 cols, possible 10 or more. Only the names of the first 3 and last cols are known, all have fixed widths of 10%. If the width of the unknown cols, however many, and the 4 known cols exceeds the max, a horizontal scroll is applied to the unknown cols, in other words, a partial horizontal scrollbar. I have seen examples of partial scrollbars, but none that don’t contain either end columns.
I’m not sure I really understand what all that means.
In Chrome and Safari you can now make the td cell scroll if the table is set to table-layout:fixed.
Of course any cell that is wider than the 10% will start to scroll.
You can set those to 10% width and any other columns that get too large can scroll.
Something like this:
I’m not sure if that’s what you meant but may serve as a starting point. Also note that browser never use to allow the td to scroll and usually you had to nest a div inside with a width of 100% and make that scroll. I haven’t tested other browsers as I’m not on my own computer at the moment but I suggest testing Edge and Firefox first before continuing with this method.
Apologies, I’m not looking for scrolling of individual cells. How can I get a block of columns however many, with unknown names or widths to scroll horizontally if their combined width is greater than 60%? The th width for each unknown column will be greater than the td’s in that column, but I’m guessing I can match the width of each th to the corresponding td’s using JavaScript.
If I understand correctly then I don’t think you can do what you want with a standard table structure as it seems you want a group of columns to scroll with one horizontal scrollbar. You would need a nested table inside one td to be able to do that.
Something like this (or roughly like this).
Is that the sort of thing you meant?
Yes, just with multiple rows.
Ah now you tell me That does complicate it a lot although I should have guessed it would be multiple rows.
If you want multiple rows that are aligned with each column (and row) and also scrollable from just the one scrollbar at the bottom then I can’t see a way to do that without an awful lot of scripting. iI think it may be possible with grid, subgrid and display:contents but support is minimal for all that.
The only other option I can see that may work is to use position:sticky to hold those four columns in place. The main caveat is that we then have to work with fixed width px columns.
Here’s an example I adapted from an old left columns sticky as proof of concept.
I think that’s about as close as you can get using a normal table (and no nested divs) and no scripting.
Perfect. Just curious, in the css you put a comment
/* could uses classes instead of all this junk */
thead th:nth-child(1), etc.
I was “messing around” with that wondering if their was a better way. What type of class are you referring to?
I used your html and css, it’s not displaying exactly the same as yours, trying to tweak the css to figure what’s what.
Any time you have a long list of comma separated rules you could simply create one class (eg .sticky) and use that class on the elements concerned.
It means you have to address the html and add the class where necessary but it tidies the css up.
It all depends whether you want to keep the html untouched or not.
I’ll be back tomorrow if you are still stuck on something.
I have a motto, if in doubt, get the hell out. Start over. I think using classes would be tidier altogether.
Have the HTML done and the sticky header. Other than color styling of columns, just missing the horizontal scrollbar. I’ll keep tinkering with it.
Thanks.
At the moment everything is scrolling horizontally, vertically the header is sticky.
This is not doing what I was hoping
.sticky {
position: sticky !important;
background-color: white;
z-index: 2;
}
.left-col-1
{
left: 0;
width: 10%;
}
.left-col-2
{
left: 10%;
width: 10%;
}
.left-col-3
{
left: 20%;
border-right: 1px solid #eee !important;
width: 10%;
}
.right-col-1
{
right: 0;
border-left: 1px solid #eee !important;
width: 10%;
}
I can set widths for cols 1 2 3 and last using
.sticky {
position: sticky !important;
background-color: white;
width: 10%;
z-index: 2;
}
however this
.left-col-1
{
left: 0;
width: 10%;
}
creates an unwanted gap between cols 1 and 2, the same for cols 2 and 3.
Can you post a working demo on codepen (it’s free) and will allow me to help more quickly,
There’s not enough code above for me to work out what could go wrong although in essence it looks correct. I’d need to see the rest of the css and the html.
I don’t think percentages will be viable as they will allow all columns to squash to virtually nothing on small screen and there will be nothing to scroll as they are all too small. They will work to a degree but they will keep shrinking as 10% just keeps getting smaller on smaller windows. That’s the reason that is said above "he main caveat is *that we then have to work with fixed width px columns ".
Also you shouldn’t need the !importants and I would stop adding them and you the right weight on your rules. (I only added them in my demo because I had loads of rules to duplicate but I’d never use!important for real (unless there was a specific reason).)
I’ve rejigged my demo to use classes and simplified it a lot.
The closest I could get with percentage widths was a bit hacky and ended up looking much like the fixed width version anyway. here’ was the attempt although I don’t think its stable enough to use.
The only other solution would likely be to use js to size the columns in px based on the width but that would be a very janky as you’d need to do it on resize as well.
If you have saved it then just copy the url from the address bar and paste into here.
Couldn’t you use clamp() for the widths to allow for minimum sizes, but still allow for fluid sizing? Not sure how much that would help but it might make it a bit less hacky…
The problem with table cells is that they need to fit the table and even though you can give widths to the cells they will not be obeyed if they are over-constrained in some manner. Even if we applied min and max-widths to the cells the problem is that the sticky columns numbered 2 and 3 have to be offset by a known amount in order to make them sticky. This is fine in fixed pixel widths as they can be placed at left:150px and miss the first column. If the cell is fluid with min and max then there is no way the sticky offset can match that measurement.
This is a similar problem with percentage widths in that they change width depending on the number of column in the table (so 10% is never 10% unless there are 10 columns).
The fixed width version is the only real non js solution that I can see at the moment
This is what I have so far, just a bit messy.
Ok I wrote a script to give some fluidity to the columns.
This is about the best I think you can get as I don’t believe it makes much sense any other way.
It makes the 4 columns 10% the width of the available width and writes that width in pixels into each column via a css variable. The left position also uses that css variable to offset the sticky columns.
The routine assumes a 10% width but that can be changed in the JS quite easily.
All columns will be the same width which is the only logical way to do this but as you resize each column will get smaller as a percentage of the available space.
The CSS is much the same and simplified with common classes.
Obviously you will need to do something different for small screens but that is a question for another day.
@PaulOB That is fantastic. Going to spend time looking over the css and js, try and make sense of it as best I can.