Pseudo element not full container width when border used - html

I have a piece of html/css that represents a button with a border.
The button has pseudo elements which overlay the button - the simple example shows one of them.
The pseudo element is taller than the original element (height set using px) but the same width (set at 100%).
There are two issues which aren't working as I expect in the current design:
Despite using box-sizing: border-box, the pseudo width does not
include the border.
The pseudo element is positioned absolutely (top, left) but this
reference position is inside the parent border.
This seems to be the same in both Chrome and Edge which would indicate I'm not doing something right - however, I'm particularly confused with regard to box-sizing.
.container {
padding: 50px;
}
.button {
border: solid 4px red;
box-sizing: border-box;
display: inline-flex;
justify-content: center;
align-items: center;
height: 36px;
padding: 0 16px;
position: relative;
z-index: 1;
}
.button::before {
background-color: rgba(76, 255, 0, 0.8);
box-sizing: inherit;
content: "";
display: block;
position: absolute;
top: -4px;
left: 0;
height: 44px;
width: 100%;
z-index: -1;
}
<div class="container">
<a class="button">Button</a>
</div>

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>
An idea to obtain what you want is to use inset box-shadow instead of border:
.container {
padding: 50px;
}
.button {
box-shadow: inset 0 0 0 4px red;
box-sizing: border-box;
display: inline-flex;
justify-content: center;
align-items: center;
height: 36px;
padding: 0 16px;
position: relative;
z-index: 1;
}
.button::before {
background-color: rgba(76, 255, 0, 0.8);
box-sizing: inherit;
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: -1;
}
<div class="container">
<a class="button">Button</a>
</div>

Try increasing the width of the pseudoelement with the size of the border of the parent and shift it to the left with left: -4px:
.container {
padding: 50px;
}
.button {
border: solid 4px red;
box-sizing: border-box;
display: inline-flex;
justify-content: center;
align-items: center;
height: 36px;
padding: 0 16px;
position: relative;
z-index: 1;
}
.button::before {
background-color: rgba(76, 255, 0, 0.8);
box-sizing: inherit;
content: "";
display: block;
position: absolute;
top: -4px;
left: -4px;
height: 44px;
width: calc(100% + 8px);
z-index: -1;
}
<div class="container">
<a class="button">Button</a>
</div>

Im 3 years late but Ive found a solution to this.
Credits to https://www.getpeblo.com I saw this implemented on their site first. Also thanks to user Temani Afif for clearing it up that the absolutely positioned pseudo element will get the width of its parent's padding box and not border box.
So to get around this you need to wrap the button in which you have set a border in a div container. This div has to have a display of inline block so its width will be the full width of the button(Note that if your container is a grid or flex child of a grid/flex container I think it sort of behaves like an inline block but id still suggest to set the display to inline-block anyway).
Now you want the pseudo element to be a descendant of the container and not the button itself so it gets the full width of the button as the container's padding box is the same width as the button's border box. Here's the snippet:
/* UNRELATED STYLES*/
*{
margin: 0;
padding: 0;
border:0;
box-sizing: border-box;
}
*::after{
box-sizing:border-box;
}
body{
font-family: "Helvetica", "sans-serif";
line-height: 1;
font-weight:400;
}
.container{
max-width:900px;
min-height:100vh;
margin: 0 auto;
display:grid;
place-items:center;
}
/* Fix */
.btn-contain{
position:relative;
display:inline-block;
}
.btn-contain::after{
content: "";
position: absolute;
top:2px;
left:2px;
height: 100%;
width: 100%;
border-radius: 4px;
background-color: #34344B;
z-index: -1;
}
.btn:any-link{
display: inline-block;
text-decoration: none;
padding: 12px 30px;
border: 2px solid #34344B;
border-radius: 4px;
font-size: 18px;
font-weight: 600;
background-color: #F031A7;
color: #34344B;
transition: 300ms;
}
<div class="container">
<div class="btn-contain">
<a class="btn" href="#">Im a button</a>
</div>
</div>

Related

Center modal horizontally without jquery

I am working on a modal in a react app, the width is set to auto and the position is fixed, I am trying to get it centered in the middle of the screen horizontally.
.Modal {
position:fixed;
width: auto;
z-index: 500;
align-content: center;
background-color: rgba(255, 255, 255, 0.889);
border: 1px solid #ccc;
box-shadow: 5px 5px 5px black;
padding: 0px;
font-size: 12px;
box-sizing: border-box;
transition: all 0.3s ease-out;
}
I have tried a few of the solutions that come up in stack overflow when searching to center the modal.
The main issue I am having is that this modal is above other elements on the z-index and if I change the position to absolute, as most of the examples suggest, the items that have been rendered below it on the z-index get shifted down the screen.
This doesn't work for me.
Try adding margin:0 auto; to your css and remove position:fixed.
Adding "margin: 0 auto;" is not going to work on a item with position: fixed.
Either lose the position fixed and do margin: 0 auto;
Or
Set the left position on (50% - width element / 2).
But i guess the first solution is the easiest one.
because your modal is position fixed, you need to use left or right css properties to change the horizontal position of your modal. But you have 'width' auto, which will not work because the width can vary. The easiest way would be to wrap the modal in a parent div, like the following
.modal-parent {
position: fixed;
display: flex;
justify-content: center;
align-items: center;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
}
.modal {
padding: 40px;
background: white;
}
<div class='modal-parent'>
<div class='modal'>
</div>
</div>
or if you don't want a parent div, you can just give it a static width, and the height can vary:
.modal {
position: fixed;
padding: 40px;
box-sizing: border-box;
top: 0;
left: calc(50% - 150px);
width: 300px;
background: teal;
}
<div class='modal'>
</div>

