DEV Community

Cover image for You Probably Don't Need Media Queries Anymore
Kathryn Grayson Nanz
Kathryn Grayson Nanz

Posted on

You Probably Don't Need Media Queries Anymore

In Ye Olden Days of Webbe Development™️, if we wanted to create websites and applications that were responsive, it meant writing a series of media queries based around specific device breakpoints and re-working our content for each size (inb4 someone in the comments says the truly old days of web dev were table-based layouts – I remember them, and they sucked too). CSS frameworks stepped in to ease the device-breakpoint paint point – Bootstrap, Skeleton, etc. – because writing all of those was a lot of work! Slowly, we saw the best practices around writing media queries shift (by necessity) from device-based breakpoints to content-based breakpoints as more and more devices came out in all shapes and sizes. Now, with screens available in more or less any size you can imagine, it's time to shift our approach once again – the era of breakpoints is over and the era of fluid design is here. Rather than hitting a point and snapping to a new layout, our content should always be adjusting based on the amount of space available.

Thankfully, CSS has also come a long way since then as well, but a lot of us got used to just throwing in a media query or five to make things responsive, and never quite broke the habit. Now that we have modern CSS features like grid, flexbox, vh, vw, calc, clamp, min, max, aspect-ratio, and more, it's time to ditch the media queries. In this article, we're going to start at the top and work our way down from the big-picture display formatting all the way to the smallest units. And as for your old stylesheets...we can refactor. We have the technology.

The Big Picture: Grid and Flexbox

Let's start with some of the most popular responsive display options, grid and flexbox. They've been around for a minute, with grid hitting full browser support in 2017 and flexbox in 2013, but a lot of folks still don't fully understand the difference between them, or when they should use one or the other (or both!). Many people assume a false equivalency between the two that can create a misguided either/or approach to choosing a tool – when in reality they not only have very different use cases, but also can (and should) be used together to compliment each other!

For our purposes, though, let's focus on how they work and how you can use them to handle the layout of elements on your page in a way that allows for natural wrapping and responsive adjustment without the use of media queries.

Grid

grid is primarily focused on, well, creating a grid with multiple rows and columns that you can populate with elements. You do this by creating a container <grid> element which you then fill with child elements. There's a great number of customizations you can make to the grid rows, columns, and cells, which allows you to create grids as simple or complex as you can imagine.

But for our goal of creating simple, responsive designs, let's take a look at the most relevant features. Grid comes with the ability to repeat columns or rows automatically, as well as auto-fit which will automatically size your columns into the available space. For example, the code below:

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

-------- 

<div class="grid">
  <div></div>
  <div></div>
  <div></div>
</div>
Enter fullscreen mode Exit fullscreen mode

In this situation, the grid will turn your content into columns which naturally fit in the space you have, with each column having a min width of at least 300px and a max width of no more than 1fr. The 1fr is a new CSS unit that stands for fraction, which tells the browser to divide the space evenly and give each column one fraction of that space. In this case, it will create three equal columns that each take up 1/3 of the available space, but never get smaller than 300px. Were we to add another div, or take one away, the grid would automatically handle the calculation and adjust the display. And if the screen is too small to fit all the columns side by side at the same time, it will automatically wrap the remaining columns down to the next row.

If you're looking to create a more complex layout using grid, here are a few of my favorite reference resources:

  • A Complete Guide to Grid, which offers a fantastic breakdown of all the ways you can customize your grid – including creating columns of varying widths, setting template areas, setting the gap between grid cells, and so much more.
  • Grid By Example is my favorite place to start when I'm looking for a jumping-off point on creating a new grid structure.
  • And if you're looking for a real-world example of a more complex grid, check out the frame.scss file in the kendo-demo app, where CSS grid was used extensively to create the menu frame that's used on every page.

Flexbox

flexbox takes a similar (but not quite the same) approach in helping you lay out your elements on the page and adjust them automatically as needed. Rather than creating a full grid with multiple rows and columns, however, flexbox is about the positioning of child elements relative to each other within the parent element. Basically: if you need to work in two directions at once (rows and columns) look at grid. If you need to focus on one direction (a single row or column), this is where you'll want flexbox.

