【问题标题】:How to use CSS (and JavaScript?) to create a blurred, "frosted" background?如何使用 CSS(和 JavaScript?)创建模糊的“磨砂”背景?
【发布时间】:2013-06-10 03:32:13
【问题描述】:

我正在尝试使用 HTML5、CSS3 和 JavaScript 创建一个 iOS 7 风格的磨砂外观,它可以在 webkit 浏览器上运行。

技术上,给定以下 HTML:

<style>
  #partial-overlay {
    width: 100%;
    height: 20px;
    background: rgba(255, 255, 255, .2); /* TODO frost */
    position: fixed;
    top: 0;
    left: 0;
  }
</style>
<div id="main-view">
  <div style="width: 50px; height: 50px; background: #f00"></div>
  To my left is a red box<br>
  Now there is just text<br>
  Text that goes on for a few pixels <br>
  or even more
</div>
<div id="partial-overlay">
  Here is some content
</div>

我想将-webkit-filter: blur(5px) 之类的东西应用到#main-view 水平方向的前20px。

如果 CSS 被修改为 #partial-overlay { width: 20px; height: 100%; ...},那么我需要将 -webkit-filter: blur(5px) 垂直应用到前 20 像素。

显而易见的解决方案是使用 javascript 克隆 #main-view,设置 overflow: hidden,然后根据需要更改宽度/高度,但在我看来这很难推广到更复杂的页面/CSS 结构。

有没有更好的方法以最小的性能损失和最大的泛化性来实现这一目标?

编辑:这是我想要实现的一个示例:

【问题讨论】:

  • CSS 是全有或全无的东西。您不能只将属性应用于它的任意部分。最接近“仅前 20px”的方法是使用 :first-line 伪元素。
  • @cimmanon 查看已编辑的“明显解决方案”
  • 您能否展示一个图像示例来说明您要做什么?如果我正确阅读了这个问题,您可以尝试使用 css 的多背景功能来实现这一点。编辑:另外,对于任何回答这个问题并想要测试的人来说,这是他的示例的 JSFIDDLE:jsfiddle.net/c6Lwf
  • @Askanison4 有帮助吗?
  • @cimmanon,刚刚尝试过,webkit-filter: blur 似乎不适用于 first-line,看起来 only some styles 允许用于该伪类

标签: javascript html css webkit


【解决方案1】:

感谢您的启发......它让我找到了这个canvas plugin,它可以解决问题

新增和改进:-webkit- and Firefox Working Example,现在可调整大小/流动。

JS

$(document).ready(function () {
    frost = function () {
        var w = $('#main-view').width();
        html2canvas(document.body, {
            onrendered: function (canvas) {
                document.body.appendChild(canvas);
                $('canvas').wrap('<div id="contain" />');
            },
            width: w,
            height: 30
        });
        $('canvas, #partial-overlay, #cover').hide();
        $('#cover').fadeIn('slow', function () {
            $('#partial-overlay').fadeIn('slow');
        });
    };

    $('body').append('<div id="cover"></div><svg id="svg-image-blur"><filter id="blur-effect-1"><feGaussianBlur stdDeviation="2"/></filter></svg>');

    $('#main-view').click(function () {
        frost();
        $('#partial-overlay').addClass('vis');
        $(window).resize(function () {
            $('canvas, #partial-overlay, #cover').hide();
        });

        function onResize() {
            if ($('#partial-overlay').hasClass('vis')) {
                frost();
            }
        }
        var timer;
        $(window).bind('resize', function () {
            timer && clearTimeout(timer);
            timer = setTimeout(onResize, 50);
        });

    });

    $('#partial-overlay').click(function () {
        $('#partial-overlay').removeClass('vis');
        $('canvas, #partial-overlay, #cover').hide();
    });
});

CSS

