As 7 práticas para um site otimizado

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 a grade do futuro 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!

63 Comentários

  1. Paulo Silveira 29/07/2010 at 11:37 #

    é 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/07/2010 at 11:44 #

    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/07/2010 at 11:58 #

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

  4. Vinicius 29/07/2010 at 12:09 #

    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/07/2010 at 13:04 #

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

  6. Sérgio Lopes 29/07/2010 at 14:29 #

    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/07/2010 at 15:06 #

    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/07/2010 at 18:44 #

    @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/07/2010 at 20:39 #

    @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/07/2010 at 16:03 #

    @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/07/2010 at 16:06 #

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

  12. Sérgio Lopes 30/07/2010 at 16:13 #

    @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/08/2010 at 15:50 #

    @Lucas_Caixeta

    Ótimo post cara!! vou seguir as ideias!

  14. Levy Carneiro Jr. 02/08/2010 at 16:39 #

    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/08/2010 at 09:15 #

    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/08/2010 at 17:45 #

    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/08/2010 at 11:22 #

    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/08/2010 at 13:12 #

    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/08/2010 at 14:24 #

    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/08/2010 at 00:19 #

    @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/08/2010 at 15:37 #

    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/08/2010 at 10:59 #

    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/08/2010 at 11:54 #

    SENSACIONAL esse post !!

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

    Forte abraço
    Ícaro

  24. Jeff 18/08/2010 at 17:21 #

    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/08/2010 at 22:53 #

    @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/11/2010 at 07:56 #

    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/11/2010 at 10:30 #

    @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/12/2010 at 12:09 #

    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/01/2011 at 14:40 #

    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/02/2011 at 10:11 #

    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/02/2011 at 13:18 #

    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/02/2011 at 16:10 #

    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/02/2011 at 00:36 #

    @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/03/2011 at 17:37 #

    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/03/2011 at 17:31 #

    @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/04/2011 at 14:13 #

    Ó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/04/2011 at 14:57 #

    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/04/2011 at 15:55 #

    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/05/2011 at 15:30 #

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

  40. Bruno 17/05/2011 at 23:35 #

    Muito bom.

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

  41. Filza Azize 16/06/2011 at 08:46 #

    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/07/2011 at 23:05 #

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

  43. Thyago Ferreira 12/07/2011 at 08:33 #

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

  44. Wolmir 06/10/2011 at 15:03 #

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

Deixe uma resposta