Again, there's a lot to look at in terms of when to use each one and what the differences of application are, but let's leave that to the other article. For now, let's focus on how flexbox handles responsiveness for you, so you can delete that unnecessary media query.

The main point of interest for this is the flex-wrap property. Flex will start by attempting to fit everything you've written into one row or column, but if that isn't going to work, you can tell flex to allow wrapping by setting flex-wrap to wrap. If flex-wrap isn't specified, flex will squish the elements to keep them all on the same line (if no min-width is specified for the child elements), or allow them to overflow out of view (if a min-width is specified).

.flex {
  display: flex;
  flex-wrap: wrap;
}

.flex > div {
    width: 300px
}

-------- 

<div class="flex">
  <div></div>
  <div></div>
  <div></div>
</div>
Enter fullscreen mode Exit fullscreen mode

Basically, with both grid and flex, you just have to decide whether you want your content to squish or wrap, and then set the properties accordingly! Both are good tools to have in your toolbox for creating responsive UIs.

If you're looking for some resources to master Flexbox, here are a few of my favorites:

  • Flexbox Froggy: a fun game to help you master what all the different properties do using some adorable frog illustrations.
  • FLEX: a simple, visual cheatsheet for you to reference as you work!

Middle of the Road: CSS Properties

Once we've got our general layout in place, it's time to set some specific properties on our elements – and good news, no media queries needed here either!

aspect-ratio

Did you know that there's a CSS property specifically designed for aspect ratios? This is especially great if you're dealing with video or big hero images, where keeping the correct aspect ratio is very important. There's a fantastic deep dive on CSS Tricks, but in general, it's pretty easy to apply – all you need is that one line:

  .video-wrapper { aspect-ratio: 16/9; }
Enter fullscreen mode Exit fullscreen mode

If you set a specific width value along with aspect-ratio, then it will use that as a basis and automatically generate the height value to match (or vice-versa). However, if you declare both a width and a height, it will honor those over the aspect-ratio, so be careful!

min-height, max-height, min-width, and max-width

