Unexpected z-index stacking behavior - css

Basically, I am trying to put overlap corners behind the #page_container on my site, so that it looks like the image is overlapping the page.
Live example: http://jsfiddle.net/xBwQp/15/
HTML :
<div id="page_container">
<div id="banner_wrapper">
<img id="banner_image" src="http://placehold.it/350x150" />
<div class="triangle-l"></div>
<div class="triangle-r"></div>
</div>
</div>
CSS :
#page_container {
background: red;
width: 400px;
position: relative;
z-index: 10;
}
#banner_wrapper {
position: relative;
}
#banner_image {
position: relative;
}
.triangle-l {
border-color: transparent green transparent transparent;
border-style: solid;
border-width: 15px;
height: 0px;
width: 0px;
position: absolute;
right: 0px;
top: 0px;
z-index: 5;
}
.triangle-r {
border-color: transparent transparent transparent blue;
border-style: solid;
border-width: 15px;
height: 0px;
width: 0px;
position: absolute;
right: 0px;
top: 0px;
z-index: 5;
}
You can see that the triangles, .triangle-l and .triangle-r, clearly have a lower z-index:5 than the #page_container z-index:10 but they still appear above the #page_container.
I have been able to accomplish my desired result by setting .triangle-l and .triangle-r to z-index:-1 however this only works in FF, Opera, and Webkit. No IE support.
I believe it has to do with the stacking context. However, I am unsure how to accomplish the desired result with cross-browser compatibility.

You are absolutely right - it is about the stacking context.
Whenever you put z-index on an element you create a new context, so because the triangles are descendants of the #page_container they are going to belong to the stacking context of the #page_container and no matter what z-index number you choose for the triangles, they only have meaning inside this context, and you will not be able to move them backwards behind this container.
Read in detail here: https://developer.mozilla.org/en/CSS/Understanding_z-index/The_stacking_context
Possible solutions are;
move the elements out of the container in the html structure (and
then position them where you want with css)
remove the z-index from the container and set the triangles to z-index -1 to move them beneath the document itself

Related

CSS Overflow hidden property is not working on touch devices

I have created a circular vertical progress bar which fills vertically on page level progress. For this I have created two divs(outer div and inner div) and I have made the circular outer div using border radius 50% and overflow hidden and the inner div with square shape and width greater than the width of outer div. So on the completion of the page the height of the inner div increases and it gives the effect of filling of circular outer div as the edges of the inner div gets hide by the overflow property of the outer div. Its working fine in desktop and IPad but not in the other touch devices(mainly mobile devices). I am adding the snippet of the css and HTML that I am using. There are similar questions available on stackoverflow but none of the answer solved my problem, so plese don't take it as a duplicate answer, thanks.
#progress-container {
position: absolute;
top: 100px;
left: 100px;
}
#progress-indicator-outer {
position: absolute;
width: 25px;
height: 25px;
border: 2px solid #fff;
border-radius: 50%;
background: #999999;
overflow: hidden;
}
#progress-indicator-inner {
position: absolute;
bottom: 0px;
width: 28px;
height: 12.5px;
margin: 0px 0 0 -2px;
background: #007BAf;
}
<div id="progress-container">
<div id="progress-indicator-outer">
<div id="progress-indicator-inner"></div>
</div>
</div>
This appears to be caused by browsers parsing the tag. To solve this problem at the source, try the following:
<meta name="viewport" content="width=device-width, initial-scale=1,
minimum-scale=1">
original answer
Some things to note:
You don't need all these position: absolute;. Try to avoid them.
Decimal pixel values are highly discouraged
The width of your inner element was not correct. If your outer is 26px, and you want to move the inner two px left, that means you also need 2px on the other side, ending up at 30px
I tested the following and this works on my mobile devices
#progress-container {
position: absolute;
top: 100px;
left: 100px;
}
#progress-indicator-outer {
width: 26px;
height: 26px;
border: 2px solid #fff;
border-radius: 50%;
background: #999999;
overflow: hidden;
}
#progress-indicator-inner {
position: relative;
width: 30px;
height: 13px;
top: -2px;
left: -2px;
background: #007BAf;
}
<div id="progress-container">
<div id="progress-indicator-outer">
<div id="progress-indicator-inner"></div>
</div>
</div>

Set space/margin all around an absolute <div> which is inside a scrollable <div>

