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.
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:
....
- 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:
- 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.
- 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
HTML Maxlength Attribute Not Working on Chrome and Safari
Including a Interactive 3D Figure with Knitr
CSS Box Shadow Around a Custom Shape
How to Include Special Characters in Query Strings
Why Is There a Default Margin on The <Body> Element
Marking Up a Search Result List with HTML5 Semantics
How to Get a Textarea to Stretch to Fit Its Content Without Using PHP or JavaScript
Browser Canvas Cors Support for Cross Domain Loaded Image Manipulation
@Font-Face Not Working with Specific Version of Internet Explorer 11
Achieving Sub Numbering on Ol Items HTML
Bootstrap - Fill Fluid Container Between Header and Footer
Can You Tab Through All Radio Buttons
How Is HTML5 Webstorage Data Physically Stored
How Many Characters Are Possible in an Input Field in HTML
Why Does Chrome 80 Cause This Grid-Template-Rows: Auto Problem
How to Insert HTML Content in Xml Document