DEV Community

Cover image for Understanding CSS Media Queries
ng-conf
ng-conf

Posted on

Understanding CSS Media Queries

Jared Youtsey | ng-conf | Jul 2020

This is not intended to be a deep dive into media queries, but a primer to help understand some common way we use media queries as web-developers.

A media query is a bit of CSS that defines rules about when to apply a set of CSS definitions. It always starts with

@media

As web-devs we’re most concerned with the screen as our rendered output, so, almost always, we follow the @media with

screen

screen means that it applies to screen-based device like a phone, tablet, or computer screen. There are other options, but they are less-frequently used.

We would then usually append a query to the statement, so, we’ll end up with something like:

@media screen and ...

Queries, like all css, are applied in the order they are defined.

This is very important to understand, as we usually want to be doing “Mobile-First” development.

What is Mobile-First?

Mobile-First means that we define the layout rules in CSS for the smallest form-factor first (a phone in portrait mode). Then, we define queries to target devices as they get incrementally larger. We usually will have some SASS variables that map roughly to common device sizes.

Why don’t we have variables for specific devices? The rules would become impossible to write and maintain. Device resolution changes drastically from one phone to another.

Two very common queries we are likely to use are min-width and max-width.

Meaning of min-width and max-width

Screenshot of an information table. There are three columns and two rows plus the header row. The columns are labeled "Rule", "Meaning", and "Notes". The first row reads "min-width" under Rule, "greater than or equal to >=" under Meaning, and "Do not use with $*-max-width variables!" under Notes. The second row reads "max-width" under Rule, "less than or equal to <=" under Meaning, and "Do not use with $*-min-width variables!" under Notes.

SASS variables and queries to target ranges of devices.

Screenshot of an information table with 7 columns and 8 rows plus the header row. The columns are "Variable", "em", "px", "Query description: If you write the query below you will afftect the checked devices.", "Phone" which is spilt into two columns, "Tablet" which is slit into two columns, and "Desktop".

Media queries can be combined with and. For example, the following query will target only landscape phones (give or take a randomly sized phone/tablet).

@media screen and (min-width: $sm-min-width) and (max-width: $sm-max-width)

Demo

Here is a simple example where we will adapt the presentation of some buttons based on the size of the device they are rendered on.

