At work today they gave us a beautiful mockup for a lot of kids overlapping each other. We wanted to have this to be the homepage of our lifestyle brand Seedling.

The idea is when you hover one of the kids, to show what the kid is into. The big challenge is that HTML pages work in “boxes” so in a picture like the one below, how do you differentiate an action between the girl and the boy if her bounding box covers the boy’s area too?

How would I solve such a problem?

In old school HTML the only option is to use a map tag but that leaves you only with click events.

I explored the canvas but seemed that it would be overkill to attach every single event to a 2d context so I explored other options. I also explored CSS masks but I didn’t see a way to attach an event to it.

SVGs FTW

I will use the SVG to create a mask to attach events. Why SVGs? SVGs are an incredible and underrated resource, and because they can be treated part of the DOM, I could use css transitions and even manipulate it through javascript and also attach javascript events. Also since I can fill shapes with images, I can very efficiently load a single JPG as a background with shapes on top that work as masks.

I used Webcode to create a rough mask to do this little test.

First things first

Make sure that you to inline the SVG (included as objets or as images won’t work).

Once inlined, My SVG has a layer that has a fill of the image, more or less things look like this.

1 <defs>
2     <pattern id="kidsHomepageTestweb01-kidsHomepageTestweb" x="-237" y="-129" width="2154" height="1506" patternUnits="userSpaceOnUse" viewBox="0 0 2154 1506">
3         <image xlink:href="KidsHomepageTest-web-01.jpg" x="0" y="0" width="1077" height="753"></image>
4     </pattern>
5 </defs>
6 ...
7 <rect id="kidsHomepageTestweb" stroke="none" fill="url(#kidsHomepageTestweb01-kidsHomepageTestweb)" x="-237" y="-129" width="1077" height="753"></rect>
8 ...

On the paths, I added a class, id but I changed, for this purpose the stroke attribute to none and made the fill to full white.

1 <path id="bezier" class="mask" stroke="none" fill="rgba(255, 255, 255, 1)" d="........."></path>

And I am setting the opacity to zero on the class I assigned to it so that the browser still responds to it but it is invisible.

1 .mask
2 {
3     opacity: 0;
4 }

Once the SVG is loaded, then I proceeded to do things with javascript to make things interesting. I created two functions that correspond with changing the opacity. In here I just want to make sure that I “dim” all the other images so I will use the masks for that purpose.

 1 var turnOn = function(evt)
 2 {
 3     var self = evt.target;
 4     $(".mask").each(function(){
 5 
 6        if(this === self)
 7        {
 8            $(this).css('opacity', 0.0);
 9            return;
10        }
11 
12        $(this).css('opacity', 0.5);
13     });
14 };
15 
16 var turnOff = function(evt)
17 {
18     var self = evt.target;
19     $(".mask").each(function(){
20 
21        $(this).css('opacity', 0.0);
22     });
23 };
24 
25 $(document).ready(function(){
26     $(".mask").mouseout(turnOff);
27     $(".mask").mouseover(turnOn);
28 });

And Voila! It looked like this (hover the image to get a full effect):

What about responsive?

Of course good ol’ Vinny would ask me if it looks good on mobile. So I did a few modifications

  • I wrapped the entire SVG in a div container that determines the max size of what I want to display and I styled it to contain the size of the svg.
1 #svg_container
2 {
3     width: 1078px;
4     height: 522px;
5 }
  • I altered the top tag of the SVG to have relative widths
1 <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" id="kids"  xml:space="preserve">
  • I grouped all paths and the background image in a div that I could manipulate and I used CSS transforms to scale the content.
 1 var resizeKids = function() {
 2 	var resizedWindowWidth = $(window).width(); // Get resized window width.
 3 	var kidsWidth = $("#svg_container").width();
 4 	var widthScale = resizedWindowWidth/kidsWidth;
 5 
 6     var resizedWindowHeight = $(window).height(); // Get resized window width.
 7 	var kidsHeight = $("#svg_container").height();
 8 	var heightScale = resizedWindowHeight/kidsHeight;
 9 
10 
11     var scale = 1.0;
12 	if (heightScale<1.0||widthScale<1.0)
13 	{
14         scale = Math.min(heightScale, widthScale);
15 	}
16 
17     var cssscale = 'scale('+scale+','+scale+') translate(0, 0)';
18     $("#all_stuff").attr('transform', cssscale);
19     $("#kids").width(kidsWidth*scale);
20     $("#kids").height(kidsHeight*scale);
21 
22 };
23 
24 $(window).resize(resizeKids);
25 resizeKids();

And using Browserstack I determined that it worked on IE10 and above, and all of the other major browsers (Safari, Chrome, Firefox)