#main-view {
    width:75%;
    height:50%;
    box-sizing: border-box;
    margin:8px;
}
#partial-overlay {
    display:none;
    width: 100%;
    height: 20px;
    position: absolute;
    top: 0;
    left: 0;
    z-index:99;
    background: rgba(255, 255, 255, 0.2);
    cursor:pointer;
}
canvas {
    position: absolute;
    top: 0;
    left: 0;
    -webkit-filter:blur(5px);
    filter: url(#blur-effect-1);
}
#cover {
    display:none;
    height:19px;
    width:100%;
    background:#fff;
    top:0;
    left:0;
    position:absolute;
}
#contain {
    height:20px;
    width:100%;
    overflow:hidden;
    position:absolute;
    top:0;
    left:0;
}
svg {
    height:0;
    width:0;
}

HTML

<div id="main-view">
    <div style="width: 10%; height: 20%; background: #f00; float: left"></div>To my left is a red box
    <br>Now there is just text
    <br>Text that goes on for a few pixels
    <br>or even more</div>
<div id="partial-overlay">Here is some content</div>

我把它放在一个点击函数中,因为我认为这将是最有可能的用例。它在准备好文档时也能正常工作。

虽然画布表示不会是像素完美的,但我认为在大多数情况下它并不重要,因为它是模糊的。

更新:现在可以重新调整大小。我还将封面 div 移到 JS 中,并为 Firefox 添加了一个 svg 后备。调整大小需要在每次调整大小时重新绘制画布,因此我将其设置为在调整大小时隐藏画布、叠加层等,然后在调整大小停止时替换它。

【讨论】:

  • 如果你能以某种方式举一个例子,背景图像是由其中一种“javascript屏幕截图”制作然后模糊的,那可能是一个非常聪明的答案。
  • 这就是诀窍。唯一的问题是模糊在画布边缘逐渐消失(边缘周围不是真正的问题,但肯定在底部)。也许这可以通过一些包装 div 之类的东西来解决,但我似乎无法让它快速工作。
  • 它看起来不错,但它仍然不像画布在 20 像素处被切断或我最终的目标是什么那样模糊。
  • 模糊中的文本发生了一些有趣的事情(它没有完全模糊,或者画布真的不透明或类似的东西)。见jsfiddle.net/TfWs3/33
  • @AaronYodaiken 如果您需要它更兼容跨浏览器,请查看此内容,您可以使用 svg 作为 firefox jsfiddle.net/apaul34208/TfWs3/61 的后备
【解决方案2】:

基本上你可以有一个覆盖占位符,你可以在其中复制主要内容并同步两个 div 的滚动,而不是仅在覆盖上应用 css 模糊过滤器。

一个简单的javascript就可以了:

$(document).ready(function(){
  $('.overlay').append( $('.content').html() );
  $('.content').on('scroll', function(){
    $('.overlay').scrollTop($(this).scrollTop());
  });
});

对于 CSS:

.overlay {
    overflow:hidden;
    -webkit-filter: blur(.25em);
    background:#fff;
}

我为您整理了一个工作示例(仅限 webkit):

http://jsfiddle.net/kmxD3/1/

玩得开心! :)

【讨论】:

  • 这似乎是迄今为止我遇到的最简单、最优雅的解决方案。
  • 这种方法非常棒,但是我可以在 div 的顶部看到一些不均匀的糖霜。知道是什么原因造成的吗?
  • @Cort3z,这是由于模糊效果的淡出(这使您可以看到下面的常规文本。为了更好地理解,请查看本文中模糊示例中的图像:@ 987654322@ (注意右侧图像的边缘逐渐变为白色)。要考虑到这一点并在模糊内容中有锐利的边缘,您必须使模糊的内容更大一点然后剪辑它(或让它消失画布外)以获得更清晰的边缘)。我希望我说得更清楚......这个例子应该有一个更清晰的边缘:jsfiddle.net/kmxD3/105
  • @GersonGoulart 太棒了!谢谢你的解释:)
【解决方案3】:

有没有更好的方法以最小的性能损失和 最大泛化性?

答案是

原因是为了做你想做的事,你需要直接访问用于浏览器窗口的位图,以提取或操作你想要模糊的区域中的像素(我希望浏览器中的“aero”可能看起来很整洁..)或适用于您应用它的元素后面的元素的过滤器(或者可以设置一个限制区域)。

