Design responsivo nos dias de hoje

Indo além das media-queries, dos recursos flexíveis e das grids fluídas

Daniel Tapias Morales
26 min readJun 16, 2016

Olá, me Chamo Daniel e atuo como desenvolvedor front-end na Engage e também possuo algumas vídeo-aulas on-line sobre front-end. Também escrevi um livro on-line sobre o mesmo tema, free.

Este artigo visa apresentar novas técnicas de desenvolvimento de sites responsivos aproveitando o que há de mais atual no mercado front-end. Ao final da leitura deste artigo o leitor terá conhecimentos teóricos e práticos sobre três aspectos que fazem parte do desenvolvimento de um site verdadeiramente responsível: semântica e usabilidade; imagens responsivas; utilização de imagens vetoriais para representação dos ícones da interface. O foco é ir além da já consagrada tríade media-queries, recursos flexíveis e grids fluídas.

A primeira vez que a comunidade da internet leu sobre o termo “Responsive Web Design” foi por meio de um artigo de Ethan Marcotte, datado em 5 de maio de 2010, para o site alistapart.com. Este artigo, sem dúvida alguma, ditou o futuro do desenvolvimento front-end apresentando os três pilares principais para o desenvolvimento de um site responsível: consultas de mídia (são as media-queries do CSS3), grids fluídas (são as colunas ocupadas por pelo design da página) e recursos flexíveis (imagens, vídeos ou outros tipos de mídias que se adaptam ao layout).

Aquele artigo foi de extrema importância e continua sendo atual ainda em 2016. Contudo, o cenário do desenvolvimento web mudou absurdamente de uns anos para cá e, naturalmente, as abordagens de desenvolvimento de sites responsivos devem acompanhar esta evolução. Os tópicos descritos a seguir são apenas alguns exemplos destas mudanças:

Pré-processadoresde CSS

Atualmente, é quase que obrigatória a utilização de um pré-processador de CSS para facilitar a manutenção e desenvolvimento de websites.

Automatização de tarefas

Podemos usar ferramentas de build para conseguir entregar arquivos otimizados para a web. Concatenar e minificar arquivos, compactar imagens ou limpar classes não utilizadas nos arquivos HTML são algumas das possibilidades que podemos alcançar muito facilmente com os automatizadores de tarefas.

Contexto de uso

O número de usuários que navegam na internet por smartphones ou tablets cresce a cada ano. Recentemente, em Maio de 2015, a gigante Google anunciou que o número de pesquisas feitas por contextos mobiles ultrapassou o mesmo número de pesquisas feitas em desktops. Ao menos nos Estados Unidos e no Japão. De qualquer maneira, fica evidente que esta transição ocorrerá, em poucos anos, no cenário mundial. Pensar em responsividade é obrigatório para os sites de hoje e do futuro.

API’s do HTML5

O surgimento de novas API’s, como geocalização e o modo offline, se bem utilizadas e em conformidades com o melhor do progressive enhancement, nos oferece possibilidades de melhorar a experiência do usuário a níveis impossíveis de se alcançar a poucos anos atrás.

Media-queries e javascript

Matchmedia: integração de media-queries e Javascript. Agora temos a possibilidade de testarmos nossas media-queries com o uso do Javascript para tomar decisões programáticas em torno da interatividade de uma página. Num site responsivo, o mesmo arquivo HTML que é visto num desktop também é visualizado num smartphone. O mesmo vale para o arquivo Javascript. E é justamente neste que reside o grande problema de termos que identificar de antemão o contexto de uso para alterar a interação de uma página. Um exemplo simples para entendermos esta questão é pensarmos na navegação principal de uma single-page, que pode ser diferente num smartphone, num tablet e num desktop, mesmo que o javascript seja exatamente o mesmo.

Mais velocidade. Menos bibliotecas

A performance de um site sempre foi um fator importante em dois quesitos: SEO e experiência do usuário. Entretanto, é o no mundo mobile que este aspecto se torna mais evidente e decisivo. Até pouco tempo atrás, a biblioteca jQuery era quase que onipresente na web. Todo site se valia da facilidade de escrever códigos cross-browser e com poucas linhas. Com a crescente do desenvolvimento para a web pensando no contexto mobile, precisamos nos questionar se o uso destas bibliotecas é realmente necessário. Não se trata apenas do tamanho do arquivo javascript, mas também do tempo de parser pelo browser mobile.

Site vs webaap

A possibilidade de criar sites que se comportem como aplicativos instalados no smartphone do usuário nos traz grandes possibilidades de desenvolvimento. O suporte ainda é limitado, mas novamente devemos pensar em progressive enhancement. A ausência de suporte desta ou de qualquer outra tecnologia não deve ser fator impeditivo de sua utilização em qualquer site ou aplicativo, mas sim deve ser tratado como uma melhoria progressiva de usabilidade.

Browsers antigos não devem ser problema

Atualmente não precisamos nos preocupar tanto com browsers antigos como o IE7 ou IE8. Muito do que se pregava há uns cinco anos não se faz mais necessário. Podemos evitar artifícios como mediaqueries.js, respond.js ou até mesmo comentários condicionais para alcançar determinado browser. Se pensarmos em progressive enhancement teremos soluções muito mais elegantes e menos dependentes do suporte ao javascript. Se, por exemplo, um site desenvolvido com a abordagem Mobile First for aberto no IE8 (sem suporte à media-queries), o usuário deste browser verá o conteúdo como se estivesse num mobile. Talvez não seja a melhor experiência possível, mas o importante é que o conteúdo estará acessível e o site estará funcionando. Não há muito o que se fazer para melhorar a experiência do usuário quando o mesmo insiste em não atualizar o seu browser.

