I am trying to understand the rules behind z-index and how it interacts with the overflow property.
I have this html:
<body>
<div class="cell">
Here is some text to keep things interesting
<div class="boxy"></div>
</div>
</body>
And this css:
.boxy {
position: absolute;
z-index: 9999;
top:70px;
width: 50px;
height: 50px;
background: #0FF;
}
.cell {
border: 2px solid #F00;
position: relative;
/* comment these two lines out and the box appears */
/* or change them both to 'visible' */
/* changing only one of them to 'visible' does not work */
overflow-y: auto;
overflow-x: auto;
}
I would have expected that the cyan box appears even though it is out of the size of the div.cell because its z-index and its position are set.
However, the only way to make the cyan box appear is to comment out the overflow-x and -y lines.
My question is: How can I make the cyan box appear on the screen while keeping the overflow as either hidden or auto? But more importantly, I'm looking to understand why this is happening. What are the css and layout rules being applied here?
See my Plunkr. This example, is of course a much simplified version of the HTML/CSS I am actually working with.
EDIT
There seems to be some confusion in the answers below because I didn't explain things well enough. If you comment the two overflow lines out, you can see that the cyan box appears. It appears outside of the border of .cell. Why does this happen? How can I make the cyan box appear, while still hiding overflow and z-index?
The reason the cyan box appears only when overflow-x and overflow-y are visible, and disappears otherwise, is simply because the cyan box is overflowing the cell box. overflow: visible simply means "paint this box even if it is overflowing its containing block" — the cell box is the containing block of the cyan box because its position is relative. Any other values of overflow cause overflowing content to be clipped from view. There is nothing special going on here; in particular, the z-index is completely irrelevant and there is no such interaction as the question title alludes to (and there really is no reason to set it to such a huge number unless you're worried about scripts injecting other elements into the cell).
The only way to allow the cyan box to appear while the cell has a non-visible overflow is to remove position: relative from the cell and apply that declaration to the parent of the cell (in your example, it's the body). Like this:
body {
position: relative;
}
.boxy {
position: absolute;
z-index: 9999;
top: 70px;
width: 50px;
height: 50px;
background: #0FF;
}
.cell {
border: 2px solid #F00;
overflow: auto;
}
<div class="cell">
Here is some text to keep things interesting
<div class="boxy"></div>
</div>
Absolute-positioned elements do not contribute to the dimensions of their parents.
Therefore, the .cell DIV has no content that affects its dimensions, making it 100% wide by 0px high.
To make the element appear, you'll have to add a height to .cell that will encompass the DIV, in this case 120px (70px top + 50px height).
The Parent Class cell need to be set it's height. because height of absolute element doesn't affect it;s parent.
.boxy {
position: absolute;
z-index: 9999;
top:70px;
width: 50px;
height: 50px;
background: #0FF;
}
.cell {
border: 2px solid #F00;
position: relative;
/* comment these two lines out and the box appears */
/* or change them both to 'visible' */
/* changing only one of them to 'visible' does not work */
overflow-y: auto;
overflow-x: auto;
min-height: 120px; /* height 70px(Top)+50px*/
}
Your problem
Your problem is related to cell node that hides boxy when overflow is specified on cell node.
The reason
The reason behind is that boxy with position absolute does not contribute to height of cell and overflow hides it.
Why is it shown without overflow?
By default overflow is visible, which for browser means do not do anything special for overflow functionality and it does not need to render overflow => does not hide boxy.
Z-indices are local inside their clipping hierarchical parent context. This is very non-intuitive. They have their own z-stack context, which normally parallels that of the enclosure hierarchy. But they're still subject to clipping! Which can be a real pain if you're intuitively expecting the z-indices to be absolute.
Note that some jquery containers, such as accordion, quietly specify overflow: auto. Even if it's not explicitly in your code. (This can be overridden locally after it's found.)
Also note that if overflow-x: visible is set, but overflow-y is set to a non-visible, then the rendering engine quietly internally changes overflow-x to be the same as overflow-y for your amusement. But you found this out already.
You probably should be able to circumvent the unwanted non-"visible" overflow clipping, even with your high z-index, by invoking transform: translate(0,0); [or whatever desired offset, % or pixels] inside the style of the div that you want to levitate. Transform should create a new local z-stack for that element and its children. Which will let you get around an overly-restrictive parent or grandparent.
Related
Applying transforms to an element, to me, has always meant that the box model isn't moving and that the element is just moving visually.
I was wondering how this works with regards to overflow. If the element's box model hasn't been moved then how does the browser know that the element is breaking out of its parent's box?
.outer {
width: 200px;
height: 200px;
background-color: blue;
overflow: scroll;
}
.inner {
width: 100px;
height: 100px;
transform: translateY(110%);
background-color: red;
}
<div class='outer'>
<div class='inner'>
</div>
</div>
You are correct in that transforms do not affect box layout, however the spec makes an exception for overflow:
For elements whose layout is governed by the CSS box model, the transform property does not affect the flow of the content surrounding the transformed element. However, the extent of the overflow area takes into account transformed elements. This behavior is similar to what happens when elements are offset via relative positioning. Therefore, if the value of the ‘overflow’ property is ‘scroll’ or ‘auto’, scrollbars will appear as needed to see content that is transformed outside the visible area.
I have a glyphicon as such:
<div class="col-xs-4 col-sm-2">
<span class="glyphicon glyphicon-circle-arrow-up glyphicon-large"></span>
</div>
.glyphicon-large {
min-height: 260px;
font-size: 35px;
width: 1em;
display: block;
top: 50%;
margin: -0.5em auto 0px;
}
The glyphicon won't align to the center, vertically. When I open firefox, inspect element, and toggle off/on the top 50% rule, it suddenly works. How come?
Browser Bug Explanation
According to MDN on top:
For relatively positioned elements (those with position: relative), it specifies the amount the element is moved below its normal position.
Note: Percentage is applied as a percentage of the height of the element's containing block
According to W3 on top:
For relatively positioned boxes, the offset is with respect to the top edges of the box itself (i.e., the box is given a position in the normal flow, then offset from that position according to these properties).
Note: Percentages refer to height of containing block
Here's my guess:
I think what's happening is that when the browser is first rendering the visual tree, and sees top:50%;, it looks to the parent to set the height. Since no height has been specifically applied, and it has not loaded any child contents, the height of this div (and all divs) effectively starts off as zero until otherwise indicated. It then pushes down the glyph by 50% of zero.
When you toggle the property later, the browser has already rendered everything, so the calculated height of the parent container is provided by the height of its children.
Minimal, Complete, and Verifiable Example
Note: This doesn't really have anything to do with Bootstrap or Glyphicons. In order to avoid a dependency on bootstrap, we'll add top: 1px that would have been applied by the .glyphicon class. Even though it is overwritten by 50%, it still plays an important role.
Here's a simple set of parent/child elements:
<div id="container">
<div id="child">Child</div>
</div>
In order to simulate the toggling the property in a more repeatable fashion, we can just wait two seconds and then apply a style in javascript like this:
window.setTimeout(function() {
document.getElementById("child").style.top = '50%';
},2000);
Example 1 (jsFiddle)
As a starting point, let's recreate your issue.
#container {
position: relative;
/* For Visual Effects */
border: 1px solid grey;
}
#child {
position: relative;
height: 50px;
top: 1px;
/* For Visual Effects */
border: 1px solid orange;
width: 50px;
margin: 0px auto;
}
Notice that as soon as you resize the window, the browser will repaint the screen and move the element back to the top.
Example 2 (jsFiddle)
If you add top: 50% to the child element, nothing will happen when the javascript adds the property because it won't have anything to overwrite.
Example 3 (jsFiddle)
If you add top: 49% to the child element, then the DOM does have something to update so we'll get the weird glitch again.
Example 4 (jsFiddle)
If you add height: 50px; to the container instead of the child, then the top property has something to position against right from the get go and you don't need to use toggle in JavaScript.
How to Vertically Align
If you just wanted to know how to vertically center something consistently, then you can do the following:
The trick to vertically centering text is to set the line-height equal to the container height. If a line takes up 100 pixels, and the line of text online takes up 10, then browsers will try to center the text within the remaining 90 pixels, with 45 on the top and bottom.
.glyphicon-large {
min-height: 260px;
line-height: 260px;
}
Solution in jsFiddle
Tried centering a glyph icon that was inside an H1 tag, that was taking a while - so I discovered that you can actually change the font size and colour inside the SPAN tag contaning the glyph.
Thus:
<h1><span class="glyphicon glyphicon-envelope" style="font-size: 24px; color: #108db7;"></span> Mes Messages</h1>
actually worked out for me.
Have you tried ? :
<span class="glyphicon glyphicon-circle-arrow-up glyphicon-large" style="vertical-align:middle"></span>
When I set #wrap {height: 0; overflow: hidden}, the inner anchor tag should be hidden, thus click on the shadow area should have nothing happened.
I tested it on Firefox and IE. Both of them works fine.
But on Chrome, when I click on the shadow area, I still get alert window.
Is it a WebKit bug?
Here is the demo:
http://jsbin.com/ofuxar/3
<div id="wrap">
click
</div>
#wrap {
height: 0;
overflow: hidden;
position: absolute;
box-shadow: 0 10px 10px 10px black;
}
#wrap a {
display: block;
height: 100px;
}
You're setting the height to 0 but it's attributes are still displayed. Ergo, any styles you have applied to that element are still going to be shown. IF you did a 1px border, it would show a 1px with that border color. Probably the most known instance of the occurrence is when you have float elements inside of a parent div and the parent div collapses. All margin and border elements are retained, but the div has a height of 0.
As #Andrew stated in the comment, you should use display:none; to hide elements. If I may ask, what is your reasoning for setting something to height: 0?
EDIT http://jsfiddle.net/bHPFN/ As stated before, the attributes to the element cause it to NOT have a height of 0px, but instead extend the functional dimension of the element to what ever the CSS attributes delegate.
I have a div with lots of content in it, and trying to set a width to be 100% of the parent element. This div also uses a padding, so I thought I should be setting the width to auto.
But for some reason it always expands past the parent width. I even have overflow set to scroll.
What I want is the div to have a scroll bar (only horizontal), and its width to fit the parent width.
Does anyone know how I can fix this?
100% width of its parent, with padding:
Given that the padding you mention is applied to the 100% wide element, the problem is within the box model that browsers use. If you apply 100% width and some padding, the element will get width + padding as its complete width, thus causing it to become too large. There are a few ways to solve this:
CSS3 introduces a new property called box-sizing, by setting it to border-box, the padding will be added within the given width of the element, instead of adding to the width causing the element to become "to big". (Notice the lack of support by older browsers).
I believe it would be possible to use left: 0; right: 0; instead of using width: 100%;. In that case you can add padding, without the element becoming to wide.
The second option in practice:
<!-- The markup -->
<div class="parent">
<div class="child">Child</div>
</div>
/* The CSS */
.parent {
width: 200px;
height: 200px;
position: relative;
background-color: #666;
}
.child {
position: absolute;
left: 0;
right: 0;
padding: 10px;
background-color: #888;
}
Here is a working example of the second option: http://jsfiddle.net/mGLRD/
Horizontal scroll-bar:
To get a horizontal scroll-bar, you will have to look in to the overflow-x CSS-property. By setting it to scroll, you will see a disabled scrollbar when there is no content to scroll, so the scrollbar is always visible. Your other option is to set it to auto, where the scrollbar will become visible if needed (may vary between different browsers).
Try:
div#content {
width:auto;
padding:20px;
overflow-x:auto;
}
See my demo: http://jsfiddle.net/HRRsU/3/
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
http://www.w3schools.com/cssref/css3_pr_box-sizing.asp
I need my content column to expand to the bottom of the page when it's content is shorter than the viewport, but still expand when the content is longer. The column has to come down a little ways from the top of the page.
Here is the HTML for what I described:
<html>
<body>
<div id="content">
<p> asdf ghjkl </p>
</div>
</body>
</html>
Here is the CSS
#content {
min-height: 100%;
margin: 100px 0 0;
}
The issue with this method though is that min-height: 100%; does not take padding into account so the page is always bigger than what I want.
This is the behavior I am seeking:
Is there any way to accomplish this without using Javascript?
Absolute positioning can do this for you:
First remove your min-height and margin then apply this rule to your CSS.
#content {
position: absolute;
top: 100px;
bottom: 0;
}
In CSS3, you can use box-sizing
By setting it to border-box, you can force the browser to instead render the box with the specified width and height, and add the border and padding inside the box.
Ok blokes and birds, here's what I ended up doing. Instead of solving the problem directly, I added a few fixer divs.
First off, here are a few observations:
We know that when #column is longer than the viewport, the length of #column needs to specify the height of <body>.
If #column is shorter than the viewport, the height of the viewport needs to specify the height of <body>.
The column needs stretch to the bottom of the page under all circumstances, regardless of how long it's content is.
For the first criteria we need to make sure that height: auto is set on <body>. Height defaluts to this if it's not set. We also need to make sure that #column has height: auto; and overflow: hidden; so that it expands to the size of it's content.
For the second criteria we need to set position: absolute; and min-height: 100%; on <body>. Now the length of <body> will expand when #column is longer than it, but won't go shorter than the viewport. This next part is where the fix comes in.
For the third criteria, the trick is to add some extra divs and give them some special css. In my HTML I added two divs right outside of #column.
<div id="colhack-outer">
<div id="colhack-inner">
</div>
</div>
<div id="column">
...
</div>
For the outside div you postiion it absolutely and set it's height to 100%, force it to use an alternative box model and shift it's content area using padding. You apply all your column styling (background color, border radius, shadow, etc.) to the inner div. Here is the CSS I applied to them:
#colhack-outer {
height: 100%;
padding: <where you want to shift the column to>;
position: absolute;
width: 50%;
}
#colhack-inner {
height: 100%;
width: 100%;
background-color: #303030;
}
You also have to make your actual content container use that special box model and shift it with padding too:
#contentbox {
position: relative;
padding: <where you want to shift the column to>;
width: 50%;
color: #EEEEEC;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
Live example here: http://nerdhow.net/
post a comment if you have questions or if something wasn't clear.
You can achieve it by using Absolute positioning and adding extra block (if you need a solid background under you column).
So, when you'll have a little content, you'll get http://jsfiddle.net/kizu/7de7m/
And if you'll have a lot of content, you'll get http://jsfiddle.net/kizu/7de7m/3/
Try this jsFiddle: http://jsfiddle.net/8R4yN/. It seems to work the way you want. I took some tips from: http://www.tutwow.com/htmlcss/quick-tip-css-100-height/. It looks like the overflow is causing the hiding, and the #content inside there is also not helping out :).