Build Whole-Tile CSS Backgrounds

Build a patterned CSS section that snaps its height to complete tiles.

Introduction

30 Second Summary

Repeating patterns can make a page feel carefully finished until the content stops halfway through the final tile. That clipped edge makes the layout look accidental.

In this project, you will build an HTML page whose patterned section uses CSS sizing to finish on a complete SVG tile. A fallback keeps the section readable in browsers without support.

What You'll Build

You'll add or remove paragraphs and watch the section grow by full tiles while its bottom row stays complete.

By the end of this project, you'll have:

  • A clean tile ending that stays complete as the amount of text changes.
  • A snapping section height powered by calc-size() and round() that grows one tile at a time.
  • A browser fallback that preserves the normal layout when the sizing functions are unavailable.
  • Secret Mission: Build a second patterned section with a different tile size to prove the CSS can be reused.

Are there any prerequisites?

You only need a text editor and Chrome. Everything runs in your browser at no cost.

Before We Start

A patterned section can look complete in one browser while another browser falls back to ordinary CSS sizing. You need a reliable comparison before you start building the page.

In this step, you will prepare a code editor for writing the page. You will also set up Google Chrome for the experimental feature path plus a second browser for the fallback path.

In this step, get ready to:
  • Prepare a code editor for writing HTML plus CSS.
  • Install Google Chrome for experimental CSS testing.
  • Prepare Firefox for fallback testing.
Prepare your code editor

Your code editor gives you one place to create the page files in the next step. Any editor that supports HTML plus CSS works.

If you need an editor, Visual Studio Code is available for macOS, Windows, plus Linux.

✔️ I already have a code editor

  • Press Cmd+Space on macOS or the Windows key on Windows to open system search.
  • Type the name of your code editor into system search.
  • Press Enter to launch the editor.

You should see an editor window ready to open a folder or create a file.

ⓧ I need a code editor

  • Open the official Visual Studio Code download page.
  • Select the installer that matches your operating system.
  • Run the downloaded installer.
  • Approve the operating system permission request if it appears.
  • Follow the installer prompts to complete the installation.
  • Press Cmd+Space on macOS or the Windows key on Windows to open system search.
  • Type Visual Studio Code into system search.
  • Press Enter to launch the editor.

You should see the Visual Studio Code welcome screen. Your editor is ready for the project files.

Editor not opening?

Check that the installation finished before searching for the editor. Reopen the installer if your system search cannot find it.

Ask for help with your specific operating system: help me install or open Visual Studio Code.

Set up Google Chrome

The main version of the page uses calc-size() with round() to snap the section height to complete pattern tiles. Chrome provides the experimental feature path used by this project.

✔️ Google Chrome is installed

  • Press Cmd+Space on macOS or the Windows key on Windows to open system search.
  • Type Google Chrome into system search.
  • Press Enter to launch Chrome.

You should see a Chrome window with a new tab. This browser is ready for the rounded-height version of the page.

ⓧ Google Chrome is not installed

  • Open the official Google Chrome download page.
  • Select Download Chrome.
  • Run the downloaded installation file.
  • Approve the operating system permission request if it appears.
  • Follow the on-screen instructions to complete the installation.
  • Press Cmd+Space on macOS or the Windows key on Windows to open system search.
  • Type Google Chrome into system search.
  • Press Enter to launch Chrome.

You should see a Chrome window with a new tab. The browser is ready for the feature test.

Why use two browsers?

Chrome lets you observe the tile-snapping behavior described by the source for this project. The second browser lets you confirm that the fallback keeps the content readable without the experimental sizing.

Testing both paths protects the section when browser support differs.

Chrome not launching?

Confirm that the installer completed before searching again. Download a fresh installation file from the official page if the installation stopped early.

Ask for targeted help: help me install or launch Google Chrome.

Add a fallback browser

A second browser gives you an independent place to test the fallback behavior. Firefox provides the same option across macOS, Windows, plus Linux.

✔️ Firefox is installed

  • Press Cmd+Space on macOS or the Windows key on Windows to open system search.
  • Type Firefox into system search.
  • Press Enter to launch Firefox.

You should see a Firefox window with a new tab. Your fallback browser is ready.

