Saltar para o conteúdo
duxt

ProseImg

Uma imagem: consciente do tema, adaptável e ampliável.

Cada imagem de uma página Markdown.

O que acrescenta

Duas variantes. Uma captura de um editor escuro sobre uma página branca — ou o contrário — é a coisa mais feia que acontece numa documentação, e o CSS não a resolve porque o que está errado são os pixels, não a moldura. Uma página pode nomear um segundo ficheiro:

![A barra lateral](/shots/sidebar.png){dark="/shots/sidebar-dark.png"}

Dois pedidos, não um ficheiro. A imagem na página e a imagem no diálogo de ampliação pedem larguras diferentes, pelo que um telemóvel já não descarrega o original de 2400 px para o desenhar numa coluna de 48rem. Ambas são srcset gerados pelo @nuxt/image; nenhuma é um ficheiro que alguém tenha de preparar.

Clique para ampliar, salvo se a imagem pedir o contrário:

![Um diagrama](/diagram.svg){zoom="false"}

Uma imagem ampliável tem um pequeno indicador de ampliação no seu canto, de forma permanente e não ao passar o cursor — um cursor não existe num dispositivo tátil e é invisível numa captura da página. A imagem é um botão: Tab alcança-o com um anel visível, Enter e Espaço abrem o diálogo, Escape fecha-o e devolve o foco. Com zoom="false" não há indicador, nem anel, nem nada para onde tabular.

Um fundo para uma imagem transparente. Um diagrama cujo traço foi pensado para uma superfície clara desaparece numa página escura. Indique uma cor por tema — qualquer cor CSS, var(--card) incluída:

![Um diagrama](/diagram.svg){background="#fafafa" dark-background="#171717"}

Cores e não classes, de propósito: a folha de estilos da camada é construída a partir dos seus próprios componentes, nunca do Markdown, pelo que uma classe dark:bg-… escrita numa página não teria CSS por trás.

O visualizador ocupa o ecrã inteiro sobre a página desfocada. Os seus controlos — diminuir o zoom, o nível de zoom (que o repõe), aumentar o zoom, abrir o original num novo separador, fechar — flutuam numa linha acima da imagem e o texto alternativo fica por baixo, pelo que nenhum a tapa. A roda amplia à volta do cursor e o gesto de pinça à volta dos dedos; um clique na imagem amplia-a para 200 % nesse ponto e um segundo clique volta atrás; +, - e 0 fazem o mesmo pelo teclado. Uma imagem ampliada arrasta-se para a deslocar e carrega o ficheiro original para continuar nítida. Um clique no espaço à volta fecha o visualizador.

API

Props

PropTipoPadrãoNotas
srcstring—Tal como escrito
altstring—Tal como escrito
darkstring—Um segundo ficheiro, servido sob o tema escuro
zoombooleantruefalse deixa a imagem inerte
widthnumber—Opcional; ver Dimensões abaixo
heightnumber—Opcional; ver Dimensões abaixo
sizesstring—Substitui a política da página; ver Tamanhos
backgroundstring—Uma cor CSS por trás de uma imagem transparente, na página e no visualizador
dark-backgroundstring—O mesmo no tema escuro; recorre a background

Tamanhos

O tema sabe uma coisa que o @nuxt/image não pode saber: qual é a largura da caixa onde desenha uma imagem. É só isso que configura.

  • Na página — sm:95vw md:768px. Abaixo de md, o artigo é a janela menos as suas margens; a partir de md fica limitado a max-w-3xl seja qual for o ecrã, pelo que a largura pedida deixa de crescer em vez de continuar a subir num ecrã 4K.
  • No diálogo — sm:96vw md:96vw lg:96vw xl:1264px, acompanhando a janela até ao limite do próprio diálogo, min(96vw, 80rem).

Ambas nomeiam apenas os breakpoints que o @nuxt/image já traz, pelo que quem redefinir image.screens mantém a sua definição. A camada não declara screens próprios.