Estes são alguns pontos que valem uma reflexão, mas não são os únicos.

Além disso, esta lista é viva, ou seja, novos tópicos podem aparecer a qualquer momento e outros tantos podem deixar de ser relevantes. Por exemplo: em um dia, o uso de font-face e web-fonts para apresentar os ícones da interface é o senso comum. No outro, torna-se ultrapassado. Um outro exemplo dessa movimentação entre as abordagens de desenvolvimento é a utilização na unidade de medidas ‘em’ como breakpoints nas media-queries. Você pode até utilizá-las hoje em dia, mas não pelo mesmo motivo que as usava a uns cinco anos atrás.

O fato é que, quando surgiu, um site responsivo era baseado apenas nos três pilares principais descritos pelo Mr. Ethan Marcotte. Porém, atualmente, apesar da base continuar a mesma, algumas inovações nos trazem novas possibilidades de desenvolvimento ao mesmo tempo em que podemos abandonar velhos hábitos.

É importante salientar que, para os iniciantes no desenvolvimento de sites responsivos, é fundamental iniciar seus estudos pela base descrita no artigo de 2010 (media-queries, grids fluídas e recursos flexíveis), mas o avanço tecnológico não nos permite parar no tempo, nos forçando a estarmos sempre antenados às inovações proporcionadas por alguns segmentos da área, como por exemplo os fabricantes de software e/ou devices (que nos presenteia com inovações como os monitores de alta resolução 4k e notebooks com telas touch) e os responsáveis pelos padrões web W3C e WHATWG, os quais trabalham em especificações como o Protocolo HTTP 2.0, API’s como Web workers e Geolocalização, novas implementações das tags semanticas no HTML5, modo off-line, entre outras;

Nos próximos parágrafos desse artigo serão apresentados alguns dos novos conceitos que norteiam o desenvolvimento da web para dispositivos móveis. Não serão apresentados em detalhes as media-queries, os recursos flexíveis nem tão pouco as grids fluídas, por serem assuntos bastante difundidos na comunidade de desenvolvedores front-end. Nem tão pouco serão apresentadas em detalhes todas as novas tecnologias que podem ser usadas para o desenvolvimento de sites responsivos.

Portanto, serão discutidos os seguintes assuntos:

Tags semânticas do HTML5 e acessibilidade em contextos mobiles

Os devices estão cada vez mais sensíveis à semântica do HTML5, especialmente quanto aos controles de formulário, visando oferecer a melhor usabilidade possível.

Imagens verdadeiramente responsivas

Há um esforço muito grande da W3C em nos oferecer uma maneira concisa de entregar arquivos de imagens específicos para dispositivos diferentes.

Ícones como Imagens vetoriais

Até pouco tempo atrás, aprendemos que tínhamos que criar nossos layouts no Photoshop e exportar para a web as imagens como arquivos bitmap (jpg, gif ou png — naquela época não se tinha ouvido falar de um arquivo .webp). Com o advento das telas de alta resolução (ou telas retinas no mundo apple), esse cenário torna-se impraticável, especialmente em mobiles, onde há uma possível limitação de velocidade de rede e de processamento. Se trabalhássemos exclusivamente com arquivos bitmaps, teríamos que entregar arquivos com muitos pixels (e muitos kbytes) para fazer com que as imagens não aparecessem borradas ou desfocadas. Uma alternativa para os elementos de ícones de nossa interface foi a utilização de font-face e icon-fonts (famílias de fontes formadas por ícones, e não por letras ou números). Mas isso resolveu um problema e criou outros. Tais problemas serão discutidos em breve.

Elementos semânticos HTML5

Quando os desenvolvedores front-end tomaram conhecimento das novas tags HTML5 para inserir áudio e vídeo em uma página da web, houve uma grande expectativa para poder começar a se valer destes novos recursos sem precisar de shockwaves ou plugins de terceiros. Naquela época, essas tags foram as mais comentadas por terem maior impacto em nossa vida como desenvolvedores. Mas se pensarmos bem, assim como outras tags do HTML5, o <audio> e o <video> são elementos que dão valor semântico ao conteúdo, pois estes elementos fazem parte da carga informativa de uma página.

Uma das características da utilização destas tags é que o desenvolvedor precisa apenas “etiquetar” o conteúdo. O papel do agente de usuário é apresentar esta informação da melhor maneira possível. Ou seja, não precisamos mais nos preocupar em desenvolver players de vídeo ou áudio, pois esta não é responsabilidade do HTML5, que, em sua essência, é uma linguagem de marcação de hipertexto.

Sabemos que um elemento de vídeo, por exemplo, é apresentado de diferentes formas dependendo do agente de usuário. Isso é bom porque faz com que os fabricantes se esforcem para melhorar cada vez mais a experiência do usuário, uma vez que a concorrência é grande.

Voltando ao contexto do design responsivo, é válido perceber que um player customizado (que o desenvolvedor criou) de um elemento de mídia pode ser eficiente num browser desktop, mas catastrófico no mundo mobile. Portanto, a melhor solução é deixarmos que o próprio browser decida qual a melhor maneira de apresentar o conteúdo. Qualquer que ele seja.

Essa facilidade de não termos mais que nos preocupar em como a informação será renderizada em todos os devices disponíveis no mercado nos traz um ganho enorme de produtividade, pois um dos papeis do desenvolvedor front-end deve ser o de escrever um código HTML5 semântico, deixando para o agente de usuário decidir qual a melhor maneira de apresentar esse conteúdo.

Interatividade em formulários

