首页 > 解决方案 > CSS/JS 模糊,除了鼠标周围

问题描述

我正在尝试从头开始开发一个网站。我正在使用 html、css 和 js(在需要时使用 jQuery 和其他 js 库)。我想拥有可以在任何地方删除而无需安装额外插件/脚本的代码。所有需要的东西都应该放在一个文件夹中,我可以放置在任何地方并运行(即插即用风格),所以我下载了所有库(只有引导程序、jQuery 和 Vague.js atm)。

在其中一个页面中,我有多个图像以类似旋转木马的方式移动。图片覆盖了页面,是页面上唯一的东西(除了徽标和菜单按钮)。我需要做的是使屏幕/图像模糊,只有光标周围的圆圈可见。目前,我设法模糊了所有图像,并在鼠标悬停在它们上方时让它们聚焦,但我不知道如何只聚焦图像的一小部分。

我知道这不是处理事情的理想方式,但为了让轮播顺利运行并在多个页面中可复制,我必须复制所有图像并进行 css 转换操作,关键帧移动 -50%。我知道这部分可能会更好,你可以忽略。我目前拥有的是:

<div class="scrollWrapper">
        <div id="scroll" class="imgScroll" onclick="toggleAnimation();">
            <img class="scrollingImage" src="image1.jpg" alt="Window showcase image">
            <img class="scrollingImage" src="image2.jpg" alt="Window showcase image">
            <img class="scrollingImage" src="image3.jpg" alt="Window showcase image">
            <img class="scrollingImage" src="image4.jpg" alt="Window showcase image">
            <img class="scrollingImage" src="image5.jpg" alt="Window showcase image">
            <img class="scrollingImage" src="image1.jpg" alt="Window showcase image">
            <img class="scrollingImage" src="image2.jpg" alt="Window showcase image">
            <img class="scrollingImage" src="image3.jpg" alt="Window showcase image">
            <img class="scrollingImage" src="image4.jpg" alt="Window showcase image">
            <img class="scrollingImage" src="image5.jpg" alt="Window showcase image">
        </div>
    </div>
.scrollWrapper{
    overflow: hidden;
}

.imgScroll{
    background-color: dimgrey;
    width: max-content;
    font-size: 0;
    z-index: -999;
    height: 100vh;
}

.scrollingImage{

    filter: blur(10px);
    -webkit-filter: blur(10px);

    display: inline-block;
    height: 100%;
}

.scrollingImage:hover{
    filter: blur(0px);
    -webkit-filter: blur(0px);
}

@keyframes scrolling{
    0% {transform: translateX(0%);}
    100% {transform: translateX(-50%);}
}

.imgScroll{
    animation: scrolling 60s linear infinite;
    z-index: -1000;
}

body .scrollWrapper .pause{
    animation-play-state: paused;
    -webkit-animation-play-state: paused;
    -moz-animation-play-state:paused;
    -o-animation-play-state:paused; 
}
function toggleAnimation() {
    scroll = document.getElementById('scroll');
    if(scroll.classList.contains('pause')){
        scroll.classList.remove('pause');
    }else{
        scroll.classList.add('pause');
    }
}

我目前的想法是用类 scrollWrapper 模糊 div 并以某种方式在光标周围有一个区域被聚焦,但我不知道该怎么做。

我环顾四周,发现了这篇文章,但据我所知,这些解决方案适用于单个静态图像,而不适用于多个移动图像。我现在在搞乱 Vague.js,但不知道该怎么做。

我不是网络开发人员,并且很少使用 js/jquery,所以我开始因为无法弄清楚这一点而感到愚蠢......这是我在改变完全不同的东西之前的最后手段,所以任何帮助都会不胜感激。

标签: javascripthtmljquerycss

解决方案


用新的CSS做到这backdrop-filter一点很容易,最难的部分是在过滤器上设置一个洞。

幸运的是,我们有 stackoverflow

对于一个圆,最简单的可能是使用径向梯度作为 a mask-image,如this answer所示。

const blur_elem = document.getElementById( "blur-around" );
document.onmousemove = (evt) => {
  blur_elem.style.transform = `translate(${evt.clientX}px, ${evt.clientY}px)`;
};
#blur-around {
  position: fixed;
  z-index: 999;
  pointer-events: none;
  /* twice the viewport size so it always covers fully */
  width: 200vw;
  height: 200vh;
  /* negative offset by half so we are sure we cover the full viewport */
  left: -100vw;
  top: -100vh;
  /* we'll use transform translate to move it */
  transform-origin: center;  
  -webkit-backdrop-filter: blur(15px);
  backdrop-filter: blur(15px);
  -webkit-mask-image: radial-gradient(50px at 50% 50%, transparent 100%, black 100%);
  mask-image: radial-gradient(50px at 50% 50% , transparent 100%, black 100%)
}

/* falback for browsers that don't have backdrop-filter */
@supports not ((backdrop-filter: blur(0px)) or (-webkit-backdrop-filter: blur(0px))) {
  #blur-around {
    background-color: rgba(255,255,255,.8);
  }
}
<div id="blur-around"></div>
<p>Works over any content</p>
<img src="https://picsum.photos/250/250">
<img src="https://picsum.photos/360/200">