由于没有本地支持来执行此操作(除了画布和扩展 API,或者从 html 生成画布图像的库 -> 相对较慢),因此需要使用技巧(图像、分割 div 等)来完成。无论哪种情况。

如果您在画布上制作页面中的所有内容,您可以做很多有趣的事情,但您还需要自己执行布局、更新、过滤等,因此您不会像 Javascript 那样没有优化比原生慢(更不用说它容易出错)。

直到浏览器允许您将窗口的一部分作为画布抓取(从不?因为这将要求该页面上的所有内容都是同源或具有设置特殊接受标头的内容),否则别无他法技巧。

更新

作为一个演示,您可以通过使用 html2canvas 等来做到这一点,但必须使用妥协(-> 性能缓慢) - 演示很粗糙,实验性并且需要调整才能正常工作 - 但仅出于演示的目的:http://jsfiddle.net/AbdiasSoftware/RCaLR/

结果:

获取部分背景的通用函数:

getBlurredBG(x, y, width, height, id);

使用 html2canvas 获取窗口的一部分:

function getBlurredBG(x, y, w, h, id) {

    html2canvas(document.body, {
        onrendered: function (canvas) {
            process(canvas, x, y, w, h, id);
        },
        width: (x + w),
        height: (y + h)
    });
}

处理内容:

function process(canvas, x, y, w, h, id) {

    //create new canvas to enable clipping
    //As html2canvas returns a canvas from 0,0 to width and height
    //we need to clip it.
    var ocanvas = document.createElement('canvas');
    ocanvas.width = w;
    ocanvas.height = h;
    ocanvas.style.left = x + 'px';
    ocanvas.style.top = y + 'px';
    ocanvas.style.position = 'absolute';
    ocanvas.id = id;

    var ctx = ocanvas.getContext('2d');
    ctx.drawImage(canvas, x, y, w, h,
                          0, 0, w, h);

    stackBlurCanvasRGB(ocanvas, x, y, w, h, 28)
    lighten(ocanvas);

    ctx.fillStyle = 'rgba(255,255,255,0.5)';
    ctx.fillRect(x, y, w, h);

    ctx.fillStyle = '#999';
    ctx.font = '32px arial';
    ctx.fillText("Partial overlay content", 10, 60);

    document.body.appendChild(ocanvas);
}

【讨论】:

  • 我知道我已经看到了截取整个页面的截图,您可以将其发送为 PNG 或其他格式(就像 Google+ 过去那样)。那不是窗口 -> 画布吗?
  • @AaronYodaiken 那是画布。 html2canvas 等库可以做到这一点。然而,它不是一个实际的快照,而是一个基于元素几何的接近表示(元素->边界->类型->渲染接近近似)。对于非来源图像,它需要使用代理。但可以达到目的。
  • @AaronYodaiken 我在回答中确实提到了这一点,但对于“实时”使用来说会很慢(也许优化的部分“快照”可以很好地工作)。人们总是可以缓存快照,但用户需要等待。由于没有原生支持,因此总是需要妥协。
  • 非常感谢您的想法和这个解决方案。如果我能平分赏金,我会的。
【解决方案4】:

最近,一个新的-webkit-backdrop-filter。目前 Safari 9.0 和 Chrome 支持此功能。

演示:

#blurred {
  -webkit-backdrop-filter: blur(10px);
  width: 200px;
  height: 100px;
  position: fixed;
  top: 50px;
  left: 50px;
  border: 3px solid white;
}
<img src="https://upload.wikimedia.org/wikipedia/commons/e/eb/Ash_Tree_-_geograph.org.uk_-_590710.jpg">

<div id="blurred"> Blurred </div>

目前仅支持 Safari。 Chrome 和 Opera 有这个标志。

注意:今天-webkit-backdrop-filter还没有很好的支持,所以现在如果你想得到这个效果,最好的方法是使用SVG的feGaussianBlur

