diff --git a/src/Plugin/DisplayVariant/BlockDisplayVariant.php b/src/Plugin/DisplayVariant/BlockDisplayVariant.php
index 7e5e394..a5d2e21 100644
--- a/src/Plugin/DisplayVariant/BlockDisplayVariant.php
+++ b/src/Plugin/DisplayVariant/BlockDisplayVariant.php
@@ -13,11 +13,13 @@ use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Component\Uuid\UuidInterface;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Display\VariantBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\ContextAwarePluginInterface;
 use Drupal\Core\Plugin\Context\ContextHandlerInterface;
+use Drupal\Core\Render\Element;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Utility\Token;
@@ -230,7 +232,7 @@ class BlockDisplayVariant extends VariantBase implements ContextAwareVariantInte
     $content = $build['#block_plugin']->build();
     // Remove the block plugin from the render array.
     unset($build['#block_plugin']);
-    if (!empty($content)) {
+    if ($content !== NULL && !Element::isEmpty($content)) {
       $build['content'] = $content;
     }
     else {
@@ -243,6 +245,15 @@ class BlockDisplayVariant extends VariantBase implements ContextAwareVariantInte
         '#cache' => $build['#cache'],
       ];
     }
+    // If $content is not empty, then it contains cacheability metadata, and
+    // we must merge it with the existing cacheability metadata. This allows
+    // blocks to be empty, yet still bubble cacheability metadata, to indicate
+    // why they are empty.
+    if (!empty($content)) {
+      CacheableMetadata::createFromRenderArray($build)
+        ->merge(CacheableMetadata::createFromRenderArray($content))
+        ->applyTo($build);
+    }
     return $build;
   }
 
diff --git a/tests/src/Unit/BlockDisplayVariantTest.php b/tests/src/Unit/BlockDisplayVariantTest.php
index 20776b5..aa8d5ae 100644
--- a/tests/src/Unit/BlockDisplayVariantTest.php
+++ b/tests/src/Unit/BlockDisplayVariantTest.php
@@ -10,6 +10,7 @@ namespace Drupal\Tests\page_manager\Unit;
 use Drupal\Component\Uuid\UuidInterface;
 use Drupal\Core\Block\BlockPluginInterface;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Cache\Context\CacheContextsManager;
 use Drupal\Core\Plugin\Context\ContextHandlerInterface;
 use Drupal\Core\Plugin\ContextAwarePluginInterface;
@@ -176,6 +177,107 @@ class BlockDisplayVariantTest extends UnitTestCase {
     $this->assertSame($expected_build, $build);
   }
 
+  /**
+   * Tests the build() method when a block is empty.
+   *
+   * @covers ::build
+   */
+  public function testBuildEmptyBlock() {
+    $container = new ContainerBuilder();
+    $cache_contexts = $this->prophesize(CacheContextsManager::class);
+    $container->set('cache_contexts_manager', $cache_contexts->reveal());
+    \Drupal::setContainer($container);
+
+    $account = $this->prophesize(AccountInterface::class);
+
+    $block1 = $this->prophesize(BlockPluginInterface::class);
+    $block1->access($account)->willReturn(TRUE);
+
+    // Building a block with empty content.
+    $block1->build()->willReturn(['#cache' => [ 'tags' => [ 0 => 'route']]]);
+    $block1->getConfiguration()->willReturn([]);
+    $block1->getPluginId()->willReturn([]);
+    $block1->getBaseId()->willReturn([]);
+    $block1->getDerivativeId()->willReturn([]);
+    $block1->getCacheTags()->willReturn(['test']);
+    $block1->getCacheMaxAge()->willReturn(0);
+    $block1->getCacheContexts()->willReturn([]);
+
+    $blocks = [
+      'top' => [
+        'block1' => $block1->reveal(),
+      ],
+    ];
+
+    $block_collection = $this->getMockBuilder(BlockPluginCollection::class)
+      ->disableOriginalConstructor()
+      ->getMock();
+    $block_collection->expects($this->once())
+      ->method('getAllByRegion')
+      ->willReturn($blocks);
+    $context_handler = $this->prophesize(ContextHandlerInterface::class);
+
+    $uuid_generator = $this->prophesize(UuidInterface::class);
+    $page_title = 'Page title';
+    $token = $this->getMockBuilder(Token::class)
+      ->disableOriginalConstructor()
+      ->getMock();
+    $display_variant = $this->getMockBuilder(BlockDisplayVariant::class)
+      ->setConstructorArgs([['page_title' => $page_title], 'test', [], $context_handler->reveal(), $account->reveal(), $uuid_generator->reveal(), $token])
+      ->setMethods(['getBlockCollection', 'drupalHtmlClass', 'renderPageTitle'])
+      ->getMock();
+
+    $page = $this->prophesize(PageInterface::class);
+    $page->id()->willReturn('page_id');
+    $page->getCacheTags()->willReturn(['page:page_id']);
+    $page_executable = new PageExecutable($page->reveal());
+    $display_variant->setExecutable($page_executable);
+
+    $display_variant->expects($this->once())
+      ->method('getBlockCollection')
+      ->willReturn($block_collection);
+    $display_variant->expects($this->once())
+      ->method('renderPageTitle')
+      ->with($page_title)
+      ->willReturn($page_title);
+
+    // Empty block.
+    $expected_build = [
+      'regions' => [
+        'top' => [
+          '#prefix' => '<div class="block-region-top">',
+          '#suffix' => '</div>',
+          'block1' => [
+            '#markup' => '',
+            '#cache' => [
+              'keys' => [
+                0 => 'page_manager_page',
+                1 => 'page_id',
+                2 => 'block',
+                3 => 'block1',
+              ],
+              'tags' => [
+                0 => 'page:page_id',
+                1 => 'route',
+                2 => 'test',
+              ],
+              'contexts' => [],
+              'max-age' => 0,
+            ],
+          ],
+        ],
+      ],
+      '#title' => 'Page title',
+    ];
+
+    // Call build and the #pre_render callback, remove it from the render array
+    // to simplify the assertion.
+    $build = $display_variant->build();
+    $build['regions']['top']['block1'] = $display_variant->buildBlock($build['regions']['top']['block1']);
+    unset($build['regions']['top']['block1']['#pre_render']);
+    // Assert that the block return no content to be renderer.
+    $this->assertSame($expected_build, $build);
+  }
 
   /**
    * Tests the build() method when blocks can be cached.
