Criando layouts responsivos e adaptativos com React e Styled-Components
Tags: react, javascript, css, design
Published: 2019-11-26 03:30:31

###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.
<a href="http://imgbox.com/dm02i7ue" target="_blank"><img src="https://images2.imgbox.com/6d/2b/dm02i7ue_o.png" alt="Estrutura de pasta create-react-app"/></a>
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.
<a href="http://imgbox.com/J5sRh5rd" target="_blank"><img src="https://images2.imgbox.com/77/c3/J5sRh5rd_o.png" alt="estrutura sem arquivos desnecessários"/></a>
Só pra gente ter uma referência, vamos usar essa imagem como layout:
<a href="http://imgbox.com/Ft3xpXOY" target="_blank"><img src="https://images2.imgbox.com/1b/db/Ft3xpXOY_o.jpg" alt="layout"/></a>

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!).
<a href="http://imgbox.com/7TlRmEY2" target="_blank"><img src="https://images2.imgbox.com/7b/07/7TlRmEY2_o.png" alt="image host"/></a>
Vamos usar aqui o styled-components para criar um estilo global. Segue o código:

``` 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;
```
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:
``` javascript
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:
``` 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;
  }
`;
```
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_:
``` 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>
  );
}
```
E agora é só ajustar nosso componente App.js para importar nosso layout:
``` 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;
```

Prontinho! Agora é só dar um _npm run start_ ou _yarn start_ e ver o resultado redimensionando a tela. Veja:
<a href="http://imgbox.com/SAlZxNRE" target="_blank"><img src="https://images2.imgbox.com/2a/a0/SAlZxNRE_o.gif" alt="image host"/></a>

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](https://github.com/carlos-cne/layoutsArticle). 
Me adicionem também no [linkedin](https://www.linkedin.com/in/carlos-queiroz-dev/) e bora trocar ideia!

**[English version is here](https://dev.to/carloscne/creating-responsive-and-adaptive-layouts-with-react-and-styled-components-1ghi)