The CSS language (‘Cascading Style Sheets’) is the basic framework for the de­vel­op­ment of modern websites – alongside HTML and JavaS­cript. CSS is a pro­gram­ming language, but it doesn’t describe the in­di­vidu­al steps you take to solve a problem. Instead, a goal is defined that is to be achieved. This makes CSS a de­clar­at­ive language, similar to SQL.

Part of CSS are the so-called media queries, which query the prop­er­ties of an output device. They are used for re­spons­ive web design. So how exactly does this work?

Cheap domain names – buy yours now
  • Free website pro­tec­tion with SSL Wildcard included
  • Free private re­gis­tra­tion for greater privacy
  • Free Domain Connect for easy DNS setup

What are CSS Media Queries?

CSS Media Queries were in­tro­duced alongside the rollout of CSS3 spe­cific­a­tion. A media query binds the as­sign­ment of CSS prop­er­ties of an element to one or more con­di­tions of a medium. In the simplest form, a dis­tinc­tion is made between the medium on which in­form­a­tion is presented – for example, on a screen, the printed page (PDF), or as a text readout:

Medium Ex­plan­a­tion
all Any output medium
screen Present­a­tion of website content on a scrolling screen
print Present­a­tion of website content on several pages with fixed di­men­sions
speech Reading of website content using a speech syn­thes­izer

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-dis­play­able 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 prop­er­ties of the re­spect­ive medium. CSS Media Queries therefore are a central technical feature enabling re­spons­ive web design in the first place.

CSS Media Queries as central control element for re­spons­ive web design

Re­spons­ive 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 prop­er­ties of the dis­play­ing device, so-called media features. This makes it possible to set style rules for different screen di­men­sions. Further, optimised style rules can be defined if a mobile device is tilted.

Here is an overview of the media features most used for re­spons­ive design:

Media Feature Ex­plan­a­tion
width Query width of the screen in pixels
height Query height of the screen in pixels
ori­ent­a­tion Detect screen ori­ent­a­tion portrait/landscape
res­ol­u­tion Detect available screen res­ol­u­tion

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 re­gard­less of the device dis­play­ing 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 ex­pli­citly over­writ­ten – 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 pro­por­tion­ally 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 prop­er­ties of the elements and then se­lect­ively overwrite prop­er­ties under certain con­di­tions.

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 im­ple­men­ted 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 con­di­tion­ally 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 di­men­sions and alignment of the device, we can also query the physical res­ol­u­tion of the screen via a media query. This is of par­tic­u­lar interest for dis­play­ing pixelated images. As an example, imagine a logo available in two versions – one optimised for low and one for high res­ol­u­tion screens. A simple trick for showing the ap­pro­pri­ate logo for each is to put both variants on the page. We use CSS Media Query to query the res­ol­u­tion 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;
	}
}
Tip

Explore more options to display images in a re­spons­ive manner in our article on re­spons­ive web design

Activate variable viewport for re­spons­ive design

Pre­vi­ously, we’ve spoken of the ‘screen’ in con­nec­tion with the available width of the output medium. This is con­cep­tu­ally correct, but tech­nic­ally not entirely so. The browser operates in­tern­ally with the concept of the ‘viewport’. For the width of the viewport to cor­res­pond to the width of the screen, a ‘meta-viewport’ spe­cific­a­tion is required in the ‘<head>‘ of the HTML document. Without this in­form­a­tion, 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>

Un­der­stand CSS units for re­spons­ive web design

With re­spons­ive web design, the elements should adapt to the existing screen. Often, this is a question of defining the di­men­sions of the elements under different con­di­tions. The CSS spe­cific­a­tion defines a variety of units; the simplest unit being the pixel. For example, a 1080p image has di­men­sions of 1,920 pixels wide by 1,080 pixels high.

The pixel is an absolute unit and by defin­i­tion does not adapt to the available space. Let’s look at an example of why this can be prob­lem­at­ic. 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 per­cent­age 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 per­cent­ages 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 di­men­sions:

.img-1080p {
	/* implicitly inherited from `img` */
	/* width: 100%; */
	max-width: 1920px;
}

In addition to pixels and per­cent­ages, CSS un­der­stands a few other units. The relative units em, rem and vw, vh are useful for re­spons­ive design. The table below gives a quick overview of common CSS units for re­spons­ive 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, di­men­sions of screen-filling elements
Em Define break­points, ‘max-width’ of layout elements
Px Define break­points, ‘max-width’ of images

Un­der­stand­ing 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 es­tab­lished media features that can be queried via CSS Media Query, several in­ter­est­ing features are planned for future versions of CSS. For example, the ‘CSS Media Queries Level 5’ (CSS5) spe­cific­a­tion includes the following new query options (among others):

Media Feature Ex­plan­a­tion
light-level Detect ambient bright­ness
prefers-colour-scheme Choose a light or dark colour 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 prop­er­ties of the container sur­round­ing them for the first time. This means that the container queries contrast the CSS Media Queries, which query global prop­er­ties of the device being displayed. The use of container queries will allow the handling of special cases for which JavaS­cript or complex media queries were pre­vi­ously used.

Un­der­stand­ing CSS break­points

