Creating an Overlay Element Without Blocking CTAs Using SVG Lines


Here at White Fox Creative, we work with various designers to create beautiful unique branded websites for businesses. But sometimes the design we’re provided, whether through Adobe XD, Photoshop, or Illustrator, has a unique element that you don’t typically find in business websites. In addition to creating that unique element, it also needs to be fully integrated into WordPress so that the user can change it as needed in the future.

The below element, yellow “speech bubbles” connected by a line, overtop of images and buttons, is not something you see everyday. It’s an element that might be more at home in print design. But create it we did! Follow along below to find out how we made it.

Jump to the jsFiddle

example of dots and lines overlaying a website


Interactivity of Elements Issue

The issue with creating a design like this stems from the fact that anything underneath this line will no longer be active. In the example above, there are buttons that the user should be able to click UNDERNEATH the line element, so you can’t simply use a “.png” file. You also have an issue that the client will want to edit the location of these as needed, so you need to be able to actively arrange the location of the speech bubbles.

By using the SVG line and a little jquery positioning, you can create an element overtop an entire section of your page, while not obscuring the interactivity of that page from the user.

Step 1: Creating the Elements

We needed two main elements to create this effect: a tiny speech bubble and a line. The speech bubble we received as an asset in an svg file format. The line, however, we created in the page using an SVG line element.

We needed to use the line as a live SVG element because we’ll need to manipulate the starting and ending points based on where the yellow speech bubbles end up.

Step 2: ACF Fields for Editing the Speech Bubble Locations

When creating a custom theme for WordPress, we utilize Advanced Custom Fields (ACF). You could use any system where the business owner/employee can add numbers into a field in the backend of the site. We won’t cover how to do this here, but if you don’t have a favorite, ACF is one of the most popular and easiest ways of adding new fields.

Each speech bubble will need a “top” and “left” location input fields, numbers only. We utilized the “Repeater” field in ACF to allow the website admin user to control the number of yellow speech bubbles as well.

Step 3: Adding the HTML/PHP to the Page

Next we’ll retrieve this information from our field (we used a get_sub_field() function since we’re also utilizing modules), and create all our SVG lines and speech bubbles. Each one has an ID that corresponds to the dot number it is.

