Lazy Load Images and Assets on WordPress with IntersectionObserver

wordpress homepage design

I write online a lot. Adding articles to this blog serves to build a catalog of technical solutions for future reference. Updating the homepage has improved user experience and SEO. The new design displays the most recent articles as clickable cards, rather than listing the entire text of each one. The changes for this were added to index.php file, in the child-theme folder. The theme’s original code already used a While() loop to iterate through the post records. My modification removed the article content, and only kept the title and image:

<div class="doc-item-wrap">
	<?php
	while ( have_posts() ) {
		the_post();
		echo "<div class='doc-item'><a href='". get_the_permalink() ."'><img class='lazy' data-src='".get_the_post_thumbnail_url()."'><h2>" . get_the_title() . "</h2></a></div>";
	} ?>
</div> <!-- doc-item-wrap -->

I used custom CSS, leveraging Flexbox, to style and position the cards:

.doc-item-wrap{
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
}
.doc-item{
    width: 30%;
    padding: 20px;
    border: 3px solid #f0503a;
    margin: 15px;
    background: black;
    flex-grow: 1;
    text-align: center;
}
.doc-item:hover{
    background-color: #34495e;
}
.doc-item p{
    margin: 0px;
    line-height: 40px;
    color: white;
}
.doc-item img{
    display: block;
    margin: 0 auto;
}
.doc-item h2{
    font-size: 22px;
    color: white;

}
@media(max-width: 1000px){
	.doc-item{
		width: 45%
	}
}
@media(max-width: 700px){
	.doc-item{
		width: 100%
	}
}

The media queries adjust the size of the cards (and how many are in a row), based on screen size.

Look and feel of the design

Card layout design is a common way to arrange blog content. It gives visitors a visual overview of what’s available. It also stops the homepage from duplicating content that’s already available on the individual post pages.

You can see this pattern throughout the digital world. Card layout translates well across screen sizes and devices. Since I put much effort into writing, making it organized was a priority. This implementation can be extended to add additional content (such as date, description, etc.) and features (share links, animations, expandability). And, it fits nicely with what WordPress already provides.

Lazy loaded images

Image content can often be the biggest drag to site speed. Lazy loading media defers rendering until it is needed. Since this blog’s homepage has an image for each post, this was essential.

While iterating through post records the image URL is assigned to a custom data-src attribute on the image tag, leaving the normal src blank. This assures the image is not immediately retrieved nor loaded. I wrote a JavaScript function to lazy load the images, relying on the IntersectionObserver API. The card’s image does not load until a user scrolls it into view. This improves the speed of the page, which has a positive effect on SEO and UX.

The code creates a IntersectionObserver object.  It observes each of the image elements, checking to see if they are within the browser viewport. Once the image elements come into view, it takes the image URL from the data-src attribute, and assigns it to the tag’s src – causing the image to load.

document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));
  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          // lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } 
});

The original JS code was referenced from a web.dev article. Web.dev is a resource created by Google that provides guidance, best practices, and tools to help web developers build better web experiences.

You can also use this same method for lazy loading videos, backgrounds, and other assets.

IntersectionObserver to lazily load JavaScript assets

I discovered another application for the IntersectionObserver implementation that I used above to load lazy load images. The Google Lighthouse performance score on my homepage was being dinged due to the “impact of third-party code”.

impact of 3rd party js on performance scores

The largest third-party resource was is used for the reCaptcha on a contact form at the bottom of my homepage. It makes sense to not load it until the user scrolls down to that section – especially because the UX expects them to take time to fill out the form before hitting “submit” anyway.

Using the same pattern as above, I created a new `IntersectionObserver` and passed the contact form section as the target:

function captchaLazyLoad(){
	contactCaptchaTarget = document.getElementById('contactSection')
	if (!contactCaptchaTarget) {
        return;
    }
	let contactCaptchaObserver = new IntersectionObserver(function(entries, observer) {
		if (entries[0].isIntersecting) {
            var script = document.createElement('script');
		    script.src = "https://www.google.com/recaptcha/api.js";
		    document.body.appendChild(script);
            contactCaptchaObserver.unobserve(contactCaptchaTarget);
        }
	})
	contactCaptchaObserver.observe(contactCaptchaTarget);
}

