Lynel Hudson
Lynel Hudson

Reputation: 2405

Why is there a small gap between an absolutely positioned child and parent with borders? All margins, padding, and positions are set to 0

I recreated a stripped down version of the phenomenon I'm facing. So the parent has position: relative and the ::after child has position: absolute with all directional values set to zero. This would normally stretch out the child directly over the parent perfectly in my experience. Also * { margin: 0; padding: 0 } is set to be safe and make sure this isn't a margin or padding issue.

I know I can just set the child element -1px left and up... but I'm kind of curious to why this is happening if the child is stretched out directly over it's parent? Is there a way to make it work with top, right, bottom, and left set to 0?

* {
  margin: 0;
  padding: 0;
}
body {
  padding: 5rem; /* to push div closer to center of snippet window */
}
div {
  transform: scale( 5 ); /* added so displacement can be easily seen */
}
div, div::after {
  display: block;
  position: relative;
  width: 1rem;
  height: 1rem;
  background-color: #eee;
  border-style: solid;
  border-width: 0.1rem;
  border-color: #666;
  border-radius: 0.25rem;
  content: '';
}
div::after {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
}
<div></div>

Notice from the snippet ( In Chrome atleast ) The div's are offset from each other by about 1 px.

Picture of what I'm seeing in Chrome on desktop:

enter image description here

Why aren't these div's placed directly on top of each other?

Upvotes: 2

Views: 1024

Answers (1)

Temani Afif
Temani Afif

Reputation: 273750

The reference is the padding-box and not the border-box

If the element has 'position: absolute', the containing block is established by the nearest ancestor with a 'position' of 'absolute', 'relative' or 'fixed', in the following way:

... the containing block is formed by the padding edge of the ancestor. ref

Then the values are over-constrained since you are defining left/right/width and the width is equal to the parent (containing block) width so the right will be ignored (use any value for it and nothing will happen)

If the values are over-constrained, ignore the value for 'left' (in case the 'direction' property of the containing block is 'rtl') or 'right' (in case 'direction' is 'ltr') and solve for that value. ref

Same logic with top/bottom/height where the bottom is ignored.

If you replace your border with a box-shadow for example you will have a perfect overlap:

* {
  margin: 0;
  padding: 0;
}
body {
  padding: 5rem; /* to push div closer to center of snippet window */
}
div {
  transform: scale( 5 ); /* added so displacement can be easily seen */
}
div, div::after {
  display: block;
  position: relative;
  width: 1rem;
  height: 1rem;
  background-color: #eee;
  box-shadow:0 0 0 0.1rem #666;
  border-radius: 0.25rem;
  content: '';
}
div::after {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
}
<div></div>

Upvotes: 2

Related Questions