Make a Square Pseudo Element Only using Padding

Why isn't a pseudo element with equal padding on all sides a square?
I am only able to achieve a square pseudo element when the right/left padding is 1.5 times that of the top/bottom padding.
See code below.
button{
width: 200px;
height: 100px;
background: gray;
border:none;
font-size:16px;
}
.icon::before {
// position: relative;
padding: 20px;
content: "";
background: black;
}
.icon2::before {
padding: 20px 30px;
content: "";
background: black;
}
<p>Pseudo element: padding on all sides is 20px.</p>
<button class="icon">
Click Me
</button>
<p>Pseudo element: padding on top/bottom is 20px, padding on left/right is 30px.</p>
<button class="icon2">
Click Me
</button>
Because it is treated as an inline element by default and the font-size will impact the size of the element. Change font-size: 0; or add display: block; with a matching height/width and it will be a square.
button{
width: 200px;
height: 100px;
background: gray;
border:none;
font-size:16px;
}
.icon::before {
// position: relative;
padding: 20px;
content: "";
background: black;
display: block;
width: 0;
height: 0;
}
.icon2::before {
padding: 20px;
content: "";
background: black;
font-size: 0;
}
<p>Pseudo element: padding on all sides is 20px.</p>
<button class="icon">
Click Me
</button>
<p>Pseudo element: padding on top/bottom is 20px, padding on left/right is 30px.</p>
<button class="icon2">
Click Me
</button>
See Michael's answer for an answer to the why in your question.
I would just like to point out, that most of the time the answer to your title is to use the fact that percentage padding is relative to the width of the thing. Yes, width, not height. I.e. you can add padding-bottom: 100% to achieve a square. Or make that 62.5% to achieve a 16:9 ratio e.g. for videos.
.square {
width: 100px;
}
.square::before {
display: block;
content: '';
padding-bottom: 100%;
border: 1px solid red;
}
<div class="square"></div>
generated content inherits font-size and its line-height from parent.
You can reset font-size to hide both or only line-height.
button{
width: 200px;
height: 100px;
background: gray;
border:none;
font-size:16px;
}
.icon::before {
font-size:0;/* remove space used from inserted text and line-height*/
padding: 10%;/* 10% of 200px width is 20px */
vertical-align:middle;/* can be usefull;*/
margin-right:0.25rem;/* keep away from next phrasing content */
content: "";
background: black;
}
.icon2::before {
padding: 20px 30px;
content: "";
background: black;
}
<p>Pseudo element: padding on all sides is 20px.</p>
<button class="icon">
Click Me
</button>
<p>Pseudo element: padding on top/bottom is 20px, padding on left/right is 30px.</p>
<button class="icon2">
Click Me
</button>

Space on sides of an absolute positioned div

I want to add a space of 10px on both sides of the #in div, like this:
I have this code - live demo:
html
<div id="out">
<div id="in"></div>
</div>
css
#out {
width: 700px;
height: 40px;
background: lightblue;
position: relative;
}
#in {
position: absolute;
width: 100%;
height: 20px;
top: 10px;
background: white;
margin: 0 10px;
}
No calc(), No box-sizing. Since the element is positioned absolutely you could set its left/right offset properties to 10px instead of specifying an explicit width and margins on its sides:
Example Here
#in {
position: absolute;
height: 20px;
top: 10px;
left: 10px;
right: 10px;
background: white;
}
You have to use css calc rule in order to count 100% width - the margin size:
#in {
width: calc(100% - 20px);
}
Hope this helps
Solution 1: Just some padding
You can greatly simplify the CSS:
Just specify the size for the outer div. box-sizing: border-box is added to prevent the padding from influencing the width of the div.
#out {
width: 700px;
padding: 10px;
box-sizing: border-box;
background: lightblue;
}
No positioning needed for the other div. Just give it a height, and it will automatically strech the other div:
#in {
height: 20px;
background: white;
}
http://codepen.io/anon/pen/yICdF
Solution 2: Use a border
If your goal is to get a blue border, you don't need two divs at all. What about this one:
#out {
width: 700px;
}
#in {
height: 20px;
border: 10px solid lightblue;
}
Of course you don't need two divs in this case. Just remove #out altogether and move the width property to #in.
http://codepen.io/anon/pen/icHjD

how to keep floated item centered within container