I included this function to the already existing `DOMContentLoaded`  event listener just below the loop to observe lazy image elements:

<script>
function captchaLazyLoad(){
	contactCaptchaTarget = document.getElementById('contactSection')
	if (!contactCaptchaTarget) {
        return;
    }
	let contactCaptchaObserver = new IntersectionObserver(function(entries, observer) {
		if (entries[0].isIntersecting) {
            var script = document.createElement('script');
		    script.src = "https://www.google.com/recaptcha/api.js";
		    document.body.appendChild(script);
            contactCaptchaObserver.unobserve(contactCaptchaTarget);
        }
	})
	contactCaptchaObserver.observe(contactCaptchaTarget);
}

document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));
  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          // lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });

    //
    captchaLazyLoad()

  } else {
    // Possibly fall back to a more compatible method here if IntersectionObserver does not exist on the browser
  }

});

</script>

This update raised my Lighthouse performance score by fifteen points!

Building my career in tech as a programmer

Anthony Pace's resume and portfolio

Building a fulfilling career can seem daunting. Technology and programming is a great option in today’s world. Resources and opportunities are abundant. You can work from anywhere and help build the future. When I started out, I faced challenges, doubt, and struggle. The ride has been worth it, and I’m excited to keep moving forward.

Starting out

About half way through college, I decided to dropout. I was majoring in Philosophy at a small school in New York.  My main source of income was delivering pizza in the Bronx.

A decade earlier, I found computer programming. I spent my nights coding desktop applications, learning HTML, and exploring the web. Those early days of technology laid the foundation for what would be my career.

When I left school in 2007, I wasn’t sure what to do next. I started earning money in tech that same year by starting a business. It focused on creating blogs and producing content. Ads and affiliate programs served to generate revenue.

It wasn’t as lucrative as I hoped. The real value came from the web development skills I honed. The software and technologies I used then, I still rely on today.

WordPress, Linux, and PHP. Writing, SEO, and digital marketing. These were the bricks I used to form the ground floor of my career in tech.

Service worker

While my early stint at entrepreneurship didn’t make me wealthy, it proved valuable. I managed to grow a freelance business leveraging this experience.

Networking and word-of-mouth were my primary means of growth. After printing business cards, I would give them to everyone I met. While delivering pizzas, I would hand them out to any small businesses or shops I passed.

I found my first paying customer in 2008. Since then, my client list has grown to triple digits.

The services I’ve offered range beyond web development. I’ve designed logos and written copy. I’ve managed infrastructure: web hosting, domain names, email, and more.

I have designed and managed both print and digital marketing campaigns. I’ve given strategy advice to young startups. Truly full stack: business, technology, and design. This has been a theme that has rung true my entire career.

The lessons learned during this period were ones of hard-work and getting the job done. The most valuable skills translate across industries. Finding clients fuels the engine of any business. The art of pitching and selling is a career-long study. Being able to manage business needs has proven to be foundational.

Office life

By 2011 I landed my first in-house gig, working at a marketing company. It felt like a turning point. I was the only developer, and got to deal directly with clients. I worked there for less than a year.

In 2012 I connected with a recruiter for the first time. They set me up on many interviews. I clicked with a small medical education company based in Manhattan. Hired as a web developer, I graduated to senior engineer and marketing specialist.

Team work

There, I was the head of all things digital. That meant building websites, coding native apps, and managing infrastructure. After a promotion to head of marketing my responsibilities expanded. Managing analytics took time. Copywriting promotional materials required patience. My horizons expanded while coordinating live events, and traveling internationally to exhibition shows.

Educational grants funded our projects. They included apps, websites, live events, and digital newsletters. Having a coordinated team was imperative to making things work. The project management and leadership was world-class and invaluable.