$yellowDots = get_sub_field('floating_yellow_dot_locations');
$i = 1;
foreach ($yellowDots as $yD){
     <div id="div<?php echo $i; ?>" class="yellow" style="top:<?php echo $yD['yellow_dot_top']; ?>px; left:<?php echo $yD['yellow_dot_left']; ?>px;">
          <img src="<?php echo get_stylesheet_directory_uri(); ?>/assets/images/speechBubble.png">
     if ( $i != 1 ){ ?>
          <svg width="" height="" class="svfDots"><line x1="50" y1="50" x2="350" y2="50" stroke="#ffd700" id="line<?php echo $i; ?>"/></svg><?php

Line 1: We retrieved the fields. These are stored in ACF, inside of “Flexible Content”, so we’ll use the “get_sub_field()” function instead of the common get_field() function. This is specific to ACF, so if you are using a different system to create the fields in the backend of the site, you’ll need to use that system’s way of retrieving the information.

Line 2: A simple strategy, but we used a counter “i” variable to distinguish between the IDs on the dots and lines. And we’ll need to distinguish because we’ll be referencing them in our jQuery in a moment.

Line 3: Our fields in Line 1 ended up in an array. The foreach will cycle through the array and create our HTML each time.

Line 5-7: This is our speech bubble wrapper DIV. We utilize our “i” variable to create a new ID for it (“div1, div2, div3”), added a class that we use in the stylesheet, and add the styles “top” and “left” that we just retrieved from our ACF field array’s variable “$yD”.

Line 6: This is our actual speech bubble image. We added the image to our theme under assets > images.

Line 9 – 11: When creating our lines, we’ll need 1 less line than there are speech bubbles. So on the first loop, we just don’t add a SVG line. Our SVG line doesn’t have a width or height. By leaving those empty, the line will be the exact length between the 2 locations (Note the Safari-specific CSS below). Note a few things about the line: the attributes “x1, y1” and “x2, y2” are the coordinates of the speech bubbles (yah graphing in Algebra!); the stroke color is our yellow color; and we also gave this one an ID. Each line ID will match the speech bubble ID of its ending point (#div2 = #line2).

Line 12: Don’t forget to iterate the “i” variable in our loop!


Our CSS is fairly simple. It makes all of them absolutely positioned, makes sure they’ll show up on top of the images (z-index), and sets the size of the speech bubbles.

.yellow, .svfDots, .line { position:absolute; z-index:9;}
.yellow { width: 20px; height: 20px; }

However, there’s a little extra we need to add into the CSS just for the Safari Browser:

.svfDots { width: auto; height: auto; overflow: unset; }

This allows the Div surrounding our SVG line to show the entire line instead of just a portion of it.

Step 4: The Magic: Adding in the jQuery Calculations

Finally, we’ll do a little magic with jQuery. Add the below section into the javascript file for your theme. This will consider whether the lines are on the page and adjust their starting/ending points for each line. The speech bubbles, remember, are already absolutely positioned in the HTML.

if ( $('.yellow_dot_block').length ){
     var totalyd = $('.svfDots').length;
     i = 1;
     while (i <= totalyd+1 ){
          if ( i == 1 || i == totalyd+2 ){
              //draw no line
          } else {
              pos1 = $('#div'+ (i-1) ).position();
              pos2 = $('#div' + i ).position();
              $('#line'+ (i) )
                   .attr('x1', pos1.left)
                   .attr('y1', + 15)
                   .attr('x2', pos2.left)
                   .attr('y2', + 15);

Line 1: Checking if our “yellow_dot_block” exists. While this isn’t in the HTML above, you can change this to whatever your Div is for this section. Our module was called “yellow_dot_block”. We just don’t want these calculations to run if we have no lines to calculate.

Line 2: First, we want to find out how many speech bubbles we have with the “length” property. Remember, those are already set in their places. This Javascript file ONLY handles drawing the lines.

Line 3: Set up our oh-so-handy counter variable “i”.

Line 4 – to end: Our “while” loop runs while the loop is under the total number of speech bubbles plus 1. Each loop, we’ll be positioning the start and ending point of one line.

Line 5:  If it’s the first speech bubble or the last+2, we don’t do any additional calculations. The first speech bubble doesn’t have a line that corresponds with it (remember our divs start at “div1”, but our lines start at “line2”).

Line 8 – 9: We’re figuring out the positions using the position() method of the starting (where this line will start) speech bubble and the ending (where this line will end) speech bubble.

Line 10 – 14: We’ll reference this line by ID and then set the starting X,Y position, and ending X,Y position, in that order. The position() method in the lines above provides the “top” and “left” qualities automatically. We simply reference it using the variable we put those in (pos1 or pos2), followed by the one we’re referencing (left or top). Since we want the line to hit the bottom of the bubble, not the top, we added 15px (the height of our speech bubble) to the position top when we set it.

Line 16: As always, don’t forget to iterate the “i” variable.

And our lines are magically created!


This wouldn’t be complete without a small note about the Responsiveness of a design element like this. Our mobile design didn’t use this element; it simple removed it when the screen was too small. And since this is purely a visual element on the page, this won’t effect rankings or SEO.

However, if this needs to be visible on mobile as well, the best option would most likely be calculating the location using “vw” or percentages. It does get much trickier trying to make this design work on mobile and desktop. If you’ve tried it out, let us know in the comments!


Integrating unusual visual elements into websites can help them stay fresh and exciting for the user. While a little unusual, these yellow speech bubbles and lines create more of a cohesive effect for these sections. Have you done something like this before? What do you think about elements like these? Let us know in the comments!

The jsFiddle

Join the Discussion

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>