I have a webpage that looks like:
<table>
<tr>
<td style=white-space:nowrap>
lots of content...
</td>
<td>
some more content
</td>
</tr>
</table>
This works nicely. The left column takes up as much width as it needs and the right column takes up as much as it can. The right column includes a lot of automatic line-wrapping.
I'd like to do this in pure CSS because semantically speaking there's nothing tabular. But everything I try either requires hard-coding widths or puts the right column underneath the left column. Is there a way?
Float the left column, and make the right column non-floated with overflow:hidden. This will cause the right column to automatically fill the remaining width, without wrapping around below the left column.
JSFiddle Demo
.column1 {
float: left;
}
.column2 {
overflow: hidden;
}
This trick tested fine in all browsers except IE6 (which shouldn't matter at this point).
You can use the CSS display:table-cell rule to simulate the table layout.
<div style=white-space:nowrap>lots of content... lots of content... lots of content... lots of content... lots of content... lots of content... lots of content...</div>
<div>some more content</div>
div {
display:table-cell;
vertical-align:middle;
}
jsFiddle example
Related
It's not easy explaining the need here, but here is the playground for the problem.
Playground
Requirements:
First cell has FIXED width
Middle cell width takes the rest of the space
Last cell's width depends on it's children's width
The Question:
How can the middle cell take the rest of the row's space, without being "taken over" by it's child's greater width?
this is a simplified version of my problem, using real tables instead of CSS tables)
Without specific markup, it's hard to propose an exact solution, but here are some things to consider.
The left-most fixed-width cell is easily handled by setting its width. e.g. width: 100px. (This cell isn't really relevant to the problem; in a sense it can be ignored.)
If I'm interpreting correctly, you want to prevent the right-most cell from wrapping. That's easy or hard, depending on the content. For pure text, it can be achieved with white-space: nowrap. If the content isn't strictly text, perhaps you can coerce it into acting like text, e.g. display: inline.
For the middle cell, you don't specify what you want to happen to the excess content. Hide it? Add a horizontal scroll bar? You also don't indicate what this content is. But most likely you'll want to set the overflow-x property to some suitable value.
Solution playground
HTML
<table>
<tr>
<td></td>
<td>
<div>
<div></div>
</div>
</td>
<td>
<b></b>
<b></b>
<b></b>
</td>
</tr>
</table>
CSS
table{ width:100%; }
/*
This is the trick. There is a wrapping DIV with a position:relative which
holds the actual content DIV which is positioned Absolute, so it's width won't
affect it's own cell width's
*/
td > div{ position:relative; width:100%; height:20px; }
div div{
position:absolute;
background:green; height:100%; width:800px;
}
/* First TD has FIXED width */
td:nth-child(1){ width:100px; background:#EEE; }
/* Middle TD width takes the rest of the space */
td:nth-child(2){ overflow:hidden; }
/* Last TD has width depends on it's children's width */
td:nth-child(3){ white-space:nowrap; width:1%; }
I'm trying to construct 3-columned page like this:
Is it possible to make a title to span over only two columns?
Using exclusions gives no result=( I'm stuck!
I need to do 3 columns with floating text:
-webkit-column-count: 3;
-webkit-column-gap: 1em;
-webkit-column-rule: 2px solid #B8B8B8;
so using table is not a solution
CSS3 offers column-count specifically for this purpose but unfortunately it's not supported in old browsers.
.newspaper
{
-moz-column-count:2; /* Firefox */
-webkit-column-count:2; /* Safari and Chrome */
column-count:2;
}
DEMO
You can use DIV with style float:left to place 2 columns next to each other. And the DIV with title could go above them.
Demo: http://jsfiddle.net/6cttL/
I needed the solution to this exact problem and found this at kmsm.ca:
Spanning columns
If we want an element, say a headline, to span across multiple columns we can make use of the new column-span property.
column-span has two possible values: all, and regular numbers (e.g. 1,2,3). Defining column-span as all means that the given element will span across the whole multi-column block, while assigning it a regular number will limit its span to that number of columns:
h2 {
-webkit-column-span:all;
-moz-column-span:all;
column-span:all;
}
hope that helps
update - this worked in Chrome but not Firefox
What about using a table with colspan?
<table>
<tr>
<td colspan="2" id="title">
</td>
</tr>
<tr>
<td id="firstcolumn">
</td>
<td id="secondcolumn">
</td>
</tr>
</table>
I'm not sure what your document structure is beneath that image, but a common technique is to place a 'wrapper' div around blocks of content to simplify their layout.
So, you'd place the far right content in a div, then everything on the left in a div. Within the left div, you'd have your heading, then below it, a div that contained the two columns.
<div id="rightMain">...</div> <!--Float right-->
<div id="leftMain">
<h2>Article Title</h2>
<div id="article">
<div id="leftArticleCol">...</div>
<div id="rightArticleCol">...</div>
</div>
</div>
Looking for some expert advice here about how best to style the following HTML:
<body>
-Some content-
<div class="parent" style="height:50%;">
<div class="child" style="background-color:#FF9999;">An image</div>
<div class="child" style="background-color:#9999FF;">Some text</div>
</div>
</body>
To obtain a result that behaves like this:
The criteria that I am working with are the following:
The container div, .parent, is a block element and fills the entire width of the browser window.
I know the width of the first/left inner div, in pixels but not as a percentage, based on the regularity of the images that will go there.
I don't know the width of the second/right inner div - as it contains a variable amount of text that should automatically fill the entire space to the right, regardless of browser window width
The height of the first/left div, when shorter than the second/right div, should stretch to the same height (here's the reason: the first/left div will have a right-border to set it off from the second/right div, and this border should be the height of the .parent div; however, the first/left div is not always present in the mark-up, in which case the border should not appear).
I cannot use JavaScript trickery.
Solutions I have tried based on my experience and help from web sources:
Float:
The traditional method that uses float:left leaves me apparently unable to stretch the first/left div to the (variable) height of either its sibling or .parent.
Inline-block:
.parent {background-color:#999999;}
.parent > .child {display:inline-block;vertical-align:top;height:100%;}
Using display:inline-block appears to work like a charm when the text in the second/right div is not enough to fill an entire line. The moment there is more text, however, the second/right div grows as wide as the outer container will let it, forcing it to wrap under the first/right div.
Any insights would be much appreciated!
Using table based markup is not the answer. However, iff you don't need to support IE7 or lower, you can use display:table to solve this. Check out this demonstration i threw together. Edit the amount of content in the second child div to see the effect.
jsfiddle demonstrating display:table
.parent {
display:table;
}
.child {
display:table-cell;
}
Basically, you tell the parent element to act like a table, the two child elements to act like table cells. This gives you the benefits of the table layout without the accessibility problems and extra markup of html tables. As I mentioned though, this doesn't work in IE7. If you need old IE support, you'll have to resort to less graceful workarounds :(
While tables have gotten a bad reputation, this would be a good application for one.
<body>
-Some content-
<table class="parent" style="height:50%;">
<tr>
<td class="child" style="background-color:#FF9999;" width="10">An image</td>
<td class="child" style="background-color:#9999FF;">Some text</td>
</tr>
</table>
</body>
If you set the width to a minimum, it will push your content over even if it's larger, and no matter which column is taller, it will push the overall content box down.
I cannot figure out this positioning problem in Firefox. It doesn't seem to follow the absolute positioning rule. Is there something I'm doing that shouldn't be done, but some browesers handle it and some don't?
JS Fiddle:
Original - http://jsfiddle.net/g9qzh/
Updated - http://jsfiddle.net/g9qzh/2/
Works in IE, Chrome, Safari, Opera
Here's the actual code. Let me know if I'm not following some kind of standard I don't know about.
HTML:
<table>
<tr>
<td>
<div id="three">Three</div>
<div id="two">Two</div>
</td>
<tr>
<tr>
<td>
<div id="three">Three</div>
<div id="two">Two</div>
</td>
<tr>
</table>
CSS:
#two {
position: absolute;
top: 0;
}
td {
position: relative;
}
My only clue is that there is some other value that I should assign to td that would cause it to work. Some other stackoverflow questions have mentioned Firefox misbehaving with this, but I haven't been able to find an answer. I tried assigning both top and left values of zero, but FF won't budge.
Change ID's to classes and also displaying it as blocks fixes it:
http://jsfiddle.net/GchWZ/
It is better and more "proper" to user an inner div though as quoted from this stack overflow post: Does Firefox support position: relative on table elements?
<td>
<div style="position:relative">
This will be positioned normally
<div style="position:absolute; top:5px; left:5px;">
This will be positioned at 5,5 relative to the cell
</div>
</div>
</td>
You are using IDs
IDs are unique. Use Classes if you want to reuse a style assignment.
The problem comes from how FF renders tables. If you set your TDs to display:inline-block; it should display correctly.
Try this:
<tr>
<td>
<div id="wrapper">
<div id="three">Three</div>
<div id="two">Two</div>
</div>
</td>
</tr>
<tr>
<td>
<div id="wrapper">
<div id="three">Three</div>
<div id="two">Two</div>
</div>
</td>
</tr>
and for css:
#two {
position: absolute;
top: 0px;
}
#wrapper {
position: relative;
}
Aside from the duplicate ID issue noted by Brandt, assigning positioning to table cells is dodgy at best - I'm surprised it works in any browsers. If you must use a table, wrap the elements you want to position in a div and assign the wrapper div position: relative:
<table>
<tr>
<td>
<div class="wrapper">
<div id="three">Three</div>
<div id="two">Two</div>
</div>
</td>
<tr>
</table>
CSS
#two {
position: absolute;
top: 0;
}
.wrapper {
position: relative;
}
In case you want to position stuff at the top and bottom of a cell, also in Firefox, I made it work doing the following mix of CSS and (unfortunately) jQuery.
Use a wrapper div (div.inner) inside your td which has position=relative style in the td. Inside the wrapper I added 2 divs which are to be positioned at the top and bottom of the cell.
Positioning at the top (class=interval-start) is for free, via CSS positioning.
Positioning the div.interval-end at the bottom is done via script, which adds the styling shown in the picture. With variable td-heights and the wrapper div being 0-height by default, you need a way to tell the element how far it should go to the bottom. The script is as follows:
$("table .inner .interval-end").each(function () {
$(this).css({top: ($(this).parent().parent().height() - 10) + "px"})
}).show()
I initially made the div.interval-end invisible, set the 'top' style, and then made it visible via jQuery show().
Hope this helps anybody trying to achieve the same. Let me know if there are better methods out there, specially if these methods do not require scripting. BTW: I tried setting the height style of the wrapper div.inner, but it messes with the table layout in Firefox.
There are legitimate reasons to use CSS display: table styling. It eliminates issues that display: block and display: inline-block do not address. These reasons occupy an entire chapter of a book on CSS styling so I won't go into them here. That same book also describes the problem of positioning within items with that display type. CSS 2.1 specs simply don't address the issue and Mozilla has chosen a course that ignores attempts to create a positioning context with those elements. CSS-table positioning is well established, mature methodology, and not "dodgy" - it just takes understanding of its limits - just like any other CSS element. For liquid layouts and other layouts where element size is variable or unknown it's indispensable for vertical spacing and positioning.
One suggestion in this thread has been presented - create a div within the "table-cell" element set to position: relative and use that for the positioning context. The other method is to embed another CSS table within that cell and use it to position elements within a grid. The third method is to wrap your CSS table within another item that creates a positioning context.
I prefer working with CSS based design, but as more of a back end coder my CSS skills are a bit weak. When I get involved with layout, I tend to fall back on table based formatting because my mind has been warped by years of table based abuse. There's one particular problem that I always trip over. What is the best CSS alternative to:
<table width="100%">
<tr>
<td align="center">
content goes here
</td>
</tr>
</table>
I sometimes use:
<div style="width:100%; text-align:center">content</div>
But this doesn't seem quite right. I'm not trying to align text, I'm trying to align content. Also, this seems to have an effect on the text alignment of enclosed elements, which requires tweaking to fix. One thing I don't get is: why isn't there a float:center style? It seems like that would be the best solution. Hopefully, I'm missing something and there is a perfect CSS way to do this.
You are right that text-align is intended for aligning text. It's actually only Internet Explorer that lets you center anything other than text with it. Any other browser handles this correctly and doesn't let block elements be affected by text-align.
To center block elements using css you use margin: 0 auto; just as Joe Philllips suggested. Although you don't need to keep the table at all.
The reason that there is no float: center; is that floating is intended to place elements (typically images) either to the left or the right and have text flow around them. Floating something in the center doesn't make sense in this context as that would mean that the text would have to flow on both sides of the element.
I would recommend putting a <div> into your <td> and setting the style attribute to style="width: 200px; margin: 0 auto;"
The catch is that you must set a fixed width.
Edit:
After looking at the question again, I would recommend scrapping the table entirely. Just use a <div style="width: 200px; margin: 0 auto;> as I suggested and no need for a table.
Here is a good resource for centering using CSS.
http://www.w3.org/Style/Examples/007/center
This demonstrates how to center text, blocks, images and how to center them vertically.
Where do you find yourself commonly doing this? For me - I am most often trying to center the entire design of the site, so I usually do this:
<html>
<body>
<div id="wrapper">
<div id="header">
</div>
<div id="content">
</div>
<div id="footer">
</div>
</div>
</body>
</html>
body {text-align:center;}
#wrapper {margin:0 auto; text-align:left; width:980px;}
This will center the entire design on the page at 980px width, while still leaving all of your text left aligned (as long as that text is within the #wrapper element).
Use display:inline-block to enable text-align:center and center content without a fixed width:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Centering</title>
<style type="text/css">
.container { text-align:center; }
/* Percentage width */
.wrapper { width: 99%; }
/* Use inline-block for wrapper */
.wrapper { display: inline-block; }
/* Use inline for content */
.content { display:inline; }
</style>
</head>
<body>
<div class="container">
<div class="content">
<div class="wrapper">
<div>abc</div>
<div>xyz</div>
</div>
</div>
</div>
</body>
</html>
d03boy's answer is correct for the right way to center things.
To answer your other comment, "Also, this seems to have an effect on the text alignment of enclosed elements, which requires tweaking to fix." That's the nature of how CSS works, setting a property on an element affects all of its children, unless the property is overridden by one of them (assuming the property is one that is inherited, of course).