DEV Community

Carlos Queiroz
Carlos Queiroz

Posted on • Updated on

Criando layouts responsivos e adaptativos com React e Styled-Components

Fala Techs!

Sabemos que nos dias atuais, para criar sites e web apps precisamos sempre estar preocupados com os diversos dispositivos e tamanhos de telas.

Muitas vezes temos um profissional de UI que faz aquele layout maravilhoso para uma tela de 1440px de largura e aí quando vamos construindo o layout usando as medidas fixas em pixels, fica um pouco estranho (Pra não dizer muito) em telas com resoluções diferentes. E as fontes então? Nem se fala.

Vou descrever aqui uma ideia que tenho usado para resolver esse problema. Existem muitas formas de fazer isso e aqui vou mostrar apenas mais uma delas.

Só precisamos alinhar alguns conhecimentos prévios e conceitos:

  • Estou utilizando o create-react-app para criar uma estrutura básica do React sem se preocupar com configuração do Webpack e afins.
  • Suponho que você saiba o que é o ReactJS e Styled-Components. Se não souber, em uma pesquisa rápida você encontra todos os conceitos. Embora eles possam ser aplicados em CSS puro também.

Layouts responsivos são aqueles que se ajustam ao tamanho da tela do usuário. Eles não mudam a posição das coisas, simplesmente ajustam.
Layouts adaptativos também se ajustam a tela do usuário, porém muitas vezes trocando a posição dos elementos e geralmente possuem media queries para adaptar ao tamanho da tela.

Bora começar!

Vamos começar criando nosso projeto com o create-react-app.
Após criar o projeto, acesse o diretório do projeto e instale o styled-component como dependência. Se você quiser configurar manual, sem usar o CRA fique a vontade.
Estrutura de pasta create-react-app
Na pasta src vamos deixar somente os arquivos App.js e index.js. Apague os outros arquivos e lembre-se de remover as referências desses arquivos deletados do projeto.
estrutura sem arquivos desnecessários
Só pra gente ter uma referência, vamos usar essa imagem como layout:
layout

Vamos também supor que o UI definiu que teremos fontes de tamanhos diferentes para Mobile com 24px, Tablet com 18px e Web com 16px.

Com essas informações em mãos, vamos seguir nosso projeto.

Reset CSS e configurações globais.

Na pasta src vamos criar outra pasta chamada styles e dentro da dessa pasta um arquivo chamado global.js (Essa organização que costumo usar em projetos pessoais. Se quiser usar de outra forma, sem problemas!).
image host
Vamos usar aqui o styled-components para criar um estilo global. Segue o código:

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;

O que fizemos aqui foi zerar algumas propriedades e definir o root do HTML com o tamanho das fontes que vamos usar.

Observe que importei uma função que chamei de px2vw. Essa função converte pixels para viewport width.

Como nosso layout será responsivo, preciso que ele se adapte em todos os tamanhos de tela e por isso vou usar o tamanho da viewport.
Poderia ter pensado em usar percentual, mas o problema é que se você definir um percentual dentro de um outro elemento menor que a viewport, ele vai usar o tamanho daquele elemento e neste caso não resolveria o problema.

Também vou usar essa função para os tamanhos de fonte pelo mesmo motivo: Se os elementos vão se ajustando a tela, as fontes também vão.

Optei por não trabalhar usando também o viewport height porque normalmente trabalhos com a largura e não com a altura da tela e também porque tive um outro problema desenvolvendo para Smart Tvs. Depois conto o que foi.

Função px2vw.

Bora então criar nossa função. Na pasta src do nosso projeto, vamos criar uma pasta utils e lá dentro vamos criar o arquivo px2vw.js.
Segue o código dele:

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

export default px2vw;

Para essa função, já deixei o valor do width padrão de 1440px, mas você pode usar qualquer outro ou ainda sempre receber como parâmetro da função ou ainda deixando ela mais genérica.

Criando a página do projeto.

Vamos agora criar uma página para exibir nosso layout.
Dentro da pasta src vamos criar uma pasta chamada pages e dentro dela vamos criar outra pasta chamada Home.
Dentro dessa pasta Home vamos criar dois arquivos. Vou separar componentes de estilo e componentes de lógica.

Vamos criar então os arquivos Home.js e HomeStyles.js.

HomeStyles.js:

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;
  }
`;

Construímos a estilização do nosso componente. Adicionei estilos de texto pra gente ver como se comporta quando o tamanho da fonte é alterado.

Quando chamo a função px2vw para um outro tamanho de tela, passo esse tamanho como parâmetro. min-height: ${px2vw(200, 320)};

Usei também media queries para fazer nosso layout ser, além de responsivo ser também adaptativo, ou seja, dependendo do tamanho da tela as "caixas" vão se ajustando conforme o layout de exemplo.

Para cada Box passei também uma propriedade bgColor para controlar a cor de cada Box.

Agora vamos ao nosso Home.js:

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>
  );
}

E agora é só ajustar nosso componente App.js para importar nosso layout:

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;

Prontinho! Agora é só dar um npm run start ou yarn start e ver o resultado redimensionando a tela. Veja:
image host

Esta é apenas mais uma das formas que você pode criar seus layouts fluidos com responsividade e adaptabilidade.

Se gostou deste texto ou até mesmo tenha um crítica ou sugestão, deixe nos comentários. É muito importante pra mim continuar me desenvolvendo e aprendendo.
O código está disponível no Github, basta clicar aqui.
Me adicionem também no linkedin e bora trocar ideia!

**English version is here

Oldest comments (5)

Collapse
 
annepattrice profile image
annepattrice

Sensacional!

Collapse
 
estrng profile image
José Ivan R. de Oliveira

Irmão parabéns, como a amiga disse, sensacional, pois foi direto ao ponto subjugando que já tenhamos um conhecimento prévio de JS, React, CSS e Html.

Collapse
 
thalycomp profile image
thalycomp

Nossa, muito obrigada! Ajudou muito!

Collapse
 
marlonkaufmann profile image
Marlon Kaufmann

Carlos, Obrigado pelo conhecimento passado. Estou aprendendo react.js e vou espelhar seu conteúdo aqui em um projeto pessoal. Faz todo sentido. Depois posto para você.Obrigado mesmo!

Collapse
 
carloscne profile image
Carlos Queiroz

Valeu Marlon! Se precisar de algo aí me chama no Linkedin.