A single project was multifarious. I would design responsive layouts, build registration websites, deploy apps, and more. Once a product would launch, I would travel to live events to handle promotion and logistics. While I fulfilled many roles, I was lucky to work with a talented group.

Software Engineer

After four years, I made the difficult decision to leave the job that helped shape my career. A better opportunity presented itself in 2016. I was hired as a software engineer. This is when I came into my own as a programmer. I was able to collaborate with a brilliant team. The technologies I became familiar with continued to grow.

I got to work with early-stage startups and brands backed by venture capital. I learned the intricacies of building digital products and growing direct-to-consumer brands. My colleagues included entrepreneurs, CEOs, and product experts. The office was exciting and full of talent.

At the time of writing this (2020), we are stuck in quarantine due to the COVID-19 pandemic. We’re working remotely, but continuing to grow. Uncertain times prompt us to evaluate our circumstances and take inventory of what we value. What is the future of my career? How does it play into my life overall?

What’s next?

I love what I do for a living. I enjoy programming; I love problem solving; I’m an artist at heart. I plan on continuing to build software products. Chances are, I’ll be doing it somewhere other than New York City – especially since remote work seems to be the future of business.

If you’re thinking about starting a career in technology as a programmer, my advice is to jump right in. Start building, keep learning, and put yourself out there. If anyone reading this wants to chat about careers, technology, programming, or anything else, feel free to email me!

Top 3 graphic design apps for social media marketing

Modern software has given creators the tools they need to showcase their work to the world. Here are the best free apps that I’ve been using that will help your talent shine in 2019:

AppWrap – Do you want to feature your latest website or app design to your followers? Are you building a portfolio for the UI/UX projects you worked on? This app is a great way to wrap your screenshots in a mobile device view. You can add effects, backgrounds, and text to really polish the look and feel. Their template gallery will give you inspiration to make something gorgeous. http://www.appwrap.in/

AntPace.com mobile device view

Canva – This is one of my favorites. With a library of over 60,000+ templates, this app has something for every platform. Whether you need to create a great looking post, story, or cover image, this app has designs for Instagram, Facebook, YouTube and much more. If you want your online presence to look professionally designed, check this one out! https://www.canva.com/

Anthony Pace creativity takes courage

Hatchful – Do you need a logo for your brand, business, or product? This app let’s you create one quickly. By customizing templates, you can draft, and iterate designs. Having logo design done fast, cheap, and easily allows you to focus on the actual product. It’s important to not get hung up on the logo, especially early into your venture, and instead focus on the actual value your service proposes. https://hatchful.shopify.com/

antpace.com

I’ve used all of these apps, and personally gained value from them. What apps do you use for your graphic design?

BJJ Tracker, a Fitness App

BJJ tracker, a fitness app

www.BJJTracker.com

BJJ Tracker is a fitness app for tracking Brazilian jiu jitsu training. It’s the sort of fitness app I was looking for, but couldn’t find. Version 1.0 is a bare bones MVP, but has a list of features on the way. Future versions will add gamification (including challenges and goals), UX/UI enhancements, training recommendations, and more.

The app allows users to record their training sessions, with details about drilling and sparring, as well as competition. This data is visualized over charts and calendars. The idea started from physically writing my training sessions onto an actual calendar, with a minimum goal per week. Building it has been a great exercise in digital product development, software design, and UI/UX strategy.

fitness tracker calendar

Software

BJJ Tracker is a web app, hosted on a AWS Linux server, running Apache, PHP, and MySql. I used Initializr to generate a bootstrap template to get my front-end started. One goal of this project was to build a web app framework that I could use to quickly get future projects running. This code would include user registration and login services, as well as other back-end concerns, on top of a front-end. I’ve cleaned most of this code into a generic repo on GitHub. You can read my post explaining its features.

Design

