overflow: hidden on div and body, different behavior - css

Given this html:
<body>
<div id="a"></div>
<div id="b"></div>
</body>
I want #b to fill all the remaining vertical space of its container block, I began with this:
body {
height: 500px;
width: 500px;
overflow: hidden;
}
#a {
height: 100px;
width: 100px;
}
#b {
height: 100%;
width: 100%;
}
So #b is 100% height, which means that it is taking the height of its parent container block, which is 500px, the problem is that the overflow: hidden; seems to not work, #b is not clipped.
On the other hand, if I wrap #a and #b with another div with the same properties as body above I have the desired result:
#wrap {
height: 500px;
width: 500px;
overflow: hidden;
}
#a {
height: 100px;
width: 100px;
}
#b {
height: 100%;
width: 100%;
}
with this html of course:
<body>
<div id="wrap">
<div id="a"></div>
<div id="b"></div>
</div>
</body>
My question is why div and body seems to have different behaviors with the same properties? and is there any way to get the same effect without the wrapper?
To illustrate the question I have created two jsFiddles:
jsFiddle with body tag as wrapper: http://jsfiddle.net/3AMtG/
jsFiddle with div tag as wrapper: http://jsfiddle.net/2QWn3/
Two jsFiddles with the same properties yield different results. Why is that?

The overflow property has certain special behaviors specific to HTML's html and body elements, which are described in the CSS2.1 spec. These special cases are in place to accommodate changing overflow settings on the entire page in normal circumstances so authors simply need to set it on either html or body, but not both.
In this case, when you apply overflow: hidden to body, it actually affects the viewport instead of body (you can see this by resizing the preview pane to make it shorter — no scrollbars will appear on the preview pane itself). This causes #b to overflow the body normally even though you give it a fixed height that's less than the sum of #a and #b. In other words, it's as though you never set it on the body in the first place.
If you set overflow to something other than visible on html, though, this causes the viewport to use the value given to html instead of body, thereby leaving the declaration on body unaffected and allowing it to behave the same way as the wrapper:
html {
overflow: auto;
}
body {
height: 500px;
width: 500px;
overflow: hidden;
}
jsFiddle preview

body and div have totally different of them. In my daily working, I like constructing my code like this.
<div class='xxx-ctn'>
<div class='xxx-inner'>
<div class='data-wrapper'>
[p|ul|ol|h1-h6|article|section].....
</div>
</div>
</div>
Okey, I missing your founding, but I think this is a good coding habbit.

Body element is considered as main parent element inside which other elements that are displayed within the browser window resides therefore, width and height property is not applicable onto it. According to the best practices it is better to create a div container like #wrapper that you did in your second example.

Related

How to ensure containing element is full page height, no matter the number of dynamic children

I am trying to get a containing div that is full page-height to expand so that is is always equal to the height of its content.
The overall structure is
search.html
<div class="outer-container">
<div class="inner-container">
<div class="body">
<app-results></app-results>
</div>
</div>
</div>
results.html
<div class="card" *ngFor="let c of content; let index = index">
<h1 class="h">{{index}}</h1>
</div>
I have tried setting the .outer-container to [display: inline-flex][1]; which works really well. Until more cards are added dynamically to the view. At that point, the containing element remains at the same place it was before the dynamic content was inserted, right at the viewport's previous bottom.
I've also tried various permutations of height: auto, and height: 100% on the entire tree of elements, but it seems like when I get the parent's height to work correctly with a batch of children that extends beyond the page, its height shrinks when it is one element; and when it looks good when there is just one element, the parent looks to short when more children are added which overflow the page height.
Also, in my app overflow: auto produces a double scrollbar, so that won't work.
How can I get the full height to persist no matter the number of elements?
More detailed StackBlitz You have to click the "search" link to get to the correct route. (I added angular router to be sure my reproduction was accurate as possible)
I looked at your StackBlitz. I assume that the issue is that when you click 'toggle' the pink background does not extend. If so, all you need to do is add overflow: auto; to your CSS as shown below. I tried it on your StackBlitz and it worked.
.outer-container {
width: 100%;
position: relative;
height: 100%;
display: inline-flex;
flex-direction: column;
background: pink;
overflow: auto;
.inner-container {
height: inherit;
}
}
The overflow property specifies what should happen if content overflows an element's box.
I changed a couple lines on your stackblitz and it seems to be working how you described. You can make the .outer-container height fit-content and min-height 100%:
.outer-container {
width: 100%;
position: relative;
height: fit-content;
min-height: 100%;
display: inline-flex;
flex-direction: column;
background: pink;
.inner-container {
height: inherit;
}
}

UI-Router: Height:100% on body element ignoring nested view height

