With the growing number of Smartphone produced in the last three years and the diversity of screen sizes it’s practically impossible to ignore users that browse on a mobile device. Whether they use an Android phone, Windows Mobile phone, a BlackBerry device or an iPhone, whether they are on a tablet, on a Smartphone or on a big screen, each user deserves the best experience possible. As designers, it is our goal to provide those users a nice experience browsing the websites we created, whatever the device used to browse is.
Media queries, the heart of Responsive Web Design, is a W3C CSS3 standard. Mozilla and Safari support extensions; A new standard dppx unit is available on some browsers; Microsoft has extensions but only for HTML5 Windows Store apps. This website creates media queries and evalute them dynamically in your browser. Hopefully these examples have given you some ideas for how you might use custom properties in your responsive design work. The main advantage is that you can redefine the value of any custom property inside @media queries instead of having to rewrite a lot of CSS inside them. This helps to keep your @media queries cleaner and less verbose.
My recommended approach is to use media queries for your site’s layout, and then this responsive components strategy for the specific components that need it (many won’t). If you really want to deliver a consistent UI across all browsers, you can load the ResizeObserver polyfill, which has great browser support (IE9+). Responsive design was only able to emerge due to the media query. The Media Queries Level 3 specification became a Candidate Recommendation in 2009, meaning that it was deemed ready for implementation in browsers. Media Queries allow us to run a series of tests (e.g. Whether the user's screen is greater than a certain width, or a.
Today most of the clients want their website to be mobile compatible, so this is particularly challenging. Creating a version for each device is impossible, due to the number and diversity of those devices, but also simply because we don’t know what will be created tomorrow. That’s where the concept of “Responsive Webdesign” comes to the rescue.
A responsive website is a website that will respond and adapt to the user’s behavior and screen size. The idea is to resize and reorder the design, adapt images, typography, columns, etc., based on screen – browser size, resolution and orientation instead of providing each device a specific website.
A Look at 3 Different Types of Layout
Basic Fluid Layout
Fluid layout is based on a system of relative units instead of absolute pixels. This kind of layout has been around for a while now, and most of the designers use fluid grids created in percentage to achieve such layouts.
The idea is pretty simple: instead of giving the layout rigid width in pixels, we will give it relative ones in percentage. The fluid layout based websites usually take the whole browser width, hence the 100% in this example.
You can see a demo of a fluid design here.
Data JavaScript credit: Andreas Bovens
The
style.css
gives us common styles for the page (color, typo), but let’s take a look at our fluid.CSS
file :Our header and footer have a 100% width, so they’ll take the whole screen available. The main content has a 60%, and our sidebars 20% and 18% so that we will be able to create a design that will fit the whole space available.
This design adapts perfectly on big screens, but we can see that the sidebar content tend to become hard to read when we resize too small.
Adaptive Layout
The adaptive layout is based on a pretty simple idea: instead of using percentage we will give our layout fixe sizes, but we will adapt those sizes depending of the width of the browser/viewport, thus creating a layout with different “break points”.
For each of those break point, we will use media queries (will come back to explain them in detail in the second part of the article) to adapt the layout of our website so that content is not too hard to read.
You can see and example of adaptive layout here.
The HTML and
style.css
did not change; all we changed was the structure of the page. Let’s take a closer look at our CSS file.The “normal” website uses this CSS:
I gave the header and footer a 100% width, but the content has a fixed width. Now the good part, the break points with media queries:
For each break point given by a media query, I changed the size of the body, the content, and the sidebar. Under
540px
, the text in the sidebar was too hard to read, so I gave the sidebar the same size as the content, what has the effect of putting the sidebars under the content.This nice thing about adaptive layout is the possibility to modify and adapt not only the size of the blocs, but the layout and there place on the page.
The big difficulty is then to choose those break points. A first technique could be to base the break points on most “common” device width. Chris Coyier from CSStricks put a nice list of media queries together. Another way to choose the break points it to actually test the design at different screen sizes and see when it gets ugly or when user can’t really read the text easily, and put break point at those size.
Live example of adaptive layout :
Foodsense
Responsive Layout
We could define the responsive layout, as a mix between the fluid and adaptive layouts. It will use the relative units of the fluid layout and the break points of the adaptive one.
Here you can see the demo of our previous example, in responsive layout.
You can see here how fluid the design is: using percentage enables us to create very smooth transition between the different break points of our design.
Here is our stylesheet for the “normal” version:
What’s important here is the use of
max-width
(instead of width for an adaptive layout). It’s this property that enables us to create this smooth transition. Using a max-width, we won’t have to use as many break points as for an adaptive layout, and all the other sizes will be given in a relative unit (percentage for our example).And the CSS for the media queries:
All the other size will be once again given in percentage, relative to the
max-width
of our body.Note that for screen size under 540px, we once again gave the sidebars and the content a 100% width, and place the sidebars under the content using some clear: both.
The advantage of the responsive layout is that you won’t have to use too many break points. Since the size are given in percentage, they will adapt automatically, so the major role of the break points will be to be place where design breaks, to re-order our layout (putting sidebars under content in our example) and give the user a more pleasant reading.
Media Queries Responsive Design Ideas
Fore Fathers Group
Media Queries: Create and Define Break Points
Media queries where introduced in the CSS3 specifications. Put in a simple way, media queries enables the web designer to create conditionals stylesheets based on width, height, but also orientation, color, etc. There’s a huge list of media queries available on the official w3c website but we will only use some of them in our case. Here is a list of the most commonly used media queries and what they do :
Media Query Utilisation
Media Query | Use |
min-width: … px | Used when the viewport’s width is bigger or equal to width |
max-width: … px | Used when the viewport’s width is smaller or equal to width |
min-device-width: … px | Used when the device’s width is bigger or equal to width |
max-device-width: … px | Used when the device’s width is smaller or equal to width |
orientation : portrait // orientation: landscape | Target orientation |
-webkit-min-device-pixel-ratio : 1.5 | Used to target high density device on android and ios |
As for print style sheets, media queries can be used as external or internal styles sheets. An external style sheet is easier to organize, it is not downloaded by browsers which don’t support it, but it uses extra http request. An internal style sheet on the other hand does not require extra http request, but the whole stylesheet is downloaded for browsers even if they do not support media queries, and it can be harder to organize. Both have then pro and cons, you’ll have.
You already saw the internal syntax in the example above:
And here is the external syntaxes:
Some “tricks” Worth Knowing About Media Queries
Cascade Matters
Yeah that’s right, as for any piece of CSS code, cascade matters.
Consider the following example:
See the example on jsfiddle.
If the width of our browser is bigger than
500px
, the color of the text gets white, and the background red
. If we enlarge the screen up to more than 700px
, the background gets blue, but the color of the text stays white because it inherited the color of the min-width:500px
media query applied before (700 being, well, bigger than 500).Creating Stacked Media Queries
Consider the following example :
See the example on jsfiddle. 3 will be free ep 5 24.
The first media query will only be applied for screen between
500px
and 699px
, and the second for screen bigger than 700px
. In the case of stacked media queries, since property is only applied for a certain width, they are not herited. In our example, if we also want to apply a serif font the layout bigger than 700px
, we will have to repeat this property.You’ll need a viewport meta tag to make the media queries work. The viewport meta tag enables you to take control of the viewport of the device. Basically, if no viewport is set, mobile device will try to fit the whole page on the screen, resulting in very small websites.
The viewport meta tag looks like this:
We basically tell the device, that we will be using the device width as the width of our page, and that there will be no zooming on the page when we first launch it.
It’s Not Only About the Mobile!
In my examples, I showed some media queries used for mobile optimization, tablets and smaller screens. But I wanted as a conclusion, to emphasize the fact that media queries are not only about mobile optimization. We tend to see more and more mobile device, but also more and bigger screens.
We know have an xbox that can connect to internet, some of the box our internet providers provide us are equipped with a browser, and even some television are able to connect to internet. Maybe tomorrow you will get a web browser on your fridge, who knows. If we use responsive webdesign to optimize for smaller screens, we can also use them to optimize for bigger ones.
Let’s remember: responsive webdesign is about adapting layout to the user’s browser size, orientation, whatever that size might be!
Some Useful Resources:
- Media queries for browser which don’t support them: Github Respond
- Mobile hardboiler template : HTML5boilerplate Mobile
- Testing responsive design: Responsive Design Tester and Responsivepx
Conclusion
As you can see, responsive webdesign is not that hard to use and enables web designers to create nice layouts that will adapt to many devices and screen sizes.
Your now it’s your turn: did you ever used responsive design? In what kind of projects? Do you have some advice and special tips? How do you define your break points? Let us know in the comments.
Container queries is a proposal that would allow web developers to style DOM elements based on the size of a containing element rather than the size of the browser viewport.
If you’re a web developer, you’ve probably heard about container queries before. For about as long as we’ve had responsive web design, we’ve had developers asking for them (initially element queries, then changing to container queries). In fact, container queries may well be the most requested CSS feature ever that we still don’t have in browsers.
There are already many, many, many posts explaining exactly why container queries are hard to do in CSS and why browser makers have been hesitant to implement them. I don’t want to rehash that discussion here.
Instead of narrowly focusing on the specific CSS feature proposal we call “container queries”, I want to focus on the broader concept of building components that respond to their environment. And if you accept this larger framing, there are actually new web APIs that already let you achieve this.
That’s right, we don’t need to wait for container queries to start building responsive components. We can start building them now!
The strategy I’m going to propose in this article can be used today, and it’s designed as an enhancement, so browsers that don’t support the newer APIs or don’t run JavaScript will work exactly as they currently do. It’s also simple to implement (copy/paste-able), highly performant, and doesn’t require any special build tools, libraries, or frameworks.
Snagit 2020 1 2 download. To see some examples of this strategy in action, I’ve built a Responsive Components demo site. Each demo links to its CSS source code, so you can see how it works.
But before going too deep with the demos, you should read the rest of this post for an explanation of how the strategy works.
The strategy
Most responsive design strategies or methodologies (this one will be no different) work according to these two core principles:
- For each component, first define a set of generic, base styles that will apply no matter what environment the component is within.
- Then define additions or overrides to those base styles that will apply at specific environment conditions.
The power of these principles is they work even if the browser doesn’t support the features required to fulfill or enable specific environment conditions. And this includes cases where the feature requires JavaScript—users with JavaScript disabled will get the base styles, and those will work just fine.
In most cases the base styles defined in #1 above are styles that work on the smallest possible screen sizes (since small screens tend to be more restrictive than large screens), and they’re not wrapped in any sort media query (so they apply everywhere).
Here’s an example that defines base styles for
.MyComponent
and then override styles at two arbitrary breakpoints, 36em
and 48em
:Of course, these breakpoints use media queries, so they apply to the size of the browser viewport. What container query advocates want is the ability to do something like this (note, this is proposed syntax, not official syntax):
Unfortunately, the above syntax doesn’t work in any browser today and probably won’t anytime soon.
However, what does work today is something like this:
Of course, this code assumes the component containers have the correct classes added to them (in this example,
.MD
and .LG
). But ignoring that detail for the moment, if you’re a CSS developer who wants to build a responsive component, the second syntax probably still makes sense to you.Whether you’re writing your container query as an explicit length comparison query (the first syntax) or whether you’re using named breakpoint classes (the second syntax), your styles are still declarative and functionally the same. As long as you can define your named breakpoints however you want, I don’t see a clear benefit to one over the other.
And to clarify the rest of this article, let me define the named breakpoint classes I’m using with the following mapping (where
min-width
applies to the container, not the viewport):Named breakpoint | Container width |
---|---|
SM | min-width: 24em |
MD | min-width: 36em |
LG | min-width: 48em |
XL | min-width: 60em |
Now all we have to do is ensure our container elements always have the right breakpoint classes on them, so the correct component selectors will match.
Observing container resizes
For most of web development history, it’s been possible to observe changes to the window, but it’s been hard or impossible (at least in a performant way) to observe size changes to individual DOM elements. This changed when Chrome 64 shipped ResizeObserver.
ResizeObserver
, following in the footsteps of similar APIs like MutationObserver and IntersectionObserver, allows web developers to observe size changes to DOM elements in a highly-performant way.Here’s the code you need to make the CSS in the previous section work with
Note: this example uses ES5 syntax because (as I explain later) I recommend inlining this code directly in your HTML rather than including it in an external JavaScript file. Older syntax is used for wider browser support.ResizeObserver
:This code creates a single
ResizeObserver
instance with a callback function. It then queries the DOM for elements with the data-observe-resizes
attribute and starts observing them. The callback function, which is invoked initially upon observation and then again after any change, checks the size of each element and adds (or removes) the corresponding breakpoint classes.In other words, this code will turn a container element that’s 600 pixels wide from this:
Into this:
And these classes will automatically and instantly get updated anytime the container’s size changes.
With this in place, now all the
.SM
and .MD
selectors in the previous section will match (but not the .LG
or .XL
selectors), and that code will just work!Customizing your breakpoints
The code in the ResizeObserver callback above defines a set of default breakpoints, but it also lets you specify custom breakpoints on a per-component basis by passing JSON via the
data-breakpoints
attribute.I recommend changing the code above to use whatever default breakpoint mappings make the most sense for your components, and then any component that needs its own set of specific breakpoints can define them inline:
My Responsive Components site has an example of a component setting its own custom breakpoints alongside components using the default breakpoints.
Handling dynamic DOM changes
The code example above only works for container elements that are already in the DOM.
For content-based sites this is usually fine, but for more complex sites whose DOM is constantly changing, you’ll need to make sure you’re observing all newly added container elements.
A one-size-fits-all solution to this problem is to expand the snippet above to include a MutationObserver that keeps track of all added DOM elements. This is the approach I use in the Responsive Components demo site, and it works well for small and medium-sized sites with limited DOM changes.
For larger sites with frequently-updating DOM, chances are you’re already using something like Custom Elements or a web framework with component lifecycle methods that track when elements are added and removed from the DOM. If that’s the case, it’s probably better to just hook into that mechanism. You probably even want to make a generic, reusable container component.
For example, a custom
Note: while it may be tempting to create a new ResizeObserver for every container element, it's actually much better to create a single ResizeObserver that observes many elements. To learn more, see Aleks Totic's findings on ResizeObserver performance in the blink-dev mailing list.<responsive-container>
element might look something like this:Nested components
In my initial experimentation with this strategy, I didn’t wrap each component with a container element. Instead, I used a single container element per distinct content area (header, sidebar, footer, etc), and in my CSS I used descendant combinators instead of child combinators.
This resulted in simpler markup and CSS, but it quickly fell apart when I tried nesting components within other components (which many complex sites do). The problem is, with the descendant combinator approach, selectors would match multiple containers at the same time.
After building a few non-trivial demos, it became clear that a direct child/parent structure for each component and its container was far easier to manage and scale. Note that containers can still host more than one component, as long as every hosted component is a direct descendant.
Advanced selectors and alternate approaches
The strategy I’ve outlined in this article takes an additive approach to styling component. In other words, you start with base styles and then add more styles on top. However, this isn’t the only way to approach styling components. In some cases, you want to define styles that match exclusively and only apply at a particular breakpoint (i.e. instead of
(min-width: 48em)
you’d want something like (min-width: 48em) and (max-width: 60em)
).If this is your preferred approach, you’d need to tweak the ResizeObserver callback code slightly to only apply the class name of the currently-matching breakpoint. So if the component were at its “large” size, rather than setting the class name
SM MD LG
, you’d just set LG
.Then, in your CSS, you could write selectors like this:
Note that when using my recommended strategy for additive matching, you can still match breakpoints exclusively via a selector like
.MD:not(.LG)
, though this is arguably less clear.At the end of the day, you can pick whichever convention makes the most sense for you and works best for your situation.
Note: the :matches()
selector isn't well supported in current browsers. However, you can use tools like postcss-selector-matches to transpile :matches()
into something the works cross-browser.Height-based breakpoints
So far all of my examples have focused on width-based breakpoints. This is because, in my experience, the overwhelming majority of responsive design implementations use width and nothing else (at least when it comes to viewport dimensions).
However, nothing in this strategy would prevent a component from responding to its container’s height. ResizeObserver reports both width and height dimensions, so if you wanted to observe height changes you could define a separate set of breakpoint classes—perhaps with a
W-
prefix for width-based breakpoints and an H-
prefix for height-based breakpoints.Browser support
While
ResizeObserver
is currently only supported in Chrome, there’s absolutely no reason you can’t (or shouldn’t) use it today. The strategy I’ve outlined here is intentionally designed to work just fine if the browser doesn’t support ResizeObserver or even if JavaScript is disabled. In either of these cases, users will see your default styles, which should be more than sufficient to deliver a great user experience. In fact, they’ll probably just be the same styles you’re already serving today.My recommended approach is to use media queries for your site’s layout, and then this responsive components strategy for the specific components that need it (many won’t).
If you really want to deliver a consistent UI across all browsers, you can load the ResizeObserver polyfill, which has great browser support (IE9+). However, make sure that you only load the polyfill if the user actually needs it.
Also consider that polyfills tend to run slower on mobile devices, and given that responsive components is primarily only something that matters at larger screen sizes, you probably don’t need to load the polyfill if the user is on a device with a small screen size.
The Responsive Components demo site takes this latter approach. It loads the polyfill, but only if the user’s browser doesn’t support
ResizeObserver
and if the user’s screen width is at least 48em
.Limitations and future improvements
Overall, I think the responsive components strategy I’ve outlined here is incredibly versatile and has very few downsides. I firmly believe that every site with content areas whose size may change independently of the viewport should implement a responsive components strategy rather than relying on just media queries (or a JavaScript-based solution that doesn’t leverage ResizeObserver).
That being said, this strategy has a few limitations that I think are worth discussing.
How To Use Media Queries
It’s not pure CSS
One obvious downside of this solution is it requires more than just CSS to implement. In addition to defining your styles in CSS, you have to also annotate your containers in the HTML and coordinate both of those with JavaScript.
While I think we’d all agree a pure CSS solution is the ultimate goal, I hope we as a community are able prevent the perfect from becoming the enemy of the good.
In matters like this, I like to remind myself of this quote from the W3C’s HTML design principles: The bible 3 1 download free.
In case of conflict, consider users over authors over implementors over specifiers over theoretical purity.
Flash of un/incorrectly-styled content
In most cases it’s a best practice to load all your JavaScript asynchronously, but in this case async loading can lead to your components initially rendering at the default breakpoint only to suddenly switch to a larger breakpoint once your JavaScript is loaded.
While this isn’t the worst experience, it’s something you wouldn’t have to worry about with a pure-CSS solution. And since this strategy involves coordination with JavaScript, you have to also coordinate when your styles and breakpoints are applied in order to avoid this re-layout.
I’ve found the best way to handle this is to inline your container query code at the end of your HTML templates, so it runs as soon as possible. You should then add a class or attribute to your container elements once they’re initialized and visible, so you know when it’s safe to show them (and make sure you consider the case where JavaScript is disabled or errors when run). You can see an example of how I do this in the demo site.
Units are based in pixels
Many (if not most) CSS developers prefer defining styles based on units with more contextual relevance (e.g.
em
based on font-size or vh
based on the viewport height, etc.), whereas ResizeObserver
, like most DOM APIs, returns all its values in pixels.At the moment there’s really no good way around this.
In the future, once browsers implement the CSS Typed OM (one of the new CSS Houdini specs), we’ll be able to easily and cheaply convert between various CSS units for any element. But until then, the cost of doing the conversion would likely hurt performance enough to degrade the user experience.
Conclusion
This article describes a strategy for using modern web technologies to build responsive components: DOM elements that can update their style and layout in response to changes in the size of their container.
While previous attempts to build responsive components were valuable in exploring this space, limitations in the platform meant these solutions were always either too big, too slow, or both.
Fortunately, we now have browser APIs that allow us to build efficient and performant solutions. The strategy outlined in this article:
- Will work, today, on any website
- Is easy to implement (copy/paste-able)
- Performs just as well as a CSS-based solution
- Doesn’t require any specific libraries, frameworks, or build tools.
- Leverages progressive enhancement, so users on browser that lack the required APIs or have JavaScript disabled can still use the site.
While the strategy I outline in this post is production-ready, I see us as being still very much in the early stages of this space. As the web development community starts shifting its component design from viewport or device-oriented to container-oriented, I’m excited to see what possibilities and best practices emerge.
Hopefully one day we’ll be able to turn those best practices into a first-class web API.