惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
K
Kaspersky official blog
Apple Machine Learning Research
Apple Machine Learning Research
B
Blog
aimingoo的专栏
aimingoo的专栏
M
MIT News - Artificial intelligence
小众软件
小众软件
云风的 BLOG
云风的 BLOG
腾讯CDC
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Hugging Face - Blog
Hugging Face - Blog
S
SegmentFault 最新的问题
Stack Overflow Blog
Stack Overflow Blog
量子位
S
Secure Thoughts
G
GRAHAM CLULEY
C
CXSECURITY Database RSS Feed - CXSecurity.com
人人都是产品经理
人人都是产品经理
雷峰网
雷峰网
T
Threat Research - Cisco Blogs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cisco Talos Blog
Cisco Talos Blog
G
Google Developers Blog
爱范儿
爱范儿
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
有赞技术团队
有赞技术团队
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Martin Fowler
Martin Fowler
The GitHub Blog
The GitHub Blog
Google DeepMind News
Google DeepMind News
C
Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
博客园 - 聂微东
宝玉的分享
宝玉的分享
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
Netflix TechBlog - Medium
Forbes - Security
Forbes - Security
Engineering at Meta
Engineering at Meta
S
Security Affairs
Help Net Security
Help Net Security
博客园 - 三生石上(FineUI控件)
AWS News Blog
AWS News Blog
博客园 - 叶小钗
Recent Commits to openclaw:main
Recent Commits to openclaw:main
V2EX - 技术
V2EX - 技术
Hacker News: Ask HN
Hacker News: Ask HN
Project Zero
Project Zero
H
Heimdal Security Blog
W
WeLiveSecurity
C
Check Point Blog

Ahmad Shadeed

Better fluid sizing with round() Use Cases for Field Sizing The Basics of Anchor Positioning Item Flow CSS Relative Colors Balancing Text In CSS Should masonry be part of CSS grid? CSS display contents CSS Grid Areas CSS Cap Unit An Interactive Guide to CSS Container Queries CSS :has() Interactive Guide CSS Nesting UX in DevTools CSS Nesting Future CSS: State Container Queries Rebuilding a comment component with modern CSS Conditional CSS with :has and :nth-last-child CSS Text balancing with text-wrap:balance CSS Masking Do we need CSS flex-wrap detection? My CSS Wishlist Conditional CSS CSS Style Queries Inside the mind of a frontend developer: Article layout Inside the mind of a frontend developer: Hero section CSS container queries are finally here The CSS behind Figma First Look At The CSS object-view-box Property Learn CSS Subgrid CSS :has Parent Selector Aligning Content In Different Wrappers Flexbox Dynamic Line Separator Hello, CSS Cascade Layers Building UI Components With SVG and CSS A Deep CSS Dive Into Radial And Conic Gradients Defensive CSS Building Real-life Components: Facebook Messenger Conditional Border Radius In CSS CSS Container Query Units Aligning a Button Label Vertically Comparing Design Mockups To Code Result Using HSL Colors In CSS Custom Scrollbars In CSS Let CSS Container Queries For Designers The State of CSS Cross-Browser Development Overflow Issues In CSS Inspect Element As A Way To Increase Your Curiosity Handling Text Over Images in CSS Digging Into CSS Logical Properties Clipping Scrollable Areas On The inline-start Side Understanding Clip Path in CSS The Art of Building Real-life Components Handling Short And Long Content In CSS CSS Scroll Snap A Deep Dive Into CSS Grid minmax() CSS Variables 101 Finding The Root Cause of a CSS Bug Learn CSS centering How to detect browser support for Flexbox Gap CSS Mistakes While On Autopilot Digging Into the Flex Property Understanding CSS Multiple Backgrounds Aligning Logo Images in CSS Grid for layout, Flexbox for components Colors in CSS Thinking About The In-between Design Cases min(), max(), and clamp() CSS Functions Image Techniques On The Web Everything About Auto in CSS Learn Box Alignment Let Learn CSS Positioning Intrinsic Sizing In CSS CSS Grid Template Areas In Action Hiding Elements On The Web Creating a Variable Color Font From Scratch Building a Football Ticket With CSS and SVG Blending Modes in CSS CSS Variables With Inline Styles Implementing Dark Mode For My Website Rebuilding Apple Music Header in HTML & CSS Accessible Checkbox Layout Flickering On Browser Resize Enhancing The Clickable Area Size Custom Underlines with SVG Part 3: The Process of Implementing A UI Design From Scratch Part 2: The Process of Implementing A UI Design From Scratch Building An Old Nav Design CSS Flexbox: 5 Real World Use Cases I Used CSS Inline Flex For The First Time The Process of Implementing A UI Design From Scratch Common CSS Issues For Front-End Projects Handling Long and Unexpected Content in CSS How to Build Web Form Layouts With CSS Grid Grid Layout Ah-ha Moment Enhancing Our Components with CSS :empty Building Resizeable Components with Relative CSS Units CSS Writing Mode The Journey of Learning Front End Web Development on a Daily Basis
Less Absolute Positioning With Modern CSS
Ahmad Shadeed · 2021-09-10 · via Ahmad Shadeed