不幸的是,Safari 并不完全支持该mask-image属性,所以我们可能需要其他东西。

我们还可以使用clip-path带有偶数路径的 CSS,如该答案所示。

不幸的是,Chrome 仍然不支持path()for 的功能clip-path,所以我们必须创造性地使用该polygon()功能并定义每个点的顶点。
尽管如此,对于一个矩形形状,它所需要的只是首先绘制与元素大小相同的外部矩形,然后在任何我们想要的地方绘制内部矩形,同时确保我们始终关闭这两个形状

const blur_elem = document.getElementById( "blur-around" );
document.onmousemove = (evt) => {
  blur_elem.style.transform = `translate(${evt.clientX}px, ${evt.clientY}px)`;
};
#blur-around {
  position: fixed;
  z-index: 999;
  pointer-events: none;
  /* twice the viewport size so it always covers fully */
  width: 200vw;
  height: 200vh;
  /* negative offset by half so we are sure we cover the full viewport */
  left: -100vw;
  top: -100vh;
  /* we'll use transform translate to move it */
  transform-origin: center;  
  -webkit-backdrop-filter: blur(15px);
  backdrop-filter: blur(15px);

  --rect-size: 100px;
  clip-path: polygon( evenodd,
    /* outer rect */
    0 0,       /* top - left */
    100% 0,    /* top - right */
    100% 100%, /* bottom - right */
    0% 100%,   /* bottom - left */
    0 0,       /* and top - left again */
    /* do the same with inner rect */
    calc(50% - var(--rect-size) / 2) calc(50% - var(--rect-size) / 2),
    calc(50% + var(--rect-size) / 2) calc(50% - var(--rect-size) / 2),
    calc(50% + var(--rect-size) / 2) calc(50% + var(--rect-size) / 2),
    calc(50% - var(--rect-size) / 2) calc(50% + var(--rect-size) / 2),
    calc(50% - var(--rect-size) / 2) calc(50% - var(--rect-size) / 2)
   );
}

/* falback for browsers that don't have backdrop-filter */
@supports not ((backdrop-filter: blur(0px)) or (-webkit-backdrop-filter: blur(0px))) {
  #blur-around {
    background-color: rgba(255,255,255,.8);
  }
}
<div id="blur-around"></div>
<p>Works over any content</p>
<img src="https://picsum.photos/250/250">
<img src="https://picsum.photos/360/200">

虽然用一个圆圈来制作它(正如评论中所要求的那样)开始变得有点不那么可读了,虽然它也可以在 CSS 中硬编码,但它会成为一个很大的规则,我更喜欢直接留下一个 javascript 生成器这个答案:

function makeCircleHoleClipPathRule( radius ) {

  const inner_path = [];
  const circumference = Math.PI * radius;
  const step = Math.PI * 2 / circumference;
  // we are coming from top-left corner
  const start_step = circumference * (5 / 8);
  for( let i = start_step; i < circumference + start_step; i++ ) {
    const angle = step * i;
    const x = radius * Math.cos( angle );
    const y = radius * Math.sin( angle );
    const str = `calc( 50% + ${ x }px ) calc( 50% + ${ y }px )`;
    inner_path.push( str );
  }
  // avoid rounding issues
  inner_path.push( inner_path[ 0 ] );

  return `polygon( evenodd,
    /* outer rect */
    0 0,       /* top - left */
    100% 0,    /* top - right */
    100% 100%, /* bottom - right */
    0% 100%,   /* bottom - left */
    0 0,       /* and top - left again */
    ${ inner_path.join( "," ) }
   )`;

}

const blur_elem = document.getElementById( "blur-around" );
// set the clip-path rule
blur_elem.style.clipPath = makeCircleHoleClipPathRule( 50 );

document.onmousemove = (evt) => {
  blur_elem.style.transform = `translate(${evt.clientX}px, ${evt.clientY}px)`;
};
#blur-around {
  position: fixed;
  z-index: 999;
  pointer-events: none;
  /* twice the viewport size so it always covers fully */
  width: 200vw;
  height: 200vh;
  /* negative offset by half so we are sure we cover the full viewport */
  left: -100vw;
  top: -100vh;
  /* we'll use transform translate to move it */
  transform-origin: center;
  -webkit-backdrop-filter: blur(15px);
  backdrop-filter: blur(15px);
}
/* falback for browsers that dont have backdrop-filter */
@supports not ((backdrop-filter: blur(0px)) or (-webkit-backdrop-filter: blur(0px))) {
  #blur-around {
    background-color: rgba(255,255,255,.8);
  }
}
<div id="blur-around"></div>
<p>Works over any content</p>
<img src="https://picsum.photos/250/250">
<img src="https://picsum.photos/360/200">

但是,backdrop-filter目前仅在最新的 Blink + Webkit 浏览器中支持,Gecko 仍然缺乏对它的支持。由于我怀疑是否有许多其他跨浏览器解决方案,您可以尝试这个 polyfill,它将在 iframe 中复制您的页面内容(即性能不是很好)。


推荐阅读