Building a Fluid Layout

Lecture notes: fixed, fluid and responsive layouts, relative units, percentage sizes

1. Fixed, fluid and responsive layout

There are three main approaches to markup:

Approach Units Behavior
Fixed Pixels (px) Sizes are hard-coded. When the window shrinks, a horizontal scrollbar appears
Fluid Percentages (%) Elements resize proportionally together with the parent block, but stay in their places
Responsive % + media queries At a certain point elements change their arrangement (for example, two columns become one)
In practice, fluid and responsive layouts are always used together: within a certain range the “fluid” behavior works, and once too little space remains, a media query kicks in and the layout changes.

More than 60–80% of users of modern websites visit from mobile devices, so responsiveness is a mandatory requirement.

2. Width in percentages

Width in percentages is calculated from the width of the parent element.

/* Fixed layout */
.container { width: 1000px; }
.content  { width: 650px; }
.sidebar  { width: 350px; }
/* Fluid layout */
.content  { width: 65%; }
.sidebar  { width: 35%; }

A block element by default takes up 100% of the available width, so you don’t have to set width:
100%
on the parent container.

When the browser window narrows, the width of the parent block decreases, and the child elements shrink proportionally along with it.

3. Height in percentages

Height in percentages works only when the parent element has an explicitly set height.

/* Doesn't work — the parent's height is auto */
.parent { }
.child  { height: 50%; } /* ignored */
/* Works — the parent's height is set explicitly */
.parent { height: 400px; }
.child  { height: 50%; } /* = 200px */
Why doesn’t width require an explicit parent width? The browser always knows the width — it is bounded by the window width. But height defaults to auto and is determined by the content, so the browser cannot compute a percentage of auto.

Fixing the height for blocks with dynamic content is bad practice: if there is more content, it will overflow beyond the block’s boundaries.

4. Percentages for position: absolute and fixed

For absolutely positioned elements, percentage sizes are taken not from the direct parent, but from the nearest ancestor with position: relative (the positioning context).

.wrapper {
position: relative;
width: 500px;
height: 300px;
}
.parent {
width: 100px;
height: 100px;
}
.child {
position: absolute;
top: 0;
left: 0;
width: 100%;  /* = 500px (from wrapper) */
height: 100%; /* = 300px (from wrapper) */
}

For position: fixed, sizes are always taken from the viewport — the browser window. width: 100% = the entire screen width, height: 100% = the entire screen height.

5. max-width and min-width

When the width is set in percentages or is unbounded, on wide screens the block stretches too much: text becomes hard to read, images get excessively cropped.

.container {
width: 100%;
max-width: 1280px;
margin-left: auto;
margin-right: auto;
}
Property What it does
max-width Limits the maximum width. The block is “fluid” but will never become wider than the specified value
min-width Limits the minimum width. If the screen is narrower, a horizontal scrollbar appears
Important: when using max-width, be sure to add margin-left:
auto
and margin-right: auto to center the block. Otherwise it will be pushed against the left edge.

min-width is a temporary solution: it does not eliminate horizontal scrolling. For correct display on narrow screens, you need a responsive layout with media queries.

6. margin-left: auto and margin-right: auto — the notation

To center a block, it’s better to write out the longhand properties instead of the shorthand notation:

/* Shorthand notation — sets unnecessary margin-top and margin-bottom */
.container { margin: 0 auto; }
/* Longhand notation — sets only what's needed */
.container {
margin-left: auto;
margin-right: auto;
}

The problem with the shorthand notation: margin: 0 auto zeroes out margin-top and margin-bottom. If you set vertical margins somewhere earlier in the CSS, they will be overwritten. With the longhand properties there is no such conflict.

7. margin and padding in percentages

A counterintuitive rule: both horizontal and vertical margin and padding in percentages are calculated from the width of the parent element.

.wrapper { width: 1000px; }
.card {
margin: 1%;   /* top, right, bottom, left — all = 10px */
padding: 1%;  /* top, right, bottom, left — all = 10px */
}
Remember: even margin-top, margin-bottom, padding-top, padding-bottom in percentages are taken from the parent’s width, not from its height. This is standard CSS behavior.

In practice, margins and padding are usually set in pixels, so this peculiarity rarely causes problems. But it underlies an interesting technique — preserving a block’s aspect ratio.

8. Aspect-ratio preservation technique (padding-hack)

Since padding-bottom in percentages is calculated from the width of the parent element, we can create a block that always preserves its aspect ratio:

.aspect-ratio-box {
height: 0;
padding-bottom: 100%; /* square */
overflow: hidden;
}

How it works:

  1. height: 0 — the content height does not affect the block’s size
  2. padding-bottom: 100% — the block’s height equals its width (because padding is calculated from the parent’s width)
  3. overflow: hidden — crops content that extends beyond the boundaries

