Creating responsive and adaptive layouts with React and Styled-Components
Tags: react, javascript, css, design
Published: 2019-12-01 19:36:09

What's up, Techs!

Nowadays, to create websites and web apps we need to care about a lot of devices and screen sizes.

In a normal situation, a UI professional creates a beautiful layout to works in a 1440px width device screen, and we begin building that layout at a fixed-size in pixels. This can become a little weird if we try to render that layout on different screens. And what about fonts, then?

I'm going to describe here an idea that I've used to handle this. There are many ways to achieve responsive and adaptive layouts, and I will show another one.

Let's align some concepts and previous knowledge:

**Responsive layouts** fit to a user's screen size. They don't change element positions, just fit.
**Adaptive layouts** fit to user screen size as well but according to screen size, elements change position to fit the screen using media queries.

I'll use ReactJS and Styled-Component. I suppose that you know about them. If you wanna know about these libs you can search here in dev.to and you'll learn a lot about them! But if you want, you can use it with SCSS or SASS.

I will use _creact-react-app_ to set up a new project without needing to set up Webpack and others. You decide if you want to configure your own project or use CRA.

####So, let's start!

Let's begin creating our project with _create_react_app_.
After that, go to the project's folder and install [_styled-component_](https://github.com/styled-components/styled-components) as a project dependency.
<a href="http://imgbox.com/dm02i7ue" target="_blank"><img src="https://images2.imgbox.com/6d/2b/dm02i7ue_o.png" alt="folder structure"/></a>
We will clean our _src_ folder and let only App.js and index.js files. Delete other files and remember to remove all references from removed files.
<a href="http://imgbox.com/J5sRh5rd" target="_blank"><img src="https://images2.imgbox.com/77/c3/J5sRh5rd_o.png" alt="new folder structure"/></a>

**Ok, now let's check out the design that we will create:**
<a href="http://imgbox.com/Ft3xpXOY" target="_blank"><img src="https://images2.imgbox.com/1b/db/Ft3xpXOY_o.jpg" alt="layout"/></a>
Our UI seted font size for mobile with 24px, tablet with 18px and web with 16px.

For our reference, mobile has 320px width, tablet 720px width and desktop starting at 1024px width.

####CSS reset and global configurations:

In _src_ folder, let's create another folder called _styles_ and inside this folder, create a file called global.js.
<a href="http://imgbox.com/7TlRmEY2" target="_blank"><img src="https://images2.imgbox.com/7b/07/7TlRmEY2_o.png" alt="image host"/></a>
We will use here _styled-component_ lib in order to create a global style. Here is the code:

``` javascript
import { createGlobalStyle } from "styled-components";
import px2vw from "../utils/px2vw";

export const Global = createGlobalStyle`
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }
  :root {
      font-size: ${px2vw(24)};

      @media (min-width: 768px) {
        font-size: ${px2vw(18)};
      }

      @media (min-width: 1024px) {
        font-size: ${px2vw(16)};
      }
    }
`;

export default Global;
```
What we did here was reset some CSS properties and define our HTML _root_ with font sizes that we will use.

I have imported a function called **px2vw**. We will create this function below. This function converts pixels to **viewport width**.
As our layout will be responsive, we need it to adapt to all screen sizes and we will use viewport size to accomplish this.

We'll also use that function for the same reason: If the elements will resize to fit the screen, fonts will as well.

I have decided to not use viewport height because normally we work with screen width and not with screen height and also **because I had another issue while developing for smart tv using viewport height**. _I'll tell you this at another opportunity_.

####px2vw function:
Let's create our function. In the _src_ folder, create a new folder called _utils_ and create a file called px2vw.js inside _utils_ folder: Let's check the code:
``` javascript
const px2vw = (size, width = 1440) => `${(size / width) * 100}vw`;

export default px2vw;
```
For this function, the default value of width is 1440px due to the layout, but if you want to use with another value or do a more generic function, feel free.

####Creating a page for our project.
Now, let's create a page to show our layout.
In the _src_ folder, create another folder called _pages_ and inside there, create another folder called _Home_.
Inside the _Home_ folder, we will create 2 files. We are going to separate style components and logic components.