ⓧ Firefox is not installed

  • Open the official Firefox for Desktop download page.
  • Select the download option for your operating system.
  • Run the downloaded installation file.
  • Approve the operating system permission request if it appears.
  • Follow the on-screen instructions to complete the installation.
  • Press Cmd+Space on macOS or the Windows key on Windows to open system search.
  • Type Firefox into system search.
  • Press Enter to launch Firefox.

You should see a Firefox window with a new tab. Your fallback browser is ready.

Firefox not launching?

Check that you downloaded the desktop build for your operating system. Run the installer again if system search cannot find Firefox.

Ask for help with the installation: help me install or launch Firefox.

Before the final check, do you expect both browser windows to be ready for the same page?

  • Switch back to the Google Chrome window from earlier.
  • Arrange the Google Chrome window beside the Firefox window.
  • Confirm that both browser windows are visible at the same time.

You should see Google Chrome beside Firefox. This gives you one browser for the experimental layout plus one browser for the fallback.

Your editing environment plus browser test bench are ready. Next up, you will build the patterned section that exposes the cut-off tile problem.

Build the Patterned Section

A repeating CSS background exposes a visual flaw when content controls the section height. The bottom edge can slice through a tile instead of landing on its boundary.

In this step, you will create an HTML section with a repeating SVG tile. You will preview the baseline in Google Chrome so you can see the incomplete final row.

In this step, get ready to:
  • Create the page content for the patterned section.
  • Add base page styles that frame the demo.
  • Apply a repeating tile background with a normal content-driven height.
Create the HTML section

The page needs enough text to give the section a natural height. This content becomes the surface behind the repeating pattern.

  • Add index.html to your code editor with the following contents:
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Patterned Section</title>
  <!-- Load the page styles from the adjacent CSS file. -->
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <main>
    <!-- Hold the demo content over the repeating tile pattern. -->
    <section class="patterned-section">
      <p>DESIGN SYSTEMS</p>
      <h1>A pattern should finish as cleanly as it starts.</h1>
      <p>Each tile creates a clear visual rhythm across the section.</p>
      <p>Extra copy changes the amount of vertical space the section needs.</p>
    </section>
  </main>
</body>
</html>

What Does This HTML Do?

  • The link element connects the page to styles.css.
  • The main element contains the single-page demo.
  • The patterned-section class gives the stylesheet one precise target for the background.
  • Save index.html.
  • Drag index.html from your code editor's file sidebar into a Google Chrome window.

You should see the eyebrow text above a large heading. The two supporting paragraphs appear underneath.

Page Not Opening?

Confirm that the file is named index.html. Check that the name does not end with an extra text-file extension.

Ask for help if Chrome displays a blank page. Help me check why my local index.html page is blank in Google Chrome.

✔️ Awesome, I've got everything!

Your HTML file is saved. The heading with its supporting text now renders in Google Chrome.

ⓧ I'd like to double check the full code

Your complete HTML file should match this reference.

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Patterned Section</title>
  <!-- Load the page styles from the adjacent CSS file. -->
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <main>
    <!-- Hold the demo content over the repeating tile pattern. -->
    <section class="patterned-section">
      <p>DESIGN SYSTEMS</p>
      <h1>A pattern should finish as cleanly as it starts.</h1>
      <p>Each tile creates a clear visual rhythm across the section.</p>
      <p>Extra copy changes the amount of vertical space the section needs.</p>
    </section>
  </main>
</body>
</html>
Add base page styles

Base styles separate the demo section from the browser window. Centering the page also makes the section's bottom edge easier to inspect.

  • Add styles.css beside index.html with the following contents:
/* Keep element dimensions predictable across the page. */
* {
  box-sizing: border-box;
}

/* Center the demo against a neutral page background. */
body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 48px;
  background: #f1f5f9;
  color: #0f172a;
  font-family: Arial, sans-serif;
}

What Do These Styles Do?

  • The universal selector makes padding count inside each element's declared dimensions.
  • The grid layout centers the page content inside the browser window.
  • The neutral background creates contrast around the patterned section.
  • Save styles.css.
  • Refresh the page in Google Chrome.

You should see the content centered against a light gray page. This confirms that index.html is loading styles.css.

Styles Not Loading?

