Complex table, different cells' widths requirements - css

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%; }

Related

Why does the parent DIV resize while there is still room for the child element to move down?

sorry if this question looks duplicate, but those explanations were in some way different from what I was looking for.
I have a DIV that is displayed a table. It has two DIVs as cells which also have their own DIVs inside.
<div class="theTable">
<div class="theRow">
<div class="cell1">
<div class="cell1Content">
cell one content
</div>
</div>
<div class="cell2">
<div class="cell2Content">
cell two content
</div>
</div>
</div>
</div>
Now, when by any means (such as writing, or changing attributes), I enlarge the content of one of these cells (say cell2) instead of the content being enlarged from downward, and filling the area of the parent DIV (which is a cell), what happens is that the parent DIV actually expands from top. This behavior is not desired. I want the parent DIV to stay the same size, and the content to resize from bottom (downward).
I know this can be achieved using, position:relative, top:2em, but that's not what I am intending to do, because I do not want to disrupt the flow of the document, rather a simple answer as to how to get round this problem.
As in the case above, the CSS file is like this:
.theTable {display:table}
.theRow {display:table-row;}
.cell1 {display:table-cell}
.cell2 {display:table-cell}
.cell1Content {display:block; height:10em; background:blue;}
.cell2Content {display:block; background:yellow; height:5em; margin-top:2em;}
If you change the last line (margin-top:0em) you'll see, it is not only the child that is changing size, but also the parent. I don't understand why? And what can be done about it?
So what you want is that the cells start from bottom to grow upwards right?
Something like this could solve it:
http://jsfiddle.net/7y19n8eh/
.theTable {display:table}
.theRow {display:table-row;}
.cell1 {display:table-cell;vertical-align: bottom}
.cell2 {display:table-cell;vertical-align: bottom}
.cell1Content {display:block; height:10em; background:blue;}
.cell2Content {display:block; background:yellow; height:5em; margin-top:2em;}
What I did was to add vertical-align:bottom to the cells.
The vertical-align property sets the vertical alignment of an element and is compatible with all major browsers.

Full width div for all screen resolution

I've been working with a html page that has a form in the bottom of the page. That form is inside a table and table is inside a div. Fiddle here : http://jsfiddle.net/2ZTvQ/
Problem is on smaller screen the div is taking 100% width(full width of the screen) but not width of the whole table containing the form. I'm not an expert with html/css so I'm not even sure if it can be done this way.
Sample HTML:
<div class='wide'>
<table width="100%">
<tr>
<td>
looooooooooooooo ooooooooooo00000 ooooooong text goes here
</td>
</tr>
</table>
</div>
CSS:
.wide {
text-align:center;
background:#e7e7e4;
width: 100%;
padding-top:20px;
}
Remove text-align:center; or create a new aligning style for the table.
What I think you will have to do is add a min-width to .wide of however small the table will get after manually trying to reduce it's width. So once it is as small as you can get it (use media queries to change classes under a certain window width) set
.wide { min-width: thatSize; }
What will happen now is instead of the content disappearing or running out of the div, you will now just have to scroll horizontally to see it all.
Or what you can do is add
.wide { overflow: scroll; }
What that will do is keep the viewport the same size, but make the content inside .wide scrollable like an iframe. Probably better looking than the first solution. Whatever you decide is a design choice on your part. But most important thing would be using media queries and trying to get the form as thin as possible. Display block and percentage widths are your friends there.

Expand parent div height to childs