The first one is _HomeStyles.js_ file. Here is the code:
``` javascript
import styled from "styled-components";
import px2vw from "../../utils/px2vw";

export const Container = styled.div`
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin: ${px2vw(32)};
  max-width: 100%;

  @media (min-width: 1024px) {
    flex-wrap: nowrap;
  }
`;

export const Box = styled.div`
  display: flex;
  width: ${px2vw(320, 320)};
  min-height: ${px2vw(200, 320)};
  flex-direction: column;
  padding: ${px2vw(20)};
  margin: ${px2vw(20)};
  background-color: ${props => props.bgColor};
  height: 100%;

  @media (min-width: 768px) {
    width: ${px2vw(320, 768)};
    min-height: ${px2vw(200, 768)};
    height: 100%;
  }

  @media (min-width: 1024px) {
    width: ${px2vw(500)};
    min-height: ${px2vw(300)};
    height: 100%;
  }
`;

export const BoxTitle = styled.h3`
  color: #333;
  font-size: 2rem;
  text-align: center;

  @media (min-width: 1024px) {
    font-size: 1.5rem;
  }
`;

export const BoxText = styled.p`
  margin-top: ${px2vw(20)};
  color: #666;
  font-size: 1.5rem;

  @media (min-width: 1024px) {
    font-size: 1rem;
  }
`;
```
We have built our presentation layer. If you noticed, I'm also added in code above some text style to manage how font sizes behave.
When we call px2vw function for another screen size, we give the screen size as a parameter: `min-height: ${px2vw(200, 320)};`

I'm also using media queries to make our layout adaptive as well as responsive. It means, depending on screen size, boxes will resize according to our example layout.

For each box, I've given a bgColor property to control the color of each box.

Now, let's build our logic layer. We will create a _Home.js_ file as follows below:
``` javascript
import React from "react";

import { Container, Box, BoxTitle, BoxText } from "./HomeStyles";

export default function Home({ boxData }) {
  return (
    <Container>
      {boxData.map(box => (
        <Box key={box.id} bgColor={box.bgColor}>
          <BoxTitle>{box.title}</BoxTitle>
          <BoxText>{box.text}</BoxText>
        </Box>
      ))}
    </Container>
  );
}
```
And now, to finish, we need to import _home.js_ to _App.js_:
``` javascript
import React from "react";

import Global from "./styles/global";

import Home from "./pages/Home/Home";

const lorem =
  "Lorem, ipsum dolor sit amet consectetur adipisicing elit. Laboriosam, sed iure blanditiis voluptatum nulla quidem minus quam tempora obcaecati necessitatibus inventore! Vitae totam quam pariatur facilis fugit maxime adipisci eaque.";

const data = [
  {
    id: Math.random(),
    title: "Box titulo 1",
    text: lorem,
    bgColor: "#D5CAFA"
  },
  {
    id: Math.random(),
    title: "Box titulo 2",
    text: lorem,
    bgColor: "#EDA9A9"
  },
  {
    id: Math.random(),
    title: "Box titulo 3",
    text: lorem,
    bgColor: "#F2EE8D"
  },
  {
    id: Math.random(),
    title: "Box titulo 4",
    text: lorem,
    bgColor: "#9FEACD"
  }
];

function App() {
  return (
    <>
      <Global />
      <Home boxData={data} />
    </>
  );
}

export default App;
```
Alright! Now, let's run our project with _npm run start_ or _yarn start_ and see the result of resizing the screen. Check it out:
<a href="http://imgbox.com/SAlZxNRE" target="_blank"><img src="https://images2.imgbox.com/2a/a0/SAlZxNRE_o.gif" alt="image host"/></a>

This is just another approach to fluid, responsive and adaptive layouts.

If you liked or have a suggestion or review, please let me know in the comments area below. It is so important to me to keep moving forward and improve.
The code of the entire project is available on Github, [just click here] (https://github.com/carlos-cne/layoutsArticle).
Please add me on [LinkedIn] (https://www.linkedin.com/in/carlos-queiroz-dev/) and let's share ideas!