I'd like to set a margin all around a <div> with a position:absolute inside a scrollable <div> to let some free space between the inside div and the scrollable area boundaries (right and bottom).
I tried something like this but with no luck:
<div style="overflow:scroll">
<div style="position:absolute; margin-right:100px; margin-bottom:100px">DRAG ME</div>
</div>
Demo here: https://jsfiddle.net/ayft01x0/
Only the margin-bottom works, and only in Chrome.
You can also imagine that there are other elements inside the scollable div and that they should stay clickable even if they are masked by the margin of the "drag me" element (which should be the case when using CSS margins).
I'm looking preferably for a CSS-only solution that works in Webkit browsers.
Any ideas?
Absolute positioning changes the way margins work, but you can get the effect you're after with borders:
We add a border to the left and the right. This interferes with the border you already had on the draggable element, so we add a pseudoelement to take care of the design. The pseudoelement covers up the "drag me" text, so we add a wrapper around that content and fix the z indices
Here's an update to your fiddle, and here's a snippet of the essential css
#container {
position: relative;
width: 200px;
height: 200px;
border: solid 1px black;
background-color: white;
}
#box {
position: absolute;
border-right: 100px solid transparent; /* changed this */
border-bottom: 100px solid transparent; /* changed this */
outline: 1px solid red; /* just for demo purposes */
width: 80px;
height: 80px;
left: 50px;
top: 50px;
/* dropped the border and background styles */
}
#box span { /* added this element */
position: relative;
z-index: 1;
}
#box:before { /* added this element */
content: '';
position: absolute;
z-index: 0;
width: 80px;
height: 80px;
/* placement adjusted to take the border into account */
left: -2px;
top: -2px;
/* border and background styles moved from #box to here */
border: solid 2px #666;
border-radius: 10px;
background: #ccc; /* shaved off a couple bytes by dropping the -color */
}
<div id="container" style="overflow:scroll">
<div id="box">
<span>DRAG ME</span><!-- added this wrapping element so that it can get a z-index -->
</div>
</div>
Note that I've kept your initial positions for the draggable box, but I would probably actually do it like this. The negative margins are just half the element's dimensions. This way if you tweak the size of #container you don't have to recalculate #box's starting position
#box {
...
width: 80px;
height: 80px;
left: 50%;
top: 50%;
margin-left: -40px;
margin-top: -40px;
}
There is a workaround by using an encapsulating div with inner padding and make it transparent to the mouse interactions using the pointer-events property.
<div style="overflow:scroll">
<div style="position:absolute; padding-right:100px; padding-bottom:100px; pointer-events:none">
<div style="pointer-events:all">DRAG ME</div>
</div>
</div>
Demo here: https://jsfiddle.net/1axtonez/
The easiest way to achieve this is to create an invisible CSS ::before pseudo-element that covers the box plus a padding, and to make it transparent to the mouse interactions using the pointer-events property:
div.box::before{
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
padding-right: 100px;
padding-bottom: 100px;
pointer-events: none;
/* background-color: rgba(255,0,0,0.2); // to understand what is going on */
}
Demo here: https://jsfiddle.net/rmxwwyno/
Be warned that it's not working when the box has an overflow property that is not set to visible.

PNG shadow with fluid height

