Categorias
Tutoriais

Lazy-loading nativo dos browsers

Lazy Loading ou Carregamento tardio para imagens e vídeos é um recurso onde você prioriza o carregamento dos itens visíveis na tela do usuário. O resultado dessa ação melhora o tempo de carregamento para a área visível do usuário e o carregamento de recursos somente quando necessário super relevante para usuários mobile.

Esse Recurso foi introduzido pelo internet Explorer 11 mas nenhum browser implementou o recurso nessa época. Em 2019 o Chrome voltou a colocar o recurso em pauta na versão 76. Atualmente o recurso está disponível para Edge, Firefox, Chrome, Opera e Android Browser. Já no Safari recurso está disponível em formato de teste.

Em Agosto de 2020 o recurso ganhou atenção quando passou a fazer parte do Core do WordPress na versão 5.5. Mas como esse recuso funciona? Nesse posts vamos ver como implementar essa funcionalidade e os requisitos para fazer uso do recurso.

Trabalhando com Lazy-Loading

Para aplicar o lazy-loading em imagens adicionamos o atributo loading na tag img, por exemplo:

<img loading="lazy"src="minha_foto.jpg" />

O atributo loading pode receber os seguintes valores:

  • auto: Executará o comportamento padrão do navegador
  • lazy: A image só será carregada quando o scroll chegar uma distância específica da área visível.
  • eager: Carrega o recurso imediatamente caso esteja localizado na página.

Além da propriedade loading as imagens precisam ter especificadas suas dimensões largura e altura. Isso porque até carregar as imagens o browser não sabe as dimensões da imagem. Além disso a falta de dimensões podem causar mudanças de layout durante o carregamento também um fator que pode comprometer a experiência do usuário.

A definição das dimensões é uma recomendação já antiga antes mesmo da propriedade loading existir. Com o lazy-loading isso se torna mais relevante sem as dimensões o carregamento fica ainda mais dependente dos browsers.

As tags picture, video e iframe também podem fazer o uso do lazy loading como no exemplo abaixo:

<picture> <source media="(min-width: 900px)" srcset="wordcamp.jpg 1x, wordcamp_2x.jpg 2x"> <img src="wordcamp_fallback.jpg" loading="lazy"> </picture>
<video src="./wordcamps/wordcamp_edinburgh_2018.MP4" width="720" height="1280" loop loading="lazy" controls="false" muted></video>
<iframe width="900" height="515" loading="lazy" src="https://www.youtube.com/embed/yT7fCspMrU8" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

No código anterior temos múltiplas alternativas de carregamento mas o atributo loading só precisa ser definido na tag img.

Carregamento de imagens e sua visualização

A implementação do recurso tenta garantir performance sem afetar a experiência do usuário. Assim o carregamento da imagem irá iniciar quando a imagem atingir uma distância minima da área visível. Mas vale lembrar que o carregamento das imagens ficam dependentes da rede do usuário.

Comparado a algumas bibliotecas de lazy loading a distância implementada pelos browsers que rodam a engine do Chrome são um pouco conservadoras.

Mas no Chrome essa distância não é fixa ele é dependente de alguns fatores:

  • O tipo da imagem que está sendo carregada
  • Se o modo econômico tá habilitado
  • Conexão efetiva do device

Mudanças em 2020

Após a implementação do recurso na versão 76 em Julho de 2020 essa distância foi reduzida baseada nos relatórios recolhidos nos primeiros meses de uso do recurso. Para conexões 4G o primeiro carregamento ficava restrito a uma área de 3000px agora foi reduzido para 1250px. e para conexões lentas de 4000px para 2500px.

Essas medidas reduzem o carregamento médio de imagens em até 40%. O assunto não é muito extenso então vamos ficando por aqui para mais tutoriais acesse a página da categoria tutoriais. Também fiz um vídeo em meu canal onde eu abordo o assunto:

