2015 update: the flexbox approach
There are two other answers briefly mentioning flexbox; however, that was more than two years ago, and they don't provide any examples. The specification for flexbox has definitely settled now.
Note: Though CSS Flexible Boxes Layout specification is at the Candidate Recommendation stage, not all browsers have implemented it. WebKit implementation must be prefixed with -webkit-; Internet Explorer implements an old version of the spec, prefixed with -ms-; Opera 12.10 implements the latest version of the spec, unprefixed. See the compatibility table on each property for an up-to-date compatibility status.
(taken from https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes)
All major browsers and IE11+ support Flexbox. For IE 10 or older, you can use the FlexieJS shim.
To check current support you can also see here:
http://caniuse.com/#feat=flexbox
Working example
With flexbox you can easily switch between any of your rows or columns either having fixed dimensions, content-sized dimensions or remaining-space dimensions. In my example I have set the header to snap to its content (as per the OPs question), I've added a footer to show how to add a fixed-height region and then set the content area to fill up the remaining space.
html,
body {
height: 100%;
margin: 0;
}
.box {
display: flex;
flex-flow: column;
height: 100%;
}
.box .row {
border: 1px dotted grey;
}
.box .row.header {
flex: 0 1 auto;
/* The above is shorthand for:
flex-grow: 0,
flex-shrink: 1,
flex-basis: auto
*/
}
.box .row.content {
flex: 1 1 auto;
}
.box .row.footer {
flex: 0 1 40px;
}
<!-- Obviously, you could use HTML5 tags like `header`, `footer` and `section` -->
<div class="box">
<div class="row header">
<p><b>header</b>
<br />
<br />(sized to content)</p>
</div>
<div class="row content">
<p>
<b>content</b>
(fills remaining space)
</p>
</div>
<div class="row footer">
<p><b>footer</b> (fixed height)</p>
</div>
</div>
In the CSS above, the flex property shorthands the flex-grow, flex-shrink, and flex-basis properties to establish the flexibility of the flex items. Mozilla has a good introduction to the flexible boxes model.
Modern HTML5 Techniques for changing classes
Modern browsers have added classList which provides methods to make it easier to manipulate classes without needing a library:
document.getElementById("MyElement").classList.add('MyClass');
document.getElementById("MyElement").classList.remove('MyClass');
if ( document.getElementById("MyElement").classList.contains('MyClass') )
document.getElementById("MyElement").classList.toggle('MyClass');
Unfortunately, these do not work in Internet Explorer prior to v10, though there is a shim to add support for it to IE8 and IE9, available from this page. It is, though, getting more and more supported.
Simple cross-browser solution
The standard JavaScript way to select an element is using document.getElementById("Id")
, which is what the following examples use - you can of course obtain elements in other ways, and in the right situation may simply use this
instead - however, going into detail on this is beyond the scope of the answer.
To change all classes for an element:
To replace all existing classes with one or more new classes, set the className attribute:
document.getElementById("MyElement").className = "MyClass";
(You can use a space-delimited list to apply multiple classes.)
To add an additional class to an element:
To add a class to an element, without removing/affecting existing values, append a space and the new classname, like so:
document.getElementById("MyElement").className += " MyClass";
To remove a class from an element:
To remove a single class to an element, without affecting other potential classes, a simple regex replace is required:
document.getElementById("MyElement").className =
document.getElementById("MyElement").className.replace
( /(?:^|\s)MyClass(?!\S)/g , '' )
/* Code wrapped for readability - above is all one statement */
An explanation of this regex is as follows:
(?:^|\s) # Match the start of the string or any single whitespace character
MyClass # The literal text for the classname to remove
(?!\S) # Negative lookahead to verify the above is the whole classname
# Ensures there is no non-space character following
# (i.e. must be the end of the string or space)
The g
flag tells the replace to repeat as required, in case the class name has been added multiple times.
To check if a class is already applied to an element:
The same regex used above for removing a class can also be used as a check as to whether a particular class exists:
if ( document.getElementById("MyElement").className.match(/(?:^|\s)MyClass(?!\S)/) )
### Assigning these actions to onclick events:
Whilst it is possible to write JavaScript directly inside the HTML event attributes (such as onclick="this.className+=' MyClass'"
) this is not recommended behaviour. Especially on larger applications, more maintainable code is achieved by separating HTML markup from JavaScript interaction logic.
The first step to achieving this is by creating a function, and calling the function in the onclick attribute, for example:
<script type="text/javascript">
function changeClass(){
// Code examples from above
}
</script>
...
<button onclick="changeClass()">My Button</button>
(It is not required to have this code in script tags, this is simply for the brevity of example, and including the JavaScript in a distinct file may be more appropriate.)
The second step is to move the onclick event out of the HTML and into JavaScript, for example using addEventListener
<script type="text/javascript">
function changeClass(){
// Code examples from above
}
window.onload = function(){
document.getElementById("MyElement").addEventListener( 'click', changeClass);
}
</script>
...
<button id="MyElement">My Button</button>
(Note that the window.onload part is required so that the contents of that function are executed after the HTML has finished loading - without this, the MyElement might not exist when the JavaScript code is called, so that line would fail.)
JavaScript Frameworks and Libraries
The above code is all in standard JavaScript, however, it is common practice to use either a framework or a library to simplify common tasks, as well as benefit from fixed bugs and edge cases that you might not think of when writing your code.
Whilst some people consider it overkill to add a ~50 KB framework for simply changing a class, if you are doing any substantial amount of JavaScript work or anything that might have unusual cross-browser behavior, it is well worth considering.
(Very roughly, a library is a set of tools designed for a specific task, whilst a framework generally contains multiple libraries and performs a complete set of duties.)
The examples above have been reproduced below using jQuery, probably the most commonly used JavaScript library (though there are others worth investigating too).
(Note that $
here is the jQuery object.)
Changing Classes with jQuery:
$('#MyElement').addClass('MyClass');
$('#MyElement').removeClass('MyClass');
if ( $('#MyElement').hasClass('MyClass') )
In addition, jQuery provides a shortcut for adding a class if it doesn't apply, or removing a class that does:
$('#MyElement').toggleClass('MyClass');
### Assigning a function to a click event with jQuery:
$('#MyElement').click(changeClass);
or, without needing an id:
$(':button:contains(My Button)').click(changeClass);
Best Answer
I still don't know what you are actually trying to achieve. Going by your fiddle sample, it would have been much easier to just use a solid border around the inner diver to get a red surrounding (instead of another div with background color and padding). But if you just don't want that the text oveflows the
div
, you have to allow thediv
to resize:http://jsfiddle.net/JQ7fr/1/
Update
I think see your problem now. What you are trying to do is not possible the way you are trying to do it. You are falling for a fundamental misconception of the CSS Box Model. The
min-height
of a box always refers to the height of its parent. If the height of the parent is not set, theheight
isauto
by default, which means the height is calculated by the browser to be as big as necessary for the content of the box to fit. It is also calculated that way if you set amin-height
!Assume you give
body
a height of100%
, the body is as high as your browser window. If give your outer div amin-height
of100%
, it will also be as high as your browser window, but since you set noheight
(settingmin-height
does NOT affect theheight
property!), the height of this box isauto
. So in fact, the real height (CSS standard calls this the "tentative height") is only as big as the content of your outer div (not necessarily 100%), yet sincemin-height
says it must be100%
it will render with a height of 100%, regardless what its real height is. If you now setmin-height
of your inner div to100%
, those 100% mean "100% of the height of my parent box height" and the parent box height isauto
, it is NOT100%
! That's why the inner div does not fill the whole screen then.Of course you can give your outer div a
height
of100%
, in that case setting themin-height
of your inner div to100%
will make it fill the whole screen, but now the outer div is really just 100% in height, it will not expand beyond 100% (it has a FIXED HEIGHT), not even if the inner div is bigger than that, that's why red color will not expand beyond the screen height, even if the yellow color goes beyond the screen height.Either your outer div has a fixed height, in which case the height will be fixed (that's the whole point of a fixed height, isn't it?) or it has a flexible height, but if it has a flexible height, it will never be "higher" than required for its content (the inner div) and thus using
100%
at the inner div, whether you setmin-height
orheight
doesn't matter, always refers to 100% of the outer div height and that one will be as big as required for the inner div. I hope you were able to understand what I'm saying here.You can surely get outer div to behave the way you want (always fill at least 100% of the screen, but expand beyond that if the content requires it) by just setting it's
min-height
to100%
, since heremin-height
will refer to the body height and your body has a fixed height, but the inner div will never behave that way. Well, it can behave that way, if your outer div has a fixed width, but then the outer div will not expand, not even if the inner div would require it, instead the inner div will overflow beyond the bounds of the outer one.I'm pretty sure it is no problem to some create a web page that will look exactly the way you want it to look, but the problem is, we (or I) don't know what it is supposed to look. I doubt you want an ugly yellow page with a red and blue border around it, do you? Yet so far this is the only page we have seen from you. I don't know what kind of color effect you are trying to achieve, whether you are using images (or if you should be using images) or how the page will really look like in the end.