Resize a Page Without Media Queries
Build a responsive CSS demo with progress() and test its fallback behaviour.
Introduction
30 Second Summary
Web pages are viewed at every width between a narrow phone and a wide monitor. Fixed jumps can make text feel awkward as the available space changes.
In this project, you will build a single page whose heading scales smoothly with the browser width using CSS progress(). You will reuse the mapped value for a progress bar plus a colour shift before proving that a fallback keeps the page readable without support.
What You'll Build
You will drag the browser edge to watch the heading, progress bar, and colour respond to the same changing width.
By the end of this project, you'll have:
- A smoothly scaling heading that responds continuously as you resize the browser window.
- A synchronised progress bar driven by the same mapped viewport value.
- A browser fallback demo that keeps the page readable when progress() is unsupported.
- Secret Mission: An optional challenge to push your responsive styling skills further.
What do I need?
You only need a text editor plus a current browser that supports progress(). Access to a browser without support helps you prove that the fallback works.
Before We Start
A browser can silently ignore a new CSS feature. This setup helps you separate a coding mistake from a browser support gap.
In this step, you’ll prepare a code editor plus contrasting browser environments. You’ll also confirm that screen recording works.
In this step, get ready to:
- Set up a code editor for your page.
- Prepare a browser pair for support testing.
- Prove your screen recorder can capture a resize.
Set up your code editor
An HTML file is plain text that your browser reads. Visual Studio Code gives you a dedicated place to write that text without adding formatting.
- Press Cmd+Space on macOS or the Windows key on Windows.
- Type Visual Studio Code.
- Press Enter.
✔️ Visual Studio Code opens
Your editor is available. You can continue with its welcome window open.
ⓧ Visual Studio Code is not installed
Visual Studio Code uses a different installer for each operating system. Choose your platform below.
macOS
- Visit the official Visual Studio Code download page.
- Select Universal under .dmg.
- Open the downloaded .dmg file.
- Drag Visual Studio Code to Applications.
- Repeat the operating system search above.
Windows
- Visit the official Visual Studio Code download page.
- Select the User Installer for your processor.
- Run the downloaded installer.
- Follow the installation prompts.
- Repeat the operating system search above.
Good. Your editor is ready for the single file you’ll build in this project.
Visual Studio Code Won’t Open?
Run the installer again if the application is missing from search. On macOS, confirm that Visual Studio Code is inside the Applications folder.
On Windows, confirm that the installer completed before repeating the search.
Help me get Visual Studio Code installed and opening on my computer.
Prepare two browser paths
The progress() function reached browsers at different times. Google Chrome has supported it since version 138.
The current Firefox ESR branch predates Firefox support for this function. It gives you a maintained browser for testing the fallback path.
Why Two Browsers?
A supporting browser applies a valid progress() declaration. A browser without support ignores that declaration.
Testing both paths proves that your responsive effect works without sacrificing a readable fallback.
- Find Google Chrome with your operating system’s search.
- Open Google Chrome if it appears in the results.
- Click More in the top-right corner.
- Select Help.
- Select About Google Chrome.
- Choose the tab that matches what you see.
✔️ I have a supported Chrome version
Your version starts with 138 or a larger number. Chrome can render the CSS function used in this project.
ⓧ I see an older version
Chrome checks for updates on the About page. Applying the update gives you the browser support this project needs.
- Wait for Chrome to finish checking for an update.
- Select Relaunch when it appears.
- Return to About Google Chrome.
- Confirm that the version starts with 138 or a larger number.
ⓧ Chrome is not installed
- Visit the official Google Chrome download page.
- Download the installer for your operating system.
- Open the downloaded installer.
- Follow the installation instructions.
- Open Google Chrome with your operating system’s search.
- Check the version from About Google Chrome.
- Find Firefox ESR with your operating system’s search.
- Choose the tab that matches what you see.
✔️ Firefox ESR opens
Your fallback test browser is available. Keep it installed beside Chrome for the comparison later.
ⓧ Firefox ESR is not installed
- Visit the official Firefox enterprise download page.
- Select the Firefox Extended Support Release download for your operating system.
- Open the downloaded installer.
- Follow the installation instructions.
- Open Firefox ESR with your operating system’s search.
That browser pair is ready. Chrome gives you the supported result while Firefox ESR gives you the fallback result.
Having Trouble With the Browsers?
If Chrome stays below the required version, return to its official download page and reinstall the current release. A managed computer may require help from its administrator.
If Firefox ESR does not appear after installation, repeat the operating system search using Firefox.
Help me prepare Chrome and Firefox ESR for CSS browser support testing.
Verify screen recording
The final demo depends on motion across several window widths. A short test now confirms that your operating system can capture that motion.
- Switch back to the Google Chrome window from earlier.
Before you test the recorder, do you expect it to capture the browser while its window changes size?
macOS
The built-in Screenshot app can record a selected portion of your screen.
- Press Shift+Command+5.
- Select Record Selected Portion.
- Drag the recording frame around the Chrome window.
- Click Record.
- Resize the Chrome window slowly.
- Click the Stop button in the menu bar.
- Play the saved recording.
Windows
The built-in Snipping Tool can record a selected area of your screen.
- Press Windows+Shift+R.
- Drag the recording frame around the Chrome window.
- Select Start.
- Resize the Chrome window slowly.
- Select Stop.
- Play the recording in Snipping Tool.
You should see the Chrome window changing width in the recording. That confirms your capture path is ready for the final resize demo.
Recorder Test Didn’t Work?
Your operating system may request permission to record the screen. Allow the recorder before repeating the test.
On Windows, open Snipping Tool from search if the keyboard shortcut does not show the recording overlay. Select Record inside the app.
Help me get my screen recorder working for a browser resize demo.
Your editor, browser pair, and recorder are ready. Next, you’ll create the plain page that gives your resize test a baseline.
Create the Plain Page
Smooth scaling needs a baseline you can trust. A fixed heading reveals what the page does before progress() controls its size.
In this step, you will create one standalone HTML file with a plain heading. Its CSS keeps the heading at a fixed size.
In this step, get ready to:
- Create index.html as a standalone page.
- Display a heading with a fixed font size.
- Resize the supporting browser to check the baseline behavior.
Create the baseline page
A standalone page keeps this experiment in one file. The fixed heading gives every later resize test a clear starting point.
- In your code editor, create a new file named index.html.
- Build the plain page by pasting this code into index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- Keep the document width aligned with the visible browser width. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Resize a Page Without a Media Query</title>
<style>
/* Keep the heading fixed for the baseline resize test. */
h1 {
font-size: 3rem;
}
</style>
</head>
<body>
<!-- Give the resize experiment one clear subject. -->
<h1>Resize a Page Without a Media Query</h1>
</body>
</html>
What Does This Page Do?
- The viewport setting keeps the document width aligned with the visible browser width.
- The h1 rule fixes the heading at 3rem. This becomes your baseline for later comparisons.
- The heading is the page's only visible content. This makes its resize behavior easy to judge.
- Save index.html.
- Locate index.html in your computer's file browser.
- Drag index.html onto the supporting browser's window.
You will see the heading “Resize a Page Without a Media Query” on a plain page. That visible heading confirms your standalone file loads correctly.
Seeing Raw Code or a Blank Page?
Confirm the file is named exactly index.html. Remove any extra .txt extension added by your editor.
If the page is blank, compare your opening tags with their closing tags in the full-file check below.
Help me find why my index.html page is blank or showing raw HTML.
✔️ Awesome, I've got everything!
Your plain heading is live in the supporting browser. Double check that index.html is saved before continuing.
ⓧ I'd like to double check the full code
Compare your complete index.html file with this version.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- Keep the document width aligned with the visible browser width. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Resize a Page Without a Media Query</title>
<style>
/* Keep the heading fixed for the baseline resize test. */
h1 {
font-size: 3rem;
}
</style>
</head>
<body>
<!-- Give the resize experiment one clear subject. -->
<h1>Resize a Page Without a Media Query</h1>
</body>
</html>
Check the plain resize behavior
The fixed font size acts as a control for your experiment. Resizing changes the available space without changing the size of the letters.
Before you resize the window, do you expect the letters themselves to grow or shrink?
- Return to the supporting browser window showing your page.
- Drag the browser window's side edge inward until the page becomes narrow.
- Drag the same edge outward until the page becomes wide again.
You will see the available space change while the heading stays at 3rem. The text can wrap when the window becomes too narrow.
Does the Heading Change Size?
Confirm the browser zoom remains at its default level during the test. Browser zoom changes the apparent letter size independently of the window width.
Help me check why my fixed 3rem heading appears to resize with the browser window.
Your plain page now gives you a working resize baseline. Next up, you will replace the fixed size with a progress() expression.
Scale the Heading With Progress
Your plain heading gives you a baseline while the browser window changes. Its fixed font size stays the same throughout that resize.
Now you will map the viewport width onto a font-size range with CSS progress(). The heading will grow smoothly as you widen the supporting browser.
In this step, get ready to:
- Define the viewport range.
- Map the range onto the heading size.
- Verify the heading scales smoothly.
Choose the scaling range
The progress() function compares the current viewport width with a defined range. Its result stays between 0 and 1.
- Use 320px as the narrow viewport value.
- Use 1200px as the wide viewport value.
- Use 16px as the minimum heading size.
- Use 64px as the maximum heading size.
How does the range work?
At a viewport width of 320px or less, progress() returns 0. At 1200px or more, it returns 1.
Widths between those endpoints produce a decimal between 0 and 1. That decimal becomes the dial controlling the heading size.
Apply the progress expression
- Return to index.html in the code editor from earlier.
- Find the font-size declaration inside the CSS rule that styles the heading.
- Replace that declaration with the code below:
/* Grow the heading by up to 48px across the viewport range */
font-size: calc(16px + progress(100vw, 320px, 1200px) * 48px);
What does this code do?
- The 100vw value represents the current viewport width.
- The progress(100vw, 320px, 1200px) expression maps that width to a number between 0 and 1.
- The * 48px calculation converts the result into up to 48px of growth.
- The starting 16px sets the minimum size. The complete calculation produces a range from 16px to 64px.
- Save index.html.
- Switch back to the supporting browser from earlier.
- Refresh the page.
Before you resize the window, do you expect a small width change to produce a jump or a gradual size change?
- Drag one edge of the browser window slightly inward.
You will see the heading shrink as the viewport narrows. Your first fluid heading is now responding to the browser width.
Heading stays the same size?
Check that the new font-size declaration sits inside the CSS rule that styles your heading. A declaration outside that rule cannot affect the heading.
Confirm that the progress() arguments use the current viewport value first. The narrow width comes second. The wide width comes third.
Make sure you are testing in the supporting browser from earlier.
Help me troubleshoot the heading scaling in index.html.
Test the full scaling range
Before the full resize, where do you expect the heading to stop shrinking? Where do you expect it to stop growing?
- Drag the supporting browser to a narrow window near 320px wide.
- Drag the supporting browser to a wide window near 1200px wide.
- Drag the browser edge slowly between those two widths.
Near 320px, you will see the heading settle near 16px. Near 1200px, it settles near 64px.
Between the endpoints, you will see continuous scaling with no sudden jump. That is your first fluid CSS result: the heading now tracks the viewport without a breakpoint.
✔️ Awesome, I've got everything!
Great. Double check that you saved index.html after testing the full resize.
ⓧ I'd like to double check the full code
Compare the heading declaration in index.html with this completed version.
/* Grow the heading by up to 48px across the viewport range */
font-size: calc(16px + progress(100vw, 320px, 1200px) * 48px);
Your heading now scales across the full viewport range. Next, you will add a readable font-size fallback for browsers that do not support the new function.
Add a Fallback Font Size
Your heading now scales smoothly in the supporting browser. That result proves the mapped viewport value works.
A browser that cannot parse progress() ignores that declaration. In this step, you will place a fixed CSS font size before it so every browser keeps a readable heading.
In this step, get ready to:
- Reveal the current unsupported behavior in your second browser.
- Add a fixed font-size fallback before the mapped declaration.
- Verify the fallback path in one browser. Verify smooth scaling in the other browser.
Test the unsupported browser
A browser applies only the declarations it understands. Your second browser exposes the support gap in the current page.
Before you compare the page, do you think the heading will still track the window width in the second browser?
- Return to the supporting browser from earlier.
- Click its address bar.
- Copy the current local address by pressing Cmd+C (macOS) or Ctrl+C (Windows).
- Switch to the second browser from earlier.
- Click its address bar.
- Paste the local address by pressing Cmd+V (macOS) or Ctrl+V (Windows).
- Press Enter.
- Drag one edge of the browser window slowly between narrow and wide widths.
You will see the page load. The heading no longer follows the mapped range as you resize.
This shortfall is expected. It gives you a baseline for the fallback test.
Heading Still Scales?
- Repeat the check in the browser you identified earlier as unsupported.
- Confirm both browser windows show the same local page address.
If the behavior is still unclear, help me confirm whether my second browser supports CSS progress().
Add the fixed fallback
A fallback relies on declaration order. The browser keeps the first valid font-size when it cannot use the declaration below it.
- Switch back to index.html in the code editor from earlier.
- Find the progress-based font-size declaration inside the heading's style rule.
- Identify the smaller font-size endpoint in its progress() expression.
- Record that endpoint here: your smaller font-size endpoint.
- Insert a fixed font-size declaration directly above the existing line using your smaller font-size endpoint as its value.
- Save index.html.
Why Does the Order Matter?
The supporting browser accepts both declarations. The later progress-based value wins in the cascade.
The unsupported browser rejects the later declaration. The earlier fixed value remains active.
Before you reload the second browser, do you expect the heading to scale or stay fixed?
- Return to the unsupported browser.
- Reload the page.
- Drag one edge of the browser window slowly between narrow and wide widths.
That support gap is closed: the unsupported browser keeps your chosen fixed heading size across the resize.
Fallback Not Showing?
- Confirm the fixed font-size declaration appears directly above the progress-based declaration.
- Confirm the fixed value uses the same unit as the copied endpoint.
- Save index.html before reloading the page.
If the browser still uses an unexpected size, help me troubleshoot my CSS fallback declaration order.
Verify both browser paths
A fallback is proven only when each browser takes its own path. The final comparison checks both behaviors without changing the file again.
Before the final comparison, which browser should resize smoothly and which browser should hold a fixed size?
- Return to the supporting browser.
- Reload the page.
- Drag one edge of the browser window slowly between narrow and wide widths.
You will see the heading scale smoothly between the selected font-size limits.
- Return to the unsupported browser.
- Reload the page.
- Drag one edge of the browser window slowly between narrow and wide widths.
You will see the heading remain at the fixed fallback size. Both browser paths now work.
✔️ Awesome, I've got everything!
Your fixed fallback appears before the mapped declaration in index.html.
ⓧ I'd like to double check the full code
- Find the heading's style rule in index.html.
- Confirm a fixed font-size declaration appears first.
- Confirm the progress-based font-size declaration appears immediately after the fallback.
- Confirm the progress() expression still uses your original viewport range.
- Confirm the expression still uses your original font-size range.
Your heading now scales where supported while staying readable everywhere else. Next, you will drive a progress bar from the same mapped value.
Link the Progress Bar
Your fallback path is now proved. The supporting browser scales the heading smoothly while the other browser keeps the fixed size.
A single moving heading demonstrates fluid type. Reusing the same progress() mapping for a bar shows how one resize value can coordinate multiple CSS properties.
In this step, get ready to:
- Add a progress-bar track with a nested fill element.
- Drive the fill width from the heading's viewport mapping.
- Resize the page to verify that the heading and bar move together.
Add the progress bar structure
The track provides a fixed frame for the progress bar. Its nested fill becomes the moving part in the next substep.
- Switch back to index.html in the code editor from earlier.
- Find the heading in the page body.
- Add a progress-bar track directly below the heading with one fill element nested inside it.
- Save index.html.
- Return to the supporting browser from earlier.
- Refresh the page.
- Use the browser's built-in element inspector to confirm that the track contains the fill.
You should see the track directly after the heading in the page structure. The fill should appear as the track's only nested element.
Track or Fill Missing?
Check that the new elements sit inside the page body. The track should come directly after the heading.
Check that the fill appears before the track's closing tag. This nesting lets the track contain the moving section.
Help me check the progress-bar structure in my HTML.
Make the track visible
The track stays the same size while the fill changes. A visible horizontal frame gives the moving fill a clear boundary.
- Switch back to index.html in your code editor.
- Add a rule for the progress-bar track inside the existing style section so it has a visible horizontal frame.
- Save index.html.
- Return to the supporting browser.
- Refresh the page.
You should see an empty horizontal track below the heading. Its size should remain fixed as you resize the browser.
Track Still Invisible?
Check that the track has a visible height. An empty element needs a defined size before the browser can draw its frame.
Check that the track rule targets the element you added below the heading.
Help me find why my progress-bar track is invisible.
Reuse the shared mapping
The fill rule matches the track's height. A contrasting colour exposes its movement.
Its width comes from the same viewport-based progress() call that drives the heading. Keeping all three arguments unchanged gives both properties one shared resize position.
- Find the viewport-based progress() call in the heading's style rule.
- Copy that exact call without changing its current value or range arguments.
- Add the complete fill rule described above inside the existing style section.
- Use the copied mapping to drive the fill's width.
- Save index.html.
Why Share One Mapping?
The progress() result represents the viewport's position within your selected range.
The heading turns that result into type size. The fill turns the same result into bar width.
✔️ Awesome, I've got everything!
Your progress-bar structure and shared mapping are saved in index.html.
ⓧ I'd like to double check the full code
Use these checks to compare the complete state of your page.
- Confirm the standalone index.html page still contains the heading.
- Confirm the progress-bar track appears directly below the heading.
- Confirm the fill element is nested inside the track.
- Confirm the heading keeps its fixed fallback font size before its progress()-based font size.
- Confirm the fill width uses the heading's exact viewport-based progress() mapping.
Before you test the page, do you expect the fill to stay fixed or follow the heading as the viewport changes?
- Return to the supporting browser.
- Refresh the page.
- Resize the window slowly from your selected minimum viewport width to your selected maximum viewport width.
You should see the heading grow smoothly. The fill should expand through the track at the same time.
- Resize the window slowly from your selected maximum viewport width back to your selected minimum viewport width.
You should see the heading shrink smoothly. The fill should contract through the same range.
Bar Not Moving with the Heading?
Compare the fill's progress() call against the heading's call. The viewport value plus both range boundaries must match.
If the bar moves in the opposite direction, compare the order of the minimum and maximum arguments.
Help me synchronize my heading and progress-bar fill.
That shared motion is working. Next, you'll map the same resize value onto colour so all three effects change together.
Shift the Color and Record
Your heading already reacts to one viewport-based value. The progress bar follows that same value.
This step adds a color shift to make the shared mapping visible. A recording captures all three responses.
An HTML comment preserves your fallback test result inside the page.
In this step, get ready to:
- Map a page color from the viewport-based progress value.
- Confirm all three visual effects stay synchronized during a resize.
- Capture the final resize in a screen recording.
Map the page color
The CSS progress() function produces a position between the lower viewport bound and the upper viewport bound. Reusing that position keeps separate visual properties synchronized.
- Switch back to index.html in the code editor from earlier.
- Find the progress-bar fill rule that uses progress() for its width.
- Copy the complete viewport-based progress() expression.
- Set the page's color property to interpolate between two visibly different colors with the copied expression.
- Save index.html.
Before you resize, do you expect the color to reach its endpoints at the same viewport bounds as the other effects?
- Return to the supporting browser from earlier.
- Resize the browser window slowly from narrow to wide.
You should see the heading scale throughout the resize. The progress-bar fill should grow over the same range.
The page color should shift at the same pace. That is one shared mapping coordinating three visible effects.
What does the shared mapping do?
- The existing progress() expression produces one position for the current viewport width.
- The heading converts that position into a font-size value.
- The bar converts that position into a fill width.
- The new color property converts that position into a color shift.
Color staying fixed?
Compare the copied progress() expression with the bar's expression character for character. Confirm that both use the same viewport bounds.
Check that the color interpolation uses the result of that expression. A fixed color value cannot respond to the resize.
Help me troubleshoot the color mapping in my responsive page.
Document the fallback result
An unsupported progress() declaration is ignored. The earlier fixed font-size declaration keeps the heading readable.
- Return to the browser without progress() support from earlier.
- Refresh index.html.
- Resize the browser window slowly from narrow to wide.
The page should remain readable. The heading should keep its fixed fallback size.
- Record the browser or browsers that showed the fallback here: browser or browsers that showed the fallback.
- Switch back to index.html in the code editor from earlier.
- Add an HTML comment near the top of the file that names browser or browsers that showed the fallback.
- State in the comment that the fixed fallback font size was shown there.
- Save index.html.
Good work. Your support result now stays attached to the demo instead of relying on memory.
Record the final demo
A slow resize shows whether the three effects truly share one input. One uninterrupted pass makes their timing easy to compare.
- Return to the supporting browser from earlier.
- Position the browser window so one resize edge stays visible in the capture area.
- Switch back to the screen recorder from earlier.
- Select the supporting browser window as the capture area.
- Begin the recording.
- Drag the visible browser edge slowly from narrow to wide.
- Stop the recording after the color reaches its final state.
- Save the recording as resize-progress-demo.mp4.
Before you play it back, do you expect all three effects to move throughout the same part of the resize?
- Play resize-progress-demo.mp4 from beginning to end.
You should see the heading scale throughout the resize. The progress-bar fill should track the same movement.
The color should shift at the same pace. You now have visible proof that one viewport mapping controls all three effects.
Recording hard to inspect?
Record another pass if the browser edge leaves the capture area. Move the edge more slowly so each change remains visible.
Check that the saved file ends with .mp4 before uploading it.
Help me improve my resize recording.
Secret mission
Prove the Fallback Side by Side
Turn your finished page into a side-by-side compatibility proof. Compare the smooth progress() behavior with the fixed fallback. Use your existing recording to explain both paths.
Clean Up Your Resources
Clean Up Your Resources
Everything in this project lives on your computer, so it creates no ongoing costs. Choose whether to keep your finished artifacts, pause the demo, or delete both files.
Resources you used:
- The index.html page containing the responsive heading, progress bar, mapped colour, fallback declaration, and browser support comment.
- The resize-progress-demo.mp4 recording showing the heading size, progress-bar width, and colour changing during a browser resize.
Keep everything running
No action is needed. Choose this option if you want to keep demonstrating the page or experimenting with its responsive values.
- Keep index.html so your fallback test remains documented inside the page.
- Keep resize-progress-demo.mp4 so you can show all three visual changes moving together.
Pause - I'll come back to this later
No background service or cloud resource remains active. Closing the local tools is enough to pause this project.
- Close the browser tabs displaying index.html.
- Close the screen-recording software if it is still running.
- Leave index.html in its current saved location.
- Leave resize-progress-demo.mp4 in its current saved location.
Delete - I don't want to use this again
Remove the two local artifacts if you want to start fresh. This permanently removes the page and its resize recording from their saved locations.
- Return to the code editor from earlier.
- Locate index.html in the file tree.
- Use the file tree's delete action to remove index.html.
- Use your operating system's file search to locate resize-progress-demo.mp4.
- Use the file manager's delete action to remove resize-progress-demo.mp4.
- Check the original saved locations for both filenames.
You should find neither project artifact in its original saved location.
Nice Work!
Nice Work!
You did it! Your single-file page now turns one viewport-based CSS mapping into a synchronized resize demo.
You learned how to:
- Created responsive type by mapping viewport width onto a range with progress().
- Built a shared visual mapping for the heading size, progress-bar fill, and page color. Captured the result in resize-progress-demo.mp4.
- Proved fallback behavior in a browser without support. Documented the tested browser inside index.html.
- Secret Mission: Took on an optional challenge to push your skills further.
Ready to quiz yourself?