You have probably faced a situation before where you really wished CSS media queries were based on elements’ width rather than the entire viewport. In this article we will explore a JavaScript approach to add different attributes to an element depending on its width using resize event and MutationObserver. You can then use these attributes to style the element differently in your CSS.

What We Will Achieve

The end result of this JavaScript bit is to dynamically add an attribute data-width="some_size" to an element depending on its width. So for instance data-width="small" , data-width="medium" , etc. and then use CSS to target these attributes:

The HTML Structure

We will not directly add this data-size attribute to the element since we need to manipulate it dynamically. Alternatively, we will use another attribute data-sizes which we will pass in it a JSON string to define the size ranges.

The JSON object will have keys of the sizes we would like to call and the values of these keys are objects with minWidth and maxWidth attributes like so:

In the example above, for small we did not define minWidth which means any width less than maxWidth will be applied. Similarly, not defining maxWidth means for minWidth and above apply this attribute.

Finally the JSON can be passed to the data-sizes attribute as so:

The JavaScript Part

To watch for width changes using JavaScript, we are going to assume that the factors that can change an element’s width are:

Changing the window size.

Manipulating the width using element’s attributes like adding style=”width:100px” or adding a class that changes the width.

Changing the content of the element.

Any other factor I am not aware of (let me know)

The first factor is going to be handled using window.resize event. The other 2 will be handled using the MutationObserver. The MutationObserver can observe changes in attributes, childList and subtree which are enough for our case.

We will create a new attribute for the element called data-width. This attribute will hold the current width of the element. Whenever the window is resized or a mutation is observed, we will compare the width of the element to the current width and update data-width when needed. Inside the mutation observer, we will check if data-width is mutated then we will update the data-size attribute accordingly. Additionally, we will create a new event onWidthChange and fire it when a change in width is detected.

Alternatively, we can remove data-sizes and initialize a new object as so:

With this way, you can call the method updateSize on el if you want to manually update the data-size attribute based on the current element width.

Finally, you can use the onWidthChange event to do something when the width of the element changes:

Here’s the final result:

Browser Compatibility

This approach uses MutationObserver which is not supported on old IE versions. You will need another workaround if you need to support these browsers or maybe use a shim layer for MutationObserver.