I'm working on a responsive layout that displays some <div> boxes as part of a rectangular grid:
http://sl.cosd.com
The six boxes you can see on this page are all ungrouped in the HTML source, all in a row:
<div class="control">
<div class="controlContent">
<a>SOME VARIABLE-HEIGHT CONTENT including an image which might float</a>
</div>
</div>
The control divs assign the boxes percentage widths to first the whole, then 1/2 or 1/3 the screen width, so they double & triple up into rows as the screen size is increased. The controlContent divs assign properties like padding, margin, background, border-radius, etc.
I have imagined this as a linear set of boxes, standards-compliant and screenreader-friendly, to be displayed via CSS like a table. I know CSS2.1 allows elements to be assigned properties like:
display: table;
display: table-row;
display: table-cell;
My main problem: I have assigned display: table-cell to these elements (via the controlContent div) which prevents margin collapse inside the content but does not provide a uniform height to the cell-like divs. I need a way for all siblings on the same row to have matching height.
The smaller cells generally have gaps below them where the gradient background only covers the box height of the cell. (Worse, the text after this array of cells sometimes fills into these gaps: another problem that could be fixed with presentation markup, though one which will probably go away when the first problem is fixed.)
I think I understand the basics of the problem: each <div> which I have told to behave like a table cell has nothing to match its height to, since I have no way of grouping elements into a containing <div> to which I can assign the display: table-row property, since this grouping changes according to CSS media queries.
In my reading about the problem I've heard of anonymous table boxes and anonymous table rows being created but don't know how to use them in this case. Since I'm using the CSS :nth-child() selectors to clear the floating boxes at the beginning of each new row, I'd hoped I could also use these selectors to establish a new table row at every such point... but how?
I'm not married to any particular solution. I'd just like to know the best-practice way of doing this. I'm hoping to find a solution that doesn't involve presentation markup, especially since a general solution should provide a responsive variable-dimension table for any number of cells, not just a small, easily factorable number like 6.
display:table-cell; should give the div/columns the same height, as long as the parent div has display:table; set.
Check this fiddle (you can add/remove as many cols as you want).
Another solution is to give .control a fixed height, then you can use height:100%; on controlContent.
If you need to use percentages only, then you've to declare an height on all the parent containers of .controlContent, up to html and body:
html, body, .control, .controlContent {
height:100%;
}
Obviously it's just a simplification. This is the most reliable method, because table-cell is not rendered properly by some older browsers.
On the other hand, you always have to know the height (in pixels or percentage) of all containers.
Then, there's the faux column method, but i don't thinks it suits your case.
Lastly, there's the JavaScript / jQuery method, which in your case would be something like
$(document).ready(function(){
var higherContent = 0;
$('.controlContent').each(function() {
var currentHeight = $(this).height();
if( currentHeight > higherContent ) higherContent = currentHeight;
}).height(higherContent);
});
Which basically (when the page loads) passes through all the controlContent and sets the value of the highest one in the variable higherContent. Then this value is assigned to all controlContent.
Probably not the best jQuery function ever written anyway :-) and you'ld have to adapt it for every resolution targeted by your media-queries.
If i were you, i would probably go for the table-cell method, so that you can set different widths for different resolution, and the layout will adapt in most of modern desktop/mobile browsers. But be sure to test it on as many devices as possible!
EDIT: I see you're using min-width media queries. You can change your code this way:
div.controlContent {
/* other stuff */
display: block;
/* other stuff */
}
#media only screen and (min-width: 480px) {
/* other stuff */
div.controlContent {
display: table-cell;
}
/* other stuff */
}
Related
I'm doing some styling and am trying to figure out why I can't get the column headers to align correctly for this phpBB bulletin board. When screen width decreases, I want the column headers to smoothly and consistently align under the list of forums and their metadata below it. Some sort of styling I think needs to be applied to the .header dt. I can specify a column width in pixels and it works for a while until screen width shrinks too much. Specifying width in percentages doesn't work either as the header alignment will not be consistent with the rows below them as screen width decreases. There's obviously a lot of styling going on and styles inherit from phpBB's prosilver style, but I need to make it consistent with the site's style.
https://phpbb33.adafruit.us/index.php
The solution in this case was to apply the following styling:
ul.topiclist dt {
margin-right: -440px;
}
I'm curious is it possible to use the Grid Layout CSS to create such thing:
************************
* row #1 *
************************
* *
* *
* row #2 *
* *
* *
************************
* row #3 *
************************
So the grid must fill the full body height. And there's also some restrictions for other elements:
The row #1 is aligned to the top of the grid and can change it's
height (but has a max-height value)
The row #3 is aligned to the
bottom and can change it's height (also has a max-height value)
So the row #2 must fill all remaining space in grid.
The grid container should not overflow the html body.
There's an example what I achieved: 3 row grid layout.
I also can make everything with absolute position like this but there's no use because I can automatically calculate the row #2 margins without any imperative js code.
I see that the original question is marked as answered, but as the original included an attempt to use the CSS Grid Layout module to solve the problem, I thought I'd complement the answers with some solutions using newer standards.
Using flexbox
First of all, this kind of layout is pretty easy using flexbox. The flex-grow property allows you to define elements that fill the remaining space in this very way. JSBin example using flexbox here
Note: Not using all prefixes (e.g. to target IE10 etc) in the quick demo, but if you use something like autoprefixer it's kind of trivial. Also, beware of bugs relating to things like vh units in iOS and min-height flexbox columns in IE.
Using grid layout
Note: This demo will only work in Chrome Canary at the time the answer was written!
Grid layout is picking up pace and the spec has stabilized a bit. Chrome Canary has an implementation that is pretty far along, as does the WebKit nightly builds.
Grid layout has the same type of flexible sizing as flexbox, and moves the layout mechanism to the container element instead. JSBin demo – remember, Chrome Canary only at the time of writing. (It would work in WebKit nightlies as well with the right prefixes.)
Basically, the whole thing boils down to these lines:
body {
margin: 0;
display: grid;
grid-template-rows: auto 1fr auto;
grid-template-columns: 100%;
height: 100vh;
}
The above means "Use the body element as a grid container, place items in it in source order, in a single column that is 100% wide, and size the first and third row according to content, and the middle one takes up all the space that is left". We don't need to specifically place the items inside the grid: they will auto-place themselves – we could change order etc if we wanted though. Grid Layout can do many more advanced things!
Most browser vendors are working on finishing their first grid implementations, so it's fun & worthwhile to start playing with it. :-)
Until then, the flexbox version gets you pretty good browser support.
You can do this with display:table property See Spec and Compatibility
Working Demo
CSS
#container {
display:table;
}
#head, #content, #foot {
display:table-row;
}
Edit:
Updated Fiddle
Added div inside table-row to prevent overflow
what about setting percentages heights like this:
.head{
height:10%;
max-height: /*max height allowed*/;
}
.content{
height:80%;
max-height: /*max height allowed*/;
}
.foot{
height:10%;
max-height: /*max height allowed*/;
}
Currently the table is too wide and causes the browser to add a horizontal scroll bar.
CSS:
table {
table-layout:fixed;
}
Update with CSS from the comments:
td {
overflow: hidden;
text-overflow: ellipsis;
word-wrap: break-word;
}
For mobile phones I leave the table width but assign an additional CSS class to the table to enable horizontal scrolling (table will not go over the mobile screen anymore):
#media only screen and (max-width: 480px) {
/* horizontal scrollbar for tables if mobile screen */
.tablemobile {
overflow-x: auto;
display: block;
}
}
Sufficient enough.
If the table content is too wide (as in this example), there's nothing you can do other than alter the content to make it possible for the browser to show it in a more narrow format. Contrary to the earlier answers, setting width to 100% will have absolutely no effect if the content is too wide (as that link, and this one, demonstrate). Browsers already try to keep tables within the left and right margins if they can, and only resort to a horizontal scrollbar if they can't.
Some ways you can alter content to make a table more narrow:
Reduce the number of columns (perhaps breaking one megalithic table into multiple independent tables).
If you're using CSS white-space: nowrap on any of the content (or the old nowrap attribute, , a nobr element, etc.), see if you can live without them so the browser has the option of wrapping that content to keep the width down.
If you're using really wide margins, padding, borders, etc., try reducing their size (but I'm sure you thought of that).
If the table is too wide but you don't see a good reason for it (the content isn't that wide, etc.), you'll have to provide more information about how you're styling the table, the surrounding elements, etc. Again, by default the browser will avoid the scrollbar if it can.
table { width: 100%; }
Will not produce the exact result you are expecting, because of all the margins and paddings used in body. So IF scripts are OKAY, then use Jquery.
$("#tableid").width($(window).width());
If not, use this snippet
<style>
body { margin:0;padding:0; }
</style>
<table width="100%" border="1">
<tr>
<td>Just a Test
</td>
</tr>
</table>
You will notice that the width is perfectly covering the page.
The main thing is too nullify the margin and padding as I have shown at the body, then you are set.
Instead of using the % unit – the width/height of another element – you should use vh and vw.
Your code would be:
your table {
width: 100vw;
height: 100vh;
}
But, if the document is smaller than 100vh or 100vw, then you need to set the size to the document's size.
(table).style.width = window.innerWidth;
(table).style.height = window.innerHeight;
Set font-size in viewport-width-related units, e.g.:
table { font-size: 0.9vw; }
This will make font unreadable when page is too narrow, but sometimes this is acceptable.
Put the table in a container element that has
overflow:scroll;
max-width:95vw;
or make the table fit to the screen and overflow:scroll all table cells.
There is already a good solution to the problem you are having. Everyone has been forgetting the CSS property font-size: the last but not least solution. One can decrease the font size by 2 to 3 pixels. It may still be visible to the user and for somewhat you can decrease the width of the table. This worked for me. My table has 5 columns with 4 showing perfectly, but the fifth column went out of the viewport. To fix the problem, I decreased the font size and all five columns were fitted onto the screen.
table th td {
font-size: 14px;
}
For your information, if your table has too many columns and you are not able to decrease, then make the font size small. It will get rid of the horizontal scroll. There are two advantages: your style for mobile web will remain the same (good without horizontal scroll) and when user sees small sizes, most users will zoom into the table to their comfort level.
I am using Yahoo's UI Grids to structure most of my pages. One of my pages is a Google map and I need about a 400 pixel fixed left column to put map legend information into. YUI Grids however only offers 3 columns for their 100% page layouts, namely 160px, 180px and 300px.
Is there a way that I can customize their 'template 3' which provides the 300px column to get my 400px column I need?
I've determined how to do this. Kudos for Nate in the YUI forums for pointing me in the right direction.
To set a fixed left column, you need to divide the column pixel width by 13 to determine the em's for all non-IE browser's. For IE, divide the column width by 13.3333
e.g. wanting a fixed 480px width, 480/13 gives me 36.9231em for non-IE and 480/13.33 is exactly 36em for IE
Using template 3, the CSS is:
.yui-t3 .yui-b {
float: left;
width: 12.3207em; *width: 12.0106em;
}
.yui-t3 #yui-main .yui-b {
margin-left: 36.9231em; *margin-left: 36em;
}
Also, if you want to tweak margin's e.g. zero margin, you can do something like:
#doc3 {
margin: auto 0;
}
Grids is presently deprecated in YUI 3 - a bit of a shock when I saw that. There will be some browser(s) that drop off the A category in July and as a result, Grids will be reworked given that some of the initial design decisions were based on older browsers of course.
There is definitely a way. I think its just a matter of tweaking the CSS to either add in another 400px column, or modifying an existing column to fit your needs. If you are adding another column, be sure to account for the additional width (plus margin) and either reduce width on other elements, or increase the width of your containing element.
If the layout is using 100% width of the browser, width may not be an issue, but if your content is wrapped in a container element which holds all of your columns, be sure to adjust the existing elements to make up for the size of your new column.
EDIT: Also if you are dealing with 100% width layouts, its probably better to size your columns using percentage, instead of a fixed pixel size. Since the containing element for your columns will be the user's screen, if you use percentage then the column sizes should adjust relative to their resolution/window size.
If you want your new column to appear on the left of the your other columns, typically you would place it before the other columns in your markup, and apply a "float:left" property. But, take a look at how the other columns are set up in the YUI CSS, and follow their method.
I hope that helps.
Acorn
Summary
What's the best way to ensure a table cell cannot be less than a certain minimum width.
Example
I want to ensure that all cells in a table are at least 100px wide regards of the width of the tables container. If there is more available space the table cells should fill that space.
Browser compatibility
I possible I would like to find a solution that works in
IE 6-8
FF 2-3
Safari
In order of preference.
This CSS should suffice:
td { min-width: 100px; }
However, it's not always obeyed correctly (the min-width attribute) by all browsers (for example, IE6 dislikes it a great deal).
Edit: As for an IE6 (and before) solution, there isn't one that works reliably under all circumstances, as far as I know. Using the nowrap HTML attribute doesn't really achieve the desired result, as that just prevents line-breaks in the cell, rather than specifying a minimum width.
However, if nowrap is used in conjunction with a regular cell width property (such as using width: 100px), the 100px will act like a minimum width and the cell will still expand with the text (due to the nowrap). This is a less-than-ideal solution, which cannot be fully applied using CSS and, as such, would be tedious to implement if you have many tables you wish to apply this to. (Of course, this entire alternative solution falls down if you want to have dynamic line-breaks in your cells, anyway).
Another hack is the old 1x1 transparent pixel trick. Insert an 1x1 transparent gif image and set its width in the image tag to the width you want. This will force the cell to be at least as wide as the image.
I know this is an old question but i thought I'd share something that wasn't mentioned (Although pretty simple in concept..) you can just put a <div> inside the table (in one of the <td>'s or something) and set the <div> to min-width. the table will stop at the <div>'s width. Just thought I'd throw that out there in case somebody comes across this on google. Also, I'm not so sure about how min-width is handled in I.E6. but that has already been covered in another answer.
I had some success with:
min-width: 193px;
width:auto !important;
_width: 193px; /* IE6 hack */
Based on a combination of Vatos' response and a min-height article here: http://www.dustindiaz.com/min-height-fast-hack/
what about this css property
min-width: 100px
but it doesn't really work in IE6 if not mistaken
if you don't want to do it in the css way, I suppose you can add this attribute
nowrap="nowrap"
in your table data tag
This is a cross-browser way for setting minimum width and/or mimimum height:
{
width (or height): auto !important;
width (or height): 200px;
min-width (or min-height): 200px;
}
IE 6 doesn't understand !important
IE 6 sees width/height:200px (overwriting auto)
Other browsers understand the min- and the !important
I am not 100% familiar with the behaviour of widths in TD elements, but this all works nicely on eg DIV tags
BTW:
Based on a combination of Vatos' response and a min-height article here: http://www.dustindiaz.com/min-height-fast-hack/
This is not working because of the order of the first 2 lines, they need to be in the right order (think about the above) ;)
IE6 handles width as min-width:
td {
min-width: 100px;
_width: 100px;/* IE6 hack */
}
If you want IE6 to handle width like normal browsers, give it an overflow:visible; (not the case here)