4

I am trying to create a ribbon at the beginning of a rectangle. However, I cannot figure out how to make it appear BEHIND the rectangle.

Please see this codepen: http://codepen.io/gosusheep/pen/aOqOBy

The part for creating the ribbon and putting it behind the rectangle is here:

.rectangle::before{
  content: "";
  width: 0;
  height: 0;
  display: block;
  position: absolute;
  z-index: -1;
  border-left: 25px solid transparent;
  border-right: 25px solid $blue;
  border-top: 25px solid $blue;
  border-bottom: 25px solid $blue;
  left: -30px;
  top: 10%;
}

Even with position: absolute, and z-index: -1, it appears ON TOP of the div.

Can anyone help with this?

Harry
  • 87,580
  • 25
  • 202
  • 214
MGreenfield
  • 355
  • 1
  • 13

3 Answers3

2

The reason for your problem is not because children cannot be positioned behind their parent but because you are using a transform on the parent. Using transforms affect the stacking context like mentioned in this answer by BoltClock.

One solution would be to avoid the transform totally and use left: calc(50% - 100px) instead to position the ribbon at the center (like in the below snippet). (50% - 100px) is used as the value because 100px is half of the box width (50% is the center point of the parent).

.rectangle {
  width: 200px;
  height: 50px;
  background-color: #8080ff;
  position: relative;
  left: calc(50% - 100px); /* newly added */
  border: 1px #6666ff solid;
}

ul {
  list-style: none;
}

li {
  display: inline;
}

li + li::before {
  content: " | ";
}

.container {
  width: 100%;
  position: relative;
}

.rectangle {
  width: 200px;
  height: 50px;
  background-color: #8080ff;
  position: relative;
  left: calc(50% - 100px); /* newly added */
  border: 1px #6666ff solid;
}

.rectangle::before {
  content: "";
  width: 0;
  height: 0;
  display: block;
  position: absolute;
  z-index: -1;
  border-left: 25px solid transparent;
  border-right: 25px solid #8080ff;
  border-top: 25px solid #8080ff;
  border-bottom: 25px solid #8080ff;
  left: -30px;
  top: 10%;
}
<p>put a pipe between nav elements</p>
<nav>
  <ul>
    <li>banana</li>
    <li>woof</li>
    <li>quack</li>
  </ul>
</nav>
<p>Ribbon on the end of a rectangle</p>
<div class='container'>
  <div class='rectangle'></div>
</div>

If in case you can't use the above solution, then you could follow the approach described below.

Assuming you don't have any other use for the ::after pseudo-element, you could use that to create the rectangle and give it a z-index higher than the ::before pseudo-element to make it appear behind the rectangle.

/* Modified */

.rectangle {
  width: 200px;
  height: 50px;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
}

/* Added */

.rectangle::after {
  content: "";
  width: 100%;
  height: 100%;
  top: 0px;
  left: 0px;
  display: block;
  position: absolute;
  background-color: #8080ff;
  border: 1px #6666ff solid;
  z-index: -1;
}

.rectangle{
  padding: 4px;
  box-sizing: border-box;
}

Below is a sample snippet:

ul {
  list-style: none;
}
li {
  display: inline;
}
li + li::before {
  content: " | ";
}
.container {
  width: 100%;
  position: relative;
}
.rectangle::before {
  content: "";
  width: 0;
  height: 0;
  display: block;
  position: absolute;
  z-index: -2;
  border-left: 25px solid transparent;
  border-right: 25px solid #8080ff;
  border-top: 25px solid #8080ff;
  border-bottom: 25px solid #8080ff;
  left: -30px;
  top: 10%;
}

/* Modified */

.rectangle {
  width: 200px;
  height: 50px;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
}

/* Added */

.rectangle::after {
  content: "";
  width: 100%;
  height: 100%;
  top: 0px;
  left: 0px;
  display: block;
  position: absolute;
  background-color: #8080ff;
  border: 1px #6666ff solid;
  z-index: -1;
}

.rectangle{
  padding: 4px;
  box-sizing: border-box;
}
<p>put a pipe between nav elements</p>
<nav>
  <ul>
    <li>banana</li>
    <li>woof</li>
    <li>quack</li>
  </ul>
</nav>
<p>Ribbon on the end of a rectangle</p>
<div class='container'>
  <div class='rectangle'>
    Some content
  </div>
</div>
Community
  • 1
  • 1
Harry
  • 87,580
  • 25
  • 202
  • 214
2

What is happening here is that apparently, the property transform: translateX(-50%); it's "overriding" in some way the z-index. My solution is just center rectangle otherwise, for example:

.rectangle{
    margin: 0 auto;
}

DEMO

lmgonzalves
  • 6,518
  • 3
  • 22
  • 41
1

Solution here, look closely at z-indexes and positions

.container{
  position: relative;
  width: 100%;
  z-index: 1;
}

.rectangle{
  width: 200px;
  height: 50px;
  background-color: $blue;
  position: absolute;
  left: 50%;
  border: 1px darken($blue,5%) solid;
}

.rectangle::after{
  content: "";
  width: 0;
  height: 0;
  border-left: 25px solid transparent;
  border-right: 25px solid $blue;
  border-top: 25px solid $blue;
  border-bottom: 25px solid $blue;
  left: -30px;
  top: 10px;
  position: absolute;
  z-index: -1;
}

And your codepen edited http://codepen.io/anon/pen/mJXeed working now

jperelli
  • 6,988
  • 5
  • 50
  • 85
  • 1
    You removed the transform, which causes the ribbon to not be centered. It seems the transforming changes the z-index as others have pointed out. – MGreenfield Jul 02 '15 at 20:54