Além das tags de elementos de mídia descritas anteriormente, há também uma série de novos tipos de campos de formulário. À primeira vista, num desktop não há muita diferença entre um <input type=”text”>, <input type=”url”> e um <input type=”email”>. Porém, é no contexto mobile que reside a grande diferença e melhoria de usabilidade, uma vez que o teclado de um smartphone pode se adaptar para melhorar o preenchimento deste ou daquele tipo de dado, prevalecendo, por exemplo, o símbolo @ no caso de um <input type=”email”> e um “.com” no caso de um <input type=”url”>.

Nesse sentido, reforçamos o que foi dito anteriormente: O papel do desenvolvedor front-end é marcar corretamente a informação, e é de responsabilidade do agente de usuário apresentar essa informação da melhor maneira possível.

Outros tipos de entradas de dados que merecem atenção nas diferentes formas de renderização em desktops e mobiles são: <input type=”search”>, <input type=”tel”>, <input type=”date”>, <input type=”month”>, <input type=”time”>, <input type=”datetime-local”>, <input type=”number”>, <input type=”range”> e <input type=”color”>.

O desenho dos teclados em aparelhos mobiles podem sofrer variações dependendo do atributo type da tag <input>

Quando as tags semânticas não são suficientes

Pode parecer óbvio, mas um texto, ou string, é composto por um conjunto de caracteres. Tendo isso em mente, propomos uma reflexão sobre que tipo de dado o parágrafo seguinte representa: <p>25/12/2016</p>.

Sabemos que é uma data. E não é uma data comum, mas trata-se do natal do ano de 2016. Como sabemos disso? Por que o ser humano faz uma série de associações cognitivas que busca em sua memória informações armazenadas anteriormente e trata de comparar com a informação presente.

Deixando de lado como as sinapses cerebrais funcionam, o browser — ainda — não é capaz de fazer estas comparações com experiências passadas, por isso, “25/12/2016” é apenas um texto comum.

Se quisermos fazer com que o computador do usuário saiba que determinado texto é a data de um evento qualquer, por exemplo, o natal, precisamos “marcar” essa informação de uma maneira que a máquina entenda. Em outras palavras, precisamos trabalhar com a micro informação, ou microdata, como é conhecida no HTML5.

As microdatas são parentes próximas do microformat ou do RDF, que têm em comum o mesmo objetivo: tratar a semântica da informação quando somente as tags não são suficientes para fazê-lo.

Para trabalhar com Microdatas, o desenvolvedor precisa utilizar um dialeto, ou um vocabulário, capaz de “se comunicar” com a máquina. Há disponível na internet uma espécie de esperanto com esse objetivo, chamado de Schema. Ao acessar este site, o desenvolvedor precisa escolher entre uma das categorias disponíveis, como por exemplo “Organization”, “Person”, “Event” entre outras.

A estas categorias chamamos de escopo. É “sobre o que a página está informando”.

Veja um exemplo:

Utilização simples de Microdatas.

<div class=”event-wrapper” itemscope itemtype=”http://schema.org/Event"><div class=”event-date” itemprop=”startDate” content=”2016–12–26T23:00–03:00">25/12/2016</div><div class=”event-title” itemprop=”name”>Natal / 2016 </div></div>

No código acima o atributo itemscope se refere ao assunto principal, que no nosso exemplo, é um evento. O atributo itemprop pode ser entendido como “o que está sendo apresentado sobre o assunto principal”. No exemplo acima, estamos falando sobre a data de início. Já o atributo content é a informação adicional necessária para fazer com que a máquina entenda o que estamos querendo comunicar.

Um exemplo um pouco mais complexo, retirado do próprio site schema.org

Utilização complexa de Microdatas.

<div class=”event-wrapper” itemscope itemtype=”http://schema.org/Event"><div class=”event-date” itemprop=”startDate” content=”2013–09–14T21:30">Sat Sep 14</div><div class=”event-title” itemprop=”name”>Typhoon with Radiation City</div><div class=”event-venue” itemprop=”location” itemscope itemtype=”http://schema.org/Place"><span itemprop=”name”>The Hi-Dive</span><div class=”address” itemprop=”address” itemscope itemtype=”http://schema.org/PostalAddress"><span itemprop=”streetAddress”>7 S. Broadway</span><br><span itemprop=”addressLocality”>Denver</span>,<span itemprop=”addressRegion”>CO</span><span itemprop=”postalCode”>80209</span></div></div><div class=”event-time”>9:30 PM</div><span itemprop=”offers” itemscope itemtype=”http://schema.org/Offer"><div class=”event-price” itemprop=”price” content=”13.00">$13.00</div><span itemprop=”priceCurrency” content=”USD” /><a itemprop=”url” href=”http://www.ticketfly.com/purchase/309433">Tickets</a></span></div>

Observe que é possível encadear assuntos. No exemplo acima, estamos aninhando Event, Place, PostalAddress e Offer.

Oferecer informações adicionais ao agente de usuário pode não parecer significante num primeiro momento. Contudo, pense no exemplo hipotético onde o device “entende” que uma página qualquer possui uma informação sobre a data e o endereço de um evento. Entre as possibilidades, estão:

  • O usuário, ao clicar sobre uma data, pode incluir o evento na agenda do seu smartphone, já configurando se quer ser avisado com antecedência.
  • Ao clicar sobre um endereço, pode verificar a rota de acordo com a sua geolocalização.

Isso melhora em muito a experiência do usuário na utilização de seu site no contexto mobile. Está certo que esta experiência pode variar de aparelho para aparelho, mas assim como no caso da tag <video> ou os novos atributos da tag <input>, é papel do desenvolvedor marcar corretamente a informação. O papel do device é saber como trabalhar com essa marcação para oferecer a melhor experiência possível para o usuário final.

Recursos flexíveis

Quando o termo “responsive design” foi cunhado em 2010, trabalhar com recursos flexíveis significava simplesmente trabalhar com o css da seguinte maneira:

Utilizando o mesmo recurso de mídia que se adapta ao design da página. Isso não é ser responsivo.

img, video, iframe, object, embed{max-width: 100%;}

Esta técnica, apesar de parecer satisfatória para quem está pagando pelo projeto, não beneficia o usuário final (o qual irá realmente interagir com o produto), pois, o mesmo arquivo de imagem que é entregue em um desktop também é apresentado em um mobile, ou seja, excesso de transferência de kbytes justamente onde a velocidade da rede é um fator problemático, supondo que este usuário está usando sua conexão 3G.

Para entregar imagens realmente responsivas, não podemos simplesmente fazer com que estas se adequem à largura de seu elemento pai. Há muitas variáveis que devem ser levadas em consideração. No que se refere ao device do usuário, devemos nos atentar a alguns pontos:

  • Devices com tamanhos de telas diferentes.
  • Devices com resoluções diferentes.
  • Usuários podem fazer zoom na página, alterando a relação device pixel vs CSS pixel.
  • Usuários podem alterar a orientação do device no contexto mobile.
  • A velocidade da internet pode estar oscilando.

Como se não bastasse todas estas variações, o desenvolvedor pode querer aumentar essa lista ainda mais. Alguns exemplos:

  • Imagens diferentes ou ausentes em contextos de uso diferentes. (à saber: imagens com display: none; ainda são transferidas para o cache do browser).
  • Imagens com tamanhos de renderização diferentes dependendo do contexto de uso. É possível que uma tela menor mostre uma imagem maior ou vice-versa. Exemplificando: Layout com uma grid que ocupa uma coluna em tela de até 480px. Acima dessa largura, a grid ocupa 3 colunas. Se dentro de uma dessas colunas há uma imagem, qual o seu tamanho final numa tela de 490px?
  • Direção de arte diferente de acordo com o contexto de uso.
  • Extensão de arquivos diferentes de acordo com o suporte do device.

Nesse sentido, várias técnicas periféricas surgiram para tentar minimizar o problema, mas nenhuma delas era 100% à prova de falhas, pois, ou dependiam de tecnologias do lado do servidor, ou precisavam de um arquivo javascript adicional apara lidar com o problema.

Por estes motivos, várias especificações foram sendo elaboradas e aprimoradas na tentativa de solucionar essa questão. Atualmente podemos contar com soluções bastante inteligentes e elegantes, e ainda contar com um fallback eficiente para browsers antigos. Antes de entrarmos em detalhes sobre isso, é bom entendermos que somente media-queries não são suficientes.

O problema das media-queries

O primeiro ponto que devemos nos atentar é que, utilizar as media-queries para oferecer ao usuário imagens diferentes para cada cenário pode parecer uma boa ideia. Contudo, para que o browser possa identificar a melhor imagem a ser mostrada na tela, este precisa ter conhecimento antecipado de três variáveis: dimensões da viewport, tamanho físico da imagem e largura ocupada pela imagem no layout após a renderização. E definitivamente as media-queries não são suficientes para informa-las.

No trecho de código abaixo é possível refletir sobre o aspecto comentado anteriormente. (Atenção: O trecho a seguir não é válido, servindo apenas para demonstrar que consultas ao tipo de mídia não são eficientes para entregar imagens responsivas).

Demonstração do motivo pelo qual a utilização de media-queries não é eficiente para entregar imagens responsívas:

<img src=”pequena_paisagem.jpg” media=”(max-width: 40em) and (orientation: landscape)”><img src=”pequena_retrato.jpg” media=”(max-width: 40em) and (orientation: portrait)”><img src=”default_paisagem.jpg” media=”(min-width: 40em) and (orientation: landscape)”><img src=”default_retrato.jpg” media=”(min-width: 40em) and (orientation: portrait)”>

Neste exemplo hipotético, o atributo media poderia receber qualquer media-querie válida, mas isso resolveria apenas uma parte do problema, uma vez que o agente de usuário não conseguiria identificar o tamanho final que esta imagem ocuparia no layout. Foi pensando nisso que surgiram dois novos atributos: srcset e sizes.

Novos atributos para imagens responsivas

Para que o browser consiga identificar qual imagem irá utilizar, é necessário informá-lo (antes de qualquer parse do css e do javascript e antes mesmo de baixar qualquer imagem do servidor) qual a largura física do arquivo de imagem em questão. Para isso, foi implementado nos browsers modernos o atributo srcset. Veja um exemplo:

Exemplo de utilização do atributo srcset:

<imgsrc=”http://lorempixel.com/400/200/"srcset=”http://lorempixel.com/600/300/ 400w, http://lorempixel.com/800/400/ 800w”alt=”texto alternativo convencional”>

Foi utilizado neste exemplo o serviço de imagens randômicas chamado lorempixel.

O atributo src funciona como um fallback para browsers que não suportam o atributo srcset. Neste atributo, passamos conjuntos separados por vírgula de URI’s e largura da imagem. Por exemplo: ao informar 600w, estamos dizendo ao browser que a imagem http://lorempixel.com/600/300/ possui 600px de largura (w = width. O nome correto para este caractere “w” é descritor) antes mesmo deste ter que fazer o download do recurso.

Mas ainda precisamos informar ao browser qual o tamanho que a imagem ocupará no layout após a renderização. Será que é possível passar essa informação antes mesmo do browser “baixar” e analisar o CSS? Veremos.

Por se tratar de um layout responsivo, é muito difícil dizer precisamente qual a dimensão final que um determinado recurso terá após a aplicação do CSS. É para resolver essa questão que há o atributo sizes. Veja mais um exemplo:

Exemplo de utilização dos atributos srcset e sizes:

<imgsrc=”http://lorempixel.com/400/200/"srcset=”http://lorempixel.com/600/300/ 600w, http://lorempixel.com/800/400/ 800w”alt=”texto alternativo convencional”sizes=”33.33vw”>

No exemplo acima, estamos informando ao browser que a imagem ocupa um terço da largura da viewport. Em outras palavras, essa imagem está inserida num grid de três colunas. Digamos que o nosso grid ocupe estas três colunas apenas se a tela for maior que 480px. Caso contrário, uma única coluna deverá ser suficiente para compor toda a nossa página. Veja mais um exemplo:

Exemplo de utilização dos atributos srcset e sizes com múltiplos valores:

<imgsrc=”http://lorempixel.com/400/200/"srcset=”http://lorempixel.com/600/300/ 600w, http://lorempixel.com/800/400/ 800w”alt=”texto alternativo convencional”sizes=”(min-width: 480px) 33.33vw, 100vw”>

Dessa forma, estamos fornecendo ao browser todas as informações necessárias para que ele decida qual o melhor arquivo de imagem deverá ser entregue ao usuário. Ou seja, nossa responsabilidade é efetuar a marcação corretamente, já o browser é responsável por decidir a melhor maneira de renderizar essa informação.

Sobre a tag <picture>

Se observarmos bem, tudo que fizemos nos exemplos acima foi passar informações adicionais, ou atributos, à tag <img>. Semanticamente, estamos passando alternativas da mesma imagem para que o browser decida qual o melhor arquivo mostrar ao usuário dependendo do contexto de uso (tipo de device, resolução, velocidade de rede, ou qualquer outro aspecto que o agente de usuário julgue necessário avaliar antecipadamente).

Contudo, há casos em que, além de alternar entre dimensões diferentes, queremos também alterar o design da página, dependendo do contexto de uso.

Para esses casos, podemos contar com a tag <picture>, o qual é um container para uma tag <img> e tags <source>, que trabalham em conjunto com um atributo obrigatório src e outros atributos opcionais, como o type e o media.

Veja o seguinte exemplo:

Exemplo de utilização da tag <picture>:

<picture><sourcemedia=”(min-width: 480px)”sizes = “33vw”srcset=”images/large.jpg 1280w,images/medium.jpg 960w,images/small.jpg 480w” /><sourcesizes=”100vw”srcset=”images/large_foco.jpg 822w,images/medium_foco.jpg 640w,images/small_foco.jpg 320w” /><imgsrc=”images/medium.jpg”alt=”Imagem de fallback para browsers antigos.” /></picture>

O código acima demonstra o uso das tags <picture> e <source> juntamente com os atributos estudados anteriormente.

Nota: O motivo pelo qual não podemos usar % como unidade de medida de sizes é devido ao fato de que a porcentagem se refere relativamente à largura do elemento pai. No momento em que este atributo é lido pelo browser, a largura do elemento pai ainda é desconhecida. Conforme mencionado anteriormente, contudo, o agente de usuário é capaz de saber antecipadamente o tamanho da viewport, por isso, usamos ‘vw’ (que significa viewport width) no lugar de porcentagem.

A vantagem de utilizar <picture> é que podemos trabalhar com as três variáveis ao mesmo tempo: tamanho do arquivo de imagem (atributo srcset e o descritor “w”), tamanho da viewport (atributo media contendo as media-queries tradicionais) e o tamanho da imagem renderizada (atributo sizes e o descritor “vw”).

Com isso, o desenvolvedor tem um maior controle sobre o layout, podendo, inclusive, alterar a direção de arte da página. Além disso, com estas três informações sendo disponibilizadas antecipadamente ao agente de usuário, este pode decidir qual a melhor solução para renderizar a página no browser.

MimeTypes responsivos

Se estamos nos propondo a desenvolver sites realmente responsivos, temos que nos preocupar em entregar ao usuário final arquivos cada vez mais leves para que estes, especialmente em redes de internet limitadas ou com alta latência, possam abrir nossas páginas com uma velocidade aceitável.

Nesse sentido, todo kbyte conta e atualmente temos novas possibilidades de extensões de arquivos de imagens mais compactas do que as tradicionais jpegs. A desvantagem é que nem todo browser aceita estes novos formatos. A solução então é entregar imagens direcionadas para browsers que aceitem ou não estas novas extensões.

Para isso, podemos trabalhar com o atributo type, da mesma forma como fazemos com <audio> e <video>. Veja um exemplo:

Exemplo de utilização do atributo type para imagens responsivas:

<picture><source type=”image/webp” srcset=”images/imagem.webp”><img src=”images/imagem.jpg” alt=”texto alternativo”></picture>

Novas extensões de imagens como WebP e JPG XR surgiram com o objetivo de compactar ainda mais os arquivos de imagens, sem abrir mão da qualidade visual destas. Infelizmente, nem todos os browsers a suportam, por isso, adotar uma estratégia como a descrita acima privilegia usuários com browsers modernos sem punir os que ainda utilizam aparelhos ou sistemas mais antigos. Internet também é democracia.

Agora que temos o conhecimento teórico necessário para trabalhar com imagens verdadeiramente responsivas, precisamos nos questionar sobre um pequeno detalhe: Será que precisamos nos preocupar com isso sempre que estivermos trabalhando com imagens?

O problema das imagens rasterizadas

Durante muito tempo os arquivos bitmaps foram as únicas opções para trabalharmos com imagens na internet. Cada um dos formatos mais usados (.gif, .jpg e .png) possuem características próprias e cumprem bem seus objetivos, ou seja, para trabalhar com imagens com muitas tonalidades, como fotografias e/ou gradientes, a melhor opção é trabalhar com os arquivos de extensão .jpg. Já quando temos uma imagem com poucas cores, como um logotipo ou um ícone, temos o .gif. E se precisamos que a imagem possua um canal de transparência com suavidade, precisamos contar com o .png de 24 bits.