Confirm that styles.css sits beside index.html in the same file location. Check that the stylesheet link uses the exact file name.

Ask for help if the page still has a white background. Help me find why styles.css is not loading beside index.html.

Add the repeating SVG tile

A data URL stores the tile directly inside the stylesheet. The browser repeats that image across the section at a fixed size.

  • Append the following selector below the existing code in styles.css.
/* Repeat one SVG tile across a content-driven section. */
.patterned-section {
  width: min(760px, 100%);
  height: auto;
  padding: 58px 64px 73px;
  background-color: #ffffff;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'%3E%3Cpath d='M 96 0 L 0 0 0 96' fill='none' stroke='%23cbd5e1' stroke-width='2'/%3E%3Ccircle cx='0' cy='0' r='4' fill='%2394a3b8'/%3E%3C/svg%3E");
  background-repeat: repeat;
  background-size: 96px 96px;
  border: 1px solid #cbd5e1;
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.16);
  line-height: 1.6;
}

How Does the Pattern Work?

  • The background-image value contains a small grid tile as encoded markup.
  • The background-repeat property fills the section with copies of that tile.
  • The background-size property gives every copy the same fixed dimensions.
  • The height value leaves the section's final height under the control of its content.
  • Save styles.css.
  • Predict whether the section's bottom edge will meet a complete tile boundary.
  • Refresh the page in Google Chrome.

You should see the grid continue across the white section. Its bottom edge cuts through the final row instead of ending after a complete tile.

Your baseline is working. The visible partial row gives you a precise layout problem to solve.

Pattern Not Visible?

Confirm that the entire background-image value was pasted into the .patterned-section selector. Check that the selector matches the class in index.html.

Ask for help if the section stays plain white. Help me debug why the repeating SVG background is missing from my patterned section.

✔️ Awesome, I've got everything!

Your complete stylesheet is saved. The section now shows a repeating grid with a partial tile row at the bottom.

ⓧ I'd like to double check the full code

Your complete stylesheet should match this reference.

/* Keep element dimensions predictable across the page. */
* {
  box-sizing: border-box;
}

/* Center the demo against a neutral page background. */
body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 48px;
  background: #f1f5f9;
  color: #0f172a;
  font-family: Arial, sans-serif;
}

/* Repeat one SVG tile across a content-driven section. */
.patterned-section {
  width: min(760px, 100%);
  height: auto;
  padding: 58px 64px 73px;
  background-color: #ffffff;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'%3E%3Cpath d='M 96 0 L 0 0 0 96' fill='none' stroke='%23cbd5e1' stroke-width='2'/%3E%3Ccircle cx='0' cy='0' r='4' fill='%2394a3b8'/%3E%3C/svg%3E");
  background-repeat: repeat;
  background-size: 96px 96px;
  border: 1px solid #cbd5e1;
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.16);
  line-height: 1.6;
}

The patterned section now exposes the exact visual flaw you need. Next, you will define the tile dimensions as reusable CSS variables so every layout calculation follows the same grid.

Define the Tile Size

The patterned section now makes the cutoff problem visible. Its repeating SVG background can finish halfway through a tile.

Later calculations need one shared tile measurement. This step stores that measurement in CSS custom properties for background-size to reuse.

In this step, get ready to:
  • Define reusable dimensions for each SVG tile.
  • Connect background-size to the shared dimensions.
  • Confirm the applied sizing in Google Chrome.
Define reusable tile dimensions

The two custom properties make the SVG tile dimensions reusable. The width is 52px while the height is 44px.

  • Find the CSS rule in styles.css that contains the existing background-image declaration.
  • Add the sizing declarations inside that rule directly above background-image by pasting this code:
  /* This must match the size of the pattern image. */
  --tile-width: 52px;
  --tile-height: 44px;
  background-size: var(--tile-width) var(--tile-height);

What Do These Values Control?

  • The --tile-width property stores the horizontal size of one repeat.
  • The --tile-height property stores the vertical size of one repeat.
  • The background-size declaration reads both properties so every repeat follows the chosen measurement.
  • Save styles.css.
  • Refresh the patterned page in Chrome.

You should see each SVG repeat render at 52px wide by 44px tall. The section can still finish partway through a tile because its height remains content-driven.