I have a problem with footer positioning. It doesn't go to the bottom/last.
So, I have a container div which has 3 divs - float:right , float:left and the center one (which has position:absolute) that comes between the two floated divs.
The center one must have fixed width and height because it's an image.
In that center div I have another div with a lot of content.
The problem is, because the center div has fixed width and height, it doesn't take the childs div height.
So my problem is how to put the footer that it comes last (after the container)?
Note - with JQuery I put the width of the floated divs because they take 100%-980px width.
This is how it looks like.
I tried putting to the center div overflow:auto,overflow:overlay,margin-left:auto;margin-right:auto;.
After reading your question again an again i come to conclusion and create the below fiddle using your code and embed a sample image for you desired size.
Please let me know if i am wrong while understanding your question. So i can work around according your needs.
fiddle: http://jsfiddle.net/ah3nr/6
Demo: http://jsfiddle.net/ah3nr/6/embedded/result/
My approach:
I have remove the position:absolute from center div and added new div for image and relate them both using css layer techniques.
Updated css:
.sectionDownContainer {
width: 980px;
/*height:270px;*/
border:1px solid red;
/*position: absolute;*/
position:relative;
top: -32px;
z-index: 1;
}
/*.sectionDownMenu {
margin-left: 50px;
margin-top: 1px;
display: block;
}
*/
#image_container {
position:relative;
width:980px;
height: 270px;
margin-top:-2px;
z-index:2;
}
.sectionDownContent {
width: 640px;
margin-top: -190px;
margin-left: 50px;
position: relative;
z-index:5;
color:#000;
font-weight:bold;
}
Screenshot:
Try this for the parent.
overflow:auto;
Also refer to this stack overflow post: Expanding a parent <div> to the height of its children
You need to set this property of the center-div: height:auto (you could also add a minimum height: min-height:400)
About your second question with the footer, this is much more complicated. You must do this:
<div id="content">
<div id="content_left">
</div>
<div id="content_center">
</div>
<div id="content_right">
</div>
<div id="footer">
</div>
</div>
I'll give you now the full CSS (because it's not so easy):
.content {position:relative; overflow:hidden;} //hidden overflow just a hack for common issues...
.content_left {height:auto; float:left} //set height to auto (very important)
.content_center {height:300; float:left} //a fixed height also works!
.content_right {height:auto; float:right}
.content_footer {width:100%; height:auto; float:right} //for tests you can also set a fixed height
This solution is also according to other threads on Stackoverflow: Align DIV's to bottom or baseline, How to align content of a div to the bottom?
But, if you experience problems with that, you may do this (my preferred solution):
<div id="content">
<div id="content_left">
</div>
<div id="content_center">
</div>
<div id="content_right">
</div>
</div>
<div id="footer">
</div>
And its CSS:
.content {position:relative; overflow:hidden;} //hidden overflow is just a hack
.content_left {height:auto; float:left} //set height to auto (very important)
.content_center {height:300; float:left} //a fixed height also works!
.content_right {height:auto; float:right}
.content_footer {width:100%; height:xxx; float:left} //you can use any height...
Note that all above solutions works only if you set all the "contents" to float, it doesn't work with absolute values! I found this here: http://wiki.answers.com/Q/How_can_a_parent_DIV_wrap_around_child_DIVs_which_are_floating_left_or_right
This is due to an issue with divs: It's not possible to "tell" a parent div the size! So childs like "content_center" or "content_right" won't tell the "content" how long they are and how long "content" must be. So it's impossible to tell the footer where to align, if you use absolute values for the childs.
So your second question, although it looks trivial, is a very important question, and not easy to solve.
IMPORTANT UPDATE:
I tried to find a solution with absolute now. The problem is, that absolute and fixed are taken out of the regular (text)flow, so their size can't influence the size/positioning of any other element anymore. But we also have to understand that an absolute element still controls all its childs, so we should rather set the childs as relative than the parent (here: "content")! So I finally found the solution, and it's quite weird, because it's almost the opposite thing I suggested above, but that solution was influenced by the posting of others, while following solution is "my own" one (I added a header for demonstration purpose):
<div id="header">
</div>
<div id="content">
<div id="content_left">
</div>
<div id="content_center">
</div>
<div id="content_right">
</div>
<div id="footer">
</div>
</div>
The CSS (the "header" clearly shows, that "content" inherites all positioning to its childs like "content_left", "content_right", aso.):
.header {position:absolute; left:0; top:0; height:100; width:100%}
.content {position:absolute; left:0; top:100; height:auto; min-width:700} //min-width is only voluntary, but quite useful
.content_left {position:relative; left:0; top:0; width:200; height:auto;} //height:auto is important to adapt the height from containing text!
.content_center {position:relative; left:200; top:0; right:200; width:auto; height:auto;} //in the middle element, also auto-width is important!
.content_right {position:fixed; right:0; top:0; width:200; height:1000;} //we set a fixed position, but that won't influence the footer anymore!
.content_footer {margin:0 0 60 0; position:relative; left:0; bottom:-60; width:100%; height:150;} //a fixed height is also okey...but relative position is needed!
//you still need to add margin:0; border:0; padding:0 or similar values for some elements to get a good layout
The important point here is, that you can decide which child element will be the longest one, and set this element's position:relative, while the other may have absolute or fixed. But if you don't know which element will be the longest, all child's positions need to be set as relative. Anyway, I suggest to set all childs to relative (beside fixed if needed), because their parent "content" will set their absolute height-position already correctly, so there's no need for any absolute at all.
I'm repeating myself: Above I wrote it's not possible to tell a parent div the size...actually it's possible, but not if the values absolute and fixed are used. Only if you use the browser standart value (static) or relative, the parent div will be informed about the size of its childs, an therefore the footer is set correctly at the bottom of the page.
Well, my solution works everywhere...even in IE (tested 6.0 and 8.0!) due to the hack margin:0 0 60 0 where the value 60 should be the positive value of bottom:-60. Now we finally got the non-floating crossbrower-solution. ;)
The problem you're experiencing is that certain CSS properties cause elements to be "removed from the flow" of the document (see the W3C Visual formatting model). Parent elements naturally grow to fit the height of children elements, however, floated and absolutely positioned elements are removed from the document flow. As mentioned in a few comments, setting overflow: auto; or overflow: hidden; on the parent element re-establishes a bounding box around floated elements. This means you can float elements within the parent container, then set overflow: hidden; on the parent element, and the parent element will contain the floats. However, this doesn't work for absolutely positioned elements: the absolutely positioned box is "removed from the normal flow entirely (it has no impact on later siblings)". The only exception is that the entire document will try and grow to display any positioned elements (give an element position: absolute; top: 3000em; and the page scrollbar will grow to allow you to scroll to that element). I don't know of any way to trigger this for elements other than the document.
Back to your intended effect… If you don't need IE7 support, you can use display: table; table-layout: fixed; to achieve a centered column with a fixed width and two columns of variable width on either side.
jsFiddle Demo
In the near future, this will also be possible using the CSS "flexbox" properties. Flexbox will allow for some nifty new features, including horizontal and vertical centering, changing the order of rendered elements, and setting "flex" values for how much of the remaining variable width an element should take. However, the standard is currently going through a period of flux, and the old standard (enjoying moderate support) is being replaced by a new standard (with little to no support). See "Old" Flexbox and "New" Flexbox and the accompanying demo. Considering the glacially slow progress of web standards implementation, I don't expect to see this in use for a few years unless a truly masterful polyfill is produced.