Esse cenário prevaleceu por muito tempo de maneira satisfatória. Mas foi com a chegada dos smartphones e tablets que isto começou a mudar. O fato de termos telas cada vez menores e em sua maioria com resoluções multiplicadas por 2 (pelo menos por enquanto), fez com que as nossas imagens ficassem com aparência desfocada nestes dispositivos. E o motivo para isso acontecer é que, nestes aparelhos, 1 pixel do device não é o equivalente a um pixel do CSS.

Se visualizarmos uma imagem de 800 por 600 pixels num monitor com a resolução de 1:1, esta imagem ocupará todo o tamanho físico da tela. Se, neste mesmo monitor, abríssemos um arquivo de imagem contendo 400 por 300 pixels, este ocuparia ¼ da tela. Entretanto, uma imagem de 400x300px apareceria bem menor num smartphone de alta-resolução, pois, para renderizar uma página da web, incluindo suas imagens, o browser do dispositivo móvel leva em consideração o tamanho em pixel físico e não do CSS pixel.

O resultado disso é que, tomando como exemplo um iPhone 6, uma página com largura física de 750px ocuparia toda a tela, já que este aparelho possui 750 por 1334 de pixels físicos e 375 por 667 de CSS pixels.

Os problemas com as imagens começam a ficar evidentes quando utilizamos a já consagrada meta tag viewport (meta name=”viewport”) para informar ao browser que este deve igualar as medidas dos pixels físicos com os CSS pixels (content=”width=device-width”). Se, antes da aplicação dessa metatag, uma imagem de 375px de largura ocupava a metade da largura da tela de um iPhone 6, após escrevermos a meta tag viewport no header, esta mesma imagem ocupará a tela toda. O resultado é que a imagem aparecerá “pixelada”, deixando o design da página com uma aparência desleixada.

Simulação do Google Chrome de uma página no iPhone 5

Na imagem da esquerda, não há qualquer meta tag viewport no <head> da página. Já na figura da direita há o seguinte: <meta name=”viewport” content=”width=device-width, initial-scale=1.0">. Conforme pode ser observado, quando inserimos a meta tag viewport, a página inteira (incluindo a imagem bitmap) é ampliada, ocasionando numa imagem “pixelada” para o usuário final.

Para resolver isso utilizando imagens rasterizadas (mapa de bits), precisamos dobrar a resolução da imagem (isto se estivermos falando de telas com o dobro da resolução, ou 2 pixel ratios). Em outras palavras, o arquivo que antes tinha 375 de largura agora precisará ter 750px. E a medida que telas com resoluções maiores forem surgindo no mercado esse número irá subir em igual proporção.

A solução: não usar imagens rasterizadas.

Imagens vetoriais direto no browser

A principal vantagem do uso de arquivos vetoriais diretamente no browser é que, além dos arquivos provavelmente ficarem mais leves (isso se não estivermos “vetorizando” imagens complexas e com muitos detalhes), são independentes de resolução do dispositivo (fabricantes podem lançar no futuro um smartwatch com 4k de resolução, se acharem válido) e também são escaláveis (imagens vetoriais sempre aparecem boas, mesmo com o zoom aumentado).

Uma desvantagem é que você precisará criar um fallback se quiser dar suporte a browsers mais antigos. Além disso, ainda há muitas inconsistências na maneira como inserir esse tipo de arquivo numa página web. Mas estamos caminhando para uma solução definitiva e cross-browser, portanto, não é cedo demais para entendermos o SVG.

SVG: Vetor, escalável, acessível, xml válido, pode ser editado com CSS, interativo e com possibilidade de ser animado.

Arquivos SVG (Scalable Vector Graphics) são especialmente úteis quando estivermos trabalhando com imagens simples e com poucas cores, como por exemplo ícones e logotipos que seguem a tendência flat design.

Até pouco tempo atrás (final de 2015) muitas pessoas usavam web-fonts para gerar famílias de fontes contendo símbolos (usados principalmente como textos no html ou com os pseudo-elementos ::after e ::before, juntamente com a propriedade content, no CSS) e utilizá-las nos designs de suas páginas. Contudo, essa abordagem gera alguns problemas como performance, fidelidade no design cross-browser e dificuldade de manutenção na hora de editar ou incluir um novo símbolo, pois, para essa finalidade, é necessário editar toda a família de fontes e exportá-los nos arquivos finais (.eot, .woff. .ttf e .svg). A não ser que você use um serviço como o font-awesome, que é uma família contendo centenas de ícones prontos e que, por esse mesmo motivo, é muito pesado, trabalhar com ícones como web-fonts não é uma tarefa das mais agradáveis no momento em que você precisa dar manutenção no site.

Escolher o SVG para representar os ícones da interface gráfica supre essa deficiência ao trabalharmos com arquivos independentes que, no fim do processo, irá gerar um sprite para ser usado em todo o site.

O primeiro passo é termos o arquivo vetorial. Nós podemos utilizar qualquer software de ilustração para isso, como o Adobe Illustrator ou o Inkscape, que é gratuito.

Depois de termos desenhado cada símbolo num arquivo vetorial separadamente (não devemos deixar muito espaço em branco “sobrando” ao redor da ilustração), devemos salvá-los como .svg. No Adobe Illustrator, utilize File > Save as ao invés de Export.

Salvar um arquivo SVG pelo Adobe Illustrator
organização das camadas de nosso arquivo

Devemos ficar atentos à organização das camadas de nosso arquivo, pois o resultado final é afetado pela maneira como organizamos os nossos elementos que compõem a ilustração.

