Responsive Layout Design for the Hero Section

Hero Section Layout

Hero section is divided into three layers:

Page Layout Layer
Controls the overall direction of the page:
– mobile uses flex-col
– desktop switches to md:flex-row
This determines whether the Hero appears above or beside the secondary content — in this case, the GitHub Grid.

Hero Component Layer
Maintains a consistent internal structure using flex-col, so the name, line, role, description, and other elements stack vertically regardless of screen size.

Button Group Layer
Uses its own breakpoint (flex-col → sm:flex-row) to adjust button layout without affecting the rest of the component.

Mobile vs Desktop
Mobile (flex-col)
Page layout: flex-col
flow: top ↓ bottom
Hero (internal: flex-col)
Buttons (mobile: flex-col)
Button A
Button B
GitHub Grid (full width under Hero)
Desktop (md:flex-row)
Page layout: md:flex-row
flow: left → right
Hero flex-col; flex-1
Buttons (sm:flex-row)
Button A
Button B
GitHub Grid flex-1

In this layout, the page controls overall direction, the Hero controls its own structure, and the buttons handle their own breakpoint


Best Pratice for transform in absolute container

  1. Why need transform when there are top or left

Without transform

The element’s left edge is aligned to the target position, so it appears shifted to the right.

/* Container */
.parent {
  position: relative;
}

/* Center target (incorrect) */
.target {
  position: absolute;
  top: 50%;
  left: 50%;
}
Element

With transform: translateX(-50%)

The element’s center aligns to the target position, so it stays visually centered no matter the width.

/* Container */
.parent {
  position: relative;
}

/* Center target (correct) */
.target {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translateX(-50%);
  transform: translateY(-50%)
}
Element

2. Best practice when using <motion.div>

motion.div uses the transform property to animate movement, scaling, rotation, and other effects.
During animation, Framer Motion rewrites the entire transform string, not just part of it.

Because of this:

Any layout transform you apply (like translateX(-50%)) will be overwritten by Framer Motion’s transform updates.

This is why the layout transform must live on an outer <div>, and the inner motion.div should handle animation only.

For example,

<motion.div
  initial={{ y: 40 }}
  animate={{ y: 0 }}
/>

What the browser actually renders in the DOM

<div style="transform: translateY(40px);"></div>

During the animation, Framer Motion continuously updates the transform value

transform: translateY(32px);
transform: translateY(20px);
transform: translateY(10px);
transform: translateY(0px);

Therefore, translateY will be overwritten over and over again.

The better practice is to wrap motion.div with a div container:

{/* Layout container (keeps transform untouched) */}
<div className="absolute left-1/2 -translate-x-1/2">

  {/* Framer Motion only applies animation */}
  <motion.div
    initial={{ opacity: 0, y: 20 }}
    animate={{ opacity: 1, y: 0 }}
  >
    Centered badge
  </motion.div>

</div>

Summary

  • Page-Hero component: buttons can control each stack independently
  • Centering uses a combination of left/top with transform
  • motion.div is wrapped inside a container div to prevent transform override and keep items centered

Leave a Reply

Discover more from Daily Learning

Subscribe now to keep reading and get access to the full archive.

Continue reading