CSS Media Queries
The CSS language (“Cascading Style Sheets”) is the basic framework for the development of modern websites – alongside HTML and JavaScript. CSS is a programming language, but it doesn’t describe the individual steps you take to solve a problem. Instead, a goal is defined that is to be achieved. This makes CSS a declarative language, similar to SQL.
Part of CSS are the so-called media queries, which query the properties of an output device. They are used for responsive web design. So how exactly does this work?
- Simple registration
- Premium TLDs at great prices
- 24/7 personal consultant included
- Free privacy protection for eligible domains
What are CSS Media Queries?
CSS Media Queries were introduced alongside the rollout of CSS3 specification. A media query binds the assignment of CSS properties of an element to one or more conditions of a medium. In the simplest form, a distinction is made between the medium on which information is presented – for example, on a screen, the printed page (PDF), or as a text readout:
Medium | Explanation |
---|---|
all | Any output medium |
screen | Presentation of website content on a scrolling screen |
Presentation of website content on several pages with fixed dimensions | |
speech | Reading of website content using a speech synthesizer |
A CSS Media Query is defined within a CSS code block using a special “@ media” rule. The CSS selectors and rules contained therein are only activated under the specified condition. That means you can hide non-displayable elements when printing a page:
/* Hide non-displayable elements */
@media print {
video, audio {
display: none;
}
}
In addition to the medium used, CSS Media Queries can be used to query specific properties of the respective medium. CSS Media Queries therefore are a central technical feature enabling responsive web design in the first place.
CSS Media Queries as central control element for responsive web design
Responsive web design aims to adapt a website as optimally as possible to the device it’s viewed on. Media queries are used to query various properties of the displaying device, so-called media features. This makes it possible to set style rules for different screen dimensions. Further, optimized style rules can be defined if a mobile device is tilted.
Here is an overview of the media features most used for responsive design:
Media Feature | Explanation |
---|---|
width | Query width of the screen in pixels |
height | Query height of the screen in pixels |
orientation | Detect screen orientation portrait/landscape |
resolution | Detect available screen resolution |
Let’s look at a few examples. Imagine the main headline for a website. In HTML this is denoted as “h1”. First, we define the style rules for the h1 element regardless of the device displaying it:
h1 {
font-size: 24px;
line-height: 1.25;
}
Next, we define a media query that queries the width of the screen. Within the query, we define the style rules that should apply to the heading according to the width. In the example below, we want to increase the font size of the h1 heading on screens that are at least 1,024 pixels wide:
@media screen and (min-width: 1024px) {
h1 {
font-size: 36px;
}
}
Note that we are only adjusting the “font-size” property of the h1 heading. The line spacing is defined as a relative unit using the “line-height” property and is – as it is not explicitly overwritten – inherited. In this example, the line spacing of the h1 element in the basic state is 24px * 1.25 = 30px. On screens with a width of 1,024 pixels or more the line spacing is proportionally 36px * 1.25 = 45px.
In “CSS”, the mixing of existing and newly defined style rules is expressed by the word “cascading”: an element inherits style rules from parent elements or general rules that have been pre-defined. Usually, you define the basic properties of the elements and then selectively overwrite properties under certain conditions.
Let’s look at another example. Imagine we want to display three elements in a container. The elements should be displayed one below the other on the screen of a mobile device when the device is held upright. When tilting the device to landscape format, the layout should switch so that the elements are displayed side by side. With the Flexbox Layout module and a CSS Media Query, which asks for the alignment of the device, the layout can be implemented with a few lines of HTML and CSS. First, we define the container and the elements it contains in HTML:
<div class="container">
<div class="element">…</div>
<div class="element">…</div>
<div class="element">…</div>
</div>
We also set the following CSS rules. We set the “display: flex” property in the container and conditionally adjust the “flex-direction” property for it via a CSS Media Query. If the device is held in landscape format, the elements are displayed in a row next to each other. When used in portrait format, the elements are arranged one below the other in a line:
.container {
display: flex;
}
/* Landscape format */
@media screen and (orientation: landscape) {
.container {
flex-direction: row;
}
}
/* Horizontal format */
@media screen and (orientation: portrait) {
.container {
flex-direction: column;
}
}
In addition to the screen dimensions and alignment of the device, we can also query the physical resolution of the screen via a media query. This is of particular interest for displaying pixelated images. As an example, imagine a logo available in two versions – one optimized for low and one for high resolution screens. A simple trick for showing the appropriate logo for each is to put both variants on the page. We use CSS Media Query to query the resolution of the screen and hide the version that is not required using “display: none”. The following code shows what that may look like in HTML and CSS code:
<!--—Image in high resolution ---->
<img class="logo--high-res" src="/img/logo-high-res.png" alt="Logo in high resolution">
<!--—Image in low resolution ---->
<img class="logo--low-res" src="/img/logo-low-res.png" alt="Logo in low resolution">
/* Hide high resolution image on low resolution screen */
@media (max-resolution: 149dpi) {
.logo--high-res {
display: none;
}
}
/* Hide low resolution image on high resolution screen */
@media (min-resolution: 150dpi) {
.logo--low-res {
display: none;
}
}
Explore more options to display images in a responsive manner in our article on responsive web design
Activate variable viewport for responsive design
Previously, we’ve spoken of the “screen” in connection with the available width of the output medium. This is conceptually correct, but technically not entirely so. The browser operates internally with the concept of the “viewport”. For the width of the viewport to correspond to the width of the screen, a “meta-viewport” specification is required in the “<head>” of the HTML document. Without this information, the page will display the same on mobile as on desktop devices, only greatly reduced in overall size.
<head>
<!—Activate CSS Media Queries -->
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
Understand CSS units for responsive web design
With responsive web design, the elements should adapt to the existing screen. Often, this is a question of defining the dimensions of the elements under different conditions. The CSS specification defines a variety of units; the simplest unit being the pixel. For example, a 1080p image has dimensions of 1,920 pixels wide by 1,080 pixels high.
The pixel is an absolute unit and by definition does not adapt to the available space. Let’s look at an example of why this can be problematic. Say a web page contains an image that is 1,920 pixels wide. If we set the image width to this value using CSS, the display may be disrupted on small screens. The image will spill beyond the available space.
Below, we define an image in HTML with the “<img>” tag:
<img class="img-1080p" src="/image-1080p.png">
We use CSS to fix the width to 1,920 pixels:
.img-1080p {
width: 1920px;
}
In this scenario, it would be better to use a relative unit instead of pixels. As of the early days of table-based layouts, CSS uses percentage as a relative unit. If we set the width of the image to “100%” with CSS, the image adapts fluidly to the available space. This works because percentages always refer to the enclosing element.
img {
width: 100%;
}
We are now closer to our goal of adapting the width of an image to the available space. However, we have created a new problem: on a screen that is wider than 1,920 pixels, the image is displayed enlarged and thus pixelated. Therefore, we must also limit the maximum width of the image to its actual pixel dimensions:
.img-1080p {
/* implicitly inherited from `img` */
/* width: 100%; */
max-width: 1920px;
}
In addition to pixels and percentages, CSS understands a few other units. The relative units em, rem and vw, vh are useful for responsive design. The table below gives a quick overview of common CSS units for responsive design:
CSS unit | Usage |
---|---|
Rem | Font size of body text, “max-width” of layout elements; “width” of elements |
% | “width” of images and layout elements, possibly limited by “max-width” |
vw, vh | Font size of headings, hero texts, dimensions of screen-filling elements |
Em | Define breakpoints, “max-width” of layout elements |
Px | Define breakpoints, “max-width” of images |
Understanding advanced media queries
In addition to simple media queries, complex CSS Media Queries can be written. The logical operators “and”, “or”, and “not” are useful to this end. Here is an example of a complex query:
@media screen and (min-width: 30em) and (orientation: landscape) { /* … */ }
In addition to established media features that can be queried via CSS Media Query, several interesting features are planned for future versions of CSS. For example, the “CSS Media Queries Level 5” (CSS5) specification includes the following new query options (among others):
Media Feature | Explanation |
---|---|
light-level | Detect ambient brightness |
prefers-color-scheme | Choose a light or dark color scheme |
prefers-contrast | Select high-contrast mode |
With the launch of CSS5, the addition of container queries is expected. Using these, it will be possible to link element style rules to the properties of the container surrounding them for the first time. This means that the container queries contrast the CSS Media Queries, which query global properties of the device being displayed. The use of container queries will allow the handling of special cases for which JavaScript or complex media queries were previously used.
Understanding CSS breakpoints
In connection with responsive web design and CSS Media Queries, “breakpoints” are often used. A breakpoint is a defined screen width for which a set of CSS rules is activated as defined by a CSS Media Query. You can visualize the breakpoints on a website by opening the developer tools in the browser. If the responsive view is active, the breakpoints are displayed as colored bars above the actual website.
Understanding mobile-first, CSS processors, and CSS utility frameworks
One recognized best practice of responsive web design is the mobile-first approach. When web design and development follow this approach, the style specifications for the smallest screens are set first. These definitions form the backbone of the design. Based on this, several breakpoints are set for successively increasing screen sizes. New style rules for elements are selectively defined within the breakpoints, thereby overwriting the existing rules for smaller screens.
The mobile-first approach is easy to understand by looking at the CSS utility framework “Tachyons”. This defines three breakpoints by default: “not-small”, “medium”, and “large”:
/* Tachyons breakpoints */
/* 'not-small' breakpoint */
@media screen and (min-width: 30em) { /* … */ }
/* 'medium' breakpoint */
@media screen and (min-width: 30em) and (max-width: 60em) { /* … */ }
/* 'large' breakpoint */
@media screen and (min-width: 60em) { /* … */ }
Note that following the mobile-first approach, there is no separate “small” breakpoint. Details for small devices are simply defined without a breakpoint.
Tachyons breakpoint | Explanation |
---|---|
not-small | Includes the screen widths of the breakpoints “medium” and “large” |
medium | Covers the screen widths between the breakpoints “not-small” and “large” |
large | Includes large screens only |
Style rules for elements are defined within the breakpoints and their display is adapted to various screen sizes. You may notice that the centralization of the CSS codebase of a web project is problematic. It’s usually preferable to collect all of an element’s CSS properties in a separate file.
- Easily get your business online
- Integrated online booking tools
- Professional templates & 17,000 stock images
Understanding CSS pre- and post-processors
To modularize the CSS code of a project, various CSS pre-processors were initially used. You may already be familiar with the languages Sass, Less, or Stylus. With Node.js project PostCSS, a CSS post-processor was added later on. All technologies mentioned allow CSS Media Queries to be encapsulated below a CSS selector. In this way, the style rules of an element can be defined collectively for all media conditions. Here is an example using a stylus:
Stylus file “text.styl” for text properties:
// Mobile-first definitions
p
font-size: 16px
// Definitions for 'not-small' breakpoint
@media screen and (min-width: 30em)
font-size: 18px
Stylus file 'link.styl' for link properties:
// Mobile-first definitions
a
color: blue
// Definitions for 'not-small' breakpoint
@media screen and (min-width: 30em)
text-decoration: underline
The stylus pre-processor translates the files into CSS and collects the indented CSS Media Query rules in a single breakpoint. The stylus code shown is translated to the following CSS code:
/* Mobile-first definitions */
p {
font-size: 16px;
}
a {
color: blue;
}
/* Definitions for 'not-small' breakpoint */
@media screen and (min-width: 30em) {
p {
font-size: 18px;
}
a {
text-decoration: underline;
}
}
Understanding CSS utility frameworks
Encapsulating CSS Media Queries within the style rules of an element and processing them using a CSS processor works, but it forces the developer to switch back and forth between HTML and CSS. They also need to assign unique class names to the elements in HTML. It leads to undesirable complexity. This is where the CSS utility frameworks come in.
A CSS utility framework links atomic CSS properties with breakpoints. The resulting CSS classes can be assigned to any element in HTML. This makes it possible to define responsive layouts and components in HTML only, without having to write CSS code. The use of a CSS utility framework allows rapid prototyping and is ideal for developing components. Therefore, CSS utility frameworks are often used in conjunction with component-oriented technologies such as React and Vue.
Let’s consider another example borrowed from Tachyon's CSS utility framework. Look at the following CSS code. First, we define the classes “mw1” to “mw3”, which limit the maximum width of any element to values between “1rem” and “3rem”. Furthermore, within the already introduced breakpoints “medium” and “large”, we define corresponding CSS classes whose names contain the abbreviated breakpoints:
/* Tachyons */
/* Mobile-first size */
.mw1 { max-width: 1rem; }
.mw2 { max-width: 2rem; }
.mw3 { max-width: 3rem; }
/* 'medium' breakpoint */
@media screen and (min-width: 30em) and (max-width: 60em) {
.mw1-m { max-width: 1rem; }
.mw2-m { max-width: 2rem; }
.mw3-m { max-width: 3rem; }
}
/* 'large' breakpoint */
@media screen and (min-width: 60em) {
.mw1-l { max-width: 1rem; }
.mw2-l { max-width: 2rem; }
.mw3-l { max-width: 3rem; }
}
Using these CSS classes, we can write responsive elements entirely in HTML. The following HTML code snippet defines an image that has a maximum width of “1rem” on small screens. The image automatically adapts to the available screen width. On medium-sized screens the element takes up a maximum of “2rem”, on large screens a maximum of “3rem”.
<img class="mw1 mw2-m mw3-l" src="/image.png" alt="A responsive image">
CSS utility frameworks define many atomic classes, with each class specifying only one CSS property. In addition to the dimensions of an element, this includes information on typography, color, and all other conceivable properties. For each atomic property, a CSS utility framework contains classes for each defined breakpoint. By combining several classes, almost any responsive elements can be put together.
The Tachyons framework is now a few years old and is no longer actively being developed. However, because of its simplicity, Tachyons is still a great way to learn responsive web design. The simplest way to understand the approach is to look at the Tachyons components. These are example elements that are fully defined using utility classes.
A successor to Tachyons is TailwindCSS. TailwindCSS has several advantages over Tachyons. The project continues to be actively developed and supports many popular systems for front-end development. Furthermore, TailwindCSS can be fully adapted to the respective needs of a project. All pre-settings such as breakpoints, font size scale, etc., can be easily configured.
Though working with CSS utility frameworks is practical, the approach has one major disadvantage: many atomic classes may be required to define a single element. The CSS source file also contains classes for all combinations of CSS property values and breakpoints by default. In the case of TailwindCSS, there are thousands of classes, which means that the CSS file in the uncompressed state can increase to a file size of several megabytes – an unsustainable size from a performance point of view.
Fortunately, TailwindCSS remedies this in two ways. On the one hand, the framework understands the “@ apply” instruction, which is used to combine repeatedly used combinations of utility classes under a new class name. On the other hand, TailwindCSS supports the PurgeCSS tool. This is used as part of the build process to remove any unused utility classes from the production build. PurgeCSS processes the HTML templates of the project and only includes the CSS classes found in the generated CSS source text file. This reduces the size of the source text file to an acceptable level.