Henrik Haugberg
Written by Henrik Haugberg
Published 2013-08-21

Responsive CSS

The days when it was enough to create html stylesheets that work on one given screen width (eg 1024px) is over. As smartphones and tablets took the market, it was very common to have separate pages for such devices, like m.domain.com or touch.domain.com. Today, browsers are found on devices of all shapes and sizes. The transition between mobile and tablet is starting to blur, and soon browsers are found in both the television and the watch.

Entry image

Responsive design is all about making the combination of markup and CSS flexible for display. To make a website provident, and available on as many devices as possible, it is wise not to resolve this by just making a fixed set of mediaqueries for specific widths that are applicable to most common devices on the market. This often requires far more lines of CSS and (and thereby maintenance) than a liquid responsive stylesheet. Let’s look at some basic techniques to achieve a good responsive css.

As long as the page layout does not change, it is with few exceptions possible to achieve full scalability on all elements and sizes. Meaning page layout and elements are scaled to the same relative size on screens of different size and pixel resolution. Meanwhile, mediaqueries can be used to control changes in the layout. For example, if the page should have a maximum width (as most websites have today), elements can move or disappear for smaller screens. Additional columns can be combined into one or be placed below each other.

1. Layout

To make a column layout scalable, you can simply use percentages. For example, a page that has two columns of ¾ and ¼ of the page width:

This works until we are in need of padding around the contents of the columns. For example “padding: 20px”, this will be added to the percentage widths, and cause the two items to take up more than 100% width. Previously, this was often solved by having an outer and an inner element (eg two div elements inside each other) where the exterior has percentage width and no padding / margin, while the margin / padding was set on the inner element. It is not optimal to insert extra html elements only to achieve a given css-effect, and fortunately this was resolved in CSS3 using the property “box-sizing: border-box”, which makes the percentage width apply to the outside of padding / border instead of just the content area inside padding:

Although we have now solved the problem with the combination out of width and column padding, we have introduced a size that is not scalable. With this stylesheet, the two columns get 20px padding around the content no matter how big the screen is. This means that padding take up a large portion of the column width on small screens, and a smaller portion of large screens. This can be solved by calculating percentages on the basis of a given maximum size. If the page content area has a max width of 950px, we can calculate the percentage 20px is out of this total, set padding in percentages and subtract this from the width. Thus, both the width and padding scale equally on screens of all sizes:

This solution creates numbers that are hard to know the basis for unless you write a comment on the property such as in the example above. Here, multiple percentages is calculated based on the page width, so this variable is included in many formulas, perhaps spread over several different stylesheets. This can easily lead to difficult maintenance and errors when changes are made in the stylesheet. It’s not easy to know what originally was the basis for setting a number you find in a stylesheet. This can be done far better if you use a meta language such as SASS. A meta language make it possible to create a much more readable and understandable css code:

Besides making the stylesheet far more readable, this also makes it easier to perform changes. If, for example if the maximum width of the page is to be extended from 950px to 1200px, this can be changed easily in one place in the style sheet as long as this variable is used in all situations where properties are affected by the maximum width of the page.

2. Images

Images are used in many contexts on the web, and can lead to many different design requirements. When you resize images directly in the browser with CSS, your browser process the image scaling during display. This leads to additional processing and lowers performance. At the same time it may be difficult to achieve a liquid responsive design without image scaling in css. One of the most common challenges is to let the image scale without losing the ratio between height and width. A simple solution to this is to set the width (for example to 100% of the surrounding element) and let the height automatically adjust by not including a height property in the css:

Sometimes, images should be displayed with a given aspect ratio even though the image may come in a different ratio. If this can not be customized directly from the image source, it can be done in CSS. The challenge is to keep the ratio between height and width. When the width differs depending on the the size of the window / screen, one can not put a height relative to this. Height in percent is based on the height of the surrounding element, and is therefore completely independent of the width. However, there are vertical properties that are actually based on the surrounding element width when the value is set as a percentage. This applies to padding-top and padding-bottom. If an element has “padding: 20%”, this does not mean the upper and lower padding will be 20% of the height of the surrounding element. It will be on the 20% of the available horizontal width on all four sides of the element.

This makes it easier to get equal size of padding on all sides of an element, and also gives us the opportunity to maintain the aspect ratio of an image. We simply sets the width to what is required (eg 100%), and sets the padding-bottom to a given size relative to the width, eg 75% to get the images to appear in 1:33 ratio . The height is set to 0, and thus the content floats outside the actual content area and across the area that actually is for padding. In addition, set “overflow: hidden” to hide the rest of the image. We now have a crop effect. This is a little “hack”, but works well in most browsers:

3. Font size

Font size set in percentages are based on the font size in the surrounding element, regardless of the browser window. The goal must therefore be to adjust the text down on smaller screens / browsers the same way as other properties set in percents do.

We can use a new unit introduced in CSS3, Viewport Width (vw). When using a vw-size, the numerical value are multiplied by a factor of 1/100 of the browser viewport width. For instance, if the width of the browser window is 1600px, a size set to 3vw will be similar to 48px (3 * 1600 * (1/100)). This therefore provides a possible solution for our requirement:

Unfortunately this is a very new unit, only supported in the latest browser versions:

  • Chrome 20+
  • Firefox 19+
  • Internet Explorer 9+
  • Safari 6+
  • Opera 15+

There is however one CSS3 unit that is wider supported, RootEM (rem). This works the same as the more familiar em-unit, except instead of relying on the font size of the surrounding element, it is based on the font size of the root element, <html>.

Since the em unit often inherits several levels, it is difficult to control the results when using this on a larger scale. On the other hand, rem is based on same size regardless of where it is used. We can therefore use mediaqueries to scale down this base size on smaller screens, which means a breakpoint based responsive font size for browsers that do not support the vw-unit. If you want a fixed base font size that is the starting point for text sizes around the website, you can still put this on <body> without affecting the rem values:

This unit is supported in far more browsers:

  • Chrome 6+
  • Firefox 3.6+
  • Internet Explorer 9+
  • Safari 5+
  • Opera 11.6+

To cover more browsers, a good solution is to use vw as the primary unit and rem as fallback. In addition, a static px size can be fallback for browsers that neither supports vw, rem or mediaqueries (like Internet Explorer 8 and older). This way the pages is normally non-responsive in these browsers. Fortunately, most browsers on devices with small screens (phones, tablets etc) are up to date. Most devices with older browsers without support for responsive design are on desktop computers or laptops, and they usually have large enough screen so that the lack of responsive design is not a problem.

To make the stylesheet tidier, we can make a SASS function in the same way as illustrated further up, where the function is given the size that applies at max page width. The function can thereby calculate the relative sizes / units to make the scaling correct:

4. Complex reusable css

Tidiness and reusability is equally important for a good CSS as it is in regular programming. It makes it easier to make adjustments both for the person who has written it and for other developers, and it significantly reduces the amount of errors and the need for maintenance. Unfortunately, this tends to get low priority in web projects. An example of reuse is when a widget or another set of markup is used in multiple contexts on a website. It should look the same in all contexts (possibly with some local overrides of the basic stylesheet), and be equally proportioned on the basis of where it is located. In addition, it should be fluid responsive across screen sizes.

This is a bit difficult to implement in practice. Percentages based on the surrounding element will work everywhere. For example, two elements side by side covering 50% width each. It gets a little harder when all other sizes should scale the same way. Imagine the tricks explained in previous sections is used. A heading have font size 32px at full page width, and is adjusted down on smaller screens by using vw / rem. The same text will then take up the same space / size in relation to surrounding elements regardless of the size of the browser / screen. What happens when this markup is placed in a smaller column of the page, which takes up 60% of the width of the main container area? The text will still adjust to full page width, so it is the same size as when the markup have the whole page width available. In other words, the text is too large, it should be adjusted down to 60% of its original size. The same applies to smaller relative sizes like padding, shadows, border-radius, etc.

If you want to implement this completely without creating too much css and maintenance needs, you can make it in two steps. Basic css, and an override that is implemented where the item should be scaled to a different size than the full page width. Preferably using a meta-language to avoid lots of copy / paste and sources of error. example:

// style.scss

// some_element_scale.scss

This can seemingly become quite a large amount of CSS in the compiled stylesheet. However the properties that should be included in the responsive part and scalable parts are only those that are dependent on the width of the page to become fluid responsive. This means all the properties that do not require this, such as properties set in percentages and all properties that do not include sizes (display, position, float, etc.) need only be in the first basic set of CSS.

Responsive css

One of the biggest advantages of creating fluid sizes in both layout and content such as text and images, is making the css code a lot shorter. If css are ​​responsive primarily using mediaqueries, one must decide on a given number of break points. Within each of them, all sizes for layout, text size of all elements in the design etc must be set. This causes a lot of extra css. Using techniques for percentages and fluid sizes, we can have a set of relative sizes applicable no matter how small the screen is.

Written by Henrik Haugberg
Published 2013-08-21