In con­nec­tion with re­spons­ive web design and CSS Media Queries, ‘break­points’ are often used. A break­point is a defined screen width for which a set of CSS rules is activated as defined by a CSS Media Query. You can visualise the break­points on a website by opening the developer tools in the browser. If the re­spons­ive view is active, the break­points are displayed as coloured bars above the actual website.

Un­der­stand­ing mobile-first, CSS pro­cessors, and CSS utility frame­works

One re­cog­nised best practice of re­spons­ive web design is the mobile-first approach. When web design and de­vel­op­ment follow this approach, the style spe­cific­a­tions for the smallest screens are set first. These defin­i­tions form the backbone of the design. Based on this, several break­points are set for suc­cess­ively in­creas­ing screen sizes. New style rules for elements are se­lect­ively defined within the break­points, thereby over­writ­ing the existing rules for smaller screens.

The mobile-first approach is easy to un­der­stand by looking at the CSS utility framework ‘Tachyons’. This defines three break­points 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’ break­point. Details for small devices are simply defined without a break­point.

Tachyons break­point Ex­plan­a­tion
not-small Includes the screen widths of the break­points ‘medium’ and ‘large’
medium Covers the screen widths between the break­points ‘not-small’ and ‘large’
large Includes large screens only

Style rules for elements are defined within the break­points and their display is adapted to various screen sizes. You may notice that the cent­ral­isa­tion of the CSS codebase of a web project is prob­lem­at­ic. It’s usually prefer­able to collect all of an element’s CSS prop­er­ties in a separate file.

MyWebsite Now Plus
Create a business website
  • Pro­fes­sion­al templates, domain, and email
  • SEO tools and over 17,000 stock images
  • Easy online bookings

Un­der­stand­ing CSS pre- and post-pro­cessors

To mod­u­lar­ise the CSS code of a project, various CSS pre-pro­cessors 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 tech­no­lo­gies mentioned allow CSS Media Queries to be en­cap­su­lated below a CSS selector. In this way, the style rules of an element can be defined col­lect­ively for all media con­di­tions. Here is an example using a stylus:

Stylus file ‘text.styl’ for text prop­er­ties:

// 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 prop­er­ties:

// Mobile-first definitions
a
    color: blue
    // Definitions for 'not-small' breakpoint
    @media screen and (min-width: 30em)
        text-decoration: underline

The stylus pre-processor trans­lates the files into CSS and collects the indented CSS Media Query rules in a single break­point. The stylus code shown is trans­lated 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;
    }
}

Un­der­stand­ing CSS utility frame­works

En­cap­su­lat­ing CSS Media Queries within the style rules of an element and pro­cessing 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 un­desir­able com­plex­ity. This is where the CSS utility frame­works come in.

A CSS utility framework links atomic CSS prop­er­ties with break­points. The resulting CSS classes can be assigned to any element in HTML. This makes it possible to define re­spons­ive layouts and com­pon­ents in HTML only, without having to write CSS code. The use of a CSS utility framework allows rapid pro­to­typ­ing and is ideal for de­vel­op­ing com­pon­ents. Therefore, CSS utility frame­works are often used in con­junc­tion with component-oriented tech­no­lo­gies 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’. Fur­ther­more, within the already in­tro­duced break­points ‘medium’ and ‘large’, we define cor­res­pond­ing CSS classes whose names contain the ab­bre­vi­ated break­points:

/* 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 re­spons­ive elements entirely in HTML. The following HTML code snippet defines an image that has a maximum width of ‘1rem’ on small screens. The image auto­mat­ic­ally 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 frame­works define many atomic classes, with each class spe­cify­ing only one CSS property. In addition to the di­men­sions of an element, this includes in­form­a­tion on ty­po­graphy, colour, and all other con­ceiv­able prop­er­ties. For each atomic property, a CSS utility framework contains classes for each defined break­point. By combining several classes, almost any re­spons­ive 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 sim­pli­city, Tachyons is still a great way to learn re­spons­ive web design. The simplest way to un­der­stand the approach is to look at the Tachyons com­pon­ents. These are example elements that are fully defined using utility classes.

A successor to Tachyons is Tail­windC­SS. Tail­windC­SS has several ad­vant­ages over Tachyons. The project continues to be actively developed and supports many popular systems for front-end de­vel­op­ment. Fur­ther­more, Tail­windC­SS can be fully adapted to the re­spect­ive needs of a project. All pre-settings such as break­points, font size scale, etc., can be easily con­figured.

Though working with CSS utility frame­works is practical, the approach has one major dis­ad­vant­age: many atomic classes may be required to define a single element. The CSS source file also contains classes for all com­bin­a­tions of CSS property values and break­points by default. In the case of Tail­windC­SS, there are thousands of classes, which means that the CSS file in the un­com­pressed state can increase to a file size of several megabytes – an un­sus­tain­able size from a per­form­ance point of view.

For­tu­nately, Tail­windC­SS remedies this in two ways. On the one hand, the framework un­der­stands the ‘@ apply’ in­struc­tion, which is used to combine re­peatedly used com­bin­a­tions of utility classes under a new class name. On the other hand, Tail­windC­SS supports the PurgeCSS tool. This is used as part of the build process to remove any unused utility classes from the pro­duc­tion 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 ac­cept­able level.

Go to Main Menu