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

推荐订阅源

N
News and Events Feed by Topic
GbyAI
GbyAI
博客园 - Franky
宝玉的分享
宝玉的分享
Blog — PlanetScale
Blog — PlanetScale
Google DeepMind News
Google DeepMind News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
人人都是产品经理
人人都是产品经理
Microsoft Azure Blog
Microsoft Azure Blog
The Register - Security
The Register - Security
腾讯CDC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
I
InfoQ
The Cloudflare Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
MongoDB | Blog
MongoDB | Blog
有赞技术团队
有赞技术团队
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
F
Full Disclosure
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Vercel News
Vercel News
博客园 - 【当耐特】
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Schneier on Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Project Zero
Project Zero
量子位
M
MIT News - Artificial intelligence
Stack Overflow Blog
Stack Overflow Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
美团技术团队
Attack and Defense Labs
Attack and Defense Labs
C
Cybersecurity and Infrastructure Security Agency CISA
T
The Blog of Author Tim Ferriss
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Troy Hunt's Blog
Google Online Security Blog
Google Online Security Blog
罗磊的独立博客
P
Proofpoint News Feed
Schneier on Security
Schneier on Security
Spread Privacy
Spread Privacy
S
SegmentFault 最新的问题
L
LINUX DO - 最新话题
Simon Willison's Weblog
Simon Willison's Weblog
爱范儿
爱范儿
博客园 - 聂微东
A
About on SuperTechFans
PCI Perspectives
PCI Perspectives
D
Docker

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
The State Of Mobile First and Desktop First
Ahmad Shadeed · 2021-08-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

Have you often thought about whether to implement a mobile-first or a desktop-first approach? Recently, I shared a Twitter poll about how many uses mobile-first vs desktop-first, and the results were interesting.

The total number of votes is 648, and here are the stats:

  • Mobile-first: 33.3%
  • Desktop first: 21.9%
  • Mix of both: 24.7%

In this article, I will explore with you what each method means, and I will try to discover and see if it’s still relevant for today, along with some tips for responsive design today.

Introduction: What does each one mean?

The term Mobile-First means that when developing a website, we start writing the CSS for smaller viewport sizes first, and then use CSS media queries to alter the experience for larger ones (e.g: tablets or desktops).

Consider the following example.

.section {
  padding: 2rem 1rem;
}

@media (min-width: 62.5rem) {
  .section {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 4rem 2rem;
  }
}

We have a section that has padding for mobile, and when the viewport is large enough, it should be a flex wrapper with larger padding.

This is a simplified example. Imagine this on the scale of a whole website or web app.

On the other hand, when we day Desktop First, it’s the other way around.

.section {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 4rem 2rem;
}

@media (max-width: 62.5rem) {
  .section {
    display: block;
    padding: 2rem 1rem;
  }
}

We write CSS for larger viewport sizes first and then use a CSS media query to alter the CSS for smaller ones.

How mobile-first does look like as a workflow?

Do you open the DevTools and start development from there without even looking at the desktop size? Or should you do it in sync? i.e: write CSS mobile-first and enhance for the desktop at the same time?

I can think of two scenarios:

  1. Working on a full page for mobile. Once done, we start enhancing for larger sizes.
  2. Working in parallel. I mean, handle each section/component separately starting with mobile-first, and then enhancing for larger sizes.

Which one do you usually use? For me, the second one is better. I prefer to handle each component/section separately so that I can focus on it. Also, this process will reduce making mistakes while writing CSS.

When you start mobile-first and then enhance for desktop, there is a possibility that you will rewrite CSS for tablet and desktop. Consider the following figure:

Let’s take the hero section as an example.

.hero {
  display: flex;
  align-items: flex-end;
  background-image: url("hero.jpg");
  background-size: cover;
  background-repeat: no-repeat;
}

.hero__title {
  font-size: 1rem;
}

.hero__thumb {
  display: none;
}

@media (min-width: 60rem) {
  .hero {
    align-items: center;
    background-image: initial;
    background-color: #7ecaff;
  }

  .hero__title {
    font-size: 2rem;
  }

  .hero__thumb {
    max-width: 320px;
    display: block;
  }
}

On mobile, the hero has a background image, while on desktop, the background is a solid color, and there is an image that is positioned at the far right. As you see, the CSS is mobile-first and we don’t have many overrides except for the font-size and background.

What about the navigation? How it will look like with the mobile-first approach? Here it is.

.nav {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  padding-top: 2rem; /* Space for the toggle */
}

.nav__toggle {
  position: absolute;
  right: 1rem;
  top: 1rem;
}

