Andrew Mao
Andrew Mao

Reputation: 36930

CSS3 spotlight effect using a rounded rectangle with gradients

I'm writing an interactive tutorial for a web app that is meant to highlight the various parts of the user interface. The tutorial is meant to spotlight one part at a time and tell the user how to interact with it. You've probably seen something similar on smartphone apps.

For the specific CSS that could be used to spotlight an existing interface, the best solution I've found is using something like this, which is just a div on top of the existing interface that allows portions to be highlighted:

https://web.archive.org/web/20120414095101/http://svay.com/experiences/css3-spotlight

However, the CSS radial-gradient only allows for circles and ellipses, which is strange for user interface elements that are usually rectangular. Is there a way to achieve the same effect but with rounded rectangles (dimmed area is everything outside the rectangle)?

Upvotes: 4

Views: 14289

Answers (4)

Andrew Mao
Andrew Mao

Reputation: 36930

Vals gave an excellent answer, and gave me a great hint to figure out a simple way to get exactly what I wanted. This effect can be achieved with an inset box shadow plus a regular one, and has the added benefit that the spotlight box need only be repositioned to highlight a particular area instead of redrawing a CSS gradient.

Here's the code:

.overlay {
  position: absolute;
  left: 50px;
  top: 50px;
  width: 200px;
  height: 200px;
  border-radius: 20px;  
  box-shadow: 0px 0px 4px 10px rgba(0,0,0,0.5) inset, 0px 0px 0px 1000px rgba(0,0,0,0.5)
}

One can tweak the parameters to make the gradient border softer or more dramatic, and how much it pokes into the spotlight.

Check out the following:

Upvotes: 5

Bart Burg
Bart Burg

Reputation: 4924

This is the non CSS3 solution. The solution uses a 10% transparency black background png, the spotlight is added as image down below.

HTML

<div class="spotlightContainer">
    <div class="imageContainer">
        <img src="/images/tuinderlusten.jpg" alt="de tuin der lusten"/>
    </div>
    <div class="darkCover">
        <div class="dark darktop"> </div>
        <div class="darkmiddle">
            <div class="dark darkleft"> </div>
            <div class="spotlight"> </div>
            <div class="dark darkright"> </div>
        </div>
        <div class="dark darkbottom"> </div>
    </div>
</div>

JavaScript

var darkRight, darkLeft, darkBottom, darkTop, darkMiddle, containerHeight, containerWidth;

$(function(){
    containerWidth = $(".spotlightContainer").width();
    containerHeight = $(".spotlightContainer").height();
    darkTop = $(".darktop");
    darkBottom = $(".darkbottom");
    darkLeft = $(".darkleft");
    darkRight = $(".darkright");
    darkMiddle = $(".darkmiddle");
    darkTop.height(100-50);
  darkBottom.height(containerHeight-100-50);
  darkLeft.width(100-50);
  darkRight.width(containerWidth-100-50);
    setSpotlight(100, 100);
    $(".spotlightContainer").on("mousemove", function(e){
        setSpotlight(e.pageX, e.pageY);
    });
});

var setSpotlight = function(pageX, pageY){
    var radius = 100;
        darkMiddle.height(radius*2);
        if(pageX < radius){
            pageX = radius;
        } else if (pageX > containerWidth -radius){
            pageX = containerWidth -radius;
        }
        darkTop.height(pageY-radius);
        darkBottom.height(containerHeight-pageY-radius);
        darkLeft.width(pageX-radius);
        darkRight.width(containerWidth-pageX-radius);
}

CSS

html, body{
    width: 100%;
    height: 100%;
    margin: 0 0 0 0;
    padding: 0 0 0 0;
}

div{
    margin: 0 0 0 0;
    padding: 0 0 0 0;
    border: 0;
}

body{
    overflow: hidden;
}

.dark{
    background: url("/images/darkcover.png");
}

.darktop{
    width: 100%;
    height: 100%;
}

.darkbottom{
    width: 100%;
    height: 0px;
}

.darkmiddle{
    height:0px;
    width: 100%;
}

.darkmiddle div{
    float: left;
    height: 100%;
}

.darkleft{
    width: 200px;
}

.darkright{
    width: 200px;
}

.spotlight{
    width: 200px;
    background: url("/images/spotlight.png");
    background-size: cover;
}

.spotlightContainer{
    width: 100%; height: 100%; z-index: 500; position: fixed;
}

.spotlightContainer .imageContainer, .spotlightContainer .darkCover{
    width: 100%; height: 100%; position: absolute; top: 0; left: 0;
}

.spotlightContainer .imageContainer{
    max-height: 100%;   max-width: 100%; width: 100%;
}

The spotlight image

spotlight image that moves with the mouse

I tested this and it works on all modern and IE7+ desktop browsers.

Upvotes: 1

vals
vals

Reputation: 64244

You can do that with gradients, but achieving the rounded rectangle will be hard.

One easier way is just using box shadow

.overlay {
  position: absolute;
  left: 50px;
  top: 50px;
  width: 200px;
  height: 200px;
  border-radius: 20px;

  box-shadow: 0px 0px 0px 1000px rgba(255, 255, 255, 0.5);
}

.overlay:after {
  content: '';
  position: absolute;
  left: -25px;
  top: -25px;
  right: -25px;
  bottom: -25px;
  border: solid 1px gray;
  border-radius: 25px;
  box-shadow: 0px 0px 0px 1000px rgba(255, 255, 255, 0.6);
}

This way the rounded corners are easy. I have set a pseudo element to make it more elegant; this way you get 2 levels of transparency. You could elaborate it further using the remaining pseudo element, and also with an inset shadow.

demo

an alternate approach using gradients (no rounded corners, but not a bad effect anyway):

.overlay2 {
  position: absolute;
  left: 40px;
  top: 50px;
  width: 200px;
  height: 200px;
  border-radius: 40px;
  border: solid 1px gray;
  background-image: linear-gradient(90deg,white,transparent 25%, transparent 75%, white), linear-gradient(0deg,white,transparent 25%, transparent 75%, white);
  background-size: 100% 50%, 50% 100%;
  box-shadow: 0px 0px 0px 1000px white;
}

demo2

Upvotes: 2

Yoann
Yoann

Reputation: 5097

I have write a tiny jQuery plugin that create four div and place it arround your zone / element.

Even if it's not the answer you want don't vote down it's a first idea for your futur script.

var element = $("#element1").intro();
$("#element1").click(function() {
    element.intro('moveTo', $("#element2"), 500);
});

http://jsfiddle.net/DoubleYo/DQ6jj/

Upvotes: 0

Related Questions