Check out the Youtube channel

Hiding empty elements on your website in CSS or JS

Written by Eduard Fastovski

Nov 20, 2023

I recently published a video on hiding Shopify sections & blocks when they’re empty using Shopify Liquid, but now I’ll show you a method that works with any platform.

Because whether you are using Shopify, Wordpress, Webflow, or others, there are cases where you have an empty part of a page, and the platform doesn’t give you enough control to hide it without creating a separate template.

Let me give you two examples:

  1. An eCommerce store. Let’s say we add a size guide to our product template - now every product has a heading saying “Size Guide”, and below it, a size guide image for that particular product.
    However, not every product has a size guide image. So for some products, we have the heading “Size Guide” and then an empty space below it.

  2. A blog. Imagine you have multiple authors for a blog, and each blog post shows “Written by..” the authors name and a small profile image at the top.
    Some authors didn’t send you their image though, so you have nothing to put there. Rather than a broken image icon or a weird empty space you’d prefer to remove that image holder area entirely.
    Also, you’d prefer not to mess with the logic that controls the author image, so targeting it with CSS is the best option.

So how can we hide things, based on if a div is empty? And without editing the existing website structure or changing back-end logic.
In other words, I want a short piece of code that I can add to the site - externally from the theme - that hides those divs.

Targeting empty elements with CSS

There are some relatively new features of CSS that are very powerful and allow us to target empty elements, or elements that have (or don’t have) certain children.

Let’s explore :empty, :has, and :not.

Using :empty

Pretty self-explanatory. It targets empty elements.

To use it, add :empty on the end of a selector.

div:empty {
  display: none;
}

So assuming your html looks like this:

<section class="product-info">
  <h2 class="product-title">Cool T-shirt</h2>
  <div class="size-guide"></div>
</section>

You could hide the size guide div with this CSS:

.size-guide:empty {
  display: none;
}

However, in the real world it’s not so simple. This perfect solution is ruined by two things:

  1. Most of the time your size-guide div will have some child elements, like a heading or image wrapper div. In which case size-guide itself is not empty. Luckily we can use :has for this situation (read on).

  2. :empty doesn’t work if your div has whitespace. Even just one space would mean that according to CSS, the element is not empty. In this case we can use one of the other methods, or we have to use Javascript.

Using :has

Here is some more realistic html:

<section class="product-info">
  <h2 class="product-title">Cool T-shirt</h2>
  <div class="size-guide">
    <h3>Size Guide</h3>
    <div class="image-wrapper"></div>
  </div>
</section>

The size-guide div now has a heading inside it, and another div with the class of image-wrapper.

So now we can use this CSS:

.size-guide:has(.image-wrapper:empty) {
  display: none;
}

So any size-guide that has an empty image-wrapper inside it, will be hidden.

This is powerful because we can target the parents of empty elements.

But notice we are still relying on :empty. This example assumes there is no whitespace in the image-wrapper.

There might be ways to avoid using :empty though.

Using :not

Let’s look at an even more realistic piece of code:

<section class="product-info">
  <h2 class="product-title">Cool T-shirt</h2>
  <div class="size-guide">
    <h3>Size Guide</h3>
    <div class="image-wrapper">
      <img src="whatever.jpg" alt="An image">
    </div>
  </div>
</section>

Here we have an actual <img> inside the image-wrapper. Let’s assume that this is coming from the back-end, and when a product doesn’t have an image, then there is no <img> tag in the code. The image-wrapper is just empty, or it might have whitespace.

We don’t care if it has whitespace, because now, rather than checking if image-wrapper is :empty, we will check for the existence of <img>. If it doesn’t exist, we use :has to hie the parent size-guide.

.size-guide:not(.size-guide:has(img)) {
  display: none;
}

What about browser support?

All the above methods have around 90% to 95% browser support. That means it will work for most of your audience, but around 5% of people (depending on your audience and how updated they keep their tech) will be using a browser where this doesn’t work.

However, it’s not a crucial feature - if someone is on an older browser and sees an empty block or a heading with nothing following, it’s a bit ugly but it’s not breaking the website.

Detecting empty elements with Javascript

Obviously, CSS is just better than JS when it comes to small business and amateur coding (which is what my content is all about).

CSS is simpler and easier to use, and you are less likely to make a mistake that messes up your site.

However in some cases we will also need to combine these methods with a little bit of Javascript.

As I mentioned above, :empty won’t work if the element contains whitespace. Such as a space ’ ’ or a newline. And sometimes your website just doesn’t have the right structure for :has or :not either.

Luckily it’s easy to find empty elements with javascript. We can add the class ”.is-empty” to any empty elements it finds.

We can then target ”.is-empty” with CSS the old fashioned way.

Here is how we can find elements with just whitespace, and add a class to it. (Don’t copy/paste this, it’s not the full code)

// Trim removes whitespace.
// If there is nothing left after trim(), it means the element contained only whitespace.
if(element.textContent.trim() === '') { 
    // Add a class that we can target with CSS
    element.classList.add('is-empty');
}

But you don’t want to add ”.is-empty” to every empty element across the entire page.

There are plenty of things that may contain just whitespace that you don’t want to hide. Also, this would be a difficult operation for your browser. You don’t want to lag things up.

That’s why it’s best to limit the scope of this javascript to the smallest possible part of the page. Like the parent of the size-guide div.

You will need to use the chrome inspector on your website (right-click -> inspect) to find the class or ID of the section you are targeting.

For me, it’s a div called .product-info. But if you want it to work on the entire page (not recommended), you can just use ‘body’.

Here is our complete Javascript:

// Choose your scope
let container = document.querySelector('.product-info');

// Loop over all elements in the scope
container.querySelectorAll('*').forEach(el => {
  // Checks that it's an empty text element and that it's not a self-closing element like <img>, <br> or <hr>
  if (!el.children.length && // no children
    el.textContent.trim() === '' && // its empty
    el.nodeName !== 'IMG' && // not an image
    el.nodeName !== 'BR' && // not a <br>
    el.nodeName !== 'HR' // not a <hr>
    ) {
    // adds the is-empty class
    el.classList.add('is-empty');
  // but if it is an image, check if its src is empty
  } else if (el.nodeName === 'IMG' && el.getAttribute('src') === '') {
    // adds the is-empty class to <img> elements with an empty src attribute
    el.classList.add('is-empty');
  }
});

Copy & paste this script, but replace .product-info with your own selector.

After that, it’s easy to target elements with the class “is-empty” or even their parents by combining with :has.

/* Target the element itself */
.is-empty {
  display: none;
}

/* Target the parent size-guide */
.size-guide:has(.is-empty) {
  display: none;
}

*I haven’t thoroughly tested this script on all types of elements. It probably requires some modification if your container div contains different types of media other than images, form elements, or other self-closing elements.

Want posts like this in your inbox? Subscribe to the newsletter.

Comments