.nav__item {
  padding: 1rem;
  display: block;
}

.nav__item:not(:last-child) {
  border-bottom: 1px solid #fff;
}

/* Desktop styles */
@media (min-width: 60rem) {
  .nav {
    position: initial;
    width: initial;
    height: initial;
    overflow-y: initial;
    display: flex;
    align-items: center;
    padding-top: 0;
    background-color: blue;
  }

  .nav__toggle {
    display: none;
  }

  .nav__item:hover {
    color: blue;
    background-color: initial;
  }

  .nav__item:not(:last-child) {
    border-bottom: 0;
    border-left: 1px solid #fff;
  }
}

Do you see the amount of CSS overrides in there combined with CSS for the desktop view? This isn’t a good thing.

Not only that, but this might cause CSS specificity issues as well. Suppose that a developer wants to remove the border-bottom from the .nav__item by using the following CSS.

.nav__item {
  border-bottom: 0;
}

It won’t work since the :not pseudo-class has higher specificity in that case.

It will only work if you use one of the followings:

.nav .nav__item {
  border-bottom: 0;
}

/* Or */

.nav__item:not(:last-child) {
  border-bottom: 0;
  border-left: 1px solid #fff;
}

How desktop first does look like as a workflow?

Based on the same previous example, we will flip things around and explore the desktop-first solution.

.nav {
  display: flex;
  align-items: center;
  background-color: blue;
}

.nav__toggle {
  position: absolute;
  right: 1rem;
  top: 1rem;
}

.nav__item {
  padding: 1rem;
  display: block;
}

.nav__item:hover {
  color: blue;
  background-color: initial;
}

.nav__item:not(:last-child) {
  border-bottom: 0;
  border-left: 1px solid #fff;
}

@media (max-width: 25rem) {
  .nav {
    display: block;
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    overflow-y: auto;
    padding-top: 2rem; /* Space for the toggle */
  }

  .nav__toggle {
    display: block;
  }

  .nav__item:not(:last-child) {
    border-bottom: 1px solid #fff;
  }
}

With this approach, we have fewer overrides than using the mobile-first one. Isn’t that interesting? The reason is that by using a max-width media query, we are scoping a specific design to a specific viewport width.

Instead of writing the CSS for mobile-first, and then overriding them for desktop, we do it the other way around.

Here is a visual comparison, side by side. Notice that the desktop-first looks shorter and doesn’t have duplication (Well, it has, but a little).

Tip: make sure to test for layout flickering.

Scoping styles: A better approach

Yes, there is. For me, I prefer to not stick to a specific approach. Instead, I like to mix them both. That means, we need to write the base styles first and then we start thinking about what will happen for mobile and desktop. I like how Elad Shechter is calling it basics first in this great article.

Let’s take an abstract example.

.nav {
  /* Base styles: not related to any viewport size */
}

/* Desktop styles */
@media (min-width: 800px) {
  .nav {
    ...;
  }
}

/* Mobile styles */
@media (max-width: 799px) {
  .nav {
    ...;
  }
}

As you see, the styles are scoped per viewport size. That means we don’t need to do any overrides. This approach is useful for components that look completely different on mobile versus desktop size. In our case, it’s the navigation.

However, for something like a <section>, using the mixed approach isn’t useful since the mobile and desktop styles are very similar.

.section {
  padding: 1rem;
}

/* Desktop styles */
@media (min-width: 800px) {
  .section {
    padding: 2rem 1rem;
  }
}

How I approach responsive design

At some point, I feel that the mobile-first vs desktop-first discussion won’t be that important. Modern CSS provides us with ways to build responsive layouts with media query-less CSS.

With that being said, I think the mobile/desktop-first debate will be only about showing or hiding certain elements at specific viewport sizes (e.g: a navigation toggle button on mobile) except for complex components with big differences across viewport sizes.

Let’s take a real-life example to demonstrate the concepts.

The components that have a lot of differences on mobile versus desktop are the header and navigation. The rest have some slight differences. For the header, we can use a mix of min-width and max-width media queries to scope each design for its desired viewport size.

However, the hero section and the articles grid can have a base style, and then min-width can be used if necessary.

Do you see the kind of thinking for such a design? There is nothing strict here. It’s about the design we have at our hands. Okay, let’s show some more details.

If the mobile-first concept were adopted for the header and navigation, we will end up with lots of CSS overrides (AKA duplication). This isn’t good. Here is how I imagine the CSS for the header and navigation:

.header {
  /* Base styles */
}

/* Desktop styles */
@media (min-width: 1000px) {
  .nav__toggle,
  .nav__close {
    display: none;
  }
}

