Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a commonly supported way to make a skewed "frosted glass" effect in CSS/SVG?

Tags:

html

css

sass

svg

I'm looking to make a website splash page. The page will have one background that will be cut off on the left side with a slanted div, say at a constant 110 degrees from the horizontal (or equivalent, keep reading). This div will blur the background behind it and will allow for content to be put on it, like text. See the YouTube Brand Resources page: instead of having a plain white background on the left, I would like that to blur the background picture that sits underneath it.

I've not yet found a way to put all of the information I've found together in a way that works and is supported by most browsers. For example, I recently tried a skewed div that shared a background with the parent container, like this post asked about, but CSS clip paths aren't commonly supported yet, and a white div won't cut it for my use case (to be clear, this solution ends with a skewed background image).

Using SVG clip paths and filters (see below) gets me close, but as you can see, I don't know how to make sure the image and the SVG fills the screen and lines up with the background behind it.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Page</title>
</head>
<body>
<div class="splash">
    <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none">
        <filter id="blur" x="0" y="0">
            <feGaussianBlur stdDeviation="1"></feGaussianBlur>
        </filter>
        <clipPath id="clip">
            <polygon points="0,0 100,100 0,100"></polygon>
        </clipPath>
        <image clip-path="url('#clip')" filter="url('#blur')" x="0" y="0" width="100" height="100" xlink:href="https://cdn.pixabay.com/photo/2018/11/17/22/15/tree-3822149_960_720.jpg"></image>
    </svg>
</div>
</body>
</html>

Sass:

html, body
  position: relative

  margin: 0
  overflow-x: hidden
  height: 100%

.splash
  position: absolute
  width: 100%
  height: 100%
  overflow: hidden

  background-image: url("https://cdn.pixabay.com/photo/2018/11/17/22/15/tree-3822149_960_720.jpg")
  background-size: cover
  background-repeat: no-repeat
  background-color: lightgrey
  background-attachment: fixed

  svg
    position: absolute
    width: inherit
    height: inherit

Any ideas?

like image 292
Pheric Avatar asked Jan 03 '19 08:01

Pheric


2 Answers

You can consider skew transform without the need of clip-path. here is a basic example where the trick is to specify the correct value of background-position to create the illusion of one image.

.box {
  height:300px;
  background-image:url(https://picsum.photos/600/800?image=1069);
  background-position:left center;
  background-size:cover;
  position:relative;
  overflow:hidden;
}
.skew,
.skew::before{
  position:absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  transform-origin:top left;
  transform:skewY(30deg);
  overflow:hidden;
  background-image:inherit;
  background-position:inherit;
  background-size:0 0;
}
.skew::before {
  content:"";
  transform:skewY(-30deg);
  filter:blur(10px);
  background-size:cover;
}

/*to illustrate the separation*/
.skew {
  border-top:1px solid;
}
/**/
.container {
  position:relative;
  z-index:1;
  margin-top:150px;
  padding-left:50px;
}

body {
 margin:0;
}
<div class="box">
  <div class="skew"></div>
  <div class="container">
    <h1>some text</h1>
    <p>Lorem ipsum</p>
  </div>
</div>

<div class="box" style="background-image:url(https://picsum.photos/600/800?image=3)">
  <div class="skew"></div>
  <div class="container">
    <h1>some text</h1>
    <p>Lorem ipsum</p>
  </div>
</div>

In case you want the skew to be responsive you can add a small JS code to adjust the angle and always cover half the iamge:

var w = window.innerWidth;
var h = 300; /*the height of the box*/
document.querySelector('.box .skew').style.transform="skewY("+(Math.atan(h/w)*180/Math.PI )+"deg)";
document.querySelector('.box .skew span').style.transform="skewY(-"+(Math.atan(h/w)*180/Math.PI )+"deg)";

window.onresize = function(event) {
    w = window.innerWidth;
    document.querySelector('.box .skew').style.transform="skewY("+(Math.atan(h/w)*180/Math.PI )+"deg)";
    document.querySelector('.box .skew span').style.transform="skewY(-"+(Math.atan(h/w)*180/Math.PI )+"deg)";
};
.box {
  height:300px;
  background-image:url(https://picsum.photos/600/800?image=1069);
  background-position:left center;
  background-size:cover;
  position:relative;
  overflow:hidden;
}
.skew,
.skew span{
  position:absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  transform-origin:top left;
  transform:skewY(30deg);
  overflow:hidden;
  background-image:inherit;
  background-position:inherit;
  background-size:0 0;
}
.skew span{
  transform:skewY(-30deg);
  filter:blur(10px);
  background-size:cover;
}
/*to illustrate the separation*/
.skew {
  border-top:1px solid;
}
/**/
.container {
  position:relative;
  z-index:1;
  margin-top:150px;
  padding-left:50px;
}

body {
 margin:0;
}
<div class="box">
  <div class="skew"><span></span></div>
  <div class="container">
    <h1>some text</h1>
    <p>Lorem ipsum</p>
  </div>
</div>
like image 194
Temani Afif Avatar answered Nov 01 '22 03:11

Temani Afif


You can also make it all in a single <svg> image, using a <pattern> element to fill half a triangle with the image, and apply your filter on it.

svg {
  width: 100vw;
  height: 200px;
  position: absolute;
  top: 0;
}

.container {
  position: relative;
  z-index: 1;
  margin-top: 100px;
  padding-left: 50px;
}
<svg width="1024" height="200" viewBox="0 0 1024 200" preserveAspectRatio="none">
  <defs>
    <pattern id="pat" viewBox="0 0 1024 200" width="100%" height="100%">
      <image xlink:href="https://picsum.photos/1024/200?image=1029" width="1024" height="200"/>
    </pattern>
    <filter id="blur">
      <feGaussianBlur in="SourceGraphic" stdDeviation="10" />
    </filter>
  </defs>
  <!-- background no filter -->
  <rect width="1024" height="200" fill="url(#pat)"/>
  <!-- foreground triangle, blurred -->
  <path d="M0,0L1024,200H0Z" fill="url(#pat)" filter="url(#blur)"/>
</svg>
<div class="container">
  <h1>some text</h1>
  <p>Lorem ipsum</p>
</div>
like image 3
Kaiido Avatar answered Nov 01 '22 05:11

Kaiido