What are Media Queries?
Media Queries are a CSS feature that can be used to conditionally apply selected styles on an HTML element. Some examples of media queries include checking for the width of the browser window, checking for the media type (print, screen), or checking for dark/light mode preference.
The most common use case for media queries is using it to implement responsivity on a website. Checking for the width of the viewport and applying styles based on it allows us to define different styles on different devices (desktop, mobile, tablet).
The syntax for media queries is comprised of an optional media type and any number of media feature expressions. Media types include all,screen, and print. The default value for media type is all.
.header {
font-size: 20rem;
}
@media print {
.header {
font-size: 15rem;
}
}
The media type is followed by any number of media feature expressions enclosed in parenthesis.
.header {
font-size: 20rem;
color: pink;
}
@media (max-width: 800px) {
.header {
color: blue;
}
}
Here, max-width: 800px
is a media feature expression which signifies that this CSS will only be applied if the width of the viewport is equal to or less than 800 pixels.
There is a number of different media features we can use to apply CSS in specific situations. The most common is width because it is used when creating responsive and mobile-friendly websites.
How to use Media Queries from JavaScript?
If you want to check for a media query using JavaScript, you can use the window.matchMedia function. matchMedia
takes a single parameter, the query string you want to check for, and returns a MediaQueryList object. The MediaQuery object can be used to check for a match or to attach a change
event listener. The change
listener is called every time the result of the media query changes.
const result = window.matchMedia("(max-width: 800px)");
if (result.matches) {
// do something
}
result.addEventListener("change", (event) => {
if (event.matches) {
// do something
}
});
Custom React hook for Media Queries
matcMedia
makes it possible to implement a React Hook we can use to check for Media Query matches and change your application UI or behavior based on the results.
First, let's define the API for our hook. With TypeScript, our hooks type definition would look like this.
type useMediaQuery = (query: string) => boolean;
Our hook will take the query string as a parameter and return a boolean. Next, we'll need to add a React.useEffect
call which calls matchMedia
and adds an event listener for change
. We also need a state variable to store the match.
function useMediaQuery(query) {
const [matches, setMatches] = React.useState(false);
React.useEffect(() => {
const matchQueryList = window.matchMedia(query);
function handleChange(e) {
setMatches(e.matches);
}
matchQueryList.addEventListener("change", handleChange);
}, [query]);
return matches;
}
Great 🥳 This already works but we have one more important thing to add.. cleanup for the event handler. React.useEffect
function can return a function used for cleanup. It's commonly used to unregister event handlers or unsubscribing from external data sources.
Let's add a cleanup function to our useEffect
function useMediaQuery(query) {
const [matches, setMatches] = React.useState(false);
React.useEffect(() => {
const matchQueryList = window.matchMedia(query);
function handleChange(e) {
setMatches(e.matches);
}
matchQueryList.addEventListener("change", handleChange);
return () => {
matchQueryList.removeEventListener("change", handleChange);
};
}, [query]);
return matches;
}
Now our useMediaQuery
hook is finished. Here's how you would use it.
function SomeComponent() {
const isMobile = useMediaQuery("min-width: 768px)");
return <h1>Browsing with {isMobile ? "phone" : "desktop"}</h1>;
}
Top comments (2)
To improve this hook, it needs to start its state with "window.matchMedia(query).matches" instead of "false", to avoid false states when changing pages
const [matches, setMatches] = useState(window.matchMedia(query).matches);
isMobile should be 'max-width: 768px'😂