Due to browser performance implications I can't use box-shadow CSS property because I have many similarly looking elements on my page that should have same looking style including shadow. That's the reason I would like to implement shadows using traditional PNG imagery.
Facts
My elements have predefined and more importantly fixed pixel width
They have fluid height (auto) depending on their content
They have content directly in the element and some child elements will be positioned outside their border
CSS3 can be used but performance-critical parts (gradients, shadows...) should be avoided
CSS pseudo elements can be used without limitation
Requirements
There should be no additional wrapper element added in order to have fluid shadow
Application should run smoothly on mobile browsers - shadows seem to slow down performance significantly on mobile devices since their processing power is much lower than desktop computers.
Possible direction
I thought of using :before and :after pseudos to display top-to-bottom and bottom shadows on the containing element, but these pseudos display within their parent element and positioning parent z-index higher than these children has no effect.
Visual demo of end result
This JSFiddle Demo in pure CSS3 that I would like to achieve but using PNG shadows. In reality there are numerous of these boxes so you can imagine mobile browsers are struggling with all these shadows.
Item is one such box (see blow) that needs PNG shadow. Left menu is child element positioned outside of the box.
Display in Chrome
HTML
<div class="item">
<menu>
<li>Yes</li>
<li>No</li>
<li>Maybe</li>
</menu>
<div class="content">
Some content
</div>
</div>
CSS3 LESS
.item {
position: relative;
width: 300px;
background-color: #fff;
box-shadow: 0 0 10px #ccc;
margin: 20px 20px 20px calc(20px + 3.5em);
min-height: 5em;
&:first-child {
margin-top: 0;
}
&:after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 10px;
height: 5em;
background-color: #fff;
}
menu {
position: absolute;
top: 0;
left: -3.5em;
width: 3.5em;
margin: 0;
border: 0;
padding: 0;
list-style: none;
background-color: #fff;
box-shadow: 0 0 10px #ccc;
li a {
display: block;
text-align: center;
padding: 2px 0;
}
}
.content {
padding: .75em 1em;
}
}
Probably I am missing something, but looks like you want something in this way:
demo
The CSS is
.base {
width: 300px;
height: 150px;
font-size: 100px;
font-weight: bolder;
background-color: lightgreen;
position: relative;
z-index: auto;
}
.base:after {
content: '';
position: absolute;
top: 30px;
left: 30px;
background-color: green;
z-index: -1;
width: 100%;
height: 100%;
}
.child {
position: absolute;
left: 150px;
top: 50px;
border: solid 1px black;
color: red;
}
And just change the background of the :after to your image.
I have applied this solution to your fiddle.
The relevant CSS is for the before pseudo element:
.item:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
z-index: -1;
background-image: url(http://placekitten.com/100/100);
background-repeat: no-repeat;
background-size: 100% 100%;
}
I have used a kitten picture, that is being scaled to cover all the needed size. Just change that to whatever you want.
I needed to do it that way because I had onky a pseudo element available.
The key for that to work (and where you probably had the difficulty) is to add z-index: auto to .item
Updated demo
Well, I had said that it wasn't posible, but I have find a way.
The standard technique would be to use 2 elements, just to avoid stretching the image (as you said). The problem is that we only have 1 pseudo element available.
The solution then would be to use 1 pseudo element, but with 2 backgrounds, to solve the issue.
CSS (only relevant part)
.item:before {
background-image: url(http://placekitten.com/320/10), url(http://placekitten.com/320/500);
background-repeat: no-repeat;
background-size: 100% 9px, 100% calc(100% - 9px);
background-position: left bottom, left top;
}
We will need an image (the first one) only 10 px in height, to cover the bottom shadow. And another one, with enough height to cover the maximumitem posible, and that will be used for the remaining part of the shadow. The dark part is that we need now a calc() height, with limited support. (anyway, better than border image)
demo 3

center element within another, while parent specifies position: absolute?

I'm working with this JS Fiddle: http://jsfiddle.net/BY3tz/1/
Notice when you remove the position, left, and top properties from the dotParent CSS class, the black dot is centered within the box.
I'm looking for a way to keep the black dot centered (vertically and horizontally) while leaving the 3 properties mentioned above in place so that I can change the left and top properties to position the box anywhere, and the black dot will remain centered.
Is this possible? Can anyone see what I'm doing wrong with my dot class?
Some tweaks to the .dot class:
.dot {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50px;
margin-left: -5px; // Half of the width * (-1)
margin-top: -5px; // Half of the height * (-1)
top: 50%;
left: 50%;
background: #000;
-webkit-border-radius: 50px;
-webkit-background-clip: padding-box;
background-clip: padding-box;
}
http://jsfiddle.net/BY3tz/2/
Added dot wrapper so .dot is relative to new wrapper,
<div class="dotParent">
<div class="dot-wrapper">
<div class="dot"></div>
</div><!-- end dot-wrapper -->
</div>
New Styles.
.dot-wrapper {
position:relative;
width:100%;
height:100%;
}
Added to .dot class
.dot {
position:absolute;
top:45%;
left:45%;
}
http://jsfiddle.net/BY3tz/5/
Change the position attribute in the dotParent div to "Relative". Since its the parent Div, it needs to be positioned as Relative in order for its children to take it as a reference point.
.dotParent {
position: relative;
top: 150px;
left: 50px;
height: 68px;
width: 68px;
border: 1px solid Black;
}
http://jsfiddle.net/BY3tz/6/

CSS variating height problem with IE6

I have problem positioning left sidebar (variating height DIV) ON IE6.
Main needs:
1. I cant set height value, cause height is variating and should be computed by browser.
2. Sidebar must have top and bottom spacings.
Top bar issue is solved by replacing position to relative.
Any ideas ? Thank you in advance !
Below you can see simplified code and snapshot how it looks on standard browsers.
.container {
left: 550px;
top: 10px;
width: 196px;
position: absolute;
line-height: 0px;
font-size: 1px;
}
.inner {
width: 100%;
height: 114px;
background-color: rgb(227, 227, 227);
}
.leftbar {
left: 0px;
top: 7px;
bottom: 7px;
width: 4px;
position: absolute;
background-color: rgb(111, 111, 111);
}
.topbar {
left: 7px;
top: 0px;
right: 7px;
height: 4px;
position: absolute;
background-color: rgb(111, 111, 111);
}
<div class="container">
<div class="inner"></div>
<div class="leftbar"></div>
<div class="topbar"></div>
</div>
LINK TO SCREEN SHOT IMAGE
IE6 is tremendously bad when it comes to absolute positioning. Positioning something at the same time from left and right or from top and bottom just doesn't work.
You basically have four options:
Drop support for IE6.
Give up on absolute positioning and use some other method (floats for example).
Provide dumbed down version of the site for IE6 - for example overriding some styles using conditional comments.
Use JavaScript to aid IE6 in positioning (for example absolutefudge.js).

Resources