This app was designed with “mobile first” in mind, assuming that most users will be on a smart phone. The look and feel of the color palette, font-choice, and UI layout took some experimenting and visual research. It’s not final, and will be subject to split testing over time. I used Font Awesome to add icons as visual cues, giving the app a more finished look. The three lined (hamburger) menu in the top right comes as standard UI, using Simple MobileMenu, a jQuery plugin. Other UI elements include a top status message, and “In-Your-Face” status message, both of which are custom built notifications that I’ve wrapped as javascript plugins. Having a calendar section was important to me, and I consider to be a primary feature of the app. I use Full Calendar to generate the full month view. The homepage (dashboard) focuses on a week view. Google charts is used for the “techniques” graph.

logo design

The logo is a work-in-progress. The textual part was easy – pick a font, add a sharp outline, and a drop shadow. I always start with a 1024×1024 canvas. The symbol begins with simple shapes, triangles and circles. I left this process for last, saving my focus for the actual product. This allowed me to rapidly iterate design versions, and see how it would look directly in the user interface. Below is the current portrayal – and I’m excited for next versions.

BJJ Tracker logo
BJJTracker.com

Full Calendar

Fullcalendar.io has been my go-to solution for adding Calendars to websites. It’s free, and only needs two file references to work (a CSS file and a JavaScript file). You can host those files your self, or use a CDN. And, the UI is easily customized with a bit of <style> code:

<!-- <link href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/fullcalendar.min.css" rel="stylesheet"> -->
<link href="/css/fullcalendar.min.css" rel="stylesheet">
<style>
#calendar {
    margin: 0 auto;
    width: 100%;
}
#calendar h2{
    font-size: 18px;
}
.fc-scroller.fc-day-grid-container{
    height: auto !important;
}
.fc-button{
    padding: 5px !important;
    outline: none;
    border: 1px solid #2176AE;
    background-color: #2176AE;
    color: white;
    text-align: center;
    box-shadow: 1px 1px;
    border-radius: 6px !important;
    background-image: none;
    text-transform: capitalize;
    font-size: 12px !important;
    height: 25px !important;
    margin-left: 5px !important;
}
.fc-state-disabled{
    display: none;
}
<div class="ap-container top-ap-container" > <div id='calendar'></div> </div> 

<script src="js/vendor/moment.min.js"></script>
<script src="js/vendor/fullcalendar.js"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.9.0/fullcalendar.js"></script> -->

<script>

$(document).ready(function() {
	var date = new Date();
	var d = date.getDate();
	var m = date.getMonth();
	var y = date.getFullYear();
	var eventsArray = [];
	<?php
	if(!$view_record_response["record_not_found"]){ 
		$all_record_rows = $view_record_response["all_record_rows"];
		foreach ($all_record_rows as $key => $value){
			$record_date = $value['date'];
			$record_type = $value['type'];
			$rid = $value['recordid'];
			$nameOfDay = date('D', strtotime($record_date));
			$nameOfDay = lcfirst($nameOfDay);
			$color = "";
			if($record_type == "competition"){
				$color = "red";
			}
			?>

			var event = {
			title: "<?php echo $record_type; ?>",
			start: '<?php echo $record_date; ?>',
			end: '<?php echo $record_date; ?>',
			color: '<?php echo $color; ?>',
			url: "view-record.php?rid=<?php echo $rid?>" 
			}
			eventsArray.push(event);

	<?php
		} //end foreach
	} //end if
	?>

	$('#calendar').fullCalendar({
		editable: false,
		events: eventsArray
	});
});
</script>

You can see I get the back-end data through my PHP code (view_record_response), and pass it along on the front-end (eventsArray) to FullCalendar.

Challenges and next steps

One goal of this project was to get started fast, so people could begin using it. Deciding what to include out of a long list of ideas proved challenging. I could have kept adding features, and never been ready to make the site public. I meant to keep functionality basic, but still wanted the thing to be useful. The design needed to be simple, yet still had to look finished. I won’t know how close I came to getting this right until I analyze user feedback. The real plan is to do a little bit better next time, and to keep iterating. Using this as foundation will let future ventures start a step ahead. Already, I’ve begun implementing updates, and getting ready to deploy to the App Store and Google Play. Look out for coming updates and other products that are in the works! Don’t forget to visit the BJJ Tracker blog.

bjj tracker