Depois de termos o nosso arquivo SVG gerado, podemos abrí-lo num editor de código e avaliarmos as principais tags.

Apesar de existirem várias tags específicas para desenhar formas geométricas no browser, como <rect>, <circle> ou até mesmo <polygon>, dificilmente nós iremos gerar estas formas básicas escrevendo tais tags, entretanto, é de muita utilidade sabermos como as coisas funcionam.

<svg>

Assim como todo arquivo HTML começa com a tag <html>, todo arquivo SVG deve começar com <svg>. O principal atributo que devemos nos atentar é o viewBox. Veremos esse atributo mais à frente.

<path>

Tag utilizada para gerar um caminho, aberto ou fechado. Passamos as coordenadas dos pontos que compõem o caminho no atributo d. O ponto X Y inicial, onde o caminho começa, é definido pela letra M. Ainda neste mesmo atributo são passados outros números e letras. Cada letra representa um tipo de linha, Q = curva quadrática; C = linha cúbica; A = arco elíptico. Além disso, há outros atributos como fill e stroke usados para definir a cor de preenchimento e contorno, respectivamente. Se olharmos para um pequeno código gerado pelo Illustrator no exemplo abaixo, é muito difícil sabermos que tipo de figura este código representa, mas é possível saber o que cada atributo representa:

A tag path:

<path fill=”#FFFFFF” stroke=”#000000" d=”M32.396,67.156c0,0,11.458,157.291,50,158.333S95.938,67.155,131.354,66.114s53.125,158.333,53.125,158.333"/>

<symbol>

O principal objetivo da tag <symbol> é podermos agrupar código svg para reutilizarmos quando for preciso.

<g>

Muito semelhante à tag <symbol>. Contudo, a tag <g> não aceita o atributo viewBox, enquanto <symbol> aceita.

<defs>

Também usado para agrupar códigos SVG que possam ser reaproveitados, contudo, a tag <defs> não renderiza no browser o código gerado. Ao contrário de <symbol> e <g>.

<use>

Usado em conjunto com o <symbol> ou <g> para reutilizar um símbolo criado previamente.

Atributo viewBox

Este atributo é responsável por definir o sistema de coordenadas x e y dentro de um elemento svg. Veja o exemplo:

O atributo viewBox:

<svg width=”700" height=”500" viewBox=”0 0 70 50" ><rect x=”20" y=”10" width=”50" height=”30"style=”stroke: #000000; fill:red;”/></svg>

A área do SVG renderizada no browser será de 700x500px (atributos width e height da tag <svg>). Contudo, internamente, há um sistema de coordenada independente de seu tamanho, medindo 70x50 e começando em 0,0 (atributo viewBox da tag <svg>). Isso é útil quando precisarmos alterar o tamanho do nosso svg. Como a unidade de medida interna (o sistema de coordenada gerado pela viewBox) é independente de seu tamanho real, não precisamos nos preocupar em redefinir o tamanho dos elementos internos.

No exemplo acima, cada unidade de medida de nosso sistema de coordenada interno mede 10px. Ou seja, um retângulo medindo 20 por 10 terá, em pixels, 200px por 100px.

A tag <rect> cria um retângulo localizado na coordenada horizontal 20, 10, que é equivalente a 200px, 100px. Este mesmo retângulo mede 50 (500px) x 30 (300px). Se precisarmos aumentar ou diminuir o tamanho de nosso svg, precisaremos apenas alterar os atributos width e height da tag <svg>, não nos preocupando com os tamanhos internos de cada elemento.

O atributo viewBox não é exclusivo da tag <svg>, podendo ser utilizado em outras tags como <g> e <symbol>, entre outras.

Configurando o tamanho da viewBox

O tamanho da viewBox do nosso arquivo SVG de exemplo é definido pela configuração de nosso documento no Illustrator.

Criando uma biblioteca para seus símbolos

A melhor maneira de termos todos os ícones de nosso site em um único arquivo é pensarmos em algo parecido com uma biblioteca. Devemos criar um único arquivo .svg e incluirmos o código gerado pelo Illustrator com algumas modificações.

A nossa biblioteca deve começar com as tags básicas para receber o nosso primeiro símbolo:

Iniciando nossa biblioteca de simbolos

<svg xmlns=”http://www.w3.org/2000/svg"><symbol id=”chat-icon” viewBox=”0 0 200 200"></symbol></svg>

Abaixo, segue o código gerado pelo Illustrator.

Exemplo de código SVG criado pelo aplicativo Adobe Illustrator

<?xml version=”1.0" encoding=”utf-8"?><! — Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) →<!DOCTYPE svg PUBLIC “-//W3C//DTD SVG 1.1//EN” “http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version=”1.1" id=”Camada_1" xmlns=”http://www.w3.org/2000/svg" xmlns:xlink=”http://www.w3.org/1999/xlink" x=”0px” y=”0px” width=”200px” height=”200px” viewBox=”0 0 200 200" enable-background=”new 0 0 200 200" xml:space=”preserve”><path d=”M199,100.188C199,154.762,154.771,199,100.199,199c-54.594,0–98.822–44.238–98.822–98.812 c0–54.578,44.229–98.812,98.822–98.812C154.771,1.377,199,45.61,199,100.188z”/><path fill=”#FFFFFF” d=”M152.715,81.546h-32.296v16.377c0,9.627–7.84,17.456–17.472,17.456H80.202v20.292 c0,7.596,6.19,13.775,13.775,13.775h35.3l22.572,15.68v-15.68h0.916c7.555–0.051,13.685–6.21,13.685–13.775V95.312 C166.45,87.727,160.279,81.546,152.715,81.546z”/><path fill=”#FFFFFF” d=”M114.972,97.923V54.728c0–6.618–5.406–12.009–12.024–12.009H39.996c-6.628,0–12.024,5.391–12.024,12.009 v43.195c0,6.598,5.375,11.989,11.973,12.01l3.686,0.02v14.306l20.627–14.325h38.689C109.565,109.933,114.972,104.541,114.972,97.923 z”/></svg>

Do código acima, iremos retirar apenas o que nos interessa e acrescentar em nossa biblioteca, com algumas modificações. Juntando os dois, temos:

Mesclando o código gerado pelo Illustrator em nossa biblioteca de símbolos

<svg xmlns=”http://www.w3.org/2000/svg" style=”display: none;” viewBox=”0 0 200 200"><symbol id=”chat-icon” viewBox=”0 0 200 200"><path d=”M199,100.188C199,154.762,154.771,199,100.199,199c-54.594,0–98.822–44.238–98.822–98.812 c0–54.578,44.229–98.812,98.822–98.812C154.771,1.377,199,45.61,199,100.188z”/><path fill=”#FFFFFF” d=”M152.715,81.546h-32.296v16.377c0,9.627–7.84,17.456–17.472,17.456H80.202v20.292 c0,7.596,6.19,13.775,13.775,13.775h35.3l22.572,15.68v-15.68h0.916c7.555–0.051,13.685–6.21,13.685–13.775V95.312C166.45,87.727,160.279,81.546,152.715,81.546z”/><path fill=”#FFFFFF” d=”M114.972,97.923V54.728c0–6.618–5.406–12.009–12.024–12.009H39.996c-6.628,0–12.024,5.391–12.024,12.009v43.195c0,6.598,5.375,11.989,11.973,12.01l3.686,0.02v14.306l20.627–14.325h38.689C109.565,109.933,114.972,104.541,114.972,97.923 z”/></symbol></svg>

Duas observações sobre o código acima:

1. Cada novo ícone deverá ser incluído em uma nova tag <symbol> com um atributo id único.

2. Foi adicionado um estilo inline à tag <svg> com display: none; para que o símbolo não seja mostrado duas vezes no browser.

Incluindo o arquivo em nosso HTML

Há várias maneiras de importarmos um SVG em nossa página. Cada uma com seus prós e contras. A maneira mais segura é escrevermos as tags do SVG diretamente no documento HTML. A desvantagem dessa metodologia é que, obviamente, os ícones não serão armazenados no cache do browser. Mas se estivermos trabalhando com uma single-page, o fato de termos todo o código SVG no documento html não será um problema. Apesar de não ficar muito elegante, não apresenta nenhuma perda de performance ao usuário final. Se esse não for o caso, ainda é possível utilizarmos um arquivo javascript chamado svg4everybody.js para fornecer um mecanismo capaz de lidar com arquivos svg’s externos em browsers antigos.

Tendo disponível a nossa biblioteca, podemos incluir qualquer um dos ícones fazendo uma referência ao atributo id da tag <symbol>.

Fazendo referência a um símbolo de nossa biblioteca

<svg><use xlink:href=”#chat-icon”></use></svg>

Uma grande vantagem dessa técnica é que podemos incluir classes em nossos símbolos svg’s para termos controles visuais usando CSS, podendo inclusive trabalharmos com pseudo-classes :hover.

Se quisermos utilizar classes css para formatar nossos ícones, devemos utilizar a propriedade fill, e não background como estamos acostumados

Para referência, segue um exemplo de um svg inline no documento html e sua utilização com CSS. Parte do trecho do código SVG foi removido para facilitar o entendimento, entretanto, a parte removida é idêntica à da Listagem 14.

Exemplo de código SVG incorporado a um HTML

<!doctype html><html lang=”pt-br”><head><meta charset=”utf-8"><title>Exemplo de SVG</title><style type=”text/css”>.navigation{margin: 0;padding: 0;list-style: none;}.icon {fill: red;width: 50px;height: 50px;}.icon:hover{fill: blue;}</style></head><body><svg xmlns=”http://www.w3.org/2000/svg" style=”display: none;” viewBox=”0 0 200 200"><symbol id=”chat-icon” viewBox=”0 0 200 200"><path d=” …. “/><path fill=”#FFFFFF” d=” …. “/><path fill=”#FFFFFF” d=” …. “/></symbol></svg><nav><ul class=”navigation”><li><a href=”#”><svg class=”icon”><use xlink:href=”#chat-icon”></use></svg></a></li></ul></nav></body></html>

Com isso, temos agora nossos ícones sendo visualizados de maneira satisfatória em diversos devices, sem precisarmos nos preocupar com os diversos tamanhos e resoluções diferentes (de hoje ou do futuro), pois as imagens vetoriais são independentes destas características.

Conclusão

O mercado de desenvolvimento front-end é, ao mesmo tempo, desafiador e dinâmico. Novas soluções para novos problemas aparecem o tempo todo e devemos estar atentos à essas novas abordagens, avaliando tendências e separando o que é moda e o que veio para ficar. Um exemplo são as imagens responsivas que foram um dos grandes problemas do design responsivo no passado, mas atualmente está longe de ser motivo de preocupação.

Esse artigo discutiu apenas três aspectos da utilização de novas ferramentas no desenvolvimento de sites que funcionem bem nos mais diversos devices, mas há muito mais pela frente. Algumas soluções são muito eficientes, mas outras precisam ser melhoradas, como por exemplo, a inclusão de ícones como SVG.

Pode até parecer que ainda estamos engatinhando em alguns aspectos, mas se lembrarmos que há poucos anos estávamos produzindo layouts com tabelas, fica evidente que estamos evoluindo rapidamente para um padrão de desenvolvimento cross-browser, semântico, acessível e, principalmente, responsível.

--

--