OK, I've gotten the prelim version of my page started, but I'm having a problem with two floated div's that are wrap in header tag. Basically, I want the two rectangles to center within the containing div tag. One of the rectangles overlaps the other. I had to us positioning to be able to expand them within the container other-wise the second would jump below the first.
Here's what I've have so far.
<div id="div1" class="fluid">
<header id="headGraphics">
<div id="headRectangle1">This will be an image.</div>
<div id="headRectangle2">"This will be text adjusted using opacity."
</div>
Here is the css for the page - I have a follow-up question after we get this solved.
.gridContainer.clearfix #headGraphics {
margin-top: 0px;
margin-right: auto;
margin-left: auto;
margin-bottom: 0px;
font-family: "monotype corsiva";
font-size: 20px;
font-weight: 800;
width: 950px;
text-align: center;
}
.gridContainer.clearfix #headGraphics #headRectangle1 {
float: left;
width: 350px;
height: 75px;
position: relative;
border: medium solid #000000;
-webkit-box-shadow: 3px 3px 3px 1px #FF7878;
box-shadow: 3px 3px 3px 1px #FF7878;
margin-left: auto;
margin-right: auto;
display: inline-block;
}
.gridContainer.clearfix #headGraphics #headRectangle2 {
background-color: #FFAAAA;
float: left;
/*margin-right: 50px;*/
width: 350px;
height: 75px;
position: relative;
top: -50px;
right: 0px;
text-align: center;
clear: both;
left: 100px;
margin-left: auto;
margin-right: auto;
display: block;
}
.gridContainer.clearfix #headGraphics:after {
content: " ";
display: table;
clear: both;
}
I can't remove the position tags because they give me the layout that I'm am trying to accomplish.
Let ma know if you need more info. Thank you in advance. And yes, I have searched this page and others to find a solution, but none seem to apply to my particular situation.
let me clear a few things up... and before I go any further, most of my (98%) selectors are in the boiler plate template. That being said, here the computed effects per selector:
.gridContainer.clearfix #headGraphics;
width 950px, margin 0 auto, font-family monotype weight 800px size 20px, text-align center.
.gridContainer.clearfix #headGraphics #headRectangle1;
width 350px, height 75px, display inline-block, margin rt & lft auto, position relative, box-shadow (which isn't working properly)
.gridContainer.clearfix #headGraphics #headRectangle2
width 350px, height 75px, display inline-block, position relative, top -50px, rt 0px, bot 0px, left 100px (this is to bring object up and offset from rectangle), float left, clear both, text-aligh center.
I would suggest removing the float attributes from both, then just setting both items display as inline-block, you will need to specify width and height on both cases, then apply text-align center to the parent, that will allow the child to be centered to the parents available area.
The Display: inline-block will give the two elements the possibility to behave not just like a block element, it will be both, block and inline, so you will be able to use attributes for both at the same time.
If you need an example, I can provide you with one, Just let me know!
EDIT...
Here is a working example
My JSFiddle
http://jsfiddle.net/dq185dw9/
My CSS
#headGraphics {
margin-top: 0px;
margin-right: auto;
margin-left: auto;
margin-bottom: 0px;
font-family: "monotype corsiva";
font-size: 20px;
font-weight: 800;
width: 950px;
text-align: center;
outline: red dashed 1px;
padding: 35px; /* remove or change if needed */
}
#headGraphics [id*="headRectangle"] {
width: 350px;
height: 75px;
position: relative;
border: medium solid #000000;
-webkit-box-shadow: 3px 3px 3px 1px #FF7878;
box-shadow: 3px 3px 3px 1px #FF7878;
display: inline-block;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
-khtml-box-sizing: border-box;
box-sizing: border-box;
margin: 0px 25px;
line-height: 75px; /* remove or change if you want to have more than one line of text */
}
My HTML
<header id="headGraphics">
<div id="headRectangle1">This will be an image.</div>
<div id="headRectangle2">"This will be text adjusted using opacity.</div>
</header>

Box-sizing, why height > 100%?

I'm trying to create the markup for a simple panel. The structure is below. The <div> with "transcluded" in it should fill its parent container <div>.
<div class="container">
<div class="container-title">title</div>
<div class="container-body">
transcluded
</div>
</div>
As you can see (in http://jsfiddle.net/kAk9Z/), the "transcluded" body extends beyond its container instead of filling only.
How can I get the container to stay its size while having the "transcluded" <div> fill in the remaining space?
Why don't you set you're height on the inner body div. That way it will determine the height of your container div, and you get the result you want. You could even go for a min-height and have it grow when the content requiers it. Something like this:
.container {
width: 640px;
background-color: #dededd;
padding: 4px;
}
.container-body {
background-color: white;
height: 100%;
border: 1px solid black;
padding: 8px;
min-height: 460px;
}
And the fiddle: http://jsfiddle.net/kAk9Z/4/
This is not a box-sizing issue, when you declare height 100% it is referred to the height of the parent element, which already contains a div so the sum of the heights of the .container's children is > 100.
A solution can be switch the container body to position: absolute, here's the fiddle: http://jsfiddle.net/kAk9Z/2/
.container {
width: 640px;
height: 480px;
background-color: #dededd;
padding: 4px;
position: relative;
}
.container-body {
background-color: white;
border: 1px solid black;
padding: 8px;
position: absolute;
top: 30px;
bottom: 4px;
right: 4px;
left: 4px;
}