DEV Community

Cover image for Creating responsive and adaptive layouts with React and Styled-Components
Carlos Queiroz
Carlos Queiroz

Posted on • Updated on

Creating responsive and adaptive layouts with React and Styled-Components

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 as a project dependency.
folder structure
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.
new folder structure

Ok, now let's check out the design that we will create:
layout
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.
image host
We will use here styled-component lib in order to create a global style. Here is the code:

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;
Enter fullscreen mode Exit fullscreen mode

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:

const px2vw = (size, width = 1440) => `${(size / width) * 100}vw`;

export default px2vw;
Enter fullscreen mode Exit fullscreen mode

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:

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;
  }
`;
Enter fullscreen mode Exit fullscreen mode

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:

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

And now, to finish, we need to import home.js to App.js:

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;
Enter fullscreen mode Exit fullscreen mode

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:
image host

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.
Please add me on LinkedIn and let's share ideas!

Top comments (4)

Collapse
 
tom4244 profile image
Thomas Box

You're off to a good start I guess, but all of the objects in your example are the same height and width. That makes it unrealistically easy. So my suggestion would be to do this for different sizes of objects, which move to at least three rows on smaller devices, while minimizing or eliminating space between them for all devices. By the way, I don't know what the Portuguese equivalent is, but "responsive" in English in web site design commonly does mean that elements change position as well as size.

Collapse
 
carloscne profile image
Carlos Queiroz

Hey Thomas! Thank you for your comment! I'll revise the article and improve all this stuff. Thanks again.

Collapse
 
lankinen profile image
Lankinen

Amazing post. It's so elegant solution. I'm afraid that even after reading this my own solution will be a big mess. Well I will read this again then and maybe I get it finally as clean as this one.

Collapse
 
dchatrades profile image
Devin

Really valuable article for people like me working at an organization who's all in on reinventing CSS and all out on learning CSS lmao