100% width div for browser width

I am trying to add two divs inside the parent div, which has a button inside each div.
I need to fix the width in pixels only for the second div and the 1st div should be having width in % so that the button inside the 1st div should be covering the entire space of the browser.
I need all the widths in % and also I don't want to change either html structure and css because it is already implemented so i just need changes in css property.
Here is my demo
http://jsfiddle.net/zuyyT/2/
P.S : When I scale the browser, the second div is coming in next line. Please scale it and check once.
Fiddle is working on and off ... you can go either one of two ways; using floats (need to change the order of your markup) or positioning - like such ...
<div class="block">
<div class="block_right"> <span>last button</span> </div>
<div class="block_left"><a href="" class="scButton score" > <span>Lorem ipsum</span></a></div>
</div>
and your CSS ...
.block {
display:block; background-color:#FFC; width:100%; float:left; height:30px
}
.block_left{
background-color:#C93; margin-right: 150px;
}
.block_left a{
background-color:#CCC; border-radius:4px; padding:4px; width:100%; display:block
}
.block_right{
float:right; width:130px; background-color:#CC9
}
... using position, you'll need to add position:relative to .block and then right:0 to .block_right; keep the margin on .block_left
Using positioning, you won't need to change the order of the elements in your markup (should that be an issue).
This may be what you require. :-)
.block_right{
position :absolute;
right:0;
top:0;
float:right; width:130px; background-color:#CC9
}
If you give your block_left a width:100% and then use margin-right:-130px; you can leave your html exactly as it is.
The negative right margin leaves space on the right hand side for other elements to fit into even though the element has a 100% width.
This is happening because of the width of right div..u gave 100% to the parent and 80% to the first child..so,when the browser size is 500px(say),the first child will occupy 400px(80%) of it...And when u give 130 px to the second child,it'll come to the next line..that's pretty obvious coz it doesn't have enough space in the first line...so it should be <=100px(for this example)...

Is it possible to stop a slightly-too-big inline image (e.g a smiley) from affecting the line height of the block of text it's in?

So the problem is when you have a block of text, and an image that is slightly too tall that you want to place in-line with the text. For example, a smiley. It will cause the line height of that line of the paragraph to grow, making the block of text look ugly.
I've actually already come up with a solution, but it's messy and I don't like it... If I wrap the smiley in a relatively-positioned div, and give it an absolute position I get the effect that I'm after:
.holder{display:inline-block;position:relative;width:16px}
.holder img{position:absolute;top:-16px}
<span class="holder"><img src="/smiley.gif" height="16" width="16"></span>
But it adds extra markup. Is there any way to achieve this without adding extra HTML elements - a pure CSS solution (no javascript!)
I wonder if I'm missing some application of overflow/vertical-align/float/display etc?
Many thanks!
Depending on the desired image position and whether you have a fixed line-height in pixels you could set a maximum height on your image that equals your line-height and set vertical-align: bottom on the image so it fits exactly into your line.
See this fiddle for an example.
p {
line-height: 18px;
}
p img {
max-height: 18px;
vertical-align: bottom;
}
<p>Some text <img src="/smiley.gif"> more text.</p>
Set the image as a background of a DIV and give the DIV fixed dimensions.
<div class="smiley"></div>
CSS:
.smiley {
float:right; <-- or inline-block if you want.
background-image:url(../smiley.gif);
height:20px;
width:20px;
}

Resources