As 7 práticas para um site otimizado

Postado em 29. jul, 2010 por em Web Design

Todo mundo gosta de sites rápidos. Seus primos não sabem dizer se você tem um arquitetura escalável, se seu banco NoSQL é mais robusto ou se é melhor usar Web Services SOAP ou REST. Mas eles sabem dizer duas informações com precisão: se seu site é bonito e se ele é rápido. Performance, medida pelo usuário, é o que te diz se a velocidade de resposta da sua aplicação é aceitável. E, assim como usuários não se cansam de bordas redondas e sombrinhas bonitas, sempre haverá otimizações possíveis para tornar seu site mais rápido.

[Update] Interessado em Otimizações Web na prática com truques do básico ao avançado? Confira o novo curso online de otimizações da Caelum!

Inspirado pela recente edição 2010 da Velocity Conference organizada pela O’Reilly e por uma palestra recente que dei com o Alberto Souza aqui na Caelum, além de discussões que aparecem no nosso curso que trata de HTML, CSS e Javascript, selecionei um punhado de dicas para deixar qualquer site ou aplicação Web mais rápido em instantes. Meu TOP 7 não pretende ser uma lista completa e nem detalhada de boas práticas. É mais um guia rápido sobre tudo o que você deveria fazer em qualquer site antes de perguntar a opinião dos seus primos – ou do seu chefe, ou de qualquer usuário. Eis então:

TOP 7 das Otimizações na Web:

0. Habilite GZIP em todas as suas páginas. Se você ainda não fez isso, pare imediatamente de ler esse post e faça. É o passo zero, nem vou contá-lo. Dicas de como fazer no Tomcat, Jetty, Apache, IIS.

1. Agrupe arquivos JavaScript/CSS. 90% do trabalho de otimização consiste em diminuir o número de requests feito na página e o peso de cada um deles. Você usa JQuery (ou qualquer outro framework) com JQuery UI e mais meia dúzia de plugins, sem contar o código JS da sua aplicação? Junte tudo no menor número de arquivos possíveis para evitar muitos requests. Mesma coisa com CSS, um arquivo com tudo basta. Mas gosta de manter as coisas organizadas ao invés de escrever um arquivo com milhares de linhas? Então junte essas coisas dinamicamente como faz o pessoal do Digg ou faça o serviço no build da aplicação como preferimos aqui na Caelum.

2. Comprima o JavaScript/CSS. Você escreve JS/CSS elegante, bem documentado, com código organizado e variáveis de nomes legíveis. Mas seus primos não se importa com isso, eles querem um site rápido e isso significa não trafegar no request bytes e mais bytes de documentação ou de código legível. Comprima todo o seu código JavaScript e CSS usando o YUI Compressor ou o Google Closure Compiler. Faça isso em build time ou dinamicamente.

3. Otimize suas imagens com Smush-it. Nem todos os KB de suas imagens são necessários para o cliente. Arquivos JPEG possuem uma série de metadados e PNGs possuem palhetas de cores. Remova vários KBs desnecessários de suas imagens usando o Yahoo Smush-it em todas elas.

4. Coloque CSS no topo e JavaScript embaixo. Simples assim. Referencie os seus CSS no <head> com <link> para evitar o flash effect, e coloque seus scripts logo antes do fechamento do <body> para não atrasar a renderização da tela.

5. Não redimensione imagens no HTML. Não use os atributos width e height das imagens para redimensionar seu tamanho. Sirva as imagens já com tamanho certo e otimizadas. Mas coloque sempre o width e height de todas as imagens para ajudar o browser nos cálculos da renderização da página.

6. Configure o Expires corretamente. Use o cache do navegador para prover uma melhor experiência ao usuário no segundo request – seja no retorno ao site ou navegando para a próxima página. Permita também que Proxies entre seu servidor e o cliente cacheiem elementos do seu site para evitar um download demorado. Configure o header de Expires de todo seu conteúdo estático (JS, CSS, imagens) com alguns dias de duração.

7. Use YSlow e PageSpeed. Depois que você fez todas as otimizações anteriores, instale o YSlow e o PageSpeed para um diagnóstico detalhado de seu site. Monitore sua performance constantemente e vá implementando sempre novas otimizações. Seus usuários agradecem.

Esse TOP 7 são todas as otimizações que você deveria ter feito ontem em qualquer site seu antes de começar a falar em performance. Há muitas outras práticas, algumas mais complicadas, como CSS Sprites, usar CDNs, otimizar seus cookies, fazer preload e postload de conteúdo, ou comprimir seu HTML. Dependendo da tecnologia que você usa no seu sistema, você terá maior ou menor facilidade de aplicar todas essas práticas: no JSF e ASP.NET você terá benefícios para desenhar sua interface, mas muito mais trabalho de fazer esse ajuste fino; com Struts, Rails, ASP.NET MVC, VRaptor e frameworks action based, será o contrário.

Bônus: Onde ir depois?

E você, que outras práticas aplica no seu website?

[Update] Interessado em Otimizações Web na prática com truques do básico ao avançado? Confira o novo curso online de otimizações da Caelum!

Sérgio Lopes

Mais sobre o autor

Tags: , , , ,

54 Respostas para “As 7 práticas para um site otimizado”

  1. Paulo Silveira

    29. jul, 2010

    é um post excelente.

    vejo que muitas empresas fazem a escolha errada entre component based e action based para seus websites, tendo um prejuizo enorme de SEO e performance, por causa da dificuldade do fine tuning do html/javascript depois de pronto. é precisa conhecer bem os tradeoffs.

  2. Maurício Linhares

    29. jul, 2010

    Component based é sempre um problema quando você quer fazer esse tipo de otimização.

    Mas um detalhe, se você já está com GZIP habilitado, não vale a pena fazer o “Comprima o JavaScript/CSS”. O ganho é marginal e não vale o trabalho.

  3. Leandro

    29. jul, 2010

    ótimas dicas! é um post bem interessante muitos nem imaginavam que existiam tais “recursos” !

  4. Vinicius

    29. jul, 2010

    Não entendi o lance do png, achei que ter a paleta fosse algo que fizesse o arquivo ficar menor, afinal com paleta você pode indexar as cores usando 8 bits ao invés de 24…

  5. Hugo Roque

    29. jul, 2010

    Putz, muito bom, muita coisa aew eu não sabia xD
    Com certeza eu vou usar essas dicas =D

  6. Sérgio Lopes

    29. jul, 2010

    Pessoal, obrigado pelos comentários!

    @Paulo
    O fato é que component-based não é feito para WebSites e sim para WebApps. Usar JSF em um WebSite é a pior coisa que alguém pode fazer

    @Maurício
    Discordo que o ganho da minificação seja marginal. Pegue o JQuery, por exemplo, que muita gente usa. O não-minificado e gzipado fica com 46.1k. O minificado e gzipado fica com 24.6k, quase 50% de ganho. E, sinceramente, o trabalho de minificar é ridiculamente fácil: um scriptzinho no seu build com 3 linhas resolve isso. Vale o trabalho sim.

    @Vinicius
    Se você já se preocupa com sua palheta quando gera as imagens no Photoshop, já é metade do caminho. No post não expliquei direito mesmo, mas o Smush-it consegue, por exemplo, reduzir sua palheta sem perder qualidade. Alguns detalhes sobre o processo de smush:

    http://developer.yahoo.com/performance/rules.html#opt_images

  7. Deyvid Nascimento

    29. jul, 2010

    Sem palavras, ótimo artigo, dicas muito importantes como por exemplo a parte de comprimir código, e agrupar css e javascript, e as ferramentas YSlow e PageSpeed.

    parabéns.

  8. Roberto Nogueira

    29. jul, 2010

    @Maurício @Sergio
    mas se vc habilitar o gzip não vai perder o cache? lembre-se que no request envia um ” If-Modified-Since” e no response deve voltar o código 304 para o browser saber que pode usar o item armazenado no disco do usuario.
    Oras… se o servidor está sempre compactando automaticamentenão não vai ficar verificando o arquivo local foi modificado para retornar um 304. então sempre vai baixar já que nunca vai receber um aval pra usar o cache. sacaram?

  9. Sérgio Lopes

    29. jul, 2010

    @Roberto

    Eu não entendi a relação entre o GZIP e o If-Modified-Since. Existe cache sim de coisas GZIPadas tanto no browser quanto em alguns proxies. E o funcionamento do If-Modified-Since é o mesmo (ele verifica e devolve 304 ou 200 normalmente).

    E lembrando que se você seguir a dica do Expires, nem esse request de verificacao precisa ser feito. O cache é local no browser e não precisa bater no servidor. Você pode, porem, usar o If-Modified-Since/Date-Modified (ou, melhor ainda, ETags) para conteúdo dinâmico com pouca alteração ou para reutilizar o componente mesmo depois que o Expires terminar

  10. Roberto Nogueira

    30. jul, 2010

    @Sergio
    Obrigado pela atenção.
    a relação que me refiro é que para funcionar o recurso compactado é necessário atribuir response.setContentType(“application/x-gzip” ). Ou seja, não adianta compactar um arquivo e simplesmente colocar lá para o usuário baixar. Sendo assim, isso seria aplicado via servlet, ou seja, alguma rotima automatizada que sempre pegaria um arquivo descompactado e depois faria a compressão aplicando o respectivo header.
    É aí que entra o If-Modified-Since. Por exemplo, se fosse uma requisição de imagem por padrão o proprio servidor http iria validar a data de modificação com base no sistema de arquivos. Agora se eu coloco um servlet que gera ou manipula as imagens estaria pegando outro caminho e teria que fazer essa validação com minhas próprias mãos.
    Portanto, quando uma pessoa coloca um servlet que compacta o js com gzip e aplica o header, já perdeu a validação de cache do servidor. é isso que estava querendo dizer.

    []s,
    bob

  11. Roberto Nogueira

    30. jul, 2010

    @sergio
    ops me enganei, ao inves de setContentType(“application/x-gzip” ) o correto é setHeader(“Content-Encoding”, “gzip”);

  12. Sérgio Lopes

    30. jul, 2010

    @Roberto

    Entendi agora sua questão! Recomendo dar uma olhada nos mecanismos prontos do seu servidor para fazer o GZIP. Acho que não é uma boa tentar escrever sua própria Servlet, gerar arquivos compactados na mão ou algo assim.

    Todos os servidores Web possuem mecanismos para fazer tudo isso transparentemente, garantindo a integridade dos headers, Date-Modified, por exemplo. Eu uso aqui o AppEngine que me dá GZIP automático sem eu fazer nada (aliás, não é possível nem desabilitar). Quem usa Tomcat/Jetty etc diretamente tem que habilitar mas coloquei uns links aí no post que mostram como fazer.

  13. Lucas Pereira Caixeta

    01. ago, 2010

    @Lucas_Caixeta

    Ótimo post cara!! vou seguir as ideias!

  14. Levy Carneiro Jr.

    02. ago, 2010

    Pessoal,

    postei 4 vídeos no Youtube, com dicas de performance Client-Side. Confiram:

    http://levycarneiro.com/2010/04/webcast-como-melhorar-a-performance-do-meu-site/

    Abraços,
    Levy

  15. Tiago Allen

    03. ago, 2010

    Gostaria de agregar uma dica sobre otimização de css.
    Entendo que quanto maior a sua estrutura de código CSS mais difícil fica de mantê-la, por mais que você tenha um css organizado ainda assim fica difícil.
    A minha sugestão e fazer uso do LESS.app http://incident57.com/less/, esse aplicativo para Mac me permite escreve os arquivos em less e depois compila-los automaticamente sem que eu precise estartar um servidor Rails na minha máquina. Desta forma consigo escrever grandes linhas de código, com múltiplos arquivos e ainda padronizar uma serie de funcionalidade do código de forma inteligente e ordenada.
    Hoje utilizo esse recurso tanto para grandes projetos quanto para pequenos sites de puro html, otimização na produtividade e também na hora de projetar o css.

  16. Fabiano David

    05. ago, 2010

    Legal essa discussão e muito bom o Post. Vale todas as dicas

    http://www.fabianodavid.com.br
    http://www.aehweb.com.br

  17. Joao Polo

    06. ago, 2010

    Excelente post! Me faz repensar várias coisas… como por exemplo a parte do css ser no topo (o que eu já faço) e os scripts embaixo (o que nem eu… nem quase ninguém faz).

    Abraço!

  18. Roberto

    06. ago, 2010

    Sensacional o post! Só não entendi como fazer o procedimento 1 que é agrupar os arquivos js e css dinamicamente ou no build da app. Alguma luz?

    E parabéns pelo post. Abraço!

  19. Sérgio Lopes

    06. ago, 2010

    Oi pessoal, obrigado pelos comentários!

    @Roberto

    A ideia é você juntar vários arquivos JS ou CSS em um só. Por exemplo, se você usa JQuery, JQuery UI, um plugin qualquer e mais o código da sua aplicação. Ao invés de deixar os 4 arquivos separados, junte seu conteúdo (um “super.js”) que você carrega de uma vez só.

    Mas o ideal é não fazer essa junção na mão, misturando milhares de linhas de código diferentes, senão a manutenção fica complicada. Aí recomendo que você faça, por exemplo, uma Servlet/Filter/Action que dinamicamente lê os arquivos isolados e depois cospe uma saída única. Ou então que você faça estaticamente no build através de alguma task Ant/Maven/etc que lê os arquivos separados e junta em um só.

    O pessoal do Digg (link acima, repare na URL) fez do modo dinâmico: você chama uma URL deles passando os arquivos que quer e ele junta. Na Caelum (link acima), preferimos build time e temos um arquivo caelum.package.js que inclui uns 8 arquivos diferentes durante o Ant.

  20. Roberto

    07. ago, 2010

    @Sergio

    Foi o que pensei em fazer: montar uma Servlet/Filter/Action pra manipular os arquivos e montar um único. Ideia simples, porém genial! E mto legal mesmo o que o Digg faz.

    Agora está respondido. Mto obrigado!

    Forte abraço!

  21. Levy Carneiro Jr.

    09. ago, 2010

    Uma coisa importante também é criar travas no site ou aplicação, para que a nota do YSLOW e/ou PAGE SPEED tão suada de ser alcançada, se perca depois do designer subir uma imagem com o dobro do tamanho necessário ;)

    Ou seja, melhorar o processo para que o site/aplicação não perca a performance nunca :)

  22. Leandro

    11. ago, 2010

    Muito interessante e muito útil essas dicas da Caelum sobre aotimização de sites, será de grande valia.

    Vocês estão de Parabéns !

    Abraço,
    Leandro

  23. Icaro

    11. ago, 2010

    SENSACIONAL esse post !!

    Me ajudou muito, meus sites ficarão muito mais rápidos.

    Forte abraço
    Ícaro

  24. Jeff

    18. ago, 2010

    Desculpe a ignorância mas, alguem tem algum link com material sobre como configurar o header de expires de conteúdos estáticos?!?

  25. Sérgio Lopes

    18. ago, 2010

    @Jeff

    Depende muito da plataforma que você está usando. No pior dos casos você cria um filtro Java que chama response.addHeader(Expires) pra você. Mas o recomendado costuma ser servir coisas estáticas em uma infra própria para isso.

    Por exemplo, deixar um Apache na frente no Tomcat/JBoss/etc servindo os CSS/JS/imagens. Aí você configuraria no .htaccess dele.

    No AppEngine, por exemplo, configuramos no arquivo appconfig.xml na secao static-files (sintaxe própria). Se você usar algum CDN externo, possivelmente ele já faz isso por você também.

    Em suma: depende da sua infra, mas sempre há um jeito :)

  26. Flavio Duarte

    19. nov, 2010

    Sérgio, muito bom o post
    você pode falar como eu posso agrupar no build? “… faça o serviço no build da aplicação como preferimos aqui na Caelum.”

  27. Sérgio Lopes

    19. nov, 2010

    @Flavio

    Aqui na Caelum, temos arquivos que chamamos de *.package.js (ou CSS). Nesse arquivo de pacote a gente declara os arquivos a serem incluídos, um por linha. Por exemplo:

    /javascripts/lib/jquery.js
    /javascripts/lib/jquery-ui.js
    /javascripts/base.js
    /javascripts/outro.js

    Em tempo de desenvolvimento, temos um filtro (javax.servlet.Filter) que lê dinamicamente esses arquivos package e vai incluindo os arquivos pra gente. Em produção o filtro não existe, porque no build a gente roda um script que procura os arquivos package e faz a inclusão pra gente.

    Dá pra ver um desses arquivos no site da Caelum:
    http://www.caelum.com.br/javascripts/caelum.package.js

    (esse aí já ta minificado também, mas dá pra perceber que cada linha nova é um arquivo diferente)

  28. Thiago Araujo

    03. dez, 2010

    Eu habilitei o gzip no jboss, no page speed aparece:
    - Cabeçalhos de Resposta
    Content-Encoding: gzip

    - Cabeçalhos de Solicitação:
    Accept-Encoding: gzip,deflate

    Mas se eu executar o Analyze Performance aparece entre outro o Enable compression.

    O que eu preciso fazer alem de habilitar no Servidor de Aplicação para utilizar o gzip?

  29. Denis Santos

    06. jan, 2011

    As dicas são ótimas, parabéns!
    Vejo que em projetos com arquitetos experientes isso tudo é uma realidade, mas com o passar do tempo as aplicações são esquecidas devido a novas demandas, o que acaba caindo na mão de equipes de manutenção que não adotam as mesmas práticas.

    Mas, mais uma vez, parabéns pelo POST!

  30. Natascha

    07. fev, 2011

    Olá, adorei o post e sua palestra sobre o assunto na PHP Conf do ano passado!

    Sergio, não sei se poderia ajudar:

    Na página do Yahoo a função flush() do PHP é recomendada para otimização porque vai enviando parcialmente a resposta ao navegador.

    Mas, no manual do PHP, diz:

    1. flush() não tem efeito no funcionamento de buffer do seu servior ou do browser do cliente.
    2. Módulos de servidor para o Apache como o mod_gzip podem fazer buffer por si o que fará com que flush() não resulte em os dados serem enviados imediatamente para o cliente.

    Ou seja, realmente essa recomendação do flush() será que procede?

  31. Sérgio Lopes

    07. fev, 2011

    Oi Natascha, obrigado!

    Sobre o flush, tenho o mesmo problema por aqui, em Java. Usar o GZIP também impede que ele tenha algum efeito. Acho que em 99% dos casos, o flush é uma regra descartável, até porque usar GZIP acaba sendo bem mais importante.

    Abraços

  32. Natascha

    07. fev, 2011

    Obrigada Sérgio!

    1) Mais uma dúvida: configurei Expires alto. A configuração da ETag eliminaria ter que mudar o nome do arquivo para fazer uma atualização do cache?
    (Coloquei no Apache diretiva “FileETag MTime”, para pegar data e hora da última modificação)

    2) Meu Apache não está comprimindo GZip para arquivos javascript – adicionei:
    text/javascript e application/x-javascript

    Coloquei da mesma forma na Diretiva Expires e ali funcionou, só no GZip que não (pra html, css foi ok)

    Grata!

  33. Sérgio Lopes

    08. fev, 2011

    @Natascha

    1) Não, você ainda vai ter que mudar o nome do arquivo, caso contrário o browser não tem como saber que o arquivo mudou. O ETag (assim como o Date-Modified) vai apenas impedir que o arquivo seja baixado de novo pelo browser quando acabar o tempo do Expires.

    Aqui na Caelum, temos um script que coloca automaticamente o timestamp no nome do arquivo. Assim só muda quando o arquivo for alterado mesmo.

    2) Humm, não sei se consigo te ajudar, não conheço muito os detalhes de configuração do Apache

  34. Lucas Murata

    22. mar, 2011

    Um livro muito bom que trata destes assuntos: High Performance Web Sites: Essential Knowledge for Front-End Engineers.

    Eu uso JSF em produção, mas estou prestes a desistir dele. Agente perde liberdade na View, não tem controle sobre HTML, CSS e JS, além de códigos aliens que ele gera sozinho. Sem contar com milhoes de JS que ele importa.

    Sinceramente, acho que JSF é inadequado até para WebApp.

  35. Paulo Silveira

    23. mar, 2011

    @Lucas, tem razao, no caso de websites onde é necessario o controle de JS e HTML, JSF te trara muito trabalho para customizar.

    Se a Webapp for para intranet, rica em formularios, sem necessidade de exatidoes de html e js, pode ser uma boa escolha.

  36. Michel Banagouro

    12. abr, 2011

    Ótimo post!
    São dicas úteis e q eu costumo usar no meu dia-a-dia.
    Até fiz um post sobre um desses itens no meu blog: compressão gzip no asp .net mvc.

    http://mbanagouro.net/site/2011/04/07/compressao-gzip-no-asp-net-mvc/

  37. Rodrigo

    29. abr, 2011

    Oi, estive vendo o seu post, e achei muito bom… so fiquei com uma duvida referente ao tópico 6, para a configuração do Expires corretamente, como é feita esta configuração?

    Nao consegui encontrar nada, vi que geralmente o codigo do page speed pede para configurar o javascript e o css com estas informações, como faz isso ?

  38. Sérgio Lopes

    29. abr, 2011

    Oi Rodrigo!

    Vai depender do servidor que você está usando. No post eu linkei para tutoriais no Tomcat, Apache e IIS.

    Abraços

  39. Lucas Peperaio

    04. mai, 2011

    Muito boas as dicas, usei na minha ferramenta online.
    valeu

  40. Bruno

    17. mai, 2011

    Muito bom.

    Sou iniciante em Web Design e estou me inspirando em suas dicas para ter sucesso.

  41. Filza Azize

    16. jun, 2011

    Ola…
    Gostei das dicas…
    Gostaria de saber como redimensionar uma foto sem alterar a qualidade de imagem usando código Java..

    Obrigada

  42. Mario Santos

    03. jul, 2011

    Muito bom! Realmente isso faz toda a diferença na otimização dos sistemas na web.

  43. Thyago Ferreira

    12. jul, 2011

    Muito bom cara, recomendações práticas e objetivas, tem coisa melhor?

  44. Wolmir

    06. out, 2011

    Parabéns gostei muito das dicas, inclusive me entusiasmou muito em pesquisar mais e aprender sobre otimização de paginas….

  45. Humberto

    08. dez, 2011

    Olá, quanto à compressão gzip, isso é possível no JBoss AS 7? Pelo que vi parece que essa funcionalidade foi retirada nessa última versão.

  46. Felipe

    27. mar, 2012

    Ola,
    Estou tentando setar o Header Expires e mesmo com o Page Speed mostrando q esta tudo OK, o browser continua chamando o arquivo no servidor.
    Postei a pergunta no guj com mais detalhamento.

    http://www.guj.com.br/java/268731-problema-com-cache-no-browser—cache-control-expires-last-modified-etc

    Valeu a ajuda,
    e parabéns pelo post!!

  47. Felipe

    28. mar, 2012

    Como vcs fazem para setar a data de Expiracao/Cache-Control dos Arquivos?
    Vcs fazem um filtro manualmente no java ou configuram para q o servidor faça cache?
    E mais uma pergunta: Como fazer para configurar o cache pelo servidor? Eu achei esse link aqui será q ta certo?
    http://www.symphonious.net/2007/06/19/caching-in-tomcat/

    valeu!

Trackbacks/Pingbacks

  1. links for 2010-08-04 « pabloidz - agosto 4, 2010

    [...] As 7 práticas para um site otimizado blog.caelum.com.br (tags: webdesign css javascript) [...]

  2. Montanhismo digital | abstractj.com - agosto 9, 2010

    [...] aplicação em diferentes situações e identificar possíveis pontos de falha, cogite problemas de performance na aplicação, antes de blasfemar contra o servidor. Assim como no alpinismo, escalar montanhas sem [...]

  3. TOP 10: Os melhores posts de 2010 da Caelum | blog.caelum.com.br - dezembro 21, 2010

    [...] As 7 práticas para um site otimizadopor Sérgio Lopes, em 29/07 [...]

  4. Compressão GZIP no tomcat, faça agora =) « - janeiro 3, 2011

    [...] http://blog.caelum.com.br/top-7-praticas-para-um-site-otimizado/ [...]

  5. Otimizações na Web e o carregamento assíncrono | blog.caelum.com.br - abril 28, 2011

    [...] bitolados por otimizações Web aqui na Caelum então muitas otimizações já estavam integradas ao Site. A primeira versão, logo [...]

  6. Por uma Web mais rápida: 26 técnicas de otimização de Sites | blog.caelum.com.br - setembro 12, 2011

    [...] Há muito tempo que falo que habilitar o GZIP no servidor é o primeiro passo. Não leva mais de 30s para ser feito e é suportado em todos os navegadores e servidores dos últimos 15 anos. Com ele, todo conteúdo textual (HTML, CSS, JS etc) é comprimido antes de ser enviado para o cliente, chegando a cortar mais de 50% do tráfego total. [...]

  7. As 7 práticas para um site otimizado | blog.caelum.com.br » Web Design - março 28, 2012

    [...] As 7 práticas para um site otimizado | blog.caelum.com.br [...]

Deixar uma Resposta