Para mais informações sobre lazy loading acesse o site do web.dev: https://web.dev/native-lazy-loading/.

Categorias
HTML5 JavaScript Tutoriais

Trabalhando com XMLHttpRequest e Fetch API

Nesse post vamos trabalhar com duas opções para realizar requisições Assíncrona a dados no servidor XMLHttpRequest e Fetch API. Com a popularização do jQuery por muito tempo utilizamos a biblioteca para fazer requisições AJAX pela facilidade, melhorias com recursos extras e o suporte aos browsers antigos.

Mas temos um recurso antigo que nos permite realizar requisições ao servidor com Vanilla JavaScript, o XMLHttpRequest.

XMLHttpRequest

XMLHttpRequest é um objeto XHR para interação com servidores. Com ele podemos requisitar dados sem realizar o reload de todo conteúdo, para você que está programando agora isso pode parecer básico, mas não era possível no começo da web.

Com a popularização do AJAX o XMLHttpRequest foi utilizado como recurso base para o conceito. O nome sugere que a API é focada em XML, mas elas pode resgatar qualquer tipo de dado.

Utilizando XMLHttpRequest

Para esse exemplo iremos fazer uma requisição a um arquivo em nosso projeto:

function onLoadRequest(event) { console.log(this.responseText); } const oRequest = new XMLHttpRequest(); oRequest.addEventListener('load', onLoadRequest); oRequest.open('GET', '/dados.json'); oRequest.send();

No código acima criamos uma objeto XMLHttRequest, onde adicionamos um listener para ouvir quando a requisição for lida. Assim abrimos uma requisição do tipo GET para arquivo dados.json em nosso projeto. E por fim enviamos a requisição com o método “send”

Por padrão essa requisição será assíncrona, isso significa que a execução do código continuará sendo executada e quando os dados forem recebido a função de callback onLoadRequest será executada.

Tratando as resposta

Temos diversos tipos de atributos de respostas a requisição os principais são responseXML e responseText no exemplo anterior tratamos o responseText.

responseXML: é utilizado para tratar requisições feitas para arquivos XML, nesse tipo de requisição podemos trabalhar de quatro formas com: XPath, Parsing e serialização de XML, XMLSerializer e expressões regulares.

responseText: se você deseja ler conteúdo de texto ou de uma página web e injetar em sua página Web, esse é o caminho. Atualmente é o formato mais utilizado na web.

Monitorando o processo

No código anterior, adicionamos um listener para o evento de load mas temos a opção de trabalhar com 5 eventos:

  • progress
  • error
  • abort
  • load
  • loadend(abort, load ou error)
// evento disparado quando a requisição for completa function onLoadRequest(event) { console.log(this.responseText); } // evento disparado quando o download do arquivo tem uma progressão function onProgressRequest (oEvent) { if (oEvent.lengthComputable) { let percentComplete = oEvent.loaded / oEvent.total * 100; console.log('Percentagem:', percentComplete + '%') } else { console.log('O total do arquivo é desconhecido'); } } const oRequest = new XMLHttpRequest(); oRequest.addEventListener('load', onLoadRequest); oRequest.addEventListener('progress', onProgressRequest) oRequest.open('GET', '/dados.json'); oRequest.send();

Caso algo de errado aconteça podemos realizar uma verificação para realizar um tratamento. Assim vamos adicionar uma condicional em nosso código:

function onLoadRequest(event) { if(this.status === 200) { console.log(this.responseText) } else { console.log('Somthing wrong happen:',this.status); } }

No código acima verificamos se o status da requisição é 200(sucesso) caso contrário exibimos o status, dai temos uma várias possibilidades: 404, 401, 500…

Fetch API

Fetch API é uma melhoria sobre a XMLHttpRequest. Ela trás a possibilidade de trabalhar com interface para administrar as requisições de recursos na rede, anteriormente tínhamos XMLHttpRequest para acompanhar requisições na rede, mas era uma API bem limitada comparada com as necessidades das aplicações modernas que temos hoje em dia. Por outro lado sua desvantagem que ela está presente apenas nos browsers modernos.

