Why Doesn't Width/Height Work with Non Positioned Pseudo Elements

Why doesn't width/height work with non positioned pseudo elements?

First, it's not about percentage values. You will have the same result even with pixel values and both width and height aren't working.

Pseudo elements are inline elements and their width/height is only defined by their content and the width/height set with CSS will be ignored.

In CSS, ::before creates a pseudo-element that is the first child of the selected element. It is often used to add cosmetic content to an element with the content property. It is inline by default. ref

width

This property does not apply to non-replaced inline elements. The content width of a non-replaced inline element's boxes is that of the rendered content within them ref

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


By making the pseudo element position:absolute you will now consider the rules that applies to Absolutely positioned element in order to calculate width and height. You will also notice that the element will have a computed value of block within display.

Sample Image

You should also pay attention to the use of positioned element which means either relative, absolute, fixed or sticky BUT making the element position:relative will keep it an inline level element and you still cannot use width/height.

.positioned {
position: relative;
height: 15px;
background-color: aquamarine;
margin-bottom: 10px;
}
.positioned::before {
position: relative;
content: "";
background: red;
width: 80%;
height: 100%;
}

.not-positioned {
height: 15px;
background-color: aquamarine;
margin-bottom: 10px;
}
.not-positioned::before {
content: "";
background: red;
width: 80%;
height: 100%;
}
<div class="positioned"></div>
<div class="not-positioned"></div>

width and height doesn't seem to work on :before pseudo-element

Note: The ::before and ::after pseudo-elements are actually laid display: inline; by default.

Change the display value to inline-block for the width & height to take effect while maintaining inline formatting context.

a.infolink::before {
content: '?';
display: inline-block;
background: blue;
color: white;
width: 20px;
height: 20px;
}

http://jsfiddle.net/C7rSa/3/

Pseudo element not full container width when border used

From the specification

The position and size of an element's box(es) are sometimes calculated relative to a certain rectangle, called the containing block of the element. The containing block of an element is defined as follows:

....


  1. 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:

    1. In the case that the ancestor is an inline element, the containing block is the bounding box around the padding boxes of the first and the last inline boxes generated for that element. In CSS 2.1, if the inline element is split across multiple lines, the containing block is undefined.
    2. Otherwise, the containing block is formed by the padding edge of the ancestor

Then

The padding edge surrounds the box padding. If the padding has 0 width, the padding edge is the same as the content edge. The four padding edges define the box's padding box.

This explain why your element doesn't use the border-box as reference but the padding-box when positionned. It's also the same for percentage width1. using width:100% means the padding and the content of the containing block. Border aren't counted.


Concerning box-sizing

... , any padding or border specified on the element is laid out and drawn inside this specified width and height.

So the border need to belong to the element not a parent element in order to consider box-sizing which is not your case since the border isn't applied to the pseudo element:


1 For absolutely positioned elements whose containing block is based on a block container element, the percentage is calculated with respect to the width of the padding box of that element.ref

.box {  border:5px solid;  padding:10px;  background:red;  min-height:100px;  position:relative;}span:first-child {  display:inline-block;  width:100%;  background:blue;}span:last-child {  position:absolute;  bottom:0;  left:0;  width:100%;  background:green;}
<div class="box">  <span>I am a static element</span>  <span>I am a absolute element</span></div>

Pseudo element reduces in size when elements around grow

Try this code:

.outter-wrapper {
width: 200px;
border: 1px solid black;
}

.wrapper {
display: inline-flex;
min-height: 1.5rem;
padding: 8px 24px 8px 0px;
width: 100%;
}

.input {
position: absolute;
z-index: -1;
visibility: hidden;
}

.label-wrapper {
line-height: 1.5rem;
position: absolute;
left: 10px;
}

.label {
position: relative;
margin-bottom: 0;
display: flex;
margin-left: 0;
margin-right: 24px;
flex-direction: row-reverse;
justify-content: space-between;
flex: 1;
align-items: center;
}

.label:before {
display: block;
min-width: 20px;
height: 20px;
content: "";
background-color: #fff;
border: 1px solid black;
border-radius: 4px;
position:absolute;
top:0;
}

.label:after {
position: absolute;
display: block;
height: 20px;
content: "";
background-repeat: no-repeat;
background-position: center center;
background-size: 80%;
}

input[type="checkbox"]:checked~.label::after {
background-image: url("https://cdn-icons-png.flaticon.com/512/447/447147.png");
width: 20px;
height: 20px;
top: 0;
}
<div class="outter-wrapper">  
<div class="wrapper">
<input class="input" name="checkbox2" id="checkbox2" type="checkbox">
<label class="label" for="checkbox2">
<div class="label-wrapper">
THis world is full of creatures
</div>
</label>
</div>
</div>

CSS Sprite Doesn't Work Because Width/Height defines container

If I understand your question correctly, and your constraints, this problem may be solvable using pseudo elements.

One approach might be to slightly modify the styles for the existing CSS as below, and add a floating icon via a pseudo element.

This should give you the control you need to size, and select unique icons from your icon sprint/atlas:

[UPDATED] Sorry, just noticed my original answer was missing: content:'' in the pseudo selector - please ensure this is added

/* Leave existing styling for box sizing mostly untouched, with minor adjustments */
.simply-scroll-btn-down {
left: 0px;
top: 0px;
width: 100%;
height: 25px;
background: #000; // Remove image, etc
position:relative; // Add this so that pseudo element can be centered
}

/* Display a pseudo element for icon */
.simply-scroll-btn-down:after {

//[UPDATE] This is required
content:'';

position:absolute;
display:block;

// This translates the pseduo element for centering
left: 50%;
top: 50%;

// This adjusts the pseduo element for centering based on pseduo elements dimensions
margin-left:-20px;
margin-top:-20px;
width: 40px;
height: 40px;

// Adjust these rules to suit the icon coordinates in your sprite/atlas
background-image: url('YOUR_SPRITE_URL'); // Customise as needed
background-repeat: no-repeat; // Customise as needed
background-position: 10px 10px; // Customise as needed
}

Why do I have to set top/bottom and left/right to 0 in order for my body::before to completely cover the page?

The body element by default has margin of 8px on all sides which causes it to move slightly to bottom-right, so when you remove the margins of the body body { margin: 0; }, it fixes that.

Secondly, when you set position: relative; width: 100%; height: 100%, the element goes with the normal flow of the document and takes up 100% of width and height but you did not define the width and height of the body element. So the normal flow of ::before becomes the 100% of the parent which is 0 (i.e. not defined) and hence doesn't show up. Thus in order to use position: relative; on a child element, you need to atleast define the width and height of the parent element with absolute length units.

Hence, the following works

body{
background: #000;
width: 100vw;
height: 100vh;
}

body::before {
content: "";
position: relative;

/* 100% is a relative unit and requires its
parent to have dimensions with absolute units */
width: 100%;
height: 100%;
...
}

How is :after element's height and width determined?

.img-span:after creates a pseudo-element within the .img-span element.

The following CSS rules

position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;

are stretching the :after pseudo-element to the width / height of its parent element.

.img-span may not be the parent element, as position: absolute is relative to the first parent element it encounters with either position: relative, position: absolute, or position: fixed.



Related Topics



Leave a reply



Submit