【讨论】:

  • 这是官方的解决方案。可以设置为答案吗?
  • @trusktr 不,因为它仅在 Safari 中可用,与 Chrome 和 Firefox 相比,它并不真正流行。
  • @LucaSteeb Chrome 现在支持它,在一个标志后面。希望这在不久的将来成为答案,因为背景过滤器将是实现它的实际方法。其他答案只是廉价的黑客攻击。
  • @trusktr 廉价黑客可能有点夸张,但通常你是对的。问题是,即使所有新浏览器都支持它,你对使用旧浏览器的用户做了什么 - 这可能不是一个小数目..
  • @LucaSteeb 确实,这是一个问题,但并没有改变其他方法仍然只是黑客的事实。 Native 一直拥有这种能力。终于到了网络开始获得真正功能的时候了。
【解决方案5】:

仅 CSS 解决方案: backdrop-filter: blur(4px);

【讨论】:

    【解决方案6】:

    我做了一些没有 backdrop-filter 的 css 技巧,因为 chrome 默认不支持它

    我的原始代码with sasshttps://codepen.io/mixal_bl4/pen/EwPMWo

    $(()=>{
      let sdm = $('.some-draggable-modal');
      sdm.center().draggable();
    });
    
    jQuery.fn.center = function () {
        this.css("position","absolute");
        this.css("top", Math.max(0, (($(window).height() - $(this).outerHeight()) / 2) + 
                                                    $(window).scrollTop()) + "px");
        this.css("left", Math.max(0, (($(window).width() - $(this).outerWidth()) / 2) + 
                                                    $(window).scrollLeft()) + "px");
        return this;
    };
    body {
      background: -webkit-repeating-linear-gradient(135deg, #fff, #fff 25px, #e2edc1 25px, #e2edc1 50px) fixed;
      background: repeating-linear-gradient(-45deg, #fff, #fff 25px, #e2edc1 25px, #e2edc1 50px) fixed;
      background-attachment: fixed;
      background-size: cover;
    }
    html:before,
    body:before {
      content: "";
      display: block;
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: rgba(0, 0, 0, 0.3);
    }
    html .some-draggable-modal,
    body .some-draggable-modal {
      width: 150px;
      height: 150px;
      border: 1px solid lime;
      display: -webkit-box;
      display: -ms-flexbox;
      display: flex;
      place-content: center;
      -webkit-box-orient: vertical;
      -webkit-box-direction: normal;
          -ms-flex-direction: column;
              flex-direction: column;
      text-align: center;
      border-radius: 6px;
      cursor: move;
      position: relative;
      overflow: hidden;
    }
    html .some-draggable-modal .title,
    body .some-draggable-modal .title {
      position: relative;
      z-index: 1;
      color: black;
    }
    html .some-draggable-modal:before,
    body .some-draggable-modal:before {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: -webkit-repeating-linear-gradient(135deg, #fff, #fff 25px, #e2edc1 25px, #e2edc1 50px) fixed;
      background: repeating-linear-gradient(-45deg, #fff, #fff 25px, #e2edc1 25px, #e2edc1 50px) fixed;
      background-attachment: fixed;
      background-size: cover;
    }
    html .some-draggable-modal:hover:before,
    body .some-draggable-modal:hover:before {
      -webkit-filter: blur(2px);
              filter: blur(2px);
    }
    html .some-draggable-modal:hover:after,
    body .some-draggable-modal:hover:after {
      content: "filter: blur(2px)";
      position: absolute;
      left: 0;
      right: 0;
      bottom: 10px;
      color: green;
    }
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
    
    <div class="some-draggable-modal">
      <span class="title">You can drag me :)</span>
    </div>

    【讨论】:

      【解决方案7】:

      http://thiv.net/frost

      我所做的实时示例(并更新为与上图一样)

      代码:

      <style>
        #partial-overlay {
          width: 100%;
          height: 45px;
          background: #ffffff; /* TODO frost */
          -webkit-opacity:0.70;
          -webkit-filter: blur(5px);
          position: absolute;
          top: 20px;
          left: 0px;
          z-index:5;
        }
        #main-view
        {
         position: fixed;
         top: 20px;
         left: 80px;
         z-index:-1;
        }
      </style>
      <div id="main-view">
        <div style="width: 50px; height: 50px; background: #f00; position:fixed; left:10px; top: 40px; -webkit-filter: blur(2px); "></div>
          <div style="width: 80px; height: 60px; background: #fff; position:fixed; left:0px; top: 66px; -webkit-filter: blur(5px);"></div>
          <div style="width: 50px; height: 30px; background: #f00; position:fixed; left:10px; top: 60px;"></div>
        <p style="font-family:Sans, Arial, Verdana;">
        To my left is a red box<br>
        Now there is just text<br>
        Text that goes on for a few pixels <br>
        or even more
        </p>
      </div>
      <div id="partial-overlay">
      
      </div>
      

      我让它看起来比它需要的更漂亮,但它确实有效!

      【讨论】:

      • 抱歉,我想模糊矩形的背景,而不是矩形本身。
      • 什么意思?在里面?还是背后?
      • 你看到问题中的图片了吗?你的看起来一点也不像。
      • 谢谢大佬,好像提问者下线了...我可以托管页面,直到他回来...还有你回来做什么,这是用来做什么的?看起来很酷!
      • 这是一项不错的工作,但您所做的只是在未模糊的#main-view 顶部模糊一个白色 div,这会使部分覆盖的内容看起来有些模糊。
      【解决方案8】:

      不幸的是,没有很好的方法来做到这一点,因为你发现你需要一个主 div 的副本:

      <div class="wrapper">
         <div class="overlay"></div>
         <div id="main-copy"></div>
      </div>
      

      叠加将推动包装宽度,而主副本将在背景中模糊。如果主副本中的内容很复杂,显然会出现性能问题。

      【讨论】:

        【解决方案9】:

        它的支持仍然非常有限(仅限 Firefox),但获得它的一种方法可能是:

        Firefox only demo

        CSS 很简单:

        #partial-overlay {
            width:400px; 
            height:100px; 
            background: -moz-element(#main-view);
            top: 0px;
            left: 200px;
            position: absolute;
            opacity: 0.3;
        }
        

        关键是作为背景部分覆盖主视图元素。

        此演示仅使用不透明度,因为过滤器不适用于 Firefox。

        背景的元素属性已经被 w3c 批准,所以它可能会在未来的某个时候在 webkit 中显示

        在演示中,部分重叠已向右移动,以更清楚地说明什么是什么

        【讨论】:

        • 我已经对此进行了扩展,以使用 SVG 过滤器模糊背景:JS Fiddle - 仅限 FX,但比使用 html2canvas 快​​得多。
        • @Keith 谢谢!遗憾的是 background: element 特性并没有被广泛使用,它可以提供很多可能性
        • 谢谢 vals,一如既往;)
        • @ZachSaucier 嗨!很高兴再次见到你!一个奇怪的巧合,我九月份在波兰(一个熟悉的婚礼,与软件无关:-)
        【解决方案10】:

        您现在可以使用backdrop-filter CSS 属性。

        最新版本的 Chrome、Opera 和 Edge 默认支持它,而 Safari 和 Legacy Edge 使用 -webkit- 前缀支持它,如果 layout.css.backdrop-filter.enabled 首选项设置为 true,Firefox 支持无前缀版本。

        所以你的 CSS 变成:

        #partial-overlay {
            width: 100%;
            height: 20px;
            background: rgba(255, 255, 255, .2); /* TODO frost */
            position: fixed;
            top: 0;
            left: 0;
            
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
        }
        

        【讨论】:

          猜你喜欢
          • 2021-11-12
          • 2013-06-10
          • 2021-09-05
          • 2012-07-21
          • 2019-04-16
          • 1970-01-01
          • 2019-05-05
          • 1970-01-01
          • 2012-07-30
          相关资源
          最近更新 更多