Pattern Size Has Not Changed?

Confirm that the new declarations sit inside the CSS rule that already holds background-image. CSS ignores declarations placed outside a rule's braces.

Compare the custom property values with the tile artwork's proportions if the pattern looks stretched. A mismatched ratio distorts the SVG.

Ask for help checking why the sizing declarations are not applying.

✔️ My Tile Sizing Matches

Great. Your tile measurements now have one source of truth in styles.css.

ⓧ I'd Like to Double Check the Code

  • Compare the sizing declarations inside your existing patterned-section rule with this reference:
  /* This must match the size of the pattern image. */
  --tile-width: 52px;
  --tile-height: 44px;
  background-size: var(--tile-width) var(--tile-height);

What Should Match?

Your existing background-image stays in the same rule. These declarations add reusable dimensions for the repeating tile.

Verify the applied tile size

Chrome DevTools shows which CSS declarations apply to the selected section. This gives you a direct check that Chrome reads both custom properties.

Before you inspect the section, do you expect Chrome to show literal pixel values or variable references in the applied sizing rule?

  • Right-click the patterned section in Chrome.
  • Select Inspect from the menu.
  • Select Styles in the Elements panel.
  • Find the CSS rule that contains background-image.

You should see --tile-width: 52px plus --tile-height: 44px. The background-size declaration should show var(--tile-width) var(--tile-height).

The rendered pattern now follows the exact dimensions you chose. Its final row can remain partial because this step leaves the section at its normal content-driven height.

Can't Find the Sizing Rule?

Inspect the patterned section itself so the Styles panel shows its applied CSS. Selecting a child heading or paragraph can show a different set of rules.

Confirm that styles.css is saved if the new declarations are missing. Refresh Chrome after saving the file.

Get help locating the applied rule in Chrome DevTools.

That key foundation is in place: every repeat now uses the same dimensions. Next, you'll align the section's spacing to the tile height.

Snap the Section Padding

The tile dimensions now live in CSS custom properties. Your background repeats at the exact dimensions you chose.

Ordinary padding can still place the section content between tile rows. This step uses round() to align that spacing with the pattern.

The section height stays content-driven. Its bottom edge can still finish partway through a tile.

In this step, get ready to:
  • Connect the vertical padding to the tile height.
  • Round the padding upward to a whole tile.
  • Confirm the content begins on a tile boundary in Google Chrome.
Understand upward rounding

The round() function takes a preferred length plus a rounding interval. The up strategy chooses the smallest interval multiple that can contain the preferred length.

Why use the tile height?

The background repeats every var(--tile-height). Using that same measurement for padding keeps the spacing aligned with the pattern.

The preferred padding starts at 1rem. Upward rounding expands it to the next whole multiple of the tile height.

Round the vertical padding
  • In styles.css, find the patterned section rule containing --tile-width and --tile-height.
  • Locate the background-size declaration inside that rule.
  • Add the rounded padding declaration below background-size by entering this line:
padding-block: round(up, 1rem, var(--tile-height));

What does this code do?

  • The padding-block property controls the section's top and bottom padding.
  • The 1rem value supplies the preferred amount of spacing.
  • The up strategy rounds that spacing upward.
  • The var(--tile-height) value makes each rounding interval equal to one background tile.

Before you refresh, decide which result you expect: text between tile rows or text on a tile boundary.

  • Save styles.css.
  • Return to the patterned page from earlier in Google Chrome.
  • Refresh the page.
  • Compare the start of the content with the nearest horizontal tile boundary.

You should see the content begin after padding that occupies a whole tile-height interval. The text now starts on a tile boundary.

Good progress. Your content is now anchored to the pattern grid.

The bottom edge can still cut through a tile because the section height remains auto.

Padding Still Looks Unchanged?

Confirm the padding-block declaration sits inside the same section rule as background-size. A declaration outside the rule braces cannot affect the section.

Check that var(--tile-height) matches the existing custom property exactly. A spelling mismatch prevents the browser from calculating the padding.

Confirm you refreshed the page in Google Chrome. Other browsers may ignore this newer rounding behavior.

Help me debug why the rounded section padding is not aligning with my background tiles.

