DEV Community

Cover image for Construí o layout do site do Space Jam de 1996 com CSS moderno 🤯
Camilo Micheletto
Camilo Micheletto

Posted on

Construí o layout do site do Space Jam de 1996 com CSS moderno 🤯

Sumário


Marcação inicial 🔗

O site possui basicamente a galáxia como uma espécie de navegação e um footer contendo os links externos. Como boa prática, coloquei o conteúdo dentro de um <main> landmark e encapsulei a navegação e o footer dentro do contexto dele.

  <body>
    <main class="layout">
      <nav class="space"></nav>
      <footer class="footer"></footer>
    </main>
  </body>
Enter fullscreen mode Exit fullscreen mode

 

A navegação é basicamente uma lista não ordenada de links. Dessa forma o leitor de tela irá anunciar a entrada e a quantidade de itens ao acessar a lista e anunciar a saída quando a pessoa usuária mover o foco pra outro lugar.

As imagens tem texto alternativo que são lidos como conteúdo textual dos links!

<ul>
  <li>
    <a href="" class="space__link">
      <img
        src="./assets/p-pressbox.gif"
        alt="press box shuttle"
        class="space__img" />
    </a>
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

CSS base 🔗

No index.css criei duas camadas - a de reset que irá sobrescrever o CSS padrão do navegador (user-agent stylesheet) e a default que receberá todo código diretamente relacionado à aplicação. Isso faz com que o código da aplicação jamais seja inferior que o do reset em especificidade, mas também cria uma estrutura que pode comportar ainda mais camadas.

@layer reset, default;

@import "reset.css" layer(reset);
Enter fullscreen mode Exit fullscreen mode

 

No arquivo de reset, apenas o necessário dado o contexto do projeto. Em aplicações mais robustas talvez eu optasse por um normalizer.

* {
  margin: 0; padding: 0;
  box-sizing: border-box;
}

img {
  height: auto;
  max-width: 100%;
  vertical-align: middle;
  object-fit: contain;
}

body {
  min-block-size: 100vh;
  background-image: url("./assets/bg_stars.gif");
}

ul { list-style-type: none; }
Enter fullscreen mode Exit fullscreen mode

O que tá rolando nesse CSS?

  1. * - Zera a margin e o padding padrão de todos elementos, e com o box-sizing: border-box o box-model passa a não incluir o padding na soma na hora de definir a altura e largura dos elementos.

  2. img - max-width: 100% e height: auto fazem com que a imagem aja de forma fluida mas mantendo o aspect-ratio. vertical-align: middle remove aquele espacinho branco esquisito na parte de baixo da imagem, e object-fit: contain faz com que a figura se redimensione pra caber completamente no container, mas se mantendo totalmente visível.

  3. body - min-block-size: 100vh faz com que o site seja no mínimo do tamanho da tela toda.


O container principal 🔗

O layout é basicamente composto por 3 classes - .layout que coloca o site no centro da tela de forma responsiva, a .space que cria o grid em que os planetas vão se encaixar e a .space__item que define o alinhamento e posição dos itens do grid.

Vamos começar com o .layout.

Grid de 3 colunas contendo o conteúdo no centro

 

Essa classe é aplicada no <main>, como <nav> e <footer> são seus únicos filhos, criei um grid de 3 colunas e empurrei os seus dois filhos diretos pra segunda coluna, a do meio. O grid foi construído de forma que quando a largura da página for menor que 600px ele ocupará 100% da largura tela. Como o 1fr se refere a uma fração do espaço restante, como não restará espaço, seu valor será zero, dando a ilusão de que só há uma coluna.

.layout {
  display: grid;
  grid-template-columns: 1fr min(600px, 100%) 1fr;
  place-content: center;
  height: 100vh;
 & > * { grid-column: 2; }
}
Enter fullscreen mode Exit fullscreen mode

💡 O & nesse código não é Sass, o CSS tem suporte pra nesting nos principais navegadores, não é o suficiente pra ser usado em produção, mas já podemos brincar em projetos como esse. Caso queira saber mais, leia esse artigo do chrome sobre esse assunto, em inglês.

 

O conceito é um pouco avançado, escrevi um artigo bem visual sobre esse padrão de layout em grid:

 


A constelação 🔗

A área em que fica a galáxia do space-jam e que é uma table no original é um grid com 5 colunas e 4 linhas. O valor de cada célula usa fr pra que a distribuição de espaço nunca seja exata, mas sempre proporcional ao espaço disponível. Isso faz com que a constelação se mantenha íntegra mesmo em viewports muito pequenos.

.space {
  display: grid;
  grid-template-columns: 0.5fr 0.75fr 1fr 0.5fr 0.75fr;
  grid-template-rows: 1fr 0.5fr 0.5fr 1fr;
  width: 100%;
  aspect-ratio: 1 / 1;
}
Enter fullscreen mode Exit fullscreen mode

 

O resultado é um grid bastante complexo:

Grid com 5 colunas e 4 linhas contendo os planetas

 

