创建鼠标悬停圆形饱和度效果。

4
我有两个版本的图片:一个是去色版,一个是完整彩色版。我的目标是实现一种悬停效果,当鼠标移动到去色版的图片上时,会显示出一个圆形的彩色版本的图像。这就像是在去色版的图片上照射聚光灯以显示其颜色。当你移开鼠标时,它会渐变回去到去色状态。我知道我可能可以使用Flash,但我想用JavaScript和CSS来实现。理想情况下,如果JavaScript被禁用,它应该退化为仅仅是一张图片,并且可以根据宽度自适应(响应式)。

我的回答已更新,并附上了演示。 - Phrogz
3个回答

7

边框半径

CSS3的border-radius属性可用于创建一个圆形div,其中包含作为图像聚光灯的背景图像。聚光灯可以叠加在主图像之上,并根据鼠标坐标定位。JSFiddle演示

尽管CSS3中没有自然的方法来软化聚光灯的边缘--这需要支持向任意内容添加不透明度渐变--但是可以使用一组具有递增半径和递减不透明度的交错元素来模拟它。带有软化边缘的更新演示

更新的演示中,可以使用以下变量调整聚光灯的大小和柔软度:

var spotlightDiameter = 150;      // Base size (not including the soft edge)
var numSpotlightLayers = 6;       // More layers = softer edges
var spotlightLayerThickness = 2;  // Thinner = the softening is more subtle

这里有一个修改后的演示,其中聚光灯具有明显的涟漪效果。增加了图层的厚度以更清楚地展示其工作原理。

以下是具有锐利边缘的初始版本的简化代码。

HTML

<div class="content">
    <div class="spotlight"></div>
</div>

CSS

.content {
    position: relative;
    width: 640px;
    height: 480px;
    background: url(desaturated.jpg) no-repeat 0 0;
    overflow: hidden;
}
.spotlight {
    display: none;
    position: absolute;
    background: url(overly_saturated.jpg) no-repeat 0 0;
}

jQuery

var spotlightDiameter = 150;

// Update the spotlight position on mousemove
$('.content').on('mousemove', function(e){
    var center = {x: e.pageX - this.offsetLeft,
                  y: e.pageY - this.offsetTop};
    var x = center.x - (spotlightDiameter >> 1);
    var y = center.y - (spotlightDiameter >> 1);

    $('.spotlight').css({left: x + 'px', top: y + 'px',
                         backgroundPosition: -x + 'px ' + -y + 'px'}).show();
});

// Hide the spotlight on mouseout
$('.content').on('mouseout', function(e){
    $('.spotlight').hide();
});

// Initialize the spotlight
$(document).ready(function(){
    $('.spotlight').width(spotlightDiameter + 'px')
                   .height(spotlightDiameter + 'px')
                   .css({borderRadius: (spotlightDiameter >> 1) + 'px'});
});

替代实现

这也可以使用HTML5 Canvas或SVG来实现。下面是不同方法的浏览器支持比较:

简而言之,对于这些方法,IE8及更早版本都不是一个选择,如果需要支持Android,则选项限于border-radius和HTML5 Canvas。当然,由于这是基于鼠标的,因此Android支持可能根本不是一个因素。


太好了!能否将圆的边缘变得更加柔和一些呢? - Confused One
1
@ConfusedOne:在CSS中没有自然的方法来实现这个效果(带有不透明度渐变的图像),但是可以使用一组错开的元素来模拟,半径逐渐增加,不透明度逐渐减小。我添加了一个更新后的演示,具有更柔和的边缘和更适合此类型效果的照片。软度的程度是可配置的。 - Matt Coughlin
@ConfusedOne:谢谢!修复了与鼠标事件相关的一个重大错误,并更新了上面的演示。现在它应该在所有浏览器中都能很好地工作(除了IE8及更早版本,在那里聚光灯不可避免地呈正方形)。此外,添加了第三个演示版本,更好地说明了它的工作原理(给聚光灯添加了涟漪效果)。 - Matt Coughlin
@ConfusedOne:更新:CSS遮罩提供了一种自然的方式来软化CSS3中的聚光灯边缘,但它只被Webkit(Chrome和Safari)支持,并且标准尚未最终确定。使用具有不同alpha透明度的径向渐变作为图像遮罩将提供一定的灵活性,甚至可以消除对border-radius的需求。换句话说,一旦得到足够的支持,CSS遮罩是实现这一目标的真正自然的方式。 - Matt Coughlin
@MattCoughlin 听起来不错。我会关注它的发展。不知道是否有JavaScript方法可以在其他浏览器中添加对它的支持... - Confused One