I'm building an angular application that frequently uses nested views. Certain views, however, are taller than the other elements on the page and end up extending well beyond the end of the parent view.
I'm using Ryan Fait's Sticky Footer so I have a wrapper around a containing div set to height:100% and I would have expected the page to just adapt and move the footer to the bottom of the nested view however I'm seeing the style elements of the footer border and background-color are remaining at end of the parent div while the content of the footer is being pushed to the end of the nested div.
Including an image as I'm struggling with getting the language exact:
I'm really looking for any solution from fixing the css to something that seems hackier like changing the footer or using ng-if/ng-class on certain pages. I'm imagining I'm misunderstanding something about CSS/UI-Router but I can't really track it.
The code isn't really interesting but here is it?
CODE
.wrapper {
min-height: 100%;
margin-bottom: -50px;
}
.push {
height: 50px;
}
.footer {
display: block;
height: 50px;
}
.nested {
max-height: 500px;
}
<body>
<div class="wrapper">
<div>
<h1>Some text</h1>
<ui-view class="nested"></ui-view>
</div>
<div class="push"></div>
</div>
<footer class="footer">
<span>some copy</span>
</footer>
</body>
If you use percentage values for height (i.e. a relative height), the parent element heights have to be defined too. In your case you also need height: 100% on body and html, like
html, body {
height: 100%;
}

Body set to overflow-y:hidden but page is still scrollable in Chrome

I'm having an issue with the overflow-y property in Chrome.
Even though I've set it to hidden, I can still scroll the page with the mouse wheel.
Here is my code:
html,
body {
overflow-y: hidden;
}
#content {
position: absolute;
width: 100%;
}
.step {
position: relative;
height: 500px;
margin-bottom: 500px;
}
<body>
<div id="content">
<div class="step">this is the 1st step</div>
<div class="step">this is the 2nd step</div>
<div class="step">this is the 3rd step</div>
</div>
</body>
Does anybody know how to block the vertical scrolling in Chrome?
Thanks!
Setting a height on your body and html of 100% should fix you up. Without a defined height your content is not overflowing, so you will not get the desired behavior.
html, body {
overflow-y:hidden;
height:100%;
}
I finally found a way to fix the issue so I'm answering here.
I set the overflow-y on the #content instead, and wrapped my steps in another div. It works.
Here is the final code:
<body>
<div id="content">
<div id="steps">
<div class="step">this is the 1st step</div>
<div class="step">this is the 2nd step</div>
<div class="step">this is the 3rd step</div>
</div>
</div>
</body>
#content {
position:absolute;
width:100%;
overflow-y:hidden;
top:0;
bottom:0;
}
.step {
position:relative;
height:500px;
margin-bottom:500px;
}
What works for me on /FF and /Chrome:
body {
position: fixed;
width: 100%;
height: 100%;
}
overflow: hidden just disables display of the scrollbars. (But you can put it in there if you like to).
There is one drawback I found: If you use this method on a page which you want only temporarily to stop scrolling, setting position: fixed will scroll it to the top.
This is because position: fixed uses absolute positions which are currently set to 0/0.
This can be repaired e.g. with jQuery:
var lastTop;
function stopScrolling() {
lastTop = $(window).scrollTop();
$('body').addClass( 'noscroll' )
.css( { top: -lastTop } )
;
}
function continueScrolling() {
$('body').removeClass( 'noscroll' );
$(window).scrollTop( lastTop );
}
Another solution I found to work is to set a mousewheel handler on the inside container and make sure it doesn't propagate by setting its last parameter to false and stopping the event bubble.
document.getElementById('content').addEventListener('mousewheel',function(evt){evt.cancelBubble=true; if (evt.stopPropagation) evt.stopPropagation},false);
Scroll works fine in the inner container, but the event doesn't propagate to the body and so it does not scroll. This is in addition to setting the body properties overflow:hidden and height:100%.
Try this when you want to "fix" your body's scroll:
jQuery('body').css('height', '100vh').css('overflow-y', 'hidden');
and this when you want to turn it normal again:
jQuery('body').css('height', '').css('overflow-y', '');
Use:
overflow: hidden;
height: 100%;
position: fixed;
width: 100%;
body { overflow-x: hidden;}
With this, the overflow will be hidden on the x-line (horizontally) but you will be able to scroll vertically.
Find out the element which is larger than the body (element which is causing the page to scroll) and just set it's position to fixed.
NOTE: I'm not talking to change the position of draggable elements. Draggable elements can be dragged out of body only when there's an element larger than body (mostly in width).
Technically, the size of your body and html are wider than the screen, so you will have scrolling. You will need to set margin:0; and padding:0; to avoid the scrolling behavior, and add some margin/padding to #content instead.
Ok so this is the combination that worked for me when I had this problem on one of my websites:
html {
height: 100%;
}
body {
overflow-x: hidden;
}
The correct answer is, you need to set JUST body to overflow:hidden. For whatever reason, if you also set html to overflow:hidden the result is the problem you've described.

