Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/artsy/fresnel
An SSR compatible approach to CSS media query based responsive layouts for React.
https://github.com/artsy/fresnel
media-queries nextjs react react-18 responsive ssr
Last synced: 6 days ago
JSON representation
An SSR compatible approach to CSS media query based responsive layouts for React.
- Host: GitHub
- URL: https://github.com/artsy/fresnel
- Owner: artsy
- License: other
- Created: 2018-09-07T00:39:14.000Z (over 6 years ago)
- Default Branch: main
- Last Pushed: 2024-11-01T07:51:51.000Z (about 2 months ago)
- Last Synced: 2024-12-10T10:03:56.476Z (13 days ago)
- Topics: media-queries, nextjs, react, react-18, responsive, ssr
- Language: TypeScript
- Homepage: https://artsy.github.io/blog/2019/05/24/server-rendering-responsively
- Size: 3.1 MB
- Stars: 1,258
- Watchers: 39
- Forks: 65
- Open Issues: 15
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
- awesome-list - fresnel
README
# @artsy/fresnel
[![CircleCI][ci-icon]][ci] [![npm version][npm-icon]][npm]
> The Fresnel equations describe the reflection of light when incident on an
> interface between different optical media.– https://en.wikipedia.org/wiki/Fresnel_equations
## Installation
```sh
# React 18+
yarn add @artsy/fresnel# React 17
yarn add @artsy/fresnel@6
```**Table of Contents**
- [Overview](#overview)
- [Basic Example](#basic-example)
- [Server-side Rendering (SSR)](#server-side-rendering-ssr-usage)
- [Usage with Next](#usage-with-gatsby-or-next)
- [Example Apps](#example-apps)
- [Why not conditionally render?](#why-not-conditionally-render)
- [API](#api)
- [Pros vs Cons](#pros-vs-cons)
- [Development](#development)## Overview
When writing responsive components it's common to use media queries to adjust
the display when certain conditions are met. Historically this has taken place
directly in CSS/HTML:```css
@media screen and (max-width: 767px) {
.my-container {
width: 100%;
}
}
@media screen and (min-width: 768px) {
.my-container {
width: 50%;
}
}
``````html
```By hooking into a breakpoint definition, `@artsy/fresnel` takes this declarative
approach and brings it into the React world.## Basic Example
```tsx
import React from "react"
import ReactDOM from "react-dom"
import { createMedia } from "@artsy/fresnel"const { MediaContextProvider, Media } = createMedia({
// breakpoints values can be either strings or integers
breakpoints: {
sm: 0,
md: 768,
lg: 1024,
xl: 1192,
},
})const App = () => (
)ReactDOM.render(, document.getElementById("react"))
```## Server-side Rendering (SSR) Usage
The first important thing to note is that when server-rendering with
`@artsy/fresnel`, all breakpoints get rendered by the server. Each `Media`
component is wrapped by plain CSS that will only show that breakpoint if it
matches the user's current browser size. This means that the client can
accurately start rendering the HTML/CSS while it receives the markup, which is
long before the React application has booted. This improves perceived
performance for end-users.Why not just render the one that the current device needs? We can't accurately
identify which breakpoint your device needs on the server. We could use a
library to sniff the browser user-agent, but those aren't always accurate, and
they wouldn't give us all the information we need to know when we are
server-rendering. Once client-side JS boots and React attaches, it simply washes
over the DOM and removes markup that is unneeded, via a `matchMedia` call.### SSR Example
First, configure `@artsy/fresnel` in a `Media` file that can be shared across
the app:```tsx
// Media.tsximport { createMedia } from "@artsy/fresnel"
const ExampleAppMedia = createMedia({
breakpoints: {
sm: 0,
md: 768,
lg: 1024,
xl: 1192,
},
})// Generate CSS to be injected into the head
export const mediaStyle = ExampleAppMedia.createMediaStyle()
export const { Media, MediaContextProvider } = ExampleAppMedia
```Create a new `App` file which will be the launching point for our application:
```tsx
// App.tsximport React from "react"
import { Media, MediaContextProvider } from "./Media"export const App = () => {
return (
Hello mobile!
Hello desktop!
)
}
```Mount `` on the client:
```tsx
// client.tsximport React from "react"
import ReactDOM from "react-dom"
import { App } from "./App"ReactDOM.render(, document.getElementById("react"))
```Then on the server, setup SSR rendering and pass `mediaStyle` into a ``
tag in the header:```tsx
// server.tsximport React from "react"
import ReactDOMServer from "react-dom/server"
import express from "express"import { App } from "./App"
import { mediaStyle } from "./Media"const app = express()
app.get("/", (_req, res) => {
const html = ReactDOMServer.renderToString(<App />)res.send(`
<html>
<head>
<title>@artsy/fresnel - SSR Example</title><!–– Inject the generated styles into the page head -->
<style type="text/css">${mediaStyle}
${html}