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>
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>
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);
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; }
O que tá rolando nesse CSS?
* - Zera a
margin
e opadding
padrão de todos elementos, e com obox-sizing: border-box
o box-model passa a não incluir opadding
na soma na hora de definir a altura e largura dos elementos.img -
max-width: 100%
eheight: 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, eobject-fit: contain
faz com que a figura se redimensione pra caber completamente no container, mas se mantendo totalmente visível.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
.
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; }
}
💡 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;
}
O resultado é um grid bastante complexo:
À 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;
}
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 -->
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.
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);
}
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
|
---|---|
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%;
}
}
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)
brabo do CSS in da house 👏
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 🦤.