Unlock the Power of Responsive Design with Fresnel
Why Responsive Design Matters
In today’s digital landscape, providing an exceptional user experience (UX) is crucial for any web application. With the majority of users accessing websites through mobile devices, tablets, and desktops, responsive design has become a must-have in modern web development.
What are CSS Media Queries?
Media queries allow developers to define different styling rules for various viewport sizes. Traditionally, we create HTML elements and then use CSS to describe how they’ll behave on different screen widths via media queries.
/* Example of a media query */
@media only screen and (max-width: 480px) {
/* Styles for screen widths up to 480px */
.square-element {
background-color: blue;
}
}
Introducing Fresnel
Fresnel revolutionizes the traditional media query approach by transferring its breakpoint logic to the React ecosystem. This open-source npm project, created by Artsy, is easy to use and trusted by developers worldwide. Fresnel’s API enables us to use MediaContextProvider
and Media
components to build a solid foundation for responsive web applications.
Fresnel vs Conditional Rendering
While conditional rendering works fine for client-side rendering, it falls short when implementing server-side rendering (SSR) solutions. Fresnel shines by rendering all breakpoints on the server, allowing us to properly render HTML/CSS before React has booted. This significantly improves the UX for users.
Building a Responsive App with React and Fresnel
Let’s create a color card application that switches its layout for mobile and desktop views. We’ll use Fresnel to render the breakpoints on the server, ensuring a seamless UX.
Initializing the React App
We’ll start by creating a new project folder and initializing a new React project using npm init -y
. Next, we’ll install the necessary dependencies, including Express for the backend and Fresnel for responsive design.
npm init -y
npm install express fresnel
Modeling Data in React
We’ll separate the data from the app logic by creating a data
folder with a colors.jsx
file containing an array of color names.
// data/colors.jsx
const colors = [
'ed',
'blue',
'green',
//...
];
export default colors;
Creating Breakpoints
We’ll define specific breakpoints using the createMedia
function and export mediaStyle
, which we’ll inject into the server-side.
// media.js
import { createMedia } from 'fresnel';
const { mediaStyle } = createMedia({
breakpoints: {
mobile: '(max-width: 480px)',
desktop: '(min-width: 481px)',
},
});
export default mediaStyle;
Creating Components
We’ll create four separate files for the DesktopComponent
and MobileComponent
, along with their respective CSS files. We’ll use grid templates to define the columns and rows for the desktop view and a single-column layout for the mobile view.
/* desktop.css */
.grid-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 10px;
}
/* mobile.css */
.grid-container {
display: flex;
flex-direction: column;
}
Implementing Frontend with Fresnel
We’ll create an App
component that will render the components based on the viewport size. We’ll use Media
and MediaContextProvider
to control which components should be displayed on which viewports.
// App.jsx
import React from 'eact';
import { Media, MediaContextProvider } from 'fresnel';
import DesktopComponent from './DesktopComponent';
import MobileComponent from './MobileComponent';
const App = () => {
return (
<MediaContextProvider>
<Media at="mobile">
<MobileComponent />
</Media>
<Media at="desktop">
<DesktopComponent />
</Media>
</MediaContextProvider>
);
};
export default App;
Setting Up the Backend
We’ll create a server
folder with an index.jsx
file, using Express to provide the functionality for server-side rendering. We’ll generate HTML on the server and send the markup as a response.
// server/index.jsx
import express from 'express';
import React from 'eact';
import ReactDOMServer from 'eact-dom/server';
import App from '../App';
const app = express();
app.get('*', (req, res) => {
const markup = ReactDOMServer.renderToString(<App />);
res.send(`<html><body>${markup}</body></html>`);
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
Configuring Builds
We’ll use esbuild to bundle our files for SSR. We’ll set up scripts in package.json
to run the build commands for both the frontend and server files.
// package.json
"scripts": {
"build:frontend": "esbuild frontend/index.jsx --bundle --outdir=public",
"build:server": "esbuild server/index.jsx --bundle --platform=node --outdir=server",
"start": "node server/index.js"
}
Testing the React App
Finally, we’ll run the app using npm start
and test it in the browser. We’ll see how the responsive design works seamlessly across different viewport sizes.
- Run
npm start
to start the server. - Open the app in a browser and resize the window to see the responsive design in action.