5
使用两个重叠的SVG <image>元素。底部是灰度图像,顶部是彩色图像。将clipPath应用于彩色图像,然后调整剪切路径上的变换以显示上图像的不同区域。

简单演示:http://jsfiddle.net/hZgkz/

SVG:

<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="250px">
  <defs>
    <image id="im" width="500" height="500"
     xlink:href="http://www.nyweamet.org/wp-content/uploads/2011/09/0942a__grandCentralStationExterior.jpg"/>
    <clipPath id="clip">
      <path id="path" transform="translate(40,60)"
            d="M60,0 A30,30 1,0,0 60,120 30,30 1,0,0, 60,0"/>
    </clipPath>
  </defs>
  <use id="clippedImage" xlink:href="#im" clip-path="url(#clip)"/>
</svg>

以及移动圆圈的JavaScript代码:

var tx = document.querySelector('#path').transform.baseVal.getItem(0);
setInterval(function(){
  var ms = (new Date)*1;
  tx.matrix.e = Math.sin(ms/812)*150 + 160;
  tx.matrix.f = Math.cos(ms/437)*60 + 70;
},50); 

您需要做的就是跟踪鼠标移动并将翻译设置到正确的位置。


看起来很有希望。非常感谢你。在尝试过 SVG 并阅读了一些文章后,我成功地做出了这个: http://jsfiddle.net/GB5k8/但我有几个问题。第一个是能否使其具有流体宽度?然后,第二个是是否可以使 clipPath 的边缘不那么锐利?我希望圆的边缘可以逐渐消失。 - Confused One

2

如果我正确理解了您的请求,您可以使用一些CSS来实现结果。我已经在这里准备了一个小型演示:http://jsfiddle.net/sandro_paganotti/k3AmZ/

以下是涉及到的代码:

HTML

<figure data-desaturated></figure>
<figure data-original></figure>

CSS

figure{ width: 550px; height: 360px;
        position: absolute; top: 0; left: 0;
        margin: 0; padding: 0; 
        background-position: 50% 50%;
        background-repeat: no-repeat;
        background-image: url('yourimage.png');

}

figure[data-desaturated]{
    /* I've used CSS filters tu simulate desaturation, you can use your already desaturated image */
    -webkit-filter: grayscale(0.9);
}

figure[data-original]{
    width: 360px;
    left: 95px;
    border-radius: 180px;
    opacity: 0;
    transition: opacity 0.4s;
}

figure[data-desaturated]:hover + figure[data-original],
figure[data-original]:hover{
    opacity: 1;
}

我还添加了一个transition来增强体验。

更新

跟随鼠标移动的版本:http://jsfiddle.net/sandro_paganotti/k3AmZ/3/


你如何让圆形跟随鼠标移动,就像手电筒一样发光? - Phrogz
1
这是跟随鼠标移动的更新版本:http://jsfiddle.net/sandro_paganotti/k3AmZ/3/ - Sandro Paganotti
1
太好了。我在这里使它更加跨浏览器兼容:http://jsfiddle.net/xgSJ5/有人知道这个解决方案的浏览器支持情况吗? - Confused One
以上的border-radius jsfiddle答案非常适合将旧照片与从同一地点拍摄的新照片叠加。例如,看看您的城镇100年前的样子,悬停在上面,突出显示它今天的样子,反之亦然。非常好的一段代码。 - user4159714

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接