Uma imagem que não é tão larga como a coluna de texto — um logótipo, um distintivo, um diagrama à margem — diz-o:

![O distintivo](/badge.png){sizes="sm:50vw md:200px"}

sizes é a sintaxe do próprio @nuxt/image e alcança apenas a imagem da página. O diálogo mantém a sua política: uma que descreve a coluna de texto não pode descrever um diálogo.

Dimensões

width e height são opcionais e assim continuam — a maioria das páginas omite-os, e exigi-los partiria todas as páginas já escritas.

Indique-os mesmo assim onde puder. São eles que permitem ao navegador reservar a caixa antes de o ficheiro chegar; sem eles a imagem não tem proporção intrínseca até carregar, e o texto por baixo mexe-se quando isso acontece. O componente preserva a proporção do par que recebe e não inventa nada quando não recebe nenhum: não há proporção por omissão nem recorte, porque uma proporção errada é pior do que um salto.

Uma imagem menor do que a coluna fica no seu próprio tamanho em vez de ser esticada.

Formatos

SVG e GIF animado passam sem ser tocados, na página e no diálogo, sem qualquer srcset. Um vetor não tem pixels para reamostrar — pedir um com 608 px de largura rasteriza um ficheiro que era nítido em qualquer tamanho — e um GIF que passa por um encadeamento de rasterização volta reduzido ao seu primeiro fotograma.

É isto que o componente faz, não uma afirmação sobre fornecedores: alguns deixam estes formatos passar, outros não, e uma camada de documentação não pode saber qual foi configurado pelo consumidor. As fontes adaptáveis servem os formatos de trama para os quais a ampliação existe — PNG, JPEG, WebP, AVIF.

Fornecedores

A camada não define qualquer chave image. Que serviço transforma uma imagem pertence ao consumidor, tal como sources: um fornecedor escolhido pela camada é um fornecedor que todo o consumidor tem de desfazer, e decide uma conta e uma fatura tanto como um URL. Configure @nuxt/image como em qualquer aplicação Nuxt; o componente entrega-lhe apenas duas cadeias sizes.

Entregue a si mesmo, o @nuxt/image escolhe sozinho, e os três casos que um site de documentação encontra são:

  • Um servidor Node. O ipx transforma a pedido em /_ipx/…. Precisa do sharp, uma ligação nativa, que a saída Node já leva consigo.
  • Um site gerado (nuxt generate). O ipxStatic escreve cada variante no momento da construção. Depois disso nada corre, e a saída cresce com as variantes — o negócio que um site totalmente estático já está a fazer.
  • Um runtime na periferia — Cloudflare Workers e tudo o resto que não seja Node nem estático. Nenhum transformador corre e as imagens são servidas tal como foram versionadas. Um site pré-renderizado num runtime desses não deve ser configurado com ipx: é uma ligação nativa e não corre ali de todo. Recorra a um fornecedor de CDN se quiser as transformações.

As variantes do diálogo são geradas numa construção estática ainda que o diálogo esteja fechado quando a página é renderizada — o componente regista-as ele próprio junto do crawler de pré-renderização. Nada é descarregado até o diálogo abrir.

Uma imagem com zoom="false" não recebe nenhuma. Não há diálogo para abrir, por isso cada ficheiro do tamanho do diálogo escrito para ela seria saída que ninguém pode pedir.

Notas

A variante escura é nomeada explicitamente em vez de adivinhada por convenção. Derivar -dark de um nome de ficheiro significa que um ficheiro em falta se torna uma imagem partida, e o autor nunca fica a saber.

Uma imagem de uma fonte clonada de outro repositório não tem rota própria: o Content descarrega a árvore para .data/content/, e nada copia os seus recursos para public/. Os caminhos destes exemplos são absolutos para o public/ do próprio site consumidor, que é onde uma imagem de documentação tem de viver hoje.

Esta página foi útil?