Make a Square Pseudo Element Only using Padding - html

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>

Related

How to draw a border at the left of an element in a list

I'm doing an UI for a web application with bootstrap, font-awesome icons and I would like to replicate this style in a list:
I have tried:
HTML
<ul role="list">
<li class="btn p-0">
agosto '20
<i class="fas fa-chevron-right"></i>
</li>
</ul>
CSS
ul {
margin: 0;
padding: 0;
display: grid;
grid-gap: 0.8rem;
list-style: none;
li {
border-radius: 0.25rem;
background-color: #ffffff;
border-left: 5px solid blue;
text-align: start;
i {
color: #3C3E43;
float: right;
}
}
}
My result so far:
I can't replicate the left border with its border-radius. Looks like cut off at the right and the space between the border and the text is not applied.
What I am missing?
use pseudo element:
.box {
padding: 5px 10px 5px 20px;
position: relative;
}
.box::before {
content: "";
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 8px;
background: blue;
border-radius: 50px;
}
<div class="box"> some text</div>
As you likely discovered, border-radius on the <li> rounds the entire list item, not just the left border.
A better solution here would be to use a pseudo element to create the rounded left "border" design. Something like:
li::before {
content: '';
display: inline-block;
width: 5px;
height: 100%;
border-radius: 5px;
background-color: blue;
}
You may have to fiddle with the layout for your use case (height: 100% may not work, among other things), but that's the general direction to take.

Pseudo element not full container width when border used

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>

how to create a half-box in html/css

I'm trying to create a div that has a left and top border with text in top line. what I am trying to achieve is the following...
html half box
I am able to get the top with the text using the following css or alternately a table but can't get it with the left border also. any 'outside the box' thinkers?
.hr-sect {
display: flex;
align-items: center;
color: blue;
margin: 8px 0px;
}
.hr-sect::before
{
content: "";
width: 20px;
background: #000;
height: 1px;
font-size: 0px;
line-height: 0px;
margin: 0px 8px;
}
.hr-sect::after {
content: "";
width:100%;
background: #000;
height: 1px;
font-size: 0px;
line-height: 0px;
margin: 0px 8px;
}
CATEGORY
CATEGORY
You can simulate that interrupted border line by using an absolutely placed div that has a non-transparent background, just make sure it matches the actual background color.
.half-box {
border-left: 1px solid black;
border-top: 1px solid black;
position: relative;
padding: 30px;
}
.half-box > .title {
background-color: white;
padding: 0 10px;
position: absolute;
top: 0;
left: 30px;
font-size: 20px;
transform: translateY(-50%);
}
<div style="height: 100px">
</div>
<div class="half-box">
some content
<div class="title">
CONTENT
</div>
</div>
Set a positioning context on the outer box with position: relative;
For the border, use a pseudo ::before element with content: " "; and give it a position: absolute; to take it out of the flow. Give it a top and left border.
For the heading, also use position: absolute; and move it up with top: -20px or whatever. Set the same background color as the outer box to mask the border.
Adjust your margins and paddings as needed.
See this codepen: https://codepen.io/matthewsmith_io/pen/RVYQqy

How to avoid absolute bottom positioned div from overlapping other when window is resized

I have a page where I have a div at the bottom of the page which when clicked shows another div, just above the bottom div.
I'd like to avoid the footer divs overlapping the content div higher up the page when the window is resized.
The heights of the divs involved shouldn't change.
Is a CSS-only solution possible?
I've created a jsfiddle here
CSS
html, body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
#container {
height: 100%;
width: 100%;
background-color: white;
border: solid #aaa 1px;
padding: 4px;
}
#content {
height: 300px;
border: solid blue 1px;
}
#footer-content {
height: 100px;
border: solid red 1px;
display:none;
}
#footer-footer {
cursor: pointer;
height: 20px;
border: solid cyan 1px;
}
#footer.expanded #footer-content {
display:block;
}
#footer {
position: absolute;
bottom: 0px;
width: 100%;
}
HTML
<div id="container">
<div id="content">content
</div>
<div id="footer">
<div id="footer-content">footer-content</div>
<div id="footer-footer">Click me to expand</div>
</div>
</div>
JS
$("#footer-footer").on("click", function (evt) {
$("#footer").toggleClass("expanded");
});
Simply add position: relative to the #container. This way the absolute positioning of the footer refers to the container.
http://jsfiddle.net/5bkznxud/5/
You'll probably notice that in the example above there's always a scrollbar on the right. This is because of the borders and padding on #container. Here's an example with outline (border with no calculated width) and without any padding:
http://jsfiddle.net/5bkznxud/6/
TIP: Always use outline instead of border for blocking a layout OR use box-sizing: border-box. This causes a box' dimensions to also calculate for the border. Otherwise a box with width of 100% and border will span slightly wider than you want.
It can be solved by using calc().
In this case you can create a jQuery function that get the height of footer-content and footer-footer -> .height(). Without jQuery, I don't think it's possible.
Here is an example:
html, body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
#container {
height: 100%;
width: 100%;
background-color: white;
border: solid #aaa 1px;
padding: 4px;
min-height: 420px;
}
#content {
height:calc(100% - 135px);
border: solid blue 1px;
}
#footer-content {
height: 100px;
border: solid red 1px;
display:none;
}
#footer-footer {
cursor: pointer;
height: 20px;
border: solid cyan 1px;
}
#footer.expanded #footer-content {
display:block;
}
#footer {
position: absolute;
bottom: 0px;
width: 100%;
}
http://jsfiddle.net/dokmngv0/
Browser support for the calc() feature: http://caniuse.com/#feat=calc

CSS3-triangle before div

I'm trying to add a triangle before a div using css, but it ends up under it.
http://jsfiddle.net/lasseedsvik/LwE7u/
HTML
<div id="container">
1234
<div id="toolbar">
Want silly triangle before this div to left
</div>
</div>
CSS
#container {
width: 500px;
}
#toolbar:before
{
width: 44px;
content: '';
height: 0px;
border-style: solid;
border-width: 0 0 44px 44px;
border-color: transparent transparent blue transparent;
}
#toolbar {
float: right;
width: 350px;
height: 44px;
background: blue;
color: #fff;
}
Is there something missing like display: inline or something?
Use CSS Positioning to set the triangle correctly, in the example below, I am using position: relative; on the parent element, and than use position: absolute; for the :before pseudo..and than use left property which is dobule of the elements width
Always you should wrap the absolute positioned elements with a relative positioned containers, else your element will fly out in the wild.
Demo
#container {
width: 500px;
}
#toolbar:before {
position: absolute;
left: -88px; /* Double the element size */
width: 44px;
content: '';
height: 0px;
border-style: solid;
border-width: 0 0 44px 44px;
border-color: transparent transparent blue transparent;
}
#toolbar {
float: right;
width: 350px;
height: 44px;
background: blue;
color: #fff;
position: relative;
}
Note: Generally when you are creating triangles using CSS, it's a
common practice to set the elements height and width to 0 so if
you want, just tweak them up.
Try putting your div#toolbar in position:relative and positionning your pseudo-element in an absolute manner. Then adjust position and margins to position it correctly.
http://jsfiddle.net/LwE7u/2/