My goal is to prevent box-shadow from overlapping on top of nearby elements by using :before and z-index.
But the shadow is going underneath the container of the list item that casts it because of the z-index.
It works fine if its parent container is just the body.
Is there a workaround regarding this or should I change my HTML and CSS
HTML (PUG)
div#main
ul
li
li
li
CSS (Stylus)
#main
background-color lightyellow
height 300px
width 300px
ul
padding 10px
li
background-color lightblue
height 50px
width 50px
margin 10px
position relative
&::before
content ''
box-shadow 0px 0px 15px 20px rgba(0,0,0,0.5)
position absolute
top 0px
right 0px
bottom 0px
left 0px
z-index -1
you are using an absolutely positioned pseudo elements without setting position: relative to its parent, i.e. why its causing this type of issues also you haven't set some basic CSS rules for a better results as:
Code Snippet
html,
body {
margin: 0;
padding: 0;
}
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
#main {
background-color: lightyellow;
height: 300px;
width: 300px;
}
ul {
padding: 10px;
margin: 0;
position: relative;
}
ul li {
background-color: lightblue;
height: 50px;
width: 50px;
margin: 10px;
position: relative;
overflow: hidden;
}
ul li::before {
content: '';
box-shadow: 0px 0px 15px 20px rgba(0, 0, 0, 0.5);
position: absolute;
top: 0px;
left: 0px;
display: inline-block;
width: 100%;
height: 1px;
}
<div id="main">
<ul>
<li>List01</li>
<li>List02</li>
<li>List03</li>
</ul>
</div>
I found an answer, I don't know if this is the best way to go
HTML (PUG)
ul
li
div.content
span All
li
div.content
span By
li
div.content
span Myself
li
div.content
span ANYMORE!!!
CSS (STYLUS)
body
margin 15px
ul
display inline-block
li
width 120px
height 50px
.content
background-color lightyellow
border 1px solid rgba(0,0,0,0.85)
widows 100%
height 100%
position relative
&::after
box-shadow 0px 0px 15px 5px rgba(0,0,0,0.5)
position absolute
top 0
right 0
left 0
bottom 0
content ''
z-index -1
span
position absolute
top 50%
left 50%
transform translate(-50%, -50%)
Related
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>
I have used CSS property 'overflow' for the parent div(#trreWrapdiv). when I click triangle (in black on zone2) down, the box with check mark should be displayed fully, but it is not.
My Aim: I should use 'overflow' for parent div. The box with check should also be displayed fully(but, it is hidden partially)
Now
this should be (I should not remove 'overlow' for parent 'div' i mean box with heading 'Devices')
css
#treeWrapDiv {
border: 3px solid red;
overflow-x: hidden;
overflow-y: auto;
}
.dropdown-menu {
background-clip: padding-box;
background-color: #fff;
border: 2px solid red;
border-radius: 4px;
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.176);
display: none;
float: left;
font-size: 14px;
left: 0;
list-style: outside none none;
margin: 2px 0 0;
min-width: 160px;
padding: 5px 0;
position: absolute;
text-align: left;
top: 100%;
z-index: 1000;
}
Any help or suggestion on this please?
You could achieve that with overflow-x: visible; but from what I see you want this wrapper to be scrollable - you got overflow-y: auto; - but you cant have both scrollable box and content visible outside this box.
Solution is to place .dropdown-menu element outside container and position it absolutely relative to e.g. body with javascript.
I want the triangle shaped pointer to leave enough space between the parent and dropdown menu.
What I want is as below:
What I have done is as below:
CSS for the triangle
.sf-menu ul li:first-child a:after {
content: '';
position: absolute;
left: 40px;
top:-0.01px;
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid #072438;
}
js fiddle:
http://jsfiddle.net/2athcwe9/
you just need to adjust your top values on the ul and the arrow:
.sf-menu ul li:first-child a:after {
content: '';
position: absolute;
left: 40px;
top:-10px; <-------
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid #072438;
}
.sf-menu ul {
list-style: none;
margin: 0;
padding: 0;
display: none;
position: absolute;
top: 63px; <---------------------
left: 0;
z-index: 99999;
background-color: #2D2D2D;
border-bottom:none;
/* background-image: linear-gradient(#444, #111); */
/*-moz-border-radius: 5px;*/
/*border-radius: 5px;*/
}
FIDDLE
Let me explain something about absoluted elements that must be placed as dropdowns:
.sf-menu ul {top: 100%}
.sf-menu li a {/*height: auto*/}
.sf-menu ul li:first-child a:after {top: auto; bottom: 100%}
Example here: jsfiddle
1) You have an ul (children with position absolute) inside another ul.sf-menu (parent with position relative).
Your code have your children ul with a top with a fixed value of 35px; it caused that the children ul were overlapping ul parent.
2) To make your children ul to be automatically under the area of your ul parent, you don't have to use a fixed value, you can use top: 100% to make it move from top to bottom outside the area of the ul parent.
3) But for your particular case, your parent relative element has a border-bottom, so using: top:100% makes it overlap that area. Well in this situation you can alter the rule and use a custom value as 108% or any custom px value.
4) Your anchors have a fixed height, you can delete the height. But if for some reason you can't, you can override it with height: auto.
5) Now the problem of the arrow. Your arrow have a top with fixed value (top: -0.01px), you can fix it with another custom fixed value like -10px, -20px; but you can apply the same rule applied to children ul and make it automatically be on top outside of your element.
6) You can reset the value of top using top: auto, and then you can add a bottom: 100%. It will position your arrow from bottom 0 to bottom 100% over the top of your div relative. When you find any top, bottom, left, right that doesn't work as you expected, you can override any of them with auto.
Please, see this fiddle: http://jsfiddle.net/xg6SJ/2/
Why text jumps?
Why borders on hover expands menu's div?
*, *:before, *:after
{
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
div
{
height: 100px;
width: 960px;
margin: 0 auto;
background-color: #eee;
}
ul
{
list-style-type: none;
margin: 0;
padding: 0;
}
li
{
display: block;
float: left;
box-sizing:border-box;
}
li > a
{
text-decoration: none;
font-size: 20px;
display: table-cell;
height: 100px;
vertical-align: middle;
padding: 0 18px;
}
li:hover
{
border-top: 2px red solid;
border-bottom: 2px red solid;
background-color: #ddd;
}
<div>
<ul>
<li>sdfdf</li>
<li>sdfdf</li>
<li>sdfdf</li>
<li>sdfdf</li>
</ul>
</div>
The li doesn't have a fixed height. If you set the height of the li to 100px the border is put inside the element on hover.
To prevent the text from jumping you can remove the additional height added by the borders from the a like this:
li:hover > a {
height: 96px; /* 100 - (border-top + border-bottom) */
}
Or you can add a transparent border and a fixed height to the li (demo).
li {
...
border-top: 2px transparent solid;
border-bottom: 2px transparent solid;
height: 100px;
}
Because the border is added to the div on hover only. So on hovering, the div's height is expanded. If you added border-top: 2px grey to the li (in 'unhovered' state) , you won't have that jumping effect anymore.
Check the updated fiddle: http://jsfiddle.net/xg6SJ/3/
li
{
display: block;
float: left;
box-sizing:content-box;
}
Because, border-box ... The width and height properties include the padding and border, but not the margin. content-box ...This is the default style as specified by the CSS standard. The width and height properties are measured including only the content, but not the border, margin, or padding.
You are adding 2px to top on bottom on hover which where not their before.
Or add the two pixels of border to li and have the border be the same as the background until you hover.
li
{
display: block;
float: left;
border-top: 2px #eee; solid;
}
On my website a banner image has a certain height (responsive) but it has an overlay (#vignette) which is nested inside an a-tag together with the banner image. #vignette gets its height from its parent:
#vignette {
box-shadow: inset 0 0 50px 4px rgba(0,0,0,0.35), inset 0 10px 10px rgba(0,0,0,0.05);
position: absolute;
display: block;
width: 100%;
height: 100%;
left: 0;
top: 0;
}
And the a-tag adjust its height to its content:
a#banner-image {
display: block;
position: relative;
width: auto;
height: auto;
}
How then is it possible that the a-tag is taller than the image itself? Can't seem to solve this. Thanks.
Ensure the img is displayed as a block element.
a#banner-image img {
display: block;
}
As #Ianzz correctly states, this is because of an issue with descender space for all inline elements.