Principal diferença que agora com Fetch Api podemos ter objetos específicos para requisições(Request) e repostas(Response). Isso permite que elas sejam utilizadas em diferentes situações como por exemplo, Service Workers e Cache API.

Ela também fornece uma definição para conceitos relacionados, como CORS e semântica de cabeçalhos HTTP.

Utilizando fetch API

Para realizar uma requisição com fetch API, chamamos o método fetch() presente no Window ou em um Worker global. O método tem como parâmetro obrigatório o caminho do arquivo ao qual desejamos requisitar. Agora vamos para um exemplo simples com fetch API:

fetch('/dados.json') .then((response) => console.log(response));

Primeira diferença, é a quantidade de linhas que escrevemos, também a opção de se trabalhar com Promises. No caso acima realizamos uma requisição para o mesmo endereço caso sucesso exibimos em nosso console o tipo de resposta que será seguinte, um objeto do tipo Response com as seguintes informações:

body: (...) bodyUsed: false headers: Headers __proto__: Headers ok: true redirected: false status: 200 statusText: "OK" type: "basic" url: "http://127.0.0.1:5500/dados.json"

Com podemos ver temos o corpo de nossa resposta que terá:

  • Nosso conteúdo
  • Status da requisição e do conteúdo
  • Informações sobre redirecionamento
  • Tipo da requisição
  • Cabeçalho da requisição

Se compararmos como XMLHttpRequest as informações serão as seguinte:

onabort: null onerror: null onload: null onloadend: null onloadstart: null onprogress: null onreadystatechange: null ontimeout: null readyState: 4 response: "{↵ "name":"fellyph",↵ "sobrenome": "cintra",↵ "blog": "https://blog.fellyph.com.br"↵}" responseText: "{↵ "name":"fellyph",↵ "sobrenome": "cintra",↵ "blog": "https://blog.fellyph.com.br"↵}" responseType: "" responseURL: "http://127.0.0.1:5500/dados.json" responseXML: null status: 200 statusText: "OK" timeout: 0 upload: XMLHttpRequestUpload {onloadstart: null, onprogress: null, onabort: null, onerror: null, onload: null, …} withCredentials: false

Como podemos ver temos a informações de requisições, respostas e eventos tudo num lugar só, isso dificulta o tratamento da informação e realiza um consumo de dados desnecessário para o usuário.

Na requisição anterior caso queiramos tratar os dados da resposta fazemos da seguinte forma:

fetch('/dados.json') .then(response => response.json()) .then(data => console.log(data));

Para o tratamento de erros realizamos da seguinte forma, adicionamos um catch na chamada de nosso catch:

fetch('/dados.json') .then(response => response.json()) .then(data => console.log(data)); .catch(error => { console.log('Algo de errado aconteceu:', error ) });

Tipos de requisição

A fetch api pode realizar requisições para diferentes tipos de dados, como texto, images, como processar arquivos de text linha a linha. Além disso podemos enviar informações e realizar upload de arquivos.

Um exemplo de um envio de um arquivo json:

