1

In the following codepen - https://codepen.io/tanmaylodha/pen/MWKXJWW CSS:Line-26; the left:50% is not working correctly. But if I set display:inline-block on the containing block .section-first a of absolutely positioned element .badge then it works fine.

    <section class="section section-first">
   <a href="#">
     <h1 class="badge">Recommended</h1>
     <h1 class="plus-plan">Our PLUS Plan</h1>
     <h2>The most popular choice of our customers.</h2>
     <p>
       Benefit from increased storage and faster support to ensure that
       your mission-critical data and applications are always available!
     </p>
   </a>
 </section>

.section {
  color: #6c6164;
  background-color: #f7fafd;
  padding: 1.563rem;
  margin-bottom: 1.563rem;
  border: 5px solid #fca156;
  margin-right: 12.5rem;
  box-shadow: inset 5px 5px 10px 2px #4fbf99;
}

.section-first {
  margin-top: 8rem;
}

.section-first a {
  position: relative;
}

.badge {
  font-family: "Red Hat Display";
  background-color: #60a7bd;
  padding: 0.625rem;
  border-radius: 5px;
  margin: 0%;
  position: absolute;
  left: 50%;
}

.section h1.badge {
  color: white;
}

.section-first .plus-plan {
  margin-top: 50px;
}

.section-highlighted {
  margin-left: 200px;
  margin-right: 0px;
  box-shadow: inset 5px 5px 10px 2px #4fbf99, 5px 5px 10px 2px #60a7bd;
  text-align: right;
}

.section:hover {
  border-color: #ff943c;
}

.section a {
  text-decoration: none;
}

Now check this codepen - https://codepen.io/tanmaylodha/pen/jOWKyZP But here the results are different. .child being absolutely positioned element is getting correctly positioned after 50% width of its containing block .parent

 <a href="" class="parent">
  I am a Parent
  <div class="child">
    I am a child
  </div>
</a>

.parent {
  position: relative;
  background-color: chocolate;
}
.child {
  position: absolute;
  background-color: darkgreen;
  left: 50%;
}

In both the above Codepen, the containing block(being positioned relative) is always an inline element, then why the results are different?

Temani Afif
  • 245,468
  • 26
  • 309
  • 415

2 Answers2

2

To make the issue more clear here is the minimal code that illustrate the difference:

.parent {
  position: relative;
  background-color: chocolate;
}

.child {
  position: absolute;
  background-color: darkgreen;
  left: 50%;
}
<a href="" class="parent">
      I am a Parent
      <div class="child">
        I am a child
      </div>
    </a>
<br><br><br><br><br>
<a href="" class="parent">
  <div>I am a Parent</div>
  <div class="child">
    I am a child
  </div>
</a>

Note how in the first case you have text content inside your inline element so your element is having a width used as reference for the left property. In the second case, you have a block element inside an inline element and this one is now having a width equal to 0 (no background coloration) and this is what you are facing in your first code. left:X% of 0 is 0 so nothing will happen.

What you are doing is of course valid but having block element inside inline element will make the rendring a bit tricky. From the specification you can read:

When an inline box contains an in-flow block-level box, the inline box (and its inline ancestors within the same line box) are broken around the block-level box (and any block-level siblings that are consecutive or separated only by collapsible whitespace and/or out-of-flow elements), splitting the inline box into two boxes (even if either side is empty), one on each side of the block-level box(es). The line boxes before the break and after the break are enclosed in anonymous block boxes, and the block-level box becomes a sibling of those anonymous boxes. When such an inline box is affected by relative positioning, any resulting translation also affects the block-level box contained in the inline box.

Yes not easy to understand but let's take our example and add more CSS to better see:

.parent {
  position: relative;
  background-color: chocolate;
  border:2px solid red;
}
some text before<br>
<a href="" class="parent">
  <div>I am a Parent</div>
</a>
<br> some text after

You can see how the block element broke our inline element in two chunks that are empty.

To avoid dealing with this, avoid having block element inside inline elements. Use inline-block to fix this issue:

.parent {
  position: relative;
  background-color: chocolate;
  border:2px solid red;
  display:inline-block;
}
some text before<br>
<a href="" class="parent">
  <div>I am a Parent</div>
</a>
<br>
some text after
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • but upon inspecting `.parent` its width is `1109px` (viewport width being `1125px`) Then what's the issue, because it's width is not 0 in your 2nd case. – Tanmay Lodha Jul 10 '20 at 19:53
  • @TanmayLodha where did you inspect parent and got 1109px? technically you cannot do this because it's not more *one* element – Temani Afif Jul 10 '20 at 19:54
  • inspect the a tag and then see its dimensions. – Tanmay Lodha Jul 10 '20 at 20:03
  • @TanmayLodha the tag has no dimension, as you can see there is no coloration on it. Did you read my full answer at the end? you cannot inspect the tag because it's not more *one* element – Temani Afif Jul 10 '20 at 20:04
  • OK so then going to the elements tab and hovering over anchor tag `.parent` is showing the dimensions in the display window. what are these? – Tanmay Lodha Jul 10 '20 at 20:09
  • @TanmayLodha the browser will try to show something for you. If you try in different browser you may get different results but it's clear from the code that your element is having no width since the background is not applying. Also the specification is clear detailing what is happening. – Temani Afif Jul 10 '20 at 20:14
  • Yeah, I have understood that! But is there any way to send you screenshot to show what I am seeing regarding the dimensions. – Tanmay Lodha Jul 10 '20 at 20:25
  • @TanmayLodha the browser is giving you the width of the content inside so it's easy for your to see the layout but it's a bit missleading .. at least now you know that you should never use block element inside inline elements ;) – Temani Afif Jul 10 '20 at 21:02
  • So in actual, that's not the width and height of anchor tag? – Tanmay Lodha Jul 10 '20 at 21:20
  • @TanmayLodha no it's not. You can also use JS to get the computed width/height and you will not get the same (you will get 0) – Temani Afif Jul 10 '20 at 21:23
  • NO, I have used `console.log(document.getElementById('a').getBoundingClientRect());` (where #a is anchor tag ) and it is returning width:760px and height:159px. Hence, not width not equals to 0. – Tanmay Lodha Jul 11 '20 at 18:29
  • @TanmayLodha no, this not the same. getBoundingClientRect will consider the element and its child ... I am not expert in JS to explain this very well but it's not exactly the same as getting the computed width which is the reference for the left property. – Temani Afif Jul 11 '20 at 20:03
  • Yeah, clientWidth and clientHeight: is giving 0 width and height. That's why it was not working! – Tanmay Lodha Jul 12 '20 at 18:02
0

Please use this...

.section-first {
  position: relative;
}

Instead of the below style.

.section-first a {
  position: relative;
}

The <div> tag is a block level element. The <a> tag is tag is an inline element.

Rayees AC
  • 4,426
  • 3
  • 8
  • 31