I'm trying to create a frosted glass effect on a non-rectangular element but it's not working out. I'm experiencing an odd issue that I can't seem to wrap my head around...
The frosted glass effect is easy to accomplish by setting a fixed background-image on the document body, adding a partially transparent background color to the element and creating a ::before pseudo element with the same fixed background-image and applying a blur filter. Like so:
body {
background: url(bg-lanterns.jpg) 0 / cover fixed;
}
main {
position: relative;
margin: 1rem auto;
padding: 1rem;
height: 600px;
width: 800px;
background: rgba(255,255,255,0.7);
}
main::before {
content: '';
z-index: -1;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url(bg-lanterns.jpg) 0 / cover fixed;
filter: blur(10px);
}
Creating a non-rectangular element is also easy by using clip-path
like this:
main {
position: relative;
margin: 1rem auto;
padding: 1rem;
height: 600px;
width: 800px;
background: rgba(255,255,255,0.7);
clip-path: polygon(25% 0%, 100% 0%, 75% 100%, 0% 100%);
}
But trying to combine these two effects breaks the stacking order and causes the ::before element to appear above the white background.
I get the same result in Chrome and Firefox so I'm wondering if this is the expected behavior and I'm simply doing something wrong... Can anybody shed some light on what is happening here?
Here's a live demo:
body {
background: url(https://i.imgur.com/y1TH8fR.jpg) 0 / cover fixed;
}
main {
position: relative;
margin: 1rem auto;
padding: 1rem;
height: 600px;
width: 800px;
background: rgba(255,255,255,0.7);
clip-path: polygon(25% 0%, 100% 0%, 75% 100%, 0% 100%);
}
main::before {
content: '';
z-index: -1;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding: 1rem;
background: url(https://i.imgur.com/y1TH8fR.jpg) 0 / cover fixed;
filter: blur(10px);
}
<main></main>
According to the specification for clip-path
:
A computed value of other than none results in the creation of a stacking context [CSS21] the same way that CSS opacity [CSS3COLOR] does for values other than 1.
I managed to achieve the desired effect by adding the white color to an ::after pseudo element and clipping both pseudo elements instead of the element itself.
body {
background: url(https://i.imgur.com/y1TH8fR.jpg) 0 / cover fixed;
}
main {
position: relative;
margin: 1rem auto;
height: 600px;
width: 800px;
display: flex;
flex-flow: column nowrap;
align-content: center;
align-items: center;
justify-content: center;
}
main::before,
main::after {
content: '';
z-index: -1;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
clip-path: polygon(25% 0%, 100% 0%, 75% 100%, 0% 100%);
}
main::before {
background: url(https://i.imgur.com/y1TH8fR.jpg) 0 / cover fixed;
filter: blur(10px);
}
main::after {
background: rgba(255,255,255,0.7);
}
<main> <span> test </span> </main>