As 7 práticas para um site otimizado
Por Sérgio Lopes em 29/07/10Todo 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.
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?
- Práticas de performance do pessoal do Yahoo YSlow
- Boas práticas do pessoal do Google PageSpeed
- Slides e vídeos das palestras do Velocity 2010 com o que há de mais novo em discussão
E você, que outras práticas aplica no seu website?
é 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.
Comment by Paulo Silveira — July 29, 2010 @ 11:37 am
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.
Comment by Maurício Linhares — July 29, 2010 @ 11:44 am
ótimas dicas! é um post bem interessante muitos nem imaginavam que existiam tais “recursos” !
Comment by Leandro — July 29, 2010 @ 11:58 am
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…
Comment by Vinicius — July 29, 2010 @ 12:09 pm
Putz, muito bom, muita coisa aew eu não sabia xD
Com certeza eu vou usar essas dicas =D
Comment by Hugo Roque — July 29, 2010 @ 1:04 pm
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
Comment by Sérgio Lopes — July 29, 2010 @ 2:29 pm
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.
Comment by Deyvid Nascimento — July 29, 2010 @ 3:06 pm
@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?
Comment by Roberto Nogueira — July 29, 2010 @ 6:44 pm
@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
Comment by Sérgio Lopes — July 29, 2010 @ 8:39 pm
@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
Comment by Roberto Nogueira — July 30, 2010 @ 4:03 pm
@sergio
ops me enganei, ao inves de setContentType(“application/x-gzip” ) o correto é setHeader(“Content-Encoding”, “gzip”);
Comment by Roberto Nogueira — July 30, 2010 @ 4:06 pm
@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.
Comment by Sérgio Lopes — July 30, 2010 @ 4:13 pm
@Lucas_Caixeta
Ótimo post cara!! vou seguir as ideias!
Comment by Lucas Pereira Caixeta — August 1, 2010 @ 3:50 pm
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
Comment by Levy Carneiro Jr. — August 2, 2010 @ 4:39 pm
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.
Comment by Tiago Allen — August 3, 2010 @ 9:15 am
[...] As 7 práticas para um site otimizado blog.caelum.com.br (tags: webdesign css javascript) [...]
Pingback by links for 2010-08-04 « pabloidz — August 4, 2010 @ 9:35 am
Legal essa discussão e muito bom o Post. Vale todas as dicas
http://www.fabianodavid.com.br
http://www.aehweb.com.br
Comment by Fabiano David — August 5, 2010 @ 5:45 pm
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!
Comment by Joao Polo — August 6, 2010 @ 11:22 am
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!
Comment by Roberto — August 6, 2010 @ 1:12 pm
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.
Comment by Sérgio Lopes — August 6, 2010 @ 2:24 pm
@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!
Comment by Roberto — August 7, 2010 @ 12:19 am
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
Comment by Levy Carneiro Jr. — August 9, 2010 @ 3:37 pm
[...] 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 [...]
Pingback by Montanhismo digital | abstractj.com — August 9, 2010 @ 6:17 pm
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
Comment by Leandro — August 11, 2010 @ 10:59 am
SENSACIONAL esse post !!
Me ajudou muito, meus sites ficarão muito mais rápidos.
Forte abraço
Ícaro
Comment by Icaro — August 11, 2010 @ 11:54 am
Desculpe a ignorância mas, alguem tem algum link com material sobre como configurar o header de expires de conteúdos estáticos?!?
Comment by Jeff — August 18, 2010 @ 5:21 pm
@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
Comment by Sérgio Lopes — August 18, 2010 @ 10:53 pm