The Layout Maestro

I spent years teaching CSS layout on this blog. I put everything I know into The Layout Maestro course: 70+ lessons and 150+ interactive examples that teach you how to think CSS layouts, not just memorize syntax.

Get the course

Each time I work on a component that needs absolute positioning, I ask myself: is it really necessary? I started to notice a few use-cases where using position: absolute isn’t needed. I found this interesting and I thought about documenting the use-cases that I usually came through while working on front-end projects.

In this article, I will explore a few use-cases that using absolute positioning with them isn’t really needed.

Introduction

If we go back 5 years in time, CSS flexbox was still new and can’t be used with a proper fallback. CSS grid wasn’t even supported back then. Eventually, we would use CSS positioning to achieve the desired layout. However, some of these use-cases can be solved with CSS flexbox or grid these days.

The other day, we were working on a landing page front-end development, and my partner asked me about a layout issue she is facing. The issue was happening because of position: absolute, so I stepped in and tried to help with it, and we fixed it without even using any CSS positioning. At that time, it clicked for me that I should document that, and that’s what I’m doing right now.

Use cases and Examples

Card overlay

When we have a card that contains text over an image, we often use position: absolute to place the content over the image. This is no longer needed with CSS grid.

This is a typical text-over-image card. Here is the HTML:

<article class="card">
  <div class="card__thumb">
    <img src="assets/mini-cheesecake.jpg" alt="" />
  </div>
  <div class="card__content">
    <h2><a href="#">Title</a></h2>
    <p>Subtitle</p>
  </div>
</article>

In order to place the content over the image, we need to position .card__content absolutely.

.card {
    position: relative;
}