const data = { name: 'fellyph', sobrenome: 'cintra', blog: 'https://blog.fellyph.com.br' }; fetch('/usuario', { method: 'POST', // ou 'PUT' headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data), }) .then(response => response.json()) .then(data => { console.log('Success:', data); }) .catch((error) => { console.error('Error:', error); });

Suporte

Fetch API é suportada por 95% dos browsers, os browsers que não possuem suporte:

  • Internet Explorer 11
  • Edge 13 e inferior

Podemos verificar o suporte da seguinte forma:

if (window.fetch) { // realizamos o request com fetch } else { // utilizamos um fallback }

XMLHttpRequest vs. Fetch API

Eles surgiram em tempos diferentes, por muito tempo XMLHttpRequest deu conta do recado mas com a evolução das aplicações web começamos a ter a necessidade de multiplas requisições, foi que então começamos a ter problemas com correntes de callbacks requisições a diferentes serviços.

Para solucionar esse problema tivemos a introdução de promises e junto a ela tivemos a inclusão de novas APIs que começaram a utilizar esse recurso como Fetch API, Service Worker entre outras Web APIs.

Podemos dizer que Fetch API é a evolução da XMLHttpRequest. Apesar da estrutura ter mudado drasticamente elas possuem o mesmo objetivo solucionar o problema com requisições assíncronas. Além de ser extremamente poderosa.

Para mais tutoriais sobre desenvolvimento web acesse a página da categoria tutoriais.

Categorias
PWA - Progressive web apps Tutoriais

Geolocation API

Vamos falar sobre geolocation esse post servirá como base para o conteúdo do curso de PWA que estou rodando no meu canal. Na versão 2020 do curso iremos abordar Web APIs disponíveis para iOS e nesse primeiro posts iremos abordar a Geolocation web API.

Umas das primeiras web APIs lançadas junto com o HTML5, para termos noção esse recurso estava disponível na versão 5 do Chrome e Safari em 2010. A Geolocation API possui uma série de funções e eventos que permitem a localização do usuário através doso dados: latitude e longitude.

Relatório do “can I use”

Suporte

Esse recurso é totalmente dependente do device do usuário vimos que o recurso é presente 94% dos browsers que suporte alto. Mas a sua precisão depende que o device que possua GPS, caso contrário essa informação será gerada através de cruzamento de dados, por exemplo, rede e endereço IP. Isso significa se o device não possuir suporte essa informações não serão tão precisas.

GPS

Outro ponto importante é o consumo de bateria, para o os dispositivos móveis o acesso ao GPS causa um custo maior de processamento assim aumenta o consumo de bateria, então é importante fazer o uso consciente desse recurso.

Privacidade

Na maioria dos devices esse recurso é dependente de uma conexão HTTPS, também antes do acesso a esse recurso o browser irá requisitar permissão de acesso a Geolocalização do usuário. Como podemos ver na imagem a seguir:

Exemplo pop up de permissão da apple

Ideal caso armazene ou monitore a movimentação do usuário deixe claro o uso desse recurso. Esse recurso também só será acessado em uma aplicação que estiver rodando em um servidor web.

Código

Depois de uma introdução sobre a API agora vamos ver como utiliza-la em nossa aplicação:

navigator.geolocation.getCurrentPosition(geoSuccess, geoError); const geoSuccess = (position) => { console.log(position.coords.latitude, position.coords.longitude); }; const geoError = (error) => { console.log('Error occurred. Error code: ' + error.code); };

No código acima fazem a chamada da api dentro de navigator, podemos conferir se o browser tem suporte a geolocation verificando se o atribulo é nulo mas em 2020 a api está presente na maioria dos browsers então não vou me preocupar como esse ponto.

Chamamos a função get position responsável por requisitar a latitude e longitude do usuário. Ela recebe como parâmetro duas funções uma parar executar caso sucesso ou falha de acesso ao recurso.

Se a requisição for bem sucedida teremos a chamada da função geoSuccess com o retorno da latitude(position.coords.latitude) e longitude(position.coords.longitude). Em caso de erro teremos a chamada da função geoError com os possíveis códigos:

  • 0: erro desconhecido
  • 1: permissão negada
  • 2: erro na resposta da fonte da informação
  • 3: timed out

Essa é uma introdução ao assunto em breve estarei postando um vídeo sobre o assunto em meu canal. Qualquer dúvida deixe um comentário ou continue lendo mais tutoriais na página da categoria.

Referência: MDN Geolocation API

Veja também as aulas sobre o assunto no curso de PWA

Categorias
Tutoriais

Introdução ao npm

Estou começando uma série sobre desenvolvimento do blocos Gutenberg é um dos pré-requisitos para se trabalhar com Gutenberg e JavaScript moderno é a utilização de nodeJS e npm. Nesse post iremos realizar uma introdução ao npm e ver qual o seu papel no fluxo de desenvolvimento de blocos Gutenberg.

Se voce já desenvolveu aplicações em react, Vue e express. certamente voce fez o uso de npm para instalar as dependências de sua aplicação. O npm foi adquirido recentemente pela Microsoft/Github, mas como ele funciona funciona? Isso iremos ver a seguir:

npm

É um acrônimo da palavra node package manager em outras palavras gerenciador de pacotes node. Ele vem pre-instalado com NodeJS, quando instalado temos a capacidade de baixar dependências de nossa aplicação. Quando iniciamos um projeto node temos a criação de uma arquivo chamado package.json.

Nele irá conter a descrição e configuração onde iremos falar mais pra frente.

Onde essas dependências estão?

O diretórios de pacotes nodes ficam disponíveis na nuvem, eles podem ser públicos ou privados. Podemos encontrar os pacotes em diretório online no endereço npmjs.com

npm homepage

Temos uma caixa de busca onde podemos pesquisar por pacotes específicos. Por exemplo, se pesquisarmos por “@wordpress/blocks”, nesse caso o @wordpress é o escopo dos pacotes e o pacote em si é block, quando acionarmos a busca iremos achar a página do pacote @wordpress/blocks:

Pagina do pacote @wordpress/blocks

Geralmente na página do pacote vamos ter informações como:

  • Descrição
  • Código para instalação
  • Primeiros passos
  • Dependencias
  • Dependentes
  • Downloads semanais
  • Versões
  • tamanho
  • github page
  • colaboradores

npm CLI

Podemos dizer para desenvolvedores a interface de linha de comando é a parte mais importante do npm através de linha de comando conseguimos baixar instalar pacotes em nossa aplicação. A estrutura básica de um comando com npm e:

npm <comando> [argumentos]

Por exemplo pra instalar um pacote especifico executamos o seguinte código:

npm install webpack

No comando acima instalamos o pacote do webpack, se tudo ocorrer bem o npm irá criar uma pasta node modules com os módulos do webpack e suas dependências. Além disso podemos passar adicionar mais parâmetros para escolher uma versão especifica ou como iremos gravar a dependência.

Package.json

Funciona como uma mapa para sua aplicação nele iremos ter as configurações de dependências de nossas aplicação, organizadas por destino(dev ou produção) e versão. Com npm CLI temos um comando para iniciar um projeto node e criar um package.json.

npm init

Quando executado o comando teremos uma série de perguntas para criar o nosso arquivo package.json:

  • package name: preste atenção nesse valor caso queira publicar o seu projeto ele precisa conter um nome único
  • version: versão do seu projeto junto com o name ele é utilizado para identificar a aplicação.
  • description: descrição do projeto que será exibida quando os usuários buscarem por sua aplicação.
  • entry point: arquivo que será inicializado quando sua aplicação for executada.
  • test command: comando para executar testes
  • git repository
  • keywords: palavras chaves para a busca no repositório
  • author: o autor do pacote
  • license: tipo de licença do pacote

package-lock.json

package-lock.json é automaticamente gerado contendo informações de quando npm modifica o package.json e a árvore de dependências do projeto. É recomendado ter este arquivo listado no seu repositório pelas seguintes razões:

  • Permite aos usuários realizar uma viagem no tempo sobre o projeto.
  • Facilitar uma visibilidade maior sobre as mudanças do projeto
  • Otimiza o processo de instalação do npm evitando a duplicação de conteúdo.

Dependências

Essas são as informações que vem por padrão além disso quando instalamos dependências podemos definir se elas serão de produção ou não. Isso acontece que muitos casos temos dependências de desenvolvimento elas são utilizadas para criar testes ou “compilar” o nosso código como por exemplo babel.

As dependências são organizadas por nome e versão em um objeto:

{ "dependencies" : { "foo" : "1.0.0 - 2.9999.9999" , "bar" : ">=1.0.2 <2.1.2" , "baz" : ">1.0.2 <=2.3.4" , "boo" : "2.0.1" , "qux" : "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0" , "asd" : "http://asdf.com/asdf.tar.gz" , "til" : "~1.2" , "elf" : "~1.2.3" , "two" : "2.x" , "thr" : "3.3.x" , "lat" : "latest" , "dyl" : "file:../dyl" } }

Maioria dos casos trabalhamos com a versão exata, mas podemos ter uma série de regras para versões:

  • versão exata: “1.0.0”
  • versão maior que: “>1.0.0”
  • versão maior que ou igual: “>=1.0.0”
  • versão aproximadamente: “~1.1.0”
  • versão compatível: “1.2.x” pode ser 1.2.1… 1.2.3… 1.2.4…
  • url da versão
  • versão definidas por um range: “1.0.0 – 3.0.0” nesse caso maior

devDependencies

Se você tem planos para utilizar a dependência apenas para de desenvolvimento, nesse caso não queremos que o conteúdo dessa dependência vá para produção. para esse caso utilizamos o seguinte comando:

npm install [nome-do-pacote] --save-dev

Temos uma série de comandos para npm no meu canal do Youtube gravei dois vídeos falando mais sobre o assunto:

Parte 1

Parte 2

Vamos fechando essa introdução por aqui para mais tutoriais, acesse a página da categoria. Ou deixo uma sugestão sobre um assunto que você gostaria de ver no blog.

Categorias
HTML5 Tutoriais

Introdução a imagens responsivas com srcset

Imagens são responsáveis pela maior parte do carregamento de bytes de uma aplicação web em geral. Não podemos evitar-las pois imagens são um ponto crucial de nossa aplicação. Mas temos alternativas para reduzir esse impacto, por exemplo, geralmente nossa aplicação web possui diferentes usuários com diferentes tamanhos de tela.

Imagine o seguinte cenário, em seu website você possui uma imagem de apresentação do seu produto com 1600 pixels, na versão desktop não temos nenhum problema mas o usuário em um dispositivo móvel carrega essa mesma imagem numa tela de 340px. Porque então não servimos diferentes tamanhos de imagens para diferentes tamanhos de tela?

Imagens responsivas é uma parte do design responsivo que pode resolver essa questão. com elas podemos prover diferentes tamanhos de imagens para tamanhos de telas específicos também conseguimos fazer direção de arte disponibilizando recortes específicos da mesma imagem.

Criando imagens responsivas

Com HTML temos algumas alternativas para servir diferentes tamanhos de imagens de acordo com sua resolução de tela.

  • Media queries
  • srcset
  • Tag picture

Srcset

Para esse post iremos trabalhar com a propriedade srcset. Ela permite mais de uma resolução possível das mesma image separadas por vírgula, cada valor dessa lista representa um caso possível ela pode ser atrelada a uma condicional definida pela propriedade sizes.

Vamos usar como exemplo uma tag img tradicional para os nossos testes:

<img src="/imgs/amp-workshop-dublin-1024w.jpg" alt="AMP Workshop Dublin">
Imagem utilizada no exemplo

Agora vamos adicionar os diferentes tamanhos para a imagem:

  • amp-workshop-dublin-640w.jpg
  • amp-workshop-dublin-960w.jpg
  • amp-workshop-dublin-1024w.jpg

Agora que temos os tamanhos definidos vamos alterar nossa img tag:

<img srcset="./imgs/amp-workshop-dublin-640w.jpg 640w, ./imgs/amp-workshop-dublin-960w.jpg 960w, ./imgs/amp-workshop-dublin-1024w.jpg 1024w" src="/imgs/amp-workshop-dublin-1024w.jpg" alt="AMP Workshop">

Com o código acima especificamos o tamanho das imagens nesse caso o browser decidirá que imagem ira carregar de acordo com a densidade de pixels e tamanho de tela(janela). No caso das imagens por densidade de pixel definimos o valor que representa a densidade ao no lugar da largura:

<img srcset="./imgs/amp-workshop-dublin-640w.jpg 1x, ./imgs/amp-workshop-dublin-1600w.jpg 2x" src="./imgs/amp-workshop-dublin-640w.jpg" alt="AMP Workshop">

Muitas vezes queremos fazer direção de arte, por exemplo, queremos exibir em mobile e table uma imagem com largura cheia e para desktop layout duas colunas, nesse caso a imagem não sera proporcional a largura da tela precisamos especificar para o browser qual tamanho de imagem queremos nesse caso iremos fazer a utilização da propriedade size.

Size

Com a propriedade size tomamos o controle e definimos que imagens iremos carregar, passando uma media query e o tamanho que identifica a imagem. Vamos colocar tudo junto para isso vamos criar uma página para o exercício:

Versão Desktop
versão tablet e mobile

A imagem do header contém o código que virmos anteriormente agora vamos adicionar o código para os thumbnails, quando o usuário estiver no desktop iremos exibir o layout em duas colunas e quando ele estiver no tablet e desktop iremos exibir em uma coluna. O controle sobre a quantidade de colunas vem do css, mas com a tag image vamos garantir o carregamento da imagem correta.

Para o thumb vamos adicionar o seguinte código:

<img srcset="./imgs/thumb-480w.jpg 480w, ./imgs/thumb-960w.jpg 960w" sizes="(max-width: 480px) 480px, (max-width: 960px) 960px, (min-width: 961px) 480px" src="./imgs/thumb-960w.jpg" class="thumb-post" alt="post thumb">

No código acima temos dois tamanhos 480px e 960px, na propriedade sizes definimos as medias queries que iremos trabalhar nesse caso mobile(480px max), tablet(960px max), desktop(961px em diante).

O código completa fica da seguinte forma:

HTML

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Responsive images</title> <link rel="stylesheet" href="style.css"> </head> <body> <section> <header> <img srcset="./imgs/amp-workshop-dublin-640w.jpg 640w, ./imgs/amp-workshop-dublin-960w.jpg 960w, ./imgs/amp-workshop-dublin-1024w.jpg 1024w, ./imgs/amp-workshop-dublin-1600w.jpg 1600w" src="/imgs/amp-workshop-dublin-1024w.jpg" alt="AMP Workshop"> <h1 class="page-title">Fellyph Cintra</h1> </header> <div class="posts"> <article class="post"> <img srcset="./imgs/thumb-480w.jpg 480w, ./imgs/thumb-640w.jpg 640w, ./imgs/thumb-960w.jpg 960w" sizes="(max-width: 480px) 480px, (max-width: 640px) 640px, (max-width: 960px) 960px, (min-width: 961px) 480px" src="./imgs/thumb-960w.jpg" class="thumb-post" alt="post thumb"> <div class="content"> <h2 class="title">Post title</h2> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ducimus nostrum, soluta earum dolorem magnam eos porro, aliquam ex temporibus tempore dolor suscipit quibusdam sint impedit eveniet non placeat dicta nesciunt.</p> </div> </article> <article class="post"> <img srcset="./imgs/thumb-480w.jpg 480w, ./imgs/thumb-640w.jpg 640w, ./imgs/thumb-960w.jpg 960w" sizes="(max-width: 480px) 480px, (max-width: 640px) 640px, (max-width: 960px) 960px, (min-width: 961px) 480px" src="./imgs/thumb-960w.jpg" class="thumb-post" alt="post thumb"> <div class="content"> <h2 class="title">Post title</h2> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ducimus nostrum, soluta earum dolorem magnam eos porro, aliquam ex temporibus tempore dolor suscipit quibusdam sint impedit eveniet non placeat dicta nesciunt.</p> </div> </article> <article class="post"> <img srcset="./imgs/thumb-480w.jpg 480w, ./imgs/thumb-640w.jpg 640w, ./imgs/thumb-960w.jpg 960w" sizes="(max-width: 480px) 480px, (max-width: 640px) 640px, (max-width: 960px) 960px, (min-width: 961px) 480px" src="./imgs/thumb-960w.jpg" class="thumb-post" alt="post thumb"> <div class="content"> <h2 class="title">Post title</h2> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ducimus nostrum, soluta earum dolorem magnam eos porro, aliquam ex temporibus tempore dolor suscipit quibusdam sint impedit eveniet non placeat dicta nesciunt.</p> </div> </article> <article class="post"> <img srcset="./imgs/thumb-480w.jpg 480w, ./imgs/thumb-640w.jpg 640w, ./imgs/thumb-960w.jpg 960w" sizes="(max-width: 480px) 480px, (max-width: 640px) 640px, (max-width: 960px) 960px, (min-width: 961px) 480px" src="./imgs/thumb-960w.jpg" class="thumb-post" alt="post thumb"> <div class="content"> <h2 class="title">Post title</h2> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ducimus nostrum, soluta earum dolorem magnam eos porro, aliquam ex temporibus tempore dolor suscipit quibusdam sint impedit eveniet non placeat dicta nesciunt.</p> </div> </article> <article class="post"> <img srcset="./imgs/thumb-480w.jpg 480w, ./imgs/thumb-640w.jpg 640w, ./imgs/thumb-960w.jpg 960w" sizes="(max-width: 480px) 480px, (max-width: 640px) 640px, (max-width: 960px) 960px, (min-width: 961px) 480px" src="./imgs/thumb-960w.jpg" class="thumb-post" alt="post thumb"> <div class="content"> <h2 class="title">Post title</h2> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ducimus nostrum, soluta earum dolorem magnam eos porro, aliquam ex temporibus tempore dolor suscipit quibusdam sint impedit eveniet non placeat dicta nesciunt.</p> </div> </article> <article class="post"> <img srcset="./imgs/thumb-480w.jpg 480w, ./imgs/thumb-640w.jpg 640w, ./imgs/thumb-960w.jpg 960w" sizes="(max-width: 480px) 480px, (max-width: 640px) 640px, (max-width: 960px) 960px, (min-width: 961px) 480px" src="./imgs/thumb-960w.jpg" class="thumb-post" alt="post thumb"> <div class="content"> <h2 class="title">Post title</h2> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ducimus nostrum, soluta earum dolorem magnam eos porro, aliquam ex temporibus tempore dolor suscipit quibusdam sint impedit eveniet non placeat dicta nesciunt.</p> </div> </article> </div> <footer class="footer"> Tutorial by Fellyph </footer> </section> </body> </html>

CSS

.page-title, .posts, .footer { width: 1024px; margin: 1em auto; max-width: 100%; } .page-title { text-align: center; font-size: 3em; border-bottom: 3px solid black; padding-bottom: 1em; } .posts { display: flex; flex-wrap: wrap; } .post { width: 100%; margin: 1em; background: white; display: inline-block; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.26); border: 1px solid #eee; box-sizing: border-box; } .thumb-post { max-width:100%; height: auto; } .content { padding: 1em; } .footer { border-top: 3px solid black; padding-top: 1em; text-align: center; } @media (min-width: 960px) { .post { width: calc(50% - 2em); } }

O post serviu como introdução a imagens responsivas temos outros caminhos para trabalhar com imagens responsivas e vamos abordar em mais posts, se quiser conferir mais tutoriais confira a página da categoria tutoriais ou deixe um comentário.