/* Mobile styles */
@media (max-width: 999px) {
  .nav {
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: #4777db;
  }
}

For the hero section, we can use flexbox to handle the row versus column style, and also for reordering or moving elements.

<section class="hero">
  <div class="wrapper">
    <img src="thumb.jpg" alt="" />
    <h2><!-- Headline --></h2>
    <p><!-- Description --></p>
  </div>
</section>
.hero {
  display: flex;
  flex-direction: column;
}

@media (min-width: 1000px) {
  flex-direction: row;
}

@media (max-width: 999px) {
  .hero__thumb {
    order: -1;
  }
}

Notice that I wrote the order: -1 only once by scoping it with a max-width media query. I could have done something like that:

.hero__thumb {
  order: -1;
}

@media (min-width: 1000px) {
  .hero__thumb {
    order: initial;
  }
}

But do you see the duplication? Also, beware of using the order in flexbox as the visual order doesn’t match the order of the elements in the HTML source (The DOM).

Here is a visual chart that explains my process.

Using the same value for min-width and max-width media queries can lead to an issue that is hard to notice/debug.

@media (max-width: 500px) {
  .nav {
    display: none;
  }
}

@media (min-width: 500px) {
  .nav__toggle {
    display: none;
  }
}

These media queries might look good to you. However, 99% of the time, you’ll forget to test an important breakpoint: 500px, that 1-pixel gap between the two breakpoints. At this breakpoint, neither the navigation nor the toggle would be visible.

The 1 pixel is hard to debug without manually entering a value for a 500px media query in DevTools mobile mode. To prevent this issue, avoid using the same value in two media queries.

@media (max-width: 499px) {
  .nav {
    display: none;
  }
}

@media (min-width: 500px) {
  .nav__toggle {
    display: none;
  }
}

This issue has been borrowed from my Debugging CSS book, page 43.

Mobile first for designers

I’m a designer myself, and I don’t like to design mobile-first for different reasons:

  • It’s limiting and it’s hard to get creative with it.
  • Working on a design with a large height is annoying, you will keep scrolling up and down.

On the other hand, designing desktop-first is much better, at least for me. It gives me a way to try and experiment with ideas quickly, and I can see a broader view of the whole design without scrolling up and down (if I’m designing mobile-first).

We can start desktop-first, and then alter the design for mobile. From there, we have a good starting point and I don’t mind doing the rest of the pages mobile-first. However, for a fresh new project, I don’t prefer to start designing mobile-first.

Modern CSS reduces the need to think about mobile-first vs desktop-first

It’s never been better to write CSS than these days. We have lots of current and upcoming CSS features that will make the responsive design much easier to do.

Flexbox Wrapping

In his article How to Make a Media Query-less responsive Card Component, Geoffrey Crofte explored how to make a responsive card component without using media queries. I will explain the basic concept of it, and you can read the article for more details.

When setting a fixed flex-basis value, and allowing the item to grow and shrink when needed, this can achieve a media query-less component.

Here is an example of how the card will look when there isn’t enough space.

CSS Grid minmax()

Thanks to CSS grid, we can have a responsive grid layout that doesn’t depend on CSS media queries. Consider the following example:

.wrapper {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-gap: 1rem;
}

This is a responsive grid that gives each item a minimum width of 200px. Without CSS grid, we will need to use media queries to alter the width based on the viewport size.

Learn more about CSS grid minmax() in this article.

Viewport Units & Comparison Functions

Using CSS viewport units combined with CSS comparison functions can reduce the need to alter things like font size, padding, margin, and the size of some elements.

.title {
  font-size: clamp(16px, (1rem + 5vw), 50px);
}

.hero {
  padding: clamp(2rem, 10vmax, 10rem) 1rem;
}

.sidebar {
  flex-basis: max(30vw, 150px);
}

Container Queries

Do you know that CSS container queries are now available behind a flag in Chrome Canary? With them, we can do so many things without using any media queries.

Consider the following example:

This is a responsive pagination that works based on its container width. No media queries are needed!

.wrapper {
  contain: layout inline-size;
}

@container (min-width: 250px) {
  .pagination {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .pagination li:not(:last-child) {
    margin-bottom: 0;
  }
}

@container (min-width: 500px) {
  .pagination {
    justify-content: center;
  }

  .pagination__item {
    display: block;
  }
}

Check out the demo on Chrome Canary.

This is just the start. As you have just seen, modern CSS allows us to create responsive layouts without even using media queries. So the question is, do we need to think that much about whether to choose mobile-first versus desktop-first?

I hope you enjoyed the article. Thanks for reading!