Fifi
Fifi

Reputation: 3605

CSS position relative : width not considered

I try to build a pure CSS tree. I encountered a problem with horizontal lines between blocks (two blocks are at the same level). I isolated the problem in the following jsfiddles:

https://jsfiddle.net/8Lsv1ypd/3/

https://jsfiddle.net/8Lsv1ypd/4/

Html :

<span class="first">First</span>
<span class="second">Second</span>

CSS:

.first {
  background-color: #dc3545;
  color: #fff;
  font-size: 1.2rem;
  border: 1px #ccc solid;
  border-radius: 20px;
  padding: 5px 10px;
  margin-top: 10px;
}

.second {
  background-color: #6f42c1;
  color: #fff;
  font-size: 1.2rem;
  border: 1px #ccc solid;
  border-radius: 5px;
  padding: 5px 10px;
  margin-top: 10px;
  margin-left: 10px;
}

.second::before {
  content: "";
  position: relative;
  top: -13px;
  left: -30px;
  border-left: 1px solid #aaa;
  border-bottom: 1px solid #000;
  border-radius: 0 0 0 0px;
  height: 26px;
  width: 50px !important;
}

When the CSS position (in .second::before) is set to relative, the width (fixed in pixels) is not considered, only the vertical line is displayed and width is "forced by the browser" to 1 pixel.

When the CSS position (in .second::before) is set to absolute, the width is not taken into account and the horizontal line is displayed, but the line is not joining the two block.

I already try many combinations of the following options:

I already look at the following questions :

And the following article :

https://alistapart.com/article/css-positioning-101

Upvotes: 4

Views: 8760

Answers (1)

Temani Afif
Temani Afif

Reputation: 272842

When the CSS position (in .second::before) is set to relative, the width (fixed in pixels) is not considered, only the vertical line is displayed and width is "forced by the browser" to 1 pixel.

A pseudo element is an inline element by default, setting position:relative will not change this thus you cannot apply width and height to the element. Then the borwser is not forcing the width to 1px, it's the border you have set that is equal to 1px. The height also isn't working and the height of the element and the border is defined by the font property.

Increase the height and you will see that nothing will change:

.first {
  background-color: #dc3545;
  color: #fff;
  font-size: 1.2rem;
  border: 1px #ccc solid;
  border-radius: 20px;
  padding: 5px 10px;
  margin-top: 10px;
}

.second {
  background-color: #6f42c1;
  color: #fff;
  font-size: 1.2rem;
  border: 1px #ccc solid;
  border-radius: 5px;
  padding: 5px 10px;
  margin-top: 10px;
  margin-left: 10px;
}

.second::before {
  content: "";
  top: -13px;
  left: -30px;
  border-left: 1px solid #aaa;
  border-bottom: 1px solid #000;
  border-radius: 0 0 0 0px;
  height: 600px;
  width: 50px !important;
}
<span class="first">First</span>
<span class="second">Second</span>

Now increase the font-size and you will see some changes

.first {
  background-color: #dc3545;
  color: #fff;
  font-size: 1.2rem;
  border: 1px #ccc solid;
  border-radius: 20px;
  padding: 5px 10px;
  margin-top: 10px;
}

.second {
  background-color: #6f42c1;
  color: #fff;
  font-size: 1.2rem;
  border: 1px #ccc solid;
  border-radius: 5px;
  padding: 5px 10px;
  margin-top: 10px;
  margin-left: 10px;
}

.second::before {
  content: "";
  top: -13px;
  left: -30px;
  border-left: 1px solid #aaa;
  border-bottom: 1px solid #000;
  border-radius: 0 0 0 0px;
  height: 600px;
  font-size:50px;
  width: 50px !important;
}
<span class="first">First</span>
<span class="second">Second</span>


When the CSS position (in .second::before) is set to absolute, the width is not taken into account and the horizontal line is displayed, but the line is not joining the two block.

When adding position:absolute the element become a block level element thus you can know control its width and height and both are considered in your case but your element is positionned relatively to the viewport since there is no positionned ancestor. It's hidden because you set a negative left value so you cannot see the border you have set.

You need to make the span position:relative to make the pseudo element positionned relatively to the span:

.first {
  background-color: #dc3545;
  color: #fff;
  font-size: 1.2rem;
  border: 1px #ccc solid;
  border-radius: 20px;
  padding: 5px 10px;
  margin-top: 10px;
}

.second {
  background-color: #6f42c1;
  color: #fff;
  font-size: 1.2rem;
  border: 1px #ccc solid;
  border-radius: 5px;
  padding: 5px 10px;
  margin-top: 10px;
  margin-left: 10px;
  position:relative;
}

.second::before {
  content: "";
  position: absolute;
  top: -13px;
  left: -30px;
  border-left: 1px solid #aaa;
  border-bottom: 1px solid #000;
  border-radius: 0 0 0 0px;
  height: 26px;
  width: 50px !important;
}
<span class="first">First</span>
<span class="second">Second</span>


10.3.1 Inline, non-replaced elements

The 'width' property does not apply ref


10.6.1 Inline, non-replaced elements

The 'height' property does not apply. The height of the content area should be based on the font, ref


Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents. ref


In the absolute positioning model, a box is explicitly offset with respect to its containing block

If the element has 'position: absolute', the containing block is established by the nearest ancestor with a 'position' of 'absolute', 'relative' or 'fixed', ... If there is no such ancestor, the containing block is the initial containing block. ref

Upvotes: 5

Related Questions