Although min and max height and width properties can often be replaced in many use cases with the clamp() function (which we'll look at in the next section), these are still valid CSS and good to have in your pocket. They're also easy, since they pretty much do exactly what they say on the tin:

.img {
  width: 100%; 
  max-width: 50%;
  min-width: 200px; 
}
Enter fullscreen mode Exit fullscreen mode

Here, we have an image that we're telling first and foremost to take up as much space as it has available, up to the max-width so that we default to the largest image size possible. Then, we're giving it some guide rails – we don't want it to take up more than half the container, but we also want to make sure it's still larger than a postage stamp, so we also don't want it smaller than 200px wide. In this case, we set an absolute value only on the small end, because we know exactly how small the image can get before it becomes unrecognizable. Now, no matter how the browser is resized, we know our image will always be as big as it can be...without being either ridiculously giant, or unreadably small.

Fully Functional: Math Functions

The math functions are a newer addition to CSS, and incredibly powerful. They fill a void that CSS developers had complained over for ages – the ability to compute values within stylesheets and set ranges for properties. The sooner you can master them and put them to use in your code, the more you'll benefit!

clamp()

clamp() allows us to set a base value for a property, along with upper and lower caps to contain it as it adjusts. This is one of our best tools to ditch the media queries, as it allows us to set those responsive limits without needing to define specific breakpoints to do so. Here's how it works:

.img {
  /* the format is `clamp(min value, base value, max value)` */ 
  width: clamp(200px, 100%, 50%);
}
Enter fullscreen mode Exit fullscreen mode

Here's an updated version of our last example – the image with the min and max widths. Only here, we're doing it in one line using clamp() by telling the image to take up 100% of the available space, but never larger than half the container size, or smaller than 200px wide.

calc()

If you've ever looked at CSS and wished it had more math, calc() is for you. It allows us to do simple arithmetic with CSS units, right in the stylesheet. This is great for when you need to base something off a unit that's not absolute. You can also use CSS variables in your computations, for extra flexibility! Let's say we want to create columns that are evenly divided based on the current width of the browser:

.child { width: calc(100vw / 3); }
Enter fullscreen mode Exit fullscreen mode

Setting 1/3 widths is difficult using percentage units because of the whole .333 repeating situation – but now, we can just say "You know what, CSS – you handle it!" Here, we take the full window width, divide it by three, and set that as the width property of the child element.

min() and max()

If you're a fan of having your stylesheets handle as many decisions for you as possible, enter min() and max(). They work similarly to clamp(), but rather than setting a range in both directions, it focuses on just one at a time, allowing us to set the smallest (or largest) value depending on how the math works out. Again, this is a super useful tool for handling non-fixed values, which is one of those things you have to do a lot when creating something responsive.

.img1 { width: min(30%, 200px) }

.img2 { width: max(50vh, 800px) }
Enter fullscreen mode Exit fullscreen mode

In this case, we're setting the widths for two different images – one we'd like to keep small, and one we'd like to be large. min() will evaluate whether 200px is greater or lesser than 30% of the current container and choose whichever value is the smallest. max() will make the same comparison between 50vh and 800px and automatically go with the larger.

All the Small Things: CSS Units

It's all well and good to think about things from a birds-eye view, the way we need to when laying out the elements on our page, but we also can't forget about the little guys – the units that specify size for our various properties. When we set everything in hard units, like pixels, we have to go in and adjust it manually each time we need to resize it. But when we work in responsive units, we can let them do the work for us!

vw and vh

Two of my favorite and most used responsive CSS units are vh and vw – viewport width and viewport height. Although there's no percentage sign, vh and vw are really a type of percentage-based measurement – 1vw is 1% of the viewport width.

Gone are the days when viewport measurements had to be obtained via window.innerWidth and window.innerLength (again, dark times); we can now get them automatically in our stylesheets. They'll also automatically update as a user resizes the window, so no hoops to jump through there, either. vh is especially useful for those times when you want to center something vertically, or stick something to the bottom of the viewport. So to create a container element that's always the exact height and width of the user's current browser, all you need is:

.page-wrapper {
   height: 100vh; 
   width: 100vh; 
}
Enter fullscreen mode Exit fullscreen mode

rem and em

If you're still defining font sizes in pixels, let me introduce you to the beauty of rem and em units. The name em actually comes from old typographic standards of measurement, based around the width of the letter M in the font (which is also where the words em-dash and en-dash come from – dashes equal to the width of the M or N characters). em units are a way of defining your font sizes relative to the font size of the parent element. So, you could do something like:

.h2 { font-size: 2.5em } 
Enter fullscreen mode Exit fullscreen mode

And that would set your h2 headers to 2.5 times the size of the body font in the parent element.

rem, on the other hand, allows you to declare your font size relative to the root font size of the entire page. In fact, that's what the R stands for – root em. Both rem and em work in the same way, the difference is what they're using as the base size and scaling based upon. In general, I lean towards rem over em because I like the consistency it creates, but if you're looking to create a specific design in one area that differs from the overall style, em will be what you want to reach for.

If you're looking for a neat trick, you can combine vw with rem and clamp() to create a fluid typography system for your application:

p { font-size: clamp(1rem, 2.5vw, 2rem); }
Enter fullscreen mode Exit fullscreen mode

Here, we set the base font size to 2.5vw (remembering that 1vw is equal to 1% of the viewport width), and then set min and max values on either side to ensure that you don't end up in either a situation where the text becomes unreadably small or a situation where the text just keeps getting bigger.

Percentages

And, last but certainly not least, the humble percentage unit. If you're going to be setting widths by hand for any reason (as opposed to using a layout tool like grid or flex), you'll almost certainly want to reach for the % instead of any absolute measurement unit.

.container { width: 25%; }
Enter fullscreen mode Exit fullscreen mode

This probably isn't one you really needed an example on, but just in case – here we have an element that we're setting to be 1/4 the width of its parent. As the parent width changes, this element will automatically adjust as well. It's simple, yes, but foundational for building responsive UIs.

Conclusion

If you're still relying primarily on media queries to ensure your site or app is fully responsive, it might be time to take a look at everything CSS has to offer and see if you can swap some of those old-fashioned breakpoints out for some of these new, fluid approaches to styling. Working to create a fully fluid layout means less drastic changes for your user when they move between mobile and desktop, as well as less maintenance work for you – no more updating every breakpoint whenever there's a change to the design. Leverage these adaptive approaches to styling, and get ready to go with the flow!

Discussion (32)

Collapse
jfbrennan profile image
Jordan Brennan

You've compelled me to repent for ignoring clamp. Anxious now to refactor some stuff, thanks!

Collapse
vdsmartin profile image
Martin Vandersteen

Doesn't work on all browsers yet sadly :( But super useful

Collapse
kathryngrayson profile image
Kathryn Grayson Nanz Author • Edited on

Actually, clamp has full modern browser support currently! caniuse.com/css-math-functions

There are still a few weird ones that don't support, but in general these are safe to use for the vast majority of your users!

Thread Thread
vdsmartin profile image
Martin Vandersteen

Lots of my clients still use Safari 13 so.. yeah :( If you don't need to handle that then it's great indeed!

Thread Thread
kathryngrayson profile image
Kathryn Grayson Nanz Author

Ahh, bummer! ☹️ But good that you have that kind of data about your userbase and can accommodate them! That's the most important part.

Thread Thread
jfbrennan profile image
Jordan Brennan

Looks like Safari 13.1 and above though. 13.1 should be really widespread by now…

Thread Thread
mtrantalainen profile image
Mikko Rantalainen

Sadly, many iOS devices last longer than Apple support and many older iOS devices are stuck with iOS 12.x. To make matters worse, iOS says that "the device has latest updates" in settings, when the real status would be "your device is no longer supported and should but be used to interface with internet".

Collapse
facundocorradini profile image
Facundo Corradini

Great article! Intrinsic sizing is awesome, and definitely a better approach for most use-cases.

Nowadays the main use for media queries is when you need to completely change how an element works. For instance, switch your navigation to a hamburger menu on mobile.

Also, there's much more to media queries than just screen sizes. Things like user preferences (reduced motion, color scheme, etc) are relatively new additions that takes a great role for accessibility. And a whole bunch of awesome new stuff is coming right up ;)

We need media queries more than ever, just not for sizing

Collapse
kathryngrayson profile image
Kathryn Grayson Nanz Author

This is a super fair point!! I was laser-focused on the responsiveness use case when writing this article, but user preferences and accessibility are really good examples of where media queries still shine. Thank you for adding this comment 😊

Collapse
ortonomy profile image
🅖🅡🅔🅖🅞🅡🅨 🅞🅡🅣🅞🅝 • Edited on

Nice article - clamp is the single biggest tool to use in the box here. I find working with grids a pain in the butt, compared to flex.

However...

This is not against you, so please don't take it as a personal criticism. Because everyone makes this mistake. But people who write about CSS really gotta stop writing this nonsense about EMs and REMs.

EMs are a nightmare to work with specifically because they are a proportion of their parent element and in the simple example, it's too much to really have to comprehend when writing clean styles

<div style="font-size: 20px;">
  <div style="font-size: 50%;">
    <div style="font-size: 200%">
       <p>bizarrely, I'm 20px in size</p>
    </div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

So you revert to REM? But REM is literally bound to a root value, (usually 16px as default, commonly reset to 10px by :root { font-size: 62.5% }.)

This nonsense about 'herp, derp, are you still using pixel sizes' -- well, newsflash, using REM is just the same as using an explicty pixel size as far as I can tell. You just write it in a different format.

The REAL reason for using REM is to tie to your measurements to a single base size in a way that means a change to the root size would cause your UI to scale nicely in a proportional way.

Collapse
ludanjubara profile image
Mihael Šestak

I would like to hint you that making your font-size explicitly with 'px' values and not say REMs or EMs would make your user's browser typography preference overruled. Meaning that there would be no scaling of your font-sizes if the user chose to do so in the browser settings. So, it's always better to use resizible units like REMs unless you want something to have the same font size no matter the user's preference.

Collapse
ortonomy profile image
Comment marked as low quality/non-constructive by the community. View Code of Conduct
🅖🅡🅔🅖🅞🅡🅨 🅞🅡🅣🅞🅝

What did you not get about:

The REAL reason for using REM is to tie to your measurements to a single base size in a way that means a change to the root size would cause your UI to scale nicely in a proportional way.

EMs are just recipes for disaster.

Thread Thread
ludanjubara profile image
Mihael Šestak

Your original comment makes little sense to me then. Why make an obvious point about the difference between EM and REM when the author quite literraly stated the fact that EMs should generally be avoided and REMs should be used instead. You then go on about saying REMs and PX values are just the same..when in reality they aren't, simply 'couse of the fact that REMs are scalable and PX are not. They are only the same when looked at from coding perspective...not to the browser and users who alter their settings only to find out, to their dissapointment, that the UI hasn't changed. I'd kindly advise you to edit your comment accordingly and not to restate what author had already stated in the blog b'couse it leads to unnecessary confusion for the readers.
Ty and wish u successful coding. Sry for the long comment :/

Collapse
murkrage profile image
Mike Ekkel

This nonsense about 'herp, derp, are you still using pixel sizes' -- well, newsflash, using REM is just the same as using an explicty pixel size as far as I can tell. You just write it in a different format.

This is only true if you set the base value to be a pixel value. Ideally you wouldn’t touch it and allow the user to decide the base size. This is 16px by default but fully depends on the size of the text a user has selected.

This is great because larger text requires more whitespace, which is exactly why you would use REM for spacing as well because it scales with the font size of the user!

The mistake developers make is setting the base REM value to be a hardcoded value.

Collapse
tracygjg profile image
TGJ Gilmore • Edited on

This article makes many valuable points but one place I think media queries retain a role is in the detection of pixel density. Relying on screen dimensions alone is not always sufficient to identify the most appropriate screen presentation.

Collapse
kathryngrayson profile image
Kathryn Grayson Nanz Author

That's a very fair point! I think there are still specific use cases where you might want media queries - but in general I think they shouldn't be the first thing we reach for anymore.

I'm not a fan of all-or-nothing approaches, which is why this article is called "You Probably Don't Need Media Queries" and not "Stop Using Useless Media Queries Immediately!!!" Only a Sith deal in absolutes 😉 There are exceptions to every rule, so I agree it's unwise to throw out a tool entirely.

Collapse
adam_cyclones profile image
Adam Crockett

In 5 - 10 years we can probably do as you say, that's nice, honestly media query will still have a place also they aren't just for screen size, print, accessibility etc to name just a few purposes. Still exciting ☺️

Collapse
animald profile image
animald

No mention of container queries?

Collapse
kathryngrayson profile image
Kathryn Grayson Nanz Author

Container queries are cool, but still experimental and not widely supported yet: caniuse.com/css-container-queries ☹️

In this article, I wanted to focus on code folks could put to use right away. But I do think these are something to keep an eye on, for sure!

Collapse
animald profile image
animald

Oh sure, but they're set to be a game-changer. Thought it was worth a mention is all :).

Collapse
adam_cyclones profile image
Adam Crockett

It's been a long... Long long long long time in the waiting

Collapse
ratherwetstag profile image
Gareth Stewart

This is a good summary of how to responsively position website elements ... but remember that designing for multiple devices (or 'sizes') isn't just about the position of text and images, but also how content is edited: how much text is shown, and how images and videos are presented. A mobile website is not just a desktop site squeezed into a smaller form factor, and vice versa. Maybe that's a different article ...

Collapse
kathryngrayson profile image
Kathryn Grayson Nanz Author

Agreed!! Creating a truly responsive layout is a blend between design and development. In this article, I chose to focus exclusively on the development and technical angle, but maybe you're right and there needs to be a part 2 looking at the UX side of the problem!

Collapse
robyyo profile image
Rob • Edited on

This is a really great article. Well written in easy to understand language. I agree with Jordan Brennan, I've purposely never bothered to learn clamp(). My mistake, it's a great utility. Thanks for explaining the subject so clearly.

Collapse
mrkumar44 profile image
Manoj Kumar

I read this article the other day and it made for an engrossing read. A terrific article actually.

The migration from using media queries to some or all of the things above makes sense.

As it stands, there will be many developers who will be reluctant to jump ship instantly as many are still quite at home with the classic RWD approach using media queries.

I would love to see a video where a developer hand codes (from scratch) the same website layout, one using media queries and the other using lot of whats shown and mentioned in this article. and timing the whole thing. I'd be intrigued to see which one takes the longest.

Collapse
chuniversiteit profile image
Chun Fei Lung

I guess it’s time for me to throw away some code. 🥲

Collapse
yodasoda profile image
Jan Claasen

If you into clamp or not keen of the extra mental load of using clamp then check out github.com/bglw/postcss-fluidvars
It's a simple postcss package that takes your design max and min and applies fluid styles to it via css variables. For example "font-size: var(--s-18-32)" gives you a fluid font size between 18px and 32px for your design min and Max.

Collapse
spock123 profile image
Lars Rye Jeppesen

Haha I also ignored clamp for a long time. Thanks

Collapse
banjer71 profile image
Davide Naccarati

Wow, thanks fot this, I will have a go with all these techniques in my next side projects.

Collapse
bryan_j_myers profile image
Bryan Joseph Myers • Edited on

I like everything you said. 100% agree with the advice given. What I find a little obfuscated is the scope of your article. Which, I saw you replied to on a user comment.

Let's start here...

HTML table layout design is a plague upon the earth that may never die... email. Need I say more? (Pretty sure the "e" stands for "evil", not "electronic". :))

Okay... so let's say the scope of your article is limited to web browsers.

Some solutions don't include Chinese based, government controlled, device configurations. Aka... all of China.

Okay... so let's say the scope of your article is limited to web browsers outside of China.

Some of the solutions you provide do not work on all device configurations. Say safari browsers... mobile browsers.

The articles scope is now limited to web browsers outside of China that aren't safari mobile browsers.

The point? You're right! There "probably" are use cases that "don't need media queries". There may be workflows that could be explored for some of the use case solutions you have provided. But ultimately userbase will control scope and best practices. i.e. technology; demographic; device configuration and compatibility.

My advice? Don't let being "easy" make your solution less "complete". Define your scope before your technology. ;)

Thank you for the wonderful read. I have a feeling I could talk a lot of "shop" with you.

Collapse
kathryngrayson profile image
Kathryn Grayson Nanz Author

I do see your point here, but in general, I think the responsibility for deciding what technologies work or don't work for a specific use case are ultimately up to the developer and not the author.

I did (as you noted) make sure to say "probably" or "often" and not "definitely" and always", because there's always something that won't work for someone, haha. I also tried to use the article tags to specify audience (you'll see it's tagged with #webdev, in line with your first point), and only include CSS features with mainline browser support (the 2-3 most recent versions of Chrome, FF, Edge, and Safari). In general, that means the percentage of folks who can use these will be high – but of course, never 100%. As someone who was an email dev for many years, I can tell you that most email devs know the state of the landscape pretty darn well, and wouldn't look at an article like this and assume that it would work in their context. I'm sure the same goes for devs who know their userbase has other limitations that inform their tech usage. I'll also throw out there that not everything listed in the article has the same level of browser support – someone who can't use the math functions may yet read this article and learn about vw or rem and be able to put those to use.

But, in the end, you're right – an informed decision can only be made by the developer who has the full context on the project. My hope with this post was just to prompt people to reconsider what they might have been doing purely out of habit, and possibly introduce them to a new bit of CSS they hadn't tried before.

And thank you for leaving a comment! I think the comments section is a great place for folks to call out and hash out these kinds of edge cases, so other newer devs who read the article can learn a little more about the process of making these kinds of informed choices about technology usage.

Some comments have been hidden by the post's author - find out more