The padding-bottom value for various aspect ratios:

Aspect ratio padding-bottom
1:1 (square) 100%
16:9 (video) 56.25%
4:3 75%
3:2 66.66%

9. Embedding a YouTube video (a real-world example)

The most common use case for the padding-hack is creating a fluid container for an embedded video:

<!-- HTML -->
<div class="video-wrapper">
<iframe src="https://www.youtube.com/embed/VIDEO_ID"
allowfullscreen></iframe>
</div>
/* CSS */
.video-wrapper {
position: relative;
height: 0;
padding-bottom: 56.25%; /* 16:9 */
overflow: hidden;
}
.video-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}

How this works:

  1. The iframe with position: absolute does not affect the parent’s height
  2. The height of .video-wrapper is determined solely by padding-bottom
  3. The iframe stretches to 100% of the wrapper’s width and height
  4. When the screen width changes, the video keeps its 16:9 aspect ratio
A modern alternative: CSS has the aspect-ratio property, which solves this task more elegantly: aspect-ratio: 16 / 9. It is supported by all modern browsers (Chrome 88+, Firefox 89+, Safari 15+). But the padding-hack is still found in older projects.

10. font-size in percentages

The font size in percentages is calculated from the font-size of the parent element:

.parent { font-size: 20px; }
.child  { font-size: 50%; }  /* = 10px */

Practical example: the <button> element

The <button> element has a default font-size: 13.333px, which is not inherited from the parent. So that the button’s text size matches the container’s text size:

button {
font-size: 100%; /* inherits the size from the parent element */
}

This lets you change the font size in a single place (on the parent element), and it will automatically update in the button.

11. Flexbox: revisiting the key concepts

Two axes

Flexbox has a main and a cross axis. Instead of “left/right” it’s more correct to say “start/end of the axis”.

The height of items in a row

By default, flex items in a row stretch to the same height — this is the behavior of align-items:
stretch
. Columns of equal height are the default Flexbox behavior; you don’t need to configure anything extra.

Changing the direction of the cross axis

The direction of the cross axis can be changed in two ways:

Method Explanation
flex-direction: column The main axis becomes vertical → the cross axis becomes horizontal
flex-wrap: wrap-reverse Items wrap in the reverse direction → the cross axis changes direction

12. Flexbox instead of float

Using float to create columns is an outdated approach. All modern browsers fully support Flexbox.

Flexbox automatically cancels float

.news-item {
float: left; /* the old approach for columns */
}
.news {
display: flex; /* float automatically stops working */
}

If display: flex is set on the parent element, then the float of its child elements is ignored. This is built into the Flexbox specification.

Float problems that Flexbox solves

  • The parent block “loses” its height (a clearfix hack is needed)
  • It’s harder to control alignment and the distribution of space
  • Extra hacks are needed for equal-height columns
Rule: if you see a float used for columns, feel free to replace it with display: flex. Keep float only for its original purpose — wrapping text around images.

13. Clearfix — the float hack (historical note)

When float was used for columns, the parent block would “collapse” — it did not account for the height of the float elements. To fix this, clearfix was applied:

.clearfix::after {
content: "";
display: table;
clear: both;
}

In modern markup with Flexbox, clearfix is not needed — it’s a completely obsolete technique.

14. Summary table: percentages in CSS

Property What the % is calculated from Note
width The width of the parent element Always works
height The height of the parent element Only if the parent’s height is set explicitly
margin (all sides) The width of the parent element Even vertical ones — from the width!
padding (all sides) The width of the parent element Even vertical ones — from the width!
font-size The font-size of the parent element There are better units (em, rem)
width / height with position: absolute The size of the nearest ancestor with position: relative Not from the direct parent!
width / height with position: fixed The size of the viewport (the browser window) Always from the window

Vitalii Kaplia

Founder, Web Developer & WordPress Expert

I became interested in programming back in 1997. The first acquaintance with a future profession was using Visual Basic. In…

More about author

A digital product engineer and web solutions architect

Free consultation + cost calculation

Let’s discuss your project?

Free consultation + cost calculation

More interesting articles

Customer login

This site uses cookies

We use cookies to personalize content and ads, provide social media features, and analyze our traffic. We also share information about your use of our website with our social media, advertising, and analytics partners, who may combine it with other information you have provided to them or collected when you use their services. By continuing to use our site, you consent to our use of cookies and accept our Privacy Policy and Terms of Use.

Virtual assistant
Hi! I'm the KAPLIA.PRO virtual assistant! I can tell you about our services, portfolio projects, ballpark pricing, and how we work — from websites and eCommerce to web apps, CRMs, bots, and AI agents. Ask away!

By continuing with the AI assistant, I agree to the site’s terms of use and privacy policy.

AI assistant may make mistakes in responses