<html>
  <!--
                                                                           Phone        Tablet       Desktop
    Variable        em        px          Query                            Port  Land   Port  Land
    ------------------------------------------------------------------------------------------------------------------
    By default you should not write any media query at all. So, the first   X     X   |  X     X   |    X
    CSS definitions in your CSS file will apply to all devices unless you             |            |
    have additional media queries defined afterward.                                  |            |
    ------------------------------------------------------------------------------------------------------------------
    $sm-min-width  35.5em    568px       min-width: 35.5em                        X   |  X     X   |    X
    ------------------------------------------------------------------------------------------------------------------
    $sm-max-width  47.999em  767.984px   max-width: 47.999em                X     X   |            |
    ------------------------------------------------------------------------------------------------------------------
    $md-min-width  48em      768px       min-width: 48em                              |  X     X   |    X
    ------------------------------------------------------------------------------------------------------------------
    $md-max-width  63.999em  1023.984px  max-width: 63.999em                X     X   |  X         |
    ------------------------------------------------------------------------------------------------------------------
    $lg-min-width  64em      1024px      min-width: 64em                              |        X   |    X
    ------------------------------------------------------------------------------------------------------------------
    $lg-max-width  79.999em  1279.984px  max-width: 79.999em                X     X   |  X     X   |
    ------------------------------------------------------------------------------------------------------------------
    $xl-min-width  80em      1280px      min-width: 80em                              |        X   |    X
    ------------------------------------------------------------------------------------------------------------------
    * CSS vars cannot be used in media queries. SASS variables do since they get compiled to concrete values.
    * There is some overlap at Phone/Tablet/Desktop boundaries due to the variances in device resolutions.
    * When using CSS do not use min/max-width, rather use min/max-device-width to account for varying scale factors.
    * Most SASS pre-processors will make min/max-width work correctly for the scale factor on the device (not sure how?!).
    Rule        Meaning                       Notes
    min-width   greater than or equal to >=   Do not use with $*-max-width variables!
    max-width   less than or equal to <=      Do not use with $*-min-width variables!
    * Save this HTML/CSS as media-queries.html and open it in Chrome.
    * Open Chrome Developer Tools
    * Click the Responsive button
    * Choose iPhone 6/7/8
      * Notice that the buttons are stacked, fab buttons and it is labeled as Phone Portrait.
    * Toggle to landscape rotation
      * Notice that the buttons are flexed to either end of the screen and it’s labeled Phone Landscape.
    * Choose iPad
      * Notice that the buttons are flexed to either end of the screen and now use text labels and it’s labeled Tablet Portrait.
    * Toggle to landscape rotation
      * Notice that the buttons are flexed to either end of the screen and use both fab icons and text labels and it’s labeled Tablet Landscape/Desktop.
    What’s really going on under the covers?
    * Lines 76-126 define the default styling, which we have dictated will be mobile-first.
      So these are the default styles for a phone in portrait mode.
    * Lines 131-145 define styling for anything at least as large as a phone in landscape mode.
      The only styles defined in this block are those that override what is defined in the
      mobile-first, portrait phone section. So, we would expect at all form factors above
      portrait phone that the buttons would be in a row, rather than a column.
    * Lines 150-163 define styling for anything at least as large as a tablet in portrait mode.
      Again, we only override styles that need to change. We hide the icon and now show text
      on the button. We also go to a rounded corner button rather than a fab button. There is
      no picture for this one because subsequent queries inherit from this one and then set
      additional styling. There is no view where this query applies and other that build on it do not.
    * Lines 170-184 define styling for ONLY a tablet in portrait mode.
      This block inherits from previous queries, i.e. showing text instead of the icon. But it
      overrides the borders and radius of the button to be much more round and pronounced.
      Subsequent queries will not inherit from this one because this one has both a min and max query.
    * Lines 190-204 define styling for anything tablet in landscape or larger.
      It inherits from all previous queries except block 170-184, which is scoped with a min + max query.
      It will show both the icon and the text.
      * What kind of borders will the buttons have?
      * What kind of layout will the buttons have?
   -->
  <head>
    <style>
      /*
       * MOBILE FIRST!
       * Which technically is the same as this media query:
       * @media screen and (min-width: 0em)
       * Which means "greater than or equal to 0em wide", or, "everything".
       */
      body {
        padding: 16px;
      }
      .button-container {
        display: flex;
        flex-direction: column;
        align-items: center;
      }
      .add-button,
      .delete-button {
        border-radius: 50%;
        width: 64px;
        height: 64px;
        font-size: 48px;
        color: white;
        margin-bottom: 16px;
      }
      .add-button {
        border: solid 1px darkgreen;
        background-color: forestgreen;
      }
      .delete-button {
        border: solid 1px maroon;
        background-color: red;
      }
      span.text {
        display: none;
        margin: 0 16px;
      }
      span.fab {
        display: inline-block;
        position: relative;
        top: -5px;
      }
      .phone-portrait,
      .phone-landscape,
      .tablet-portrait,
      .tablet-landscape {
        display: flex;
        justify-content: center;
        font-weight: bold;
        font-size: 24px;
      }
      .phone-portrait {
        font-size: 48px;
      }
      .phone-landscape,
      .tablet-portrait,
      .tablet-landscape {
        display: none;
      }

      /*
       * Phone Landscape or larger
       */
      @media screen and (min-device-width: 35.5em) {
        /* These settings add to or override those that come before */
        .button-container {
          flex-direction: row;
          justify-content: space-between;
        }
        .phone-landscape {
          display: flex;
        }
        .phone-portrait,
        .tablet-portrait,
        .tablet-landscape {
          display: none;
        }
      }

      /*
       * Tablet Portrait or larger
       */
      @media screen and (min-device-width: 48em) {
        .add-button,
        .delete-button {
          border-radius: 6px;
          width: unset;
          height: unset;
        }
        span.fab {
          display: none;
        }
        span.text {
          display: inline-block;
        }
      }

      /*
       * Tablet Portrait ONLY
       * Inherits from previous queries.
       * Subsequent queries will not inherit these values.
       */
      @media screen and (min-device-width: 48em) and (max-device-width: 63.999em) {
        .add-button,
        .delete-button {
          border-radius: 32px;
          border-width: 4px;
        }
        .tablet-portrait {
          display: flex;
        }
        .phone-portrait,
        .phone-landscape,
        .tablet-landscape {
          display: none;
        }
      }

      /*
       * Tablet Landscape or larger
       * Display both text and icon.
       */
      @media screen and (min-device-width: 64em) {
        span.fab {
          display: inline-block;
          margin-left: 16px;
          top: -3px;
        }
        .tablet-landscape {
          display: flex;
        }
        .phone-portrait,
        .phone-landscape,
        .tablet-portrait {
          display: none;
        }
      }
    </style>
  </head>
  <body>
    <div class="button-container">
      <button class="add-button">
        <span class="fab">+</span>
        <span class="text">Add</span>
      </button>
      <button class="delete-button">
        <span class="fab">x</span>
        <span class="text">Delete</span>
      </button>
    </div>
    <div class="phone-portrait">Phone Portrait</div>
    <div class="phone-landscape">Phone Landscape</div>
    <div class="tablet-portrait">Tablet Portrait</div>
    <div class="tablet-landscape">Tablet Landscape/Desktop</div>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode
css-media-queries.html hosted by GitHub

For the purposes of this example, we are using min/max-device-width instead of min/max-width since the example is in plain HTML/CSS.

If you are using Angular you can use min/max-width. I’m not sure what the SASS compilation process is doing or setting to make that work. Just know that where you see min/max-device-width in the sample HTML you can use min/max-width in Angular with compiled SASS. This may or may not be true with plain CSS in Angular, or other SASS compilers?

  • Save this HTML/CSS as media-queries.html and open it in Chrome.
  • Open Chrome Developer Tools
  • Click the Responsive button
  • Choose iPhone 6/7/8
  • Notice that the buttons are stacked fab buttons and it is labeled as Phone Portrait.
  • Toggle to landscape rotation
  • Notice that the buttons are flexed to either end of the screen and it’s labeled Phone Landscape.
  • Chose iPad
  • Notice that the buttons are flexed to either end of the screen and now use text labels and it is labeled Tablet Portrait.
  • Toggle to landscape rotation
  • Notice that the buttons are flexed to either end of the screen and use both fab icons and text labels and it is labeled Tablet Landscape/Desktop.

What’s really going on under the covers?

  • Lines 76–126 define the default styling, which we have dictated will be mobile-first. So these are the default styles for a phone in portrait mode.
Lines 76–126 Phone Portrait

Screenshot. The majority of the image is black. At the top it reads "iPhone 6/7/8, 375 x 667, 150%, Online". There are some dropdown menus and in the top right corner is a screen rotation icon. On the black background is a white screen. There is a green circle with a "+" icon stacked on top of a red circle with an "x" icon. They re both stacked over bold black text reading "Phone Portrait".

Lines 131–145 define styling for anything at least as large as a phone in landscape mode. The only styles defined in this block are those that override what is defined in the mobile-first, portrait phone section. So, we would expect at all form factors above portrait phone that the buttons would be in a row, rather than a column.

Lines 131–145 Phone Landscape

Screenshot similar to the one above. A white box on black background. The white space looks wider and reads "Phone Landscape" in black text. There is a green circle with a "+" icon in the left corner, a rec circle with a "x" symbol is in the right.

Lines 150–163 define styling for anything at least as large as a tablet in portrait mode. Again, we only override styles that need to change. We hide the icon and now show text on the button. We also go to a rounded corner button rather than a fab button. There is no picture for this one because subsequent queries inherit from this one and then set additional styling. There is no view where this query applies and other that build on it do not.

Lines 170–184 define styling for ONLY a tablet in portrait mode. This block inherits from previous queries, i.e. showing text instead of the icon. But it overrides the borders and radius of the button to be much more round and pronounced. Subsequent queries will not inherit from this one because this one has both a min and max query.

Lines 150–184 Tablet Portrait

Image for post

Lines 190–204 define styling for anything tablet in landscape or larger. It inherits from all previous queries except block 170–184, which is scoped with a min + max query. It will show both the icon and the text.

Test yourself!

  • What kind of borders will the buttons have?
  • What kind of layout will the buttons have?

As you can see media queries provide us with great power to adapt our presentation incrementally for effective mobile-first presentation. Of course media queries can be used to adapt presentation for other uses, such as print or even screen readers.

Image by Photoshot from Pixabay

*ng-conf: Join us for Reliable Web Summit *

Come learn from community members and leaders the best ways to build reliable web applications, write quality code, choose scalable architectures, and create effective automated tests. Powered by ng-conf, join us for the Reliable Web Summit this August 26th & 27th, 2021.
https://reliablewebsummit.com/

Top comments (0)