.card__content {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(to top, #000, rgba(0, 0, 0, 0) bottom/100% 60% no-repeat;
    padding: 1rem;
}

There is nothing wrong with using position: absolute in the above example, but why not use an easier solution? Let’s explore that.

The first step is to add display: grid to the card component. We don’t need to set any columns or rows.

.card {
  position: relative;
  display: grid;
}

.card__content {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

By default, CSS grid will create rows automatically based on the content. In the card, we have two main elements, and so we have two rows of content.

To overlap the content with the image, we need to place both of them on the first grid area.

.card__thumb,
.card__content {
  grid-column: 1/2;
  grid-row: 1/2;
}

Even better, we can use grid-area shorthand.

.card__thumb,
.card__content {
  grid-area: 1/2;
}

Finally, we can also use grid-area: 1/-1. The -1 represents the last column and row in a grid, so it will always span to the end of the column or row.

Card Tag

Based on the previous example, we want to extend it and include a tag at the top left area of the card. To do that, we need to use the same technique which is grid-area: 1/-1, but we don’t want the tag to fill the whole card, correct?

To fix that, we need to tell the tag to justify and align itself to the start of its alignment container.

.card__tag {
  align-self: start;
  justify-self: start;
  /* Other styles */
}

Meet the tag that is positioned above its parent, without using position: absolute.

Demo

Hero section

Another perfect use case is a hero section with content overlapping an image.

This is similar to the card example, but with different styling for the content itself. Before diving into the modern way, let’s think for a minute about how we do that with absolute positioning.

We have three layers:

  • Image
  • Gradient overlay
  • Content

There are different ways to implement that. If the image is purely for decorative purposes, we can use background-image. Otherwise, we can use an <img> element.

.hero {
  position: relative;
  min-height: 500px;
}

.hero__thumb {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The overlay */
.hero:after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: #000;
  opacity: 0.5;
}

.hero__content {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 1;
  transform: translate(-50%, -50%);
  text-align: center;
}

That’s how we can implement the hero section using absolute positioning. However, we can do better. Let’s explore the modern approach.

First, we need to add display: grid to the hero element. After that, we will apply the same concept as in the card component, which is to apply grid-area: 1/-1 to every direct child item.

Unfortunately, we will need to use a fixed height for the hero section so the .hero__thumb can actually work. (A child item with height: 100% will need its parent to have an explicit fixed height, not min-height).

.hero {
  display: grid;
  height: 500px;
}

.hero__content {
  z-index: 1; /* [1] */
  grid-area: 1/-1;
  display: flex;
  flex-direction: column;
  margin: auto; /* [2] */
  text-align: center;
}

.hero__thumb {
  grid-area: 1/-1;
  object-fit: cover; /* [3] */
  width: 100%;
  height: 100%;
  min-height: 0; /* [4] */
}

.hero:after {
  content: "";
  background-color: #000;
  opacity: 0.5;
  grid-area: 1/-1;
}

I want to go through the numbered code lines since they are important:

  1. We can use z-index on a grid or flex item. No need to add position: relative at all.
  2. Since the .hero__content is a grid item, using margin: auto will center it horizontally and vertically.
  3. Don’t forget to include object-fit: cover when dealing with images.
  4. I used min-height: 0 on the hero image just in case a large image was used. Well, this is to force CSS grid to respect the height: 100% and avoid making the image larger than the hero section in case an author used a huge image. You can read more about that in my article about the minimum content size in CSS grid.

Notice how we ended up with a much cleaner solution?

Demo

CSS display: contents

I think this is the first real-life use case for display: contents. Consider the following example where we have content and an image.

Here is the HTML markup.

<div class="hero">
  <div class="hero__content">
    <h2><!-- Title --></h2>
    <p><!-- Desc --></p>
    <a href="#">Order now</a>
  </div>
  <img src="recipe.jpg" alt="" />
</div>

Nothing weird till now. On mobile, we want to achieve the following layout.

Notice that the image is now inserted between the headline and description. How you can tackle this problem? At first, you might think that the HTML markup should be changed like that.

<div class="hero">
  <div class="hero__content">
    <h2><!-- Title --></h2>
    <img src="recipe.jpg" alt="" />
    <p><!-- Desc --></p>
    <a href="#">Order now</a>
  </div>
</div>

On mobile, it can work as expected. On desktop, we need to position the <img> absolutely on the right side. While this works, there is a more straightforward solution with display: contents.

Let’s get back to the initial markup.

<div class="hero">
  <div class="hero__content">
    <h2><!-- Title --></h2>
    <p><!-- Desc --></p>
    <a href="#">Order now</a>
  </div>
  <img src="recipe.jpg" alt="" />
</div>

Notice that the content is wrapped inside .hero__content. How we can tell the browser that we want the <h2>, <p>, and <a> to become direct siblings with the <img>? Well, display: contents can do that.

.hero__content {
  display: contents;
}

By adding that, the .hero__content element is a hidden ghost now. The browser will parse the markup like the following.

<div class="hero">
  <h2><!-- Title --></h2>
  <p><!-- Desc --></p>
  <a href="#">Order now</a>
  <img src="recipe.jpg" alt="" />
</div>

All we need to do in CSS is the following.

.hero {
  display: flex;
  flex-direction: column;
}

.hero__content {
  display: contents;
}

.hero h2,
.hero img {
  order: -1;
}

When used right, display: contents is a powerful technique to achieve things that were impossible a few years ago.

Of course, we want to handle the desktop styling too.

@media (min-width: 750px) {
  .hero {
    flex-direction: row;
  }

  .hero__content {
    display: initial;
  }

  .hero h2,
  .hero img {
    order: initial;
  }
}

Demo

Reordering card component items

In this example, we have a variation of a card that places the title at the top of the card. Let’s take a look at the HTML markup.

<article class="card">
  <img src="thumb.jpg" alt="" />
  <div class="card__content">
    <h3>Title</h3>
    <p>Description</p>
    <p>Actions</p>
  </div>
</article>

Notice that we have two direct child elements: the thumb and the content. With that markup, how we can position the title <h3> at the top?

We can do it with absolute positioning.

.card {
  position: relative;
  padding-top: 3rem;
  /* Accommodate for the title space */
}

.card h3 {
  position: absolute;
  left: 1rem;
  top: 1rem;
}

However, this solution can fail when the title is too long.

That is happening because the title is out of the normal flow, so the browser doesn’t actually care about how short or long it is. We can do much better with display: contents.

.card {
  display: flex;
  flex-direction: column;
  padding: 1rem;
}

.card__content {
  display: contents;
}

.card h3 {
  order: -1;
}

This will allow us to control all child items and have the flexibility of recording them as needed with the order property.

We still have a little issue since we added padding: 1rem to the parent. The image should be stuck to the edges. Here is how we can fix that.

.card img {
  width: calc(100% + 2rem);
  margin-left: -1rem;
}

Centering

When it comes to centering, you will see a lot of jokes that it’s hard and complicated. These days, it’s much easier than ever to center an element.

No more using position: absolute with CSS transforms. For example, we can use margin: auto to center a flex item both horizontally and vertically.

.card {
  display: flex;
}

.card__image {
  margin: auto;
}

I wrote a complete guide about centering in CSS.

An image aspect ratio

The new CSS aspect-ratio property is now supported in all major browsers. We used to do the padding hack to force a box to respect a specific aspect ratio.

Here is an example.

.card__thumb {
  position: relative;
  padding-top: 75%;
}

.card__thumb img {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

With the new aspect-ratio property, it’s much easier.

/*  */
.card__thumb {
  position: relative;
  aspect-ratio: 4/3;
}

You can learn more about them in this article by yours truly.

Sometimes, using position: absolute is better

In this example, we have the content (avatar, name, and link) overlapping with the card cover. We have two options for implementing this:

  1. Use position: absolute for the card cover
  2. Use a negative margin for the content

Let’s explore the solutions and see which one of them is more suitable for that use case.

Using absolute positioning

With this solution, we can position the rectangle absolutely, and then add padding: 1rem to the card content.

.card__cover {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 50px;
}

.card__content {
  padding: 1rem;
}

That way, when the card cover is removed, we don’t have to edit or alter the CSS.

Using negative margins

In this solution, the card won’t be positioned absolutely. Instead, the content will have a negative margin from the top.

.card__content {
  padding: 1rem;
  margin-top: -1rem;
}

While this solution works when the card cover is there, it can cause a problem when we have a card variation without the card cover.

Notice how the avatar is off its parent (The card). To fix that, we need to alter the CSS and remove the negative margin.

.card--no-cover .card__content {
  margin-top: 0;
}

As a result, using position: absolute turned out to be a better solution in such a case as it will save us from writing additional CSS.

Further reading

I hope you enjoyed the article. Thanks for reading!