100vh layout margin-top causing bottom spacing issues and solutions
Inside a container highly restricted by 100vh, the margin-top property of child elements may cause unnecessary bottom spacing and scrollbars.
This article will delve into the principles of this phenomenon and provide multiple solutions to help you build more robust and precise web layouts.
1. Problem Scenario: 100vh Container and margin-top Causing Overflow
- Element A (Parent Container)
display: flex;min-height: 100vh;(Minimum height of 100% viewport height)
- Element B (A’s Flex Item)
flex: 1;(equivalent toflex-grow: 1; flex-shrink: 1; flex-basis: 0%;, making B take up all available space of A)- Implicit height: Since A has
min-height: 100vh, and B is set toflex: 1, the calculated height of element B will extend to100vh.
- Implicit height: Since A has
- Element C (Child of B)
height: 100%;(will attempt to occupy the full height of parent element B, if the parent element does not explicitly set a height, this 100% will degrade to auto)
margin-top: 84px;(The key point)
Expected:
I hope the content of element C starts to display 84px down from the top of its parent element B, and the entire layout can perfectly fill the 100vh viewport without producing any extra scrollbars.
Actual observation:
When adding margin-top: 84px to element C, extra white space appears at the bottom of the page, often accompanied by a vertical scroll bar.
2. Why does margin-top cause this overflow?
This involves the interaction between the CSS box model and Flexbox layout.
Parent element B’s height constraint: The effective height of element B (inherited from A’s
100vhvia Flexbox) is fixed. This means the sum of B’s content area and padding is constrained within100vh.margin-topis not included in the parent element’s height: When you setmargin-top: 84pxfor element C, this margin tells the browser that the actual content and border area of C should be offset84pxdownward from the top of its parent element B’s content area. However, thismargin-toptakes effect outside of C, and it is not included in the declared height of parent element B.Content overflow and container expansion: As a result, the bottom of element C will extend beyond the declared
100vhboundary of element B. Since ancestor elements (B and A) typically do not haveoverflow: hiddenoroverflow: scrollset, the browser will automatically expand their actual rendered height to accommodate the full content of C (including its margin). This additional84pxof space is the “gap” you see at the bottom of the page, often accompanied by a scrollbar.
3. Solution: Create space within 100vh
Our goal is: to have the content of element C start displaying 84px below the top of its parent container B, while ensuring the total height of parent container B remains strictly at 100vh, avoiding unnecessary page scrollbars.
Option 1: Use padding-top on the parent element (Recommended and most commonly used)
This is the most direct, semantically appropriate, and common solution, especially suitable for scenarios where you want the content of child elements to leave space inside the parent element.
- Remove
margin-top: 84px;from element C - Add
padding-top: 84px;to element B (parent container) - Ensure element B has
box-sizing: border-box;(It’s a good habit to set* { box-sizing: border-box; }in global styles).
CSS Example:
/* Element B */
.element-B {
flex: 1;
/* ...other styles */
padding-top: 84px; /* create spacing inside the parent element */
box-sizing: border-box; /* Ensure padding is included in total height */
}
/* Element C */
.element-C {
/* Remove margin-top */
height: 100%;
/* ...other styles */
}
Principle:
When box-sizing: border-box is in effect, padding is included in the element’s total height. Therefore, B’s 100vh height will include this 84px padding. The content area will start from 84px accordingly, but B’s total height remains 100vh, and there will be no overflow.
Advantages:
- Clear Semantics:
paddingis used to create internal space between the content and the border of an element. - Stable Layout: The total height of the parent container remains unchanged, perfectly avoiding overflow and unnecessary scrollbars.
- High Generalizability: Applies to most container types.
Handling the case where element C does not exist:
If element C is conditionally rendered (e.g., controlled by v-if), you may want to apply this 84px top margin only when C exists. In this case, you need to combine JavaScript or your template engine:
- Dynamically add class: When element C is rendered, dynamically add a specific class (e.g.,
has-child-spacing) to element B. - CSS:
.element-B.has-child-spacing {
padding-top: 84px;
}
Option 2: Flexbox or Grid Layout Control (Advanced Option)
If parent container B is already a Flex or Grid container (or can be set as such), we can leverage the properties of these layout models to more precisely control spacing without causing overflow.
1. Using Flexbox and pseudo-elements (::before)
- Remove
margin-top: 84px;from element C - Set element B as a Flex container and add a pseudo-element with a height of
84pxas top spacing.
CSS Example:
/* Element B */
.element-B {
display: flex;
flex-direction: column; /* Make child elements stack vertically */
/* ...other styles, such as height: 100%; */
}
.element-B::before {
content: ''; /* Pseudo-elements must have content */
display: block; /* Ensure pseudo-elements can set height */
height: 84px; /* As spacing */
flex-shrink: 0; /* Prevent compression when space is insufficient */
}
/* Element C */
.element-C {
/* Remove margin-top */
height: 100%; /* or flex: 1; to let C take up the remaining space */
/* ...other styles */
}
Principle:
An invisible 84px high placeholder was created inside the Flex container B. Since B’s total height is 100vh, this 84px space is accounted for and does not cause overflow. Element C will follow immediately.
Advantages:
- Precise control of spacing without causing overflow.
- If B is already a Flex container, this approach is very natural.
Handling the case where element C does not exist:
Similar to padding-top, the pseudo-element ::before is default present. If conditional styling is needed, it’s also required to dynamically add classes that control the pseudo-element’s styles through JS/template engine.
2. Using Grid Layout
- Remove
margin-top: 84px;from element C - Set element B as a Grid container and define a clear row height.
CSS Example:
/* Element B */
.element-B {
display: grid;
/* Define two rows: first row 84px, second row takes up remaining space */
grid-template-rows: 84px 1fr;
/* ...other styles, such as height: 100%; */
}
/* Element C */
.element-C {
/* Remove margin-top */
grid-row: 2 / 3; /* Place element C in the second row */
/* ...other styles */
}
Principle:
The Grid layout precisely controls the height of each row. Even if the content of the second row is very little, the height of the first row (84px) will be retained. Since B’s total height is 100vh, 84px plus 1fr will precisely allocate this 100vh without overflow.
Advantages:
- Extremely precise and powerful layout control.
- Very suitable for complex grid layouts.
Handling the case where element C does not exist:
The rows defined by Grid’s grid-template-rows always exist. Conditional styling also requires dynamic class control.
Summary
1、The key lies in understanding the different behaviors of margin-top and padding-top when the container has a fixed height: margin-top attempts to push the child element outside the parent’s boundary, forcing the parent element to expand; whereas padding-top creates a blank area inside the parent element, with its size constrained by the parent element’s own dimensions.
2、Understand the role of height: 100%; when the parent element does not explicitly set a height, this height will not take effect, meaning it is determined by the height of the child element’s content.
3、Understand that block formatting context (BFC) elements (flex/grid/overflow: hidden) do not have margin collapsing. It is recommended to use grid/flex for all layout purposes.
References
- MDN — CSS Viewport Units — Documentation on viewport units (vh, svh, dvh, lvh)
- The Large, Small, and Dynamic Viewport Units — web.dev — Guide to new viewport units solving mobile 100vh issues
- CSS Tricks — Fun with Viewport Units — Practical examples and solutions for viewport unit challenges
Be the first to know when I post cool stuff
Subscribe to get my latest posts by email.
Thanks for signing up! Check your email to confirm your subscription.
Whoops, we weren't able to process your signup.