Your content now respects the tile grid. Next up, you will make the section's bottom edge finish on a whole tile.

Round the Section Height Up

Your rounded padding now places the content on a tile boundary. The section still uses its natural content height.

The CSS background can therefore stop midway through the final tile. In this step, calc-size() reads the natural height so round() can move the bottom edge up to the next tile boundary.

In this step, get ready to:
  • Measure the section's content-driven height with calc-size().
  • Round the measured height up to a tile boundary.
  • Confirm the last row of tiles is complete.
Inspect the unfinished bottom edge

Padding controls where the content begins inside the section. Height controls where the repeating background ends.

  • Switch back to the patterned page in Google Chrome.
  • Refresh the page.
  • Scroll to the bottom edge of the patterned section.

You should still see the background finish partway through a tile. This confirms that rounded padding has not changed the section's content-driven height.

Add the rounded height rule

A feature query lets the browser apply the rounded height only when it understands calc-size(). The existing auto height remains the fallback outside the support block.

  • In styles.css, place your cursor after the closing brace of the existing .section rule.
  • Add the feature query by pasting this code:
@supports (height: calc-size(auto, size)) {
  .section {
    /* Finish the section on a complete background tile. */
    height: calc-size(auto, round(up, size, var(--tile-height)));
  }
}

What does this rule do?

  • The @supports condition checks whether the browser accepts calc-size() as a height value.
  • The auto basis captures the height required by the section's content.
  • The size keyword represents that measured height inside the calculation.
  • The up strategy moves the result to the next multiple of --tile-height.
  • Save styles.css.

Before you refresh, where do you expect the section's bottom edge to land now?

  • Refresh the patterned page in Google Chrome.
  • Inspect the final row of background tiles.

You should see a complete final row of tiles. The section grows to the next whole multiple of --tile-height.

You have closed the visible gap. Your patterned section now finishes cleanly after its content.

Still seeing a cut-off tile?

Confirm that the feature query sits outside the existing .section rule. Check that its inner selector is also .section.

Make sure the height calculation uses the same --tile-height variable as the background pattern. A different interval makes the section edge miss the tile boundary.

If the bottom edge remains unchanged in Google Chrome, help me debug my calc-size() feature query.

✔️ Awesome, I've got everything!

Great. Your saved stylesheet now rounds the section height up to a complete tile.

ⓧ I'd like to double check the full code

Compare the feature query at the end of styles.css with this complete rule.

@supports (height: calc-size(auto, size)) {
  .section {
    /* Finish the section on a complete background tile. */
    height: calc-size(auto, round(up, size, var(--tile-height)));
  }
}

Your section now expands to finish on a whole tile. Next, you will swap round(up) for round(down) to compare how each strategy affects the content spacing.

Compare Rounding Down

Your CSS now rounds the patterned section upward to the next tile boundary. The final row of the pattern finishes cleanly.

Rounding down chooses the previous tile boundary. This comparison reveals what that smaller height does to the content spacing.

In this step, get ready to:
  • Change the supported section height to round down.
  • Compare the new bottom edge in Google Chrome.
Change the height rounding direction

The round() function uses a strategy to choose a nearby tile boundary. You will change only the height strategy so the upward-rounded padding stays in place.

  • In styles.css, find the @supports rule for calc-size().
  • Locate this current height declaration:
height: calc-size(auto, round(up, size, var(--tile-height)))

What Are You Comparing?

The up strategy pushes the intrinsic size to the next multiple of the tile height. That extra space protects the bottom edge of the content.

  • Replace up with down so the declaration looks like this:
height: calc-size(auto, round(down, size, var(--tile-height)))

What Changes Here?

The down strategy selects the previous multiple of var(--tile-height). The tile size stays unchanged.

Padding still rounds upward. This isolates the effect of changing the section height.

  • Save styles.css.

✔️ Awesome, I've got everything!

Great. styles.css now rounds the supported height down while preserving the tile size and upward-rounded padding.

ⓧ I'd like to double check the full code

The end state has these parts.

  • The index.html file still contains the patterned content section with its headings and paragraphs.
  • The base page styles remain unchanged.
  • The repeating SVG background remains unchanged.
  • The tile variables still control background-size.
  • The section padding still rounds upward to the tile height.
  • The normal auto-height fallback remains outside @supports.