body background extends into margins or is cut-off when scrolling

I have a layout where I need to use height: 100% on html and body (and any wrapper divs I resort to using) to achieve an effect similar to pages, so that the content on my first "page" is centred, scrolling down the content on the second "page" is centred etc.
The html looks like this:
<section class="page" id="p01">
<div class="spacer">
</div>
<div class="outer">
<div class="inner">
Some content
</div>
<div class="inner">
Some content
</div>
</div>
</section>
<section class="page" id="p02">
<div class="spacer">
</div>
<div class="outer">
<div class="inner">
Some content
</div>
<div class="inner">
Some content
</div>
</div>
</section>
and the vertical centring etc. achieved with this styling:
body, .page {height: 100%; margin: 0 auto;}
.spacer {
float: left;
height: 50%;
margin-bottom: -150px;
}
.outer {
height: 300px;
width: 100%;
background-color: #fca;
clear: both;
position: relative;
display: block;
white-space: nowrap;
}
.inner {
width: 41%;
margin: 0 6%;
height: 300px;
background-color: green;
display: inline-block;
vertical-align: middle;
white-space: normal;
}
.inner:first-child {
margin-right: 0;
}
You can see it at work in this fiddle:
http://jsfiddle.net/terraling/3V5rV/
The problem is the body background (here I'm just using color, but on my site it will be an image) leaks out into the body margins, i.e. the body content has a max-width and should be centred with white margins.
I can fix that either by... setting html background-color to white, as per
http://jsfiddle.net/terraling/yM53t/
...but body background becomes cutoff when scrolling into the second page (that wasn't a problem in the first fiddle).
Alternatively I could set the background image on a wrapper div and not on the body. That solves the problem of it leaking into the body margins, but it still has the same problem that it is cut off on scrolling.
(see: http://jsfiddle.net/terraling/3V5rV/1/ )
Any solution that involves removing the height: 100% declaration from any of html, body or wrapper collapses the layout (including replacing with max-height: 100%).
There's a whole lot of problems with this construct and not all of them can be solved, unfortunately.
The background issue
As you have seen yourself the background of body extends to the viewport if html does not have a background. That's solvable.
The float issue
When an element floats it does not contribute to the height of its parent element. So they don't grow (e.g. body does not expand). That can be solved if you can use alternatives. For vertically centering an element you could use display: table-cell e.g., which allows you to vertically center the content.
The height issue
This is where all hope is gone. height: 100% refers to the height of the parent, of course. The parent of body is html which in turn is the child of the viewport. You gave html the size of 100% (= the size of the viewport) and body the size of 100% (= size of html = size of viewport).
So now body has a fixed height and it can't expand meaning the background doesn't expand as well. Now one might have the idea to give body no size so that it can expand. But .page has 100% too. If a parent (in this case body) has no fixed size 100% has no meaning and will be treated as auto, which means as big as the content. And the content has a height of 300px. So the .page elements wouild no longer have the height of the viewport but 300px.
As for the collapse of the CSS, you should either specify the height specifically height:200px; or add padding to the bottom/top of the page so that the content wraps. You can also use min-height:200px; then add the margin-bottom:20px; to separate the pages. I would approach this at a specific height with the wrapper having the specific background-image and bottom-margin.
In order to center your background-image to the <html> you can specify the position as 50%.
This can be done by doing background:url('yourimage.jpg') repeat 0 50%;This will ensure the background is centered.

How to set height of DIV with CSS in relative positioning?

I have some HTML+CSS code that wants to layout several divs. The layout is like this: all divs stay in a parent div whose size is fixed. Then each child div should stay on its own line, and use the minimum height for drawing its content. The last div should consume all remaining height, so that the parent div is entirely filled.
This code shows my approach using CSS float and clear properties:
<html>
<head>
<style>
.container {
width: 500px;
height: 500px;
border: 3px solid black;
}
.top {
background-color: yellow;
float: left;
clear: left;
width: 100%;
}
.bottom {
background-color: blue;
height: 100%;
float: left;
clear: left;
width: 100%;
}
</style>
</head>
<body>
<div class="container">
<div class="top">top1</div>
<div class="top">top2</div>
<div class="top">top3</div>
<div class="top">top4</div>
<div class="bottom">bottom</div>
</div>
</body>
</html>
However, the last div overflows from the its parent. I guess it is because of the width: 100%.
Is there any way to solve this problem? I want to avoid setting the overflow attribute of the parent, and also I have to avoid using absolute positioning. If somehow I could trick the last div to use the height of the parent minus the sum of height of the other divs.
Add:
div.container { overflow: hidden; }
It's not overflowing because it's 100% width. It's overflowing because it's a float and thus removed from the normal layout. Changing the overflow property will change how the browser caters for contained floats.
Oh and if you aren't already, make sure you're using a DOCTYPE. It particularly matters for IE.

Resources