À partir disso, eu podia criar várias classes pra cada item desse grid com :nth-child e definir uma grid-area e um alinhamento pra cada um, mas escolhi uma abordagem diferenciada:

.space__item {
  --size: auto;
  display: grid;
  place-items: center;
  height: var(--size);
  width: var(--size);

  align-self: var(--align, center);
  justify-self: var(--justify, center);
  grid-area: var(--area);

  aspect-ratio: 1 / 1;
}
Enter fullscreen mode Exit fullscreen mode

 

Pense nessas variáveis como props ou como argumentos de uma função em Javascript. A width e o height podem ser customizados pela variável --size, mas se não forem, o valor padrão é auto, o mesmo vale pros alinhamentos. Dessa forma, ao invés de criar uma dúzia de classes pra estilizar cada planeta, eu transferi essa responsabilidade para o template.

<li
  class="space__item"
  style="
    --area: 1 / 1 / 2 / 3;
    --align: end;
    --justify: end"
>
  <a href="" class="space__link">
    <img
     src="./assets/p-pressbox.gif"
     alt="press box shuttle"
     class="space__img" />
   </a>
</li>

<!-- outros elementos -->

Enter fullscreen mode Exit fullscreen mode

 

Dessa forma, cada elemento no HTML passaria como "props" sua própria orientação e alinhamento para a mesma classe no CSS. Se pensar, tem a mesma manutenabilidade e legibilidade de uma classe Tailwind.

Como a galáxia faz um circulo bem decente, apenas com os alinhamentos do grid não foi possível alinhar de forma circular os planetas nas extremidades.

Site com os planetas desalinhados

 

Pra isso, houve um ajuste em planetas específicos:

.space__link:nth-child(3) {
  transform: translateY(12vmin);
}

.space__link:nth-child(10) {
  transform: translateY(-6vmin);
}
Enter fullscreen mode Exit fullscreen mode

O vmin é calculado pelo tamanho do menor eixo de viewport, os valores foram definidos na base do teste. O vmin foi escolhido pois eu precisava de uma unidade que diminuísse o espaçamento do translate proporcionalmente ao tamanho da tela quando esse diminuísse.

Exemplo do layout em 320px:

Com o ajuste no transform Sem o ajuste no transform
Com o ajuste no transform Sem o ajuste no transform

Finalmente 🔗

Fiquei super feliz que foi possível construir esse layout usando apenas 98 linhas de CSS e um template bem enxuto. Com Sass, seriam 81 linhas. Mas não é só uma questão de contagem de linhas, mas usar o CSS de forma a extrair o máximo do seu potencial de forma robusta e sem desperdício de recursos.

O código em scss, se tiver curiosidade
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

:where(img) {
  height: auto;
  max-width: 100%;
  vertical-align: middle;
  object-fit: contain;
}

:where(body) {
  min-block-size: 100vh;
  background-image: url("./assets/bg_stars.gif");
}

:where(ul) { list-style-type: none; }

.layout {
  display: grid;
  grid-template-columns: 1fr min(600px, 100%) 1fr;
  place-content: center;
  height: 100vh;
  & > * { grid-column: 2; }
}

.space {
  width: 100%;
  & ul {
    display: grid;
    grid-template-columns: 0.5fr 0.75fr 1fr 0.5fr 0.75fr;
    grid-template-rows: 1fr 0.5fr 0.5fr 1fr;
    aspect-ratio: 1 / 1;
  }

  &__item {
    --size: auto;
    display: grid;
    place-items: center;
    height: var(--size);
    width: var(--size);

    align-self: var(--align, center);
    justify-self: var(--justify, center);
    grid-area: var(--area);

    aspect-ratio: 1 / 1;

    &:nth-child(3) { transform: translateY(12vmin); }
    &:nth-child(10) { transform: translateY(-6vmin); }
  }
}

.footer {
  display: grid;
  justify-items: center;
  gap: 2ch;
  width: 100%;
  color: rgb(255, 76, 76);
  &__link {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 2ch;
  }

  &__link-item {
    flex-grow: 2;
    text-align: center;
    a { color: inherit; }
  }

  &__text {
    max-width: 40ch;
    text-align: center;
    line-height: 150%;
  }
}

Enter fullscreen mode Exit fullscreen mode

 

Sites antigos assim são uma ótima referência de estudos, principalmente porque naquela época o propósito da web era outro que não meramente comercial, permitindo com que pessoas transbordassem liberdade criativa nos seus lotes na internet.

Se quiser ver o site online e inspecionar o código, basta acessar o link abaixo.

.

Top comments (2)

Collapse
 
leandronsp profile image
Leandro Proença

brabo do CSS in da house 👏

Collapse
 
raulferreirasilva profile image
Raul Ferreira

Muito bom acompanhar essa sequencia de artigos, sempre fico surpreso com sua escrita e com a qualidade técnica dos posts, esse conteúdo é um deleite para meus olhos KKKK, obrigado por compartilhar seu conhecimento 🦤.