Inside @supports, the height declaration is:

height: calc-size(auto, round(down, size, var(--tile-height)))

This declaration is the only temporary code change in the comparison.

Compare the lower tile boundary

Supporting browsers now use the smaller whole-tile height. Google Chrome lets you see the difference immediately.

Before you refresh, make a prediction about whether the section will gain or lose vertical space.

  • Switch back to the patterned-section page in Google Chrome.
  • Refresh the page.

You should see the section shrink to the previous tile boundary. The background still ends on a complete tile.

  • Compare the bottom spacing with the top spacing.

You have made the tradeoff visible. The final paragraph now sits closer to the bottom edge.

Why Does Rounding Down Feel Cramped?

The round(down, ...) strategy selects the smaller whole-tile height. The same content now has less vertical room.

The reduced height leaves less space below the final paragraph. Upward rounding provides safer breathing room for changing content.

Section Did Not Shrink?

  • Confirm the page is running in Google Chrome. Browsers without support for calc-size() retain the normal auto height.
  • Check that round(down, size, var(--tile-height)) remains inside the existing @supports rule.
  • Save styles.css before refreshing the page again.

help me find why my patterned section does not shrink after changing round up to round down.

The downward version is ready for a tougher test. Next, you will vary the content in Chrome before comparing the fallback in another browser.

Test the Snapping Fallback

Your last comparison showed why downward rounding can squeeze content against the bottom edge. The reusable CSS snippet needs upward rounding restored before its final test.

In this step, you will change the supported height back to upward snapping. You will test changing content in Google Chrome. You will also confirm that unsupported browsers keep the normal auto-height fallback.

In this step, get ready to:
  • Restore upward height rounding inside the existing feature query.
  • Add and remove paragraphs to watch the section snap between tile boundaries.
  • Compare the enhanced layout with the fallback in a non-Chrome browser.
Restore upward height snapping

The existing @supports rule limits the enhanced height calculation to browsers that understand calc-size(). Restoring upward rounding gives the content enough space before the height snaps to a tile boundary.

  • In styles.css, find the height declaration inside the existing @supports rule.
  • Replace that declaration with the following line:
height: calc-size(auto, round(up, size, var(--tile-height)));

Why Restore Upward Rounding?

The up strategy selects the next tile-height multiple that can contain the section. This keeps the final tile row complete without squeezing the content.

The declaration stays inside @supports. Browsers without calc-size() continue using the base section height.

  • Save styles.css.
  • Switch back to the patterned page in Google Chrome.
  • Refresh the page.

You should see more space below the content than you saw with downward rounding. The final row of background tiles should finish cleanly at the bottom edge.

Still Seeing the Smaller Height?

  • Confirm that the height declaration now contains round(up, size, var(--tile-height)).
  • Check that you edited the declaration inside the existing @supports rule.
  • Refresh Google Chrome after saving styles.css.

Help me check why upward height snapping is not appearing in Chrome.

Test changing content in Chrome

A reusable section must respond to content changes without exposing a partial tile. Adding one paragraph at a time lets you see the height wait for a boundary before jumping to the next whole tile.

  • In index.html, select one complete paragraph element inside the patterned section.
  • Duplicate the selected paragraph.
  • Save index.html.
  • Before the refresh, predict whether the bottom edge moves by part of a tile or by a whole tile.
  • Refresh the page in Google Chrome.
  • Repeat this three-step edit cycle until the section grows.

You will see the bottom edge jump to a new tile boundary once the extra content needs more room. The section still ends after a complete row of tiles.

  • Return to index.html.
  • Remove one of the duplicated paragraphs.
  • Save index.html.
  • Before the refresh, predict whether the section shrinks by part of a tile or by a whole tile.
  • Refresh the page in Google Chrome.
  • Repeat this removal cycle until you reach the original paragraph count.

The section shrinks only when its content fits within the previous tile boundary. Its bottom edge continues to finish after a whole tile.

Section Height Not Changing?

  • Confirm that the duplicated paragraph sits inside the patterned section.
  • Add another paragraph if the current content still fits within the same tile boundary.
  • Check that background-size still uses var(--tile-width) var(--tile-height).

Help me find why adding paragraphs does not make my patterned section snap to a new tile boundary.

Confirm the non-Chrome fallback

A CSS feature query protects the page when a browser does not support the enhanced height declaration. A non-Chrome browser such as Safari or Firefox ignores the unsupported rule and keeps the section at its normal auto height.

  • Press Cmd+Space on macOS or the Windows key on Windows to open system search.
  • Type Safari on macOS or Firefox on Windows.
  • Press Enter to open the browser.

The second browser gives you a direct comparison against the enhanced Chrome result. Both browsers use the same saved files.

  • In Google Chrome, copy the current page address.
  • Paste the copied address into the address bar in Safari or Firefox.
  • Before loading the page, predict whether the section uses snapped height or normal auto height.
  • Press Enter to load the page.

In Safari or Firefox, the section follows its normal auto height. Its background can finish partway through a tile because the supported-browser height rule does not apply.

Switch back to Chrome to compare the same content. You should see the section end on a complete tile boundary there.

Why Keep the Fallback?

At the time of writing, the source records calc-size() support as Chrome-only. The base auto height keeps all content visible in browsers that do not apply the enhanced rule.

The fallback preserves a usable section everywhere. Supporting browsers add the clean tile alignment.

✔️ Awesome, I've got everything!

Great. Save both files with the upward-snapping declaration restored.

ⓧ I'd like to double check the full code

Compare your reusable snippet against these final checkpoints.

  • Your index.html contains the reusable patterned section with headings and paragraphs.
  • Your styles.css contains the repeating SVG background image.
  • The section defines --tile-width and --tile-height.
  • The background-size declaration uses var(--tile-width) var(--tile-height).
  • The section padding rounds upward to var(--tile-height).
  • The base section retains normal auto height as its fallback.
  • The existing @supports rule contains this final declaration:
height: calc-size(auto, round(up, size, var(--tile-height)));

Solid work. Your reusable section now finishes on complete tiles in Chrome. Unsupported browsers keep the normal auto-height layout.

Secret mission

Stress-Test the Pattern

Push your patterned section through long content. Test it again at a narrow viewport. Compare the snapped Chrome result with the normal-height fallback before restoring the original snippet.

Clean Up Your Resources

Clean Up Your Resources

Your HTML page plus its CSS stylesheet run entirely locally. There are no ongoing costs.

Choose whether to keep the reusable snippet or delete it entirely. The pause option closes your preview while preserving both files.

Resources you used:

  • The index.html page containing your reusable patterned section plus its test paragraphs.
  • The styles.css stylesheet containing the repeating SVG tile pattern plus its browser fallback.

Keep everything running

No action needed. This option preserves the finished snippet for future patterned sections.

  • Keep index.html beside styles.css so the page continues to load its styles.
  • Keep the auto-height fallback in styles.css so unsupported browsers can display the section normally.
  • Reuse the patterned section whenever a repeating background needs to finish on a complete tile.

Pause - I'll come back to this later

This local project has no server or background process to stop. Pausing means closing the preview while keeping both files.

  • Close the browser tab displaying index.html.
  • Keep index.html in the same folder as styles.css.
  • Return to the page later when you want to test different amounts of content.

Your reusable snippet remains on your machine without using memory or creating ongoing costs.

Delete - I don't want to use this again

Deleting these two files is permanent. The Keep tab remains the safe choice if you may reuse the snippet.

  • Return to the file list in the text editor from earlier.
  • Delete index.html from the file list.
  • Delete styles.css from the file list.
  • Check the file list after deletion.

You should no longer see index.html or styles.css in the file list.

Nice Work!

Nice Work!

You did it! Your reusable patterned section now grows in complete tile steps without losing its normal auto-height fallback.

What you've learned:

  • Built a reusable patterned section with an SVG background that repeats at exact dimensions from CSS variables.
  • Used round(up) to create tile-aligned padding that starts content on a whole-tile boundary.
  • Added tile-by-tile height snapping with calc-size(). Verified the cross-browser fallback by changing paragraph counts in Chrome and a non-Chrome browser.
  • Completed the optional Secret Mission to extend the reusable pattern technique with an additional challenge.

Ready to quiz yourself?