What I'm looking for is to have a container div with any number of headers and footers which would then have another scrolling div in between the various headers/footers. The catch is here that the headers and footers can't scroll and the container/headers/footers can take any height depending on their content.
I've only been able to get this working with a statically sized header/footer. In the code I've added the problem I've come across: the text in the header/footer may wrap, which will bring it to two lines. So the header should grow to allow this extra line and the content should shrink to give space to the header. Is there any way to do this without using javascript? I will know the number of headers/footers ahead of time if that helps.
This is going to be a component in a page possibly with one or more per page, for example in a 2x2 setup where each takes up a 4th of the browser window. The functionality is mainly needed as the width of the browser might change causing the header content to break a new line. This could be done pretty easily with javascript but I've always heard that resize event handlers are evil.
For example if my wrapper is 600px high, I may have 2 headers and 1 footer. Lets say the first header's content causes it to break to a new line, but the second header's doesn't. So the first headers height is 20px where the second's is 10px. And lets say the footer's content also causes a line break and thus has 20px height. This gives us 50px worth of headers and footers so now the height of the scroller should be 550px.
Ascii Art:
____________________________________________
| HEADER 1 |
|________breaks to new line__________________|
|____________________________HEADER2_________|
| | ||
| | ||
| This is my scroller | ||
| | ||
| | ||
| | ||
|_________________________________________|_||
| Some |
|_____Footer_________________________________|
HTML:
<div class="wrapper">
<div class="header">
Some<br/>
Header
</div>
<div class="scroller">
Content<br />
Content<br />
Content<br />
Content<br />
...
</div>
<div class="footer">
Some<br/>
Footer
</div>
</div>
CSS:
body{
height:100%;
}
.wrapper{
height:400px;
border-left:1px solid red;
}
.header, .footer{
background-color: #EEE;
height:27px;
}
.scroller{
height:calc(100% - 54px);
background-color: #CCC;
overflow:auto;
}
the red border is to show how far the wrapper goes down, so the footer doesn't show up below. I did this instead of overflow: hidden simply for debugging.
http://jsfiddle.net/yKTdz/4/
Achieved with pure CSS
(not even CSS3), by mixing table display with relative and absolute positioning.
Running Demo: http://jsfiddle.net/x4vhW/
HTML
<div class="wrapper">
<div class="tr stretch">
<div class="td">a header</div>
</div>
<div class="tr">
<div class="td">
<div class="contentWrapper">
<div class="content">
content 0
...............
...............
...............
content 29
</div>
</div>
</div>
</div>
<div class="tr stretch">
<div class="td stretch">a footer</div>
</div>
</div>
CSS Dark Magic(tm)
.wrapper {
height : 200px;
width : 200px;
display : table;
}
.tr { display : table-row; }
.td { display : table-cell; }
.stretch { height : 1%; }
.contentWrapper {
position : relative;
overflow-y : scroll;
height : 100%;
}
.content {
position : absolute;
right : 0;
left : 0;
}
Note: the stretch class is used in order to prevent headers and footers to grow if content has a small content; with stretch, they will auto-fit.
And finally, according to CanIUse, it is supported by almost all browsers, including IE8.
Building on DMoses answer, this solution involves just a bit more jquery, but it removes the issue of the scrollbar being slightly hidden by the footer/header
the jQuery:
$(document).ready(function(){
$('.scroller').css("margin-top", $('.header').height());
var height = $('.wrapper').height() - ($('.footer').height() + $('.header').height());
$('.scroller').css("height", height);
});
jsfiddle.net/XSADu/5/
I took Matt Cooper's solution and updated it a bit. This resolves the inability to add more than one widget to a page, and also the footer sizing issue.
http://jsfiddle.net/XSADu/10/
Steps:
Make the wrapper relative so that absolute children can be position
Make header,footer,scroller absolute. Position the footer at the bottom
Add javascript to size the scroller top/bottom.
CSS
.wrapper{
height:400px;
border-left:1px solid red;
position: relative;
}
.header, .footer, .scroller {
background-color: #EEE;
position:absolute;
width: 100%;
}
.footer {
bottom: 0;
}
.scroller{
background-color: #CCC;
overflow:auto;
}
JS
$(document).ready(function(){
$('.scroller').css("top", $('.header').height());
$('.scroller').css("bottom", $('.footer').height());
});
NOTE: If the header/footer sizing are dynamic, you may want to give them some max heights as a percentage of the wrapper, so that the content isn't hidden.
This can now be done using CSS grids pretty easily. without the need of an filler elements even.
If you want multiple headers, simply put a few divs in there, or make the "header" div a flexbox if that's what you want.
HTML stays the same:
<div class="wrapper">
<div class="header">
Some<br/>
Header
</div>
<div class="scroller">
Content<br />
Content<br />
Content<br />
Content<br />
...
</div>
<div class="footer">
Some<br/>
Footer
</div>
</div>
CSS:
.wrapper{
height:400px;
border-left:1px solid red;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: [header] auto [content]1fr [footer]auto;
}
.header{
background-color: #EEE;
grid-row: header;
}
.footer{
background-color: #EEE;
grid-row: footer;
}
.scroller{
background-color: #CCC;
overflow:auto;
grid-row: content
}
http://jsfiddle.net/yKTdz/15/
There's no way to do this with just Css, You'd need to use Javascript to check the height of the header and footer when the page loads and adjust things accordingly. Otherwise when you use position:fixed you'll get some overlap. See the Attached fiddle! http://jsfiddle.net/XSADu/
I use jQuery to adapt the padding-top on the scroller on document ready. like so
$(document).ready(function(){
$('.scroller').css("padding-top", $('.header').height());
});
As stated by Matt Cooper, I don't think there's a css pure solution. Here's my attempt: jsfiddle
var CalcHeight = function() {
this.init = function() {
var totHeight = $('body').height();
var componentsHeight = $('.headers').height() + $('.footers').height();
var diff = totHeight - componentsHeight;
$('.hider').css({
height: diff
});
}
this.init();
}
var calcHeight = new CalcHeight;
Related
I've really hit the wall on this one and need some help. I'm trying to create a two column layout with both widths and heights adjusted to the contents of the left column. It seems to be a rather basic layout, but I'm starting to think it can't be done (without resorting to JS).
This fiddle describes what I'm trying to do. It's a container DIV with two DIVs inside, aligned horizontally. The left inner DIV should adjust its size (both width and height) to its content. The right inner DIV (which contains a Google Map) should have the same height as the left one while filling up the remaining width of the container.
<div id="container">
<div id="left">
This DIV should adjust<br/>
both its width and height<br/>
to its content, not taking up<br/>
more space than needed!<br/>
<br/><br/><br/>
More content here...
</div>
<div id="right">
Google Map here.
</div>
</div>
I've tried everything I know and all tricks I've found, but no success!
#container {
background-color: #EEE;
overflow: hidden;
}
#container div {
border: 1px solid black;
padding: 5px;
}
#left {
background-color: lightblue;
display: inline-block;
float: left;
}
#right {
background-color: lightgreen;
height: 100%; /* THIS IS WHAT I WANT, BUT IT WON'T WORK, OF COURSE */
overflow: hidden;
}
I've found many similar questions, but in all those cases the left DIV/column had a fixed width, which makes it a whole lot easier.
Any input is much appreciated, especially if it works in IE9+ (and modern browsers)!
Edit
Some clarification. The purpose of the right column is to hold a Google map and consequently the map is supposed to fill up the entire DIV. Try setting a fixed height (e.g. 100px) for #right in the fiddle that I link to above and you will see the map showing up.
jsfiddle demo
css :
.container {
overflow: hidden;
background-color: #EEE;
}
.column {
float: left;
background-color: grey;
padding-bottom: 1000px;
margin-bottom: -1000px;
}
p {
padding: 10px;
margin-top: 10px;
width: 50%;
}
html
<script src="//maps.googleapis.com/maps/api/js?sensor=false"></script>
<div class="container">
<div class="column">
This DIV should adjust<br/>
both its width and height<br/>
to its content, not taking up<br/>
more space than needed!<br/>
<br/><br/><br/>
More content here...
</div>
<div class="column">
<div id="map"></div>
</div>
</div>
<p>
The right DIV (which contains a Google Map)
should be the same height as the left DIV,
while filling up the remaining width.
</p>
<p>How to do that?</p>
Here what I came up with -> link
When you remove the overflow property of your #right div it stretches as expected. However in this case you won't be able to hide the overflowed content.
CSS
#right {
background-color: lightgreen;
height: 100%; /* THIS WON'T WORK */ // height works as expected
}
So. My code is something along the lines of
<html>
<body>
<div id="header" style="width:100%;min-height:0;display:block;background-color:#000">
<img src="header_image.svg" />
</div>
<div id="content" style"display:block">
Some content
</div>
</body>
</html>
I have an svg in the header that I have set so that it matches the width of the window and the height scales to preserve the svg. Then I have the rest of the page in another div. I would like it so that the page doesn't scroll and this content div fills to fit the rest of the window. The problem is that since the height of the header changes with the width of the window, I can't set the content div in pixels or percentage or anything concrete.
How can I set the height of the content div to change dynamically with the height of the header?
I don't know Javascript or JQuery (I know, I know - I should), but ideally the height of the content div would be set to be something like height:(height of viewport)-(height of header), but I haven't a clue how to do this.
you don't have to use a script for that.
and also: I recommend you to separate your styling from your markup.
HTML
<div id="wrapper">
<div id="header">
<img src="header_image.svg" alt="the img is empty"/>
</div>
<div id="content">Some content</div>
</div>
add this to your CSS
html, body {
height: 100%;
margin: 0px;
}
/* this is the big trick*/
#wrapper:before {
content:'';
float: left;
height: 100%;
}
#wrapper {
height: 100%;
background-color: black;
color: white;
}
#header {
background-color:#000;
}
#content {
background-color: gray;
}
/* this is the big trick*/
#content:after {
content:'';
display: block;
clear: both;
}
Working Fiddle
Tested on: IE10, IE9, IE8, FF, Chrome.
didn't use absolute positioning
didn't use Script (Pure CSS solution)
fluid layout
cross-browser
Explanation:
with pseudo element, I'm creating a floating element (without content or width, so he's invisible)
that has 100% of the container height.
and with another pseudo element I'm creating a div just after the content div. (also without content, so he's also invisible) that has the clear attribute. so he has to be below the floated one I've created earlier. making the content to go all the way down.
Please, consider the following jsFiddle - http://jsfiddle.net/mark69_fnd/hwCuB/ (you can find the code after the body of the question).
It represents a trivial example of the classic header, content, footer HTML layout. Notice that:
The content never overlaps with the footer. Resizing the window will finally create a vertical scrollbar rather than move the content over the footer.
There are no redundant scrollbars.
No absolute heights, except of the footer, which may be assumed to be no higher than 2em.
The content height is less than the available height between the header and the footer.
I would like to keep the first three properties, but change the last one, so that the content height is the full height between the header and the footer. And I would like to do so without resorting to javascript.
How can I do so, if at all?
EDIT
The given html and css are just an example. You are free to change them as long as the final result satisfies the conditions of my question.
EDIT2
Apparently, I am not very clear on what I want to achieve with the content. Here is what I have now:
Notice how the content does not extend the full height available to it between the header and the footer.
What I am after is this:
(edited in mspaint, I do not know to do it really)
EDIT3
Added an except clause to the 3rd condition:
except of the footer, which may be assumed to be no higher than 2em.
HTML:
<html>
<head>
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/3.7.3/build/cssreset/reset-min.css">
</head>
<body>
<div class="container">
<div class="header">
Header goes here.
</div>
<div class="content">
<div class="innerWrapper">
Content goes here.
</div>
</div>
<div class="footer">
<div class="status">
Footer goes here.
<div>
</div>
</div>
</body>
</html>
CSS:
html, body {
height: 100%;
width: 100%;
}
.container {
position: relative; /* needed for footer positioning*/
margin: 0 auto;
height: auto;
min-height: 100%;
background-color: #ddd;
}
.content {
padding: 0em 0em 2em; /* bottom padding for footer */
background-color: #bbb;
}
.footer {
position: absolute;
width: 100%;
bottom: 0; /* stick to bottom */
}
.status, .header {
background-color: #999;
border: solid 1px #000000;
}
There might be couple ways to do this, but the only ways i can think of at the moment all involve setting/knowing the height of your header and footer.
Here is one using display:table http://jsfiddle.net/fLnkf/
There may be other solutions depending on if your requirements allow you to change your html or use CSS3.
hope this helps!
I have a column of text, with wide margins on either side. Below it, I have a full-width section of data (in tabular format).
I can align these against each other quite readily. My problem is that there is a 'tab' that sits on top of the table section. It's narrow enough that it doesn't interfere with the center column of text, and the layout calls for it to slide up into the white space to the left of the text.
The easy solution would a position:absolute, with top:foopx to slide it up relative to the rest of the div. The only problem is, the tab's height is dynamic. I need to somehow to top:'height'px, but (obviously) CSS doesn't contain anything for dynamic values.
What I need to do is align the bottom edge of the 'tab' against the top edge of the containing div, and I cannot for the life of me figure out any CSS statement that does that. I'd rather avoid a javascript based approach (e. g. at runtime get the height of the tab, then set top equal to that height) because the entire bottom div is refreshed from time to time using an AJAX call, and adjusting the height in that process causes the page to 'jitter' on the update (not sure why it doesn't happen without the height update; the jitter is in a separate section of the code).
Requested code example:
<html>
<head>
<style>
#smallColumn
{
float:left;
width:100px;
height:100px;
background:#000;
margin:5px;
}
#fullColumn
{
float:left;
width:200px;
height:300px;
background:#000;
margin:5px;
}
#bottomDiv
{
position:relative;
}
#tab
{
position:absolute;
top:-40px;
}
</style>
</head>
<body>
<div id="smallColumn">a</div>
<div id="fullColumn">b</div>
<div style="clear:both"></div>
<div id="bottomDiv">
<div id="tab">Tab</div>
<hr />
DATA DATA DATA
</div>
</body>
</html>
Use top margins, the appropriate display properties and vertical-align:bottom. See the code below + comments for an explanation. You have to set a height and negative margin-top value which is larger than the actual height of the tab's content. Otherwise, the content may jump back to the top.
Relevant HTML/CSS:
<div id="cont">
<div id="tab">
<div id="tab-fix">
Tab
</div>
</div>
Rest of content
</div>
#cont {
margin-top: 30px; /*Reserve space*/
height: 100px;
background: lightgreen;
}
#tab {
display: table; /* Necessary for the application */
margin-top: -30px;/* Move tab to the top*/
}
#tab-fix {
height: 30px; /* Expecting the height to not exceed 30px*/
display: table-cell;
vertical-align: bottom; /* Aligns the content at the bottom*/
}
Fiddle: http://jsfiddle.net/stEW3/2/
Update2
So this is a tough problem to solve! The only thing I could think of was to put a wrapper around the tab. That wrapper needs to be relatively positioned and have a height equal to that of the tab. Then you can use absolute and negative top of 100%.
http://jsfiddle.net/mrtsherman/BC8Xr/2/
Update
With posted code I now understand. How about using absolute and specifying a bottom value of 0?
http://jsfiddle.net/mrtsherman/BC8Xr/
<div id="content">
<div id="smallColumn">a</div>
<div id="fullColumn">b</div>
<div style="clear:both"></div>
<div id="bottomDiv">
<div id="tab">Something</div>
<hr />
</div>
</div>
#content { border: 1px solid red; position: relative; }
#bottomDiv
{
position:absolute;
bottom: 0px;
}
#tab
{
/*
position:absolute;
top:-40px;
*/
}
Old
Without html structure and a somewhat vague description this is a bit hard to decipher. But this is what I think you mean:
http://jsfiddle.net/mrtsherman/VM99L/
Basically you want the tab above the tabular data to be drawn up into the div before it. You can use a negative top margin for this. Just set it to the same height as the height of your tab. If you have padding on the div then you will need to compensate for that also.
<div id="tabulardata">
<div id="tab">Tab X</div>
<table>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
</table>
</div>
#tabulardata { margin-top: -50px; }
#tab { height: 50px; width: 80px; background: gray; color: white; }
im trying to get some background images around a content div. Thing is, the content div should have a flexible width (no problem). The background pics should always be left and right attached to the content div. BUT: the horizontal scrollbar should only be triggered, when the user reduces the window to the width of the content div.
Picture: Structure
I came up with something like this:
<div>
<div class="header">/div>
<div class="wrapper">
<div class="left"></div>
<div class="right"></div>
<div class="content">Content</div>
</div>
<div class="footer">/div>
</div>
.wrapper{
margin:auto;
width:950px;
position:relative;
}
.left {
background:transparent url(../images/left.png) no-repeat scroll 0 0;
position:absolute;
top:0;
left:-120px;
width:120px;
height:500px;
}
.right {
background:transparent url(../images/right.png) no-repeat scroll 0 0;
position:absolute;
top:0;
right:-120px;
width:120px;
height:500px;
}
Scrollbars always appear when window hits the right absolute div. I need them to be two divs (left/right) because the content div should be flexible and not hide the background when it extends to much.
Someone got a tecnique for this?
you have an unnamed plain root container div.
Add this style for that div (or give a class/id name to wire css deceleration).
Main point is min-width... Keep it same with your container div's width.
also adding body,html{margin:0;padding:0;} will be nicer.
style="width:100%;overflow:hidden;min-width:950px;position:relative; height:100px;"
this will work fine exept for ie6.
For ie, you can apply some js magic.
Let's assume you're using jquery library and you gave id name "shell" to your root container div.
Then try this script only for ie6. (create exclusion or something like that):
$(document).ready(function(){
$('#shell').each(function(){
var that = this;
var contentWidth = 950;
check();
$(window).resize(check);
function check() {
var winWidth = Math.ceil($('body').width());
if(winWidth <= contentWidth) {
$(that).css({'width':contentWidth});
} else {
$(that).css({'width':'100%'});
}
}
});
});
This script will make "shell"s width 100%. (if browser's width is larger than 950px) otherwise it'll lock shell's width with 950px and that will enable scrollbar.
I did something similar for a website, the solution I came with was this:
I created an image with the left and right content on the background and the space of the content in the middle to just be a solid color, even though the image is 1400 x 539 it weights 12 KB, so it's pretty good.
<html>
<body>
<div id="wrapper"></div>
</body>
</html>
body {
background: #fff url(left-and-right.jpg) no-repeat center top;
text-align: center;
}
#wrapper {
margin: auto;
text-align: left;
width: 960px;
}