1
\$\begingroup\$

I'm using flexbox to create a simple header, hero image with caption and footer.

As you can see from my snippet, the header is fixed and the hero image scrolls underneath.

Is there a way to achieve my layout without fixed or absolute positioning? I'm relatively new to flexbox and and haven't come across a solution.

For the image, I could use the background property, but I'd like to maintain what I have to easily implement img srcset and an alt tag.

body {
  margin: 0;
}

/* Flexbox */
.main-navigation,
.main-navigation ul,
.hero {
	display: flex;
	flex-flow: row wrap;
}

.main-navigation {
	justify-content: space-between;
	align-items: center;
}

/* Site header */
.site-header {
  position: fixed;
	top: 0;
	z-index: 9999; /* Always on top */
	width: 100%; /* Must have width for flex */
  padding: 24px;
  color: #fff;
  background-color: #021928;
}

/* Hero */
.hero {
	position: relative; /* For image */
	height: 100vh; /* Fill viewport */
  justify-content: center;
	align-items: center;
}

.hero img {
  position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	z-index: -1; /* Send image to back */
	height: 100vh;
	object-fit: cover;
	object-position: bottom;
}

/* Cosmetic */
ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

li {
 margin-right: 12px;
}

li:last-child {
  margin: 0;
}

a,
a:visited,
a:focus,
a:hover {
  color: #fff;
}

p {
  padding: 24px;
}

.caption {
  padding: 0;
}


h1 {
  margin: 0 0 12px;
}

.logo {
  margin: 0;
}

.caption {
  max-width: 600px;
	text-align: center;
  color: #fff;
}

.site-footer {
  padding: 24px;
  background-color: #021928;
  color: #fff;
}
<div class="site-header">
  
  <nav class="main-navigation">
    <h1 class="logo">Logo</h1>
    <ul>
      <li><a href="#">Item One</a></li>
      <li><a href="#">Item Two</a></li>
      <li><a href="#">Item Three</a></li>
    </ul>
  </nav>
  
</div><!-- .site-header -->

<div class="hero">
  
  <div class="caption">  
    <h1>Title goes here</h1>
    <p class="caption">And a caption</p>
  </div>

  <img src="https://ichef.bbci.co.uk/news/660/cpsprodpb/3963/production/_103119641_7623dbe4-9ef2-4108-a2f1-a745d0640c53.jpg" alt="Kittens">

</div><!-- .hero -->

<div class="main">
  <p>Main page content</p>
</div><!-- .main -->

<div class="site-footer">
  <span>Some information about stuff</span>
</div><!-- .site-footer -->

\$\endgroup\$
2
\$\begingroup\$

Neither the fixed position of the header nor the positioning of the background image is achievable with flexbox.

You can replace fixed with sticky. This fixes the offset of the background image for .hero (sticky effects the flow of elements). This also allows us to drop the width attribute which is incorrectly set to width: 100% (should be width: calc(100% - 48px)) and thus fix so that the entire header is visible.

I think you should use background-image. I agree with this post stating you don't need an alt for a background image. And there's decent support for the image-set css property (although I don't have experience with this property myself).

https://codepen.io/a-morn/pen/xvdVZm

Edit: I recommend Flexbox Zombies if you want to learn more about what flexbox can and can't do.

\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks for your answer. I like position: sticky and your method for the background image. \$\endgroup\$ – Sam Jul 30 at 20:29
2
\$\begingroup\$

If you want the header to be "sticky" the only way is to make it position:fixed. In order to to push the rest of the content down, you need to know the headers height. Then you set a margin-top to your #hero.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.