简体   繁体   中英

Creating a circular mouseover saturation effect

I have two versions of an image: a desaturated version and a full color version. What I want to accomplish is a hover effect in which mousing over the desaturated image reveals a circle of the color version of the image. It would be sort of like shining a spotlight on the desaturated image to show its color. And then when you move the mouse away, it would fade back to its desaturated state.

I know I could probably use flash, but I'd like to do this with JavaScript and CSS. Ideally this would degrade to just an image if JavaScript is disabled and could be fluid in width (responsive).

border-radius

CSS3 border-radius can be used to create a round div with a background image which serves as the image spotlight. The spotlight can be overlaid on top of the main image, and positioned based on the mouse coordinates. JSFiddle Demo

Although there's no natural way to soften the edges of the spotlight in CSS3 -- which would require support for adding an opacity gradient to arbitrary content -- it can be simulated using a staggered set of elements with increasing radius and decreasing opacity. Updated demo with softened edges

In the updated demo , the size and softness of the the spotlight can be adjusted using the following variables:

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

Here's a modified demo where the spotlight has noticeable ripples. The thickness of the layers was increased to show more clearly how it works.

Below is a simplified version of the code for the initial version with sharp edges.

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'});
});

Alternative implementations

This could also be implemented using HTML5 Canvas or SVG. Below is a browser-support comparison of the different approaches:

In short, IE8 and earlier is not an option for any of these approaches, and if Android support is needed, that limits the choices to border-radius and HTML5 Canvas. Of course, since this is mouse-based, Android support may not be a factor anyhow.

Use two SVG <image> elements overlaid exactly on top of one another. The bottom is the greyscale image. The top is the color image. Apply a clipPath to the color image, and then adjust the transform on the clipping path to reveal different areas of the upper image.

Simple Demo: 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>

and the JavaScript that moves the circle around:

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); 

All you have to do is track the mouse movement and set the translation to the right spot.

You can use some CSS to achieve the result, if I have understood correctly your request. I've prepared a small fiddle as a demo here: http://jsfiddle.net/sandro_paganotti/k3AmZ/

Here's the code involved:

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;
}

I've also added a transition to enhance the experience.

Update

Version that follows mouse movements: http://jsfiddle.net/sandro_paganotti/k3AmZ/3/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM