Escolar Documentos
Profissional Documentos
Cultura Documentos
Marco Peregrino
HTML5: instalado e
funcionando por Mark Pilgrim
Publicado por O'Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
Os livros da O'Reilly podem ser adquiridos para uso educacional, comercial ou promocional de vendas. Edições online
também estão disponíveis para a maioria dos títulos (http:// my.safaribooksonline.com). Para mais informações, entre em
contato com nosso departamento de vendas corporativas/institucionais: (800) 998-9938 ou corporate@oreilly.com.
Histórico de impressão:
Agosto de 2010: Primeira edição.
Nutshell Handbook, o logotipo Nutshell Handbook e o logotipo O'Reilly são marcas registradas da O'Reilly Media, Inc.
HTML5: Up and Running, a imagem de uma camurça alpina e imagem comercial relacionada são marcas registradas da
O'Reilly Media, Inc.
Muitas das designações utilizadas pelos fabricantes e vendedores para distinguir os seus produtos são reivindicadas como
marcas comerciais. Onde essas designações aparecem neste livro, e a O'Reilly Media, Inc. estava ciente de uma
reivindicação de marca registrada, as designações foram impressas em letras maiúsculas ou iniciais.
Embora todas as precauções tenham sido tomadas na preparação deste livro, o editor e o autor não assumem nenhuma
responsabilidade por erros ou omissões, ou por danos resultantes do uso das informações aqui contidas.
MT
ISBN: 978-0-596-80602-6
[M]
1281030545
Índice
Prefácio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix
em
Leitura adicional 29
5. Vídeo na Web. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Mergulhando 81
em contêineres de 81
vídeo Codecs de 83
vídeo 84
Codecs 84
de 85
áudio H.264 85
Theora VP8 MPEG-1 Audio 86
Layer 3 Codificação de áudio 87
87
avançada Vorbis O que funciona 88
na Web Problemas de licenciamento com vídeo H.264 90
vi | Índice
Índice | vii
Mergulhando 147
Texto de espaço reservado 147
Campos de foco automático 148
Endereço de e-mail 150
Endereços da Web 151
Índice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
viii | Índice
Prefácio
Mergulhando
O que é HTML5? HTML5 é a próxima geração de HTML, substituindo HTML 4.01, XHTML 1.0 e
XHTML 1.1. HTML5 fornece novos recursos necessários para aplicativos da web modernos. Ele
também padroniza muitos recursos da plataforma web que os desenvolvedores web usam há anos,
mas que nunca foram examinados ou documentados por um comitê de padrões. (Você ficaria
surpreso ao saber que o objeto Window nunca foi formalmente documentado? Além dos novos
recursos, o HTML5 é a primeira tentativa de documentar formalmente muitos dos padrões “de fato”
que os navegadores da Web suportam há anos.)
Assim como seus antecessores, o HTML5 foi projetado para ser multiplataforma. Você não precisa
executar Windows ou Mac OS X ou Linux ou Multics ou qualquer sistema operacional específico
para aproveitar as vantagens do HTML5. A única coisa que você precisa é de um navegador
moderno. Existem navegadores modernos disponíveis gratuitamente para todos os principais
sistemas operacionais. Talvez você já tenha um navegador da Web compatível com determinados recursos do HTML5.
As versões mais recentes do Apple Safari, Google Chrome, Mozilla Firefox e Opera suportam muitos
recursos HTML5. (Você encontrará tabelas mais detalhadas de compatibilidade de navegadores ao
longo deste livro.) Todos os navegadores móveis pré-instalados em iPhones, iPads e telefones
Android têm excelente suporte para HTML5. Até a Microsoft anunciou que a próxima versão 9 do
Internet Explorer suportará algumas funcionalidades do HTML5.
ix
• Aplicativos web off-line que funcionam mesmo após a interrupção do acesso à rede
(Capítulo 8) •
que permitem criar seus próprios vocabulários além do HTML5 e estender suas páginas web com
semântica personalizada (Capítulo 10)
O HTML5 foi projetado, tanto quanto possível, para ser compatível com versões anteriores dos navegadores
da web existentes. Novos recursos baseiam-se em recursos existentes e permitem fornecer conteúdo
substituto para navegadores mais antigos. Se precisar de um controle ainda maior, você pode detectar
suporte para recursos HTML5 individuais (Capítulo 2) usando algumas linhas de JavaScript. Não confie na
detecção frágil de navegadores para decidir quais navegadores suportam HTML5! Em vez disso, teste os
recursos necessários usando o próprio HTML5.
Itálico
Indica novos termos, URLs, endereços de e-mail, nomes de arquivos e extensões de arquivos.
Largura constante
Usado para listagens de programas, bem como dentro de parágrafos para se referir a elementos de
programas, como nomes de variáveis ou funções, bancos de dados, tipos de dados, variáveis de
ambiente, instruções e palavras-chave.
Largura constante negrito
Mostra comandos ou outro texto que deve ser digitado literalmente pelo usuário.
Largura constante em itálico
Mostra o texto que deve ser substituído por valores fornecidos pelo usuário ou por valores
determinados pelo contexto.
x | Prefácio
Este livro está aqui para ajudá-lo a realizar seu trabalho. Em geral, você pode usar o código deste livro em
seus programas e documentação. Você não precisa entrar em contato conosco para obter permissão, a
menos que esteja reproduzindo uma parte significativa do código. Por exemplo, escrever um programa
que utilize vários trechos de código deste livro não requer permissão. Vender ou distribuir um CD-ROM
com exemplos de livros da O'Reilly requer permissão. Responder a uma pergunta citando este livro e
citando código de exemplo não requer permissão. Incorporar uma quantidade significativa de código de
exemplo deste livro na documentação do seu produto requer permissão.
Agradecemos, mas não exigimos, atribuição. Uma atribuição geralmente inclui título, autor, editora e ISBN.
Por exemplo: “HTML5: instalado e funcionando por Mark Pilgrim.
Copyright 2010 O'Reilly Media, Inc., 978-0-596-80602-6.”
Se você acha que o uso de exemplos de código está fora do uso justo ou da permissão dada acima, sinta-
se à vontade para nos contatar em permissions@oreilly.com.
Este livro é derivado de sua fonte HTML5, encontrada em http://diveintohtml5.org/ e mantida pelo autor.
As edições do e-book e do Safari Books Online incluem todos os hiperlinks originais, enquanto a edição
impressa inclui apenas um subconjunto dos hiperlinks, definidos como URLs entre parênteses. Se você
estiver lendo a edição impressa, consulte uma das outras edições – ou a fonte original – para uma
experiência de vinculação mais rica. Como o autor mantém http://diveintohtml5.org/ em HTML5, o site
inclui exemplos dinâmicos do código descrito neste livro, muitos dos quais tiveram que ser modificados
para publicação.
Visite http://diveintohtml5.org/ para ver esses exemplos, mas esteja ciente de que sua renderização pode
variar entre os navegadores.
Safari Books Online é uma biblioteca digital sob demanda que permite pesquisar facilmente
mais de 7.500 livros e vídeos de referência de tecnologia e criativos para encontrar
rapidamente as respostas que você precisa.
Com uma assinatura, você pode ler qualquer página e assistir a qualquer vídeo de nossa biblioteca online.
Leia livros em seu celular e dispositivos móveis. Acesse novos títulos antes que estejam disponíveis para
impressão e tenha acesso exclusivo aos manuscritos em desenvolvimento e poste feedback para os
autores. Copie e cole exemplos de código, organize seus favoritos, baixe capítulos, marque seções
principais, crie notas, imprima páginas e aproveite vários outros recursos que economizam tempo.
Prefácio | XI
A O'Reilly Media carregou este livro no serviço Safari Books Online. Para ter acesso digital completo a este livro
e outros sobre temas semelhantes da O'Reilly e de outros editores, inscreva-se gratuitamente em http://
my.safaribooksonline.com.
Por favor, envie comentários e perguntas sobre este livro à editora: O'Reilly Media, Inc.
Temos uma página web para este livro, onde listamos erratas, exemplos e qualquer informação adicional. Você
pode acessar esta página em:
http://oreilly.com/catalog/9780596806026/ Para
comentar ou tirar dúvidas técnicas sobre este livro, envie e-mail para: bookquestions@oreilly.com
Para obter mais informações sobre nossos livros, conferências, Centros de Recursos e a Rede O'Reilly, consulte
nosso website em: http://www.oreilly.com
xii | Prefácio
CAPÍTULO 1
Mergulhando
Implementações e especificações precisam fazer uma dança delicada juntas. Você não quer
que as implementações aconteçam antes da conclusão da especificação, porque as pessoas
começam a depender dos detalhes das implementações e isso restringe a especificação. No
entanto, você também não quer que a especificação seja concluída antes que haja
implementações e experiência do autor com essas implementações, porque você precisa do feedback.
Há uma tensão inevitável aqui, mas só temos que seguir em frente.
Mantenha esta citação em mente e deixe-me explicar como o HTML5 surgiu.
Tipos MIME
Este livro é sobre HTML5, não sobre versões anteriores de HTML e não sobre qualquer versão de
XHTML. Mas para entender a história do HTML5 e as motivações por trás dele, você precisa
primeiro entender alguns detalhes técnicos. Especificamente, tipos MIME.
Cada vez que seu navegador solicita uma página, o servidor web envia vários cabeçalhos antes de
enviar a marcação real da página. Esses cabeçalhos normalmente são invisíveis, embora existam
várias ferramentas de desenvolvimento web que os tornarão visíveis se você estiver interessado.
Os cabeçalhos são importantes porque informam ao navegador como interpretar a marcação da
página a seguir. O cabeçalho mais importante é chamado Content-Type e tem a seguinte aparência:
text/html é chamado de “tipo de conteúdo” ou “tipo MIME” da página. Este cabeçalho é a única
coisa que determina o que realmente é um recurso específico e, portanto, como ele deve ser
renderizado. As imagens têm seus próprios tipos MIME (image/jpeg para imagens JPEG, image/
png para imagens PNG e assim por diante). Os arquivos JavaScript têm seu próprio tipo MIME. CSS
folhas de estilo têm seu próprio tipo MIME. Tudo tem seu próprio tipo MIME. A Web funciona em tipos
MIME.
Claro, a realidade é mais complicada do que isso. Os primeiros servidores web (estou falando de
servidores web de 1993) não enviavam o cabeçalho Content-Type , porque ele ainda não existia.
(Ele não foi inventado até 1994.) Por motivos de compatibilidade que datam de 1993, alguns navegadores
populares irão ignorar o cabeçalho Content-Type sob certas circunstâncias. (Isso é chamado de “sniffing
de conteúdo”.) Mas, como regra geral, tudo o que você já viu na Web – páginas HTML, imagens, scripts,
vídeos, PDFs, qualquer coisa com URL – foi servido para você com um tipo MIME específico no cabeçalho
Content-Type .
Uma das grandes vantagens dos padrões desenvolvidos “aberto” é que você pode voltar no tempo e
responder a esse tipo de pergunta. As discussões ocorrem em listas de discussão, que geralmente são
arquivadas e podem ser pesquisadas publicamente. Então, decidi fazer um pouco de “arqueologia de e-
mail” para tentar responder à questão do elemento <img> . Tive que voltar antes de existir uma organização
chamada World Wide Web Consortium (W3C).
Voltei aos primórdios da Web, quando era possível contar o número de servidores Web nos dedos de
ambas as mãos, e talvez em alguns dedos dos pés.
Isso nomeia um arquivo bitmap ou pixmap para o navegador tentar puxar pela rede e interpretar como uma
imagem, para ser incorporada ao texto no ponto de ocorrência da tag.
Um exemplo é:
<IMG SRC="file://foobar.com/foo/bar/blargh.xbm">
(Não há tag de fechamento; esta é apenas uma tag independente.)
Esta tag pode ser incorporada em uma âncora como qualquer outra; quando isso acontece, ele se
torna um ícone sensível à ativação, assim como uma âncora de texto normal.
Os navegadores devem ter flexibilidade quanto aos formatos de imagem que suportam. Xbm e Xpm
são bons para suporte, por exemplo. Se um navegador não puder interpretar um determinado
formato, ele poderá fazer o que quiser (o X Mosaic exibirá um bitmap padrão como espaço
reservado).
Esta é uma funcionalidade necessária para o X Mosaic; temos isso funcionando e pelo menos
usaremos internamente. Certamente estou aberto a sugestões sobre como isso deve ser tratado no
HTML; se você tiver uma ideia melhor do que a que estou apresentando agora, por favor me avise.
Sei que isso é confuso em relação ao formato da imagem, mas não vejo alternativa a não ser
apenas dizer “deixe o navegador fazer o que pode” e esperar que apareça a solução perfeita (MIME,
algum dia, talvez).
Esta citação requer alguma explicação. Xbm e Xpm eram formatos gráficos populares em sistemas Unix.
“Mosaic” foi um dos primeiros navegadores da web. (“X Mosaic” era a versão executada em sistemas Unix.)
Quando escreveu esta mensagem no início de 1993, Marc ainda não havia fundado a empresa que o tornou
famoso, a Mosaic Communications Corporation, nem havia começado a trabalhar no principal produto dessa
empresa. , “Mosaico Netscape”. (Você pode conhecê-los melhor pelos seus nomes posteriores, “Netscape
Corporation” e “Netscape Navigator”.)
“MIME, algum dia, talvez” é uma referência à negociação de conteúdo, um recurso do HTTP onde um cliente
(como um navegador da web) informa ao servidor (como um servidor da web) quais tipos de recursos ele
suporta (como imagem/jpeg) para que o o servidor pode retornar algo no formato preferido do cliente. “O HTTP
original conforme definido em 1991” (a única versão implementada em fevereiro de 1993) não tinha como os
clientes informarem aos servidores quais tipos de imagens eles suportavam, daí o dilema de design que Marc
enfrentou.
Eu tenho algo muito semelhante no Midas 2.0 (em uso aqui no SLAC, e com lançamento público
previsto para qualquer semana), exceto que todos os nomes são diferentes e tem um argumento
extra NAME="name". Tem quase exatamente a mesma funcionalidade da tag IMG proposta. por
A ideia do parâmetro name era permitir que o navegador tivesse um conjunto de imagens
“integradas”. Se o nome corresponder a uma imagem “integrada”, ele a usaria em vez de ter que
sair e buscar a imagem. O nome também pode servir como uma dica para navegadores de “modo
linha” sobre que tipo de símbolo colocar no lugar da imagem.
Não me importo muito com os nomes dos parâmetros ou tags, mas seria sensato se usássemos
as mesmas coisas. Não ligo muito para abreviações, ou seja, por que não IMAGE= e SOURCE=.
Eu prefiro um pouco o ÍCONE, pois implica que a IMAGEM deve ser pequena, mas talvez o ÍCONE
seja uma palavra sobrecarregada?
Midas foi outro dos primeiros navegadores, contemporâneo do X Mosaic. Era multiplataforma; ele rodava em
Unix e VMS. “SLAC” refere-se ao Stanford Linear Accelerator Center, agora SLAC National Accelerator
Laboratory, que sediou o
primeiro servidor web nos Estados Unidos (na verdade, o primeiro servidor web fora da Europa). Quando
Tony escreveu esta mensagem, o SLAC era um veterano na WWW, tendo hospedado cinco páginas
em seu servidor web por impressionantes 441 dias.
Tony continuou:
Enquanto estamos no assunto de novas tags, tenho outra tag, um tanto semelhante, que gostaria de oferecer
suporte no Midas 2.0. Em princípio é:
<INCLUIR HREF="...">
A intenção aqui seria que o segundo documento fosse incluído no primeiro documento no local onde ocorreu a
etiqueta. Em princípio o documento referenciado poderia ser qualquer coisa, mas o objetivo principal era permitir
que imagens (neste caso de tamanho arbitrário) fossem incorporadas aos documentos. Novamente, a intenção
seria que, quando o HTTP2 aparecesse, o formato do documento incluído fosse negociado separadamente.
“HTTP2” é uma referência ao HTTP Básico conforme definido em 1992. Neste ponto, no início de 1993,
ainda estava em grande parte não implementado. O rascunho conhecido como “HTTP2” evoluiu e
acabou sendo padronizado como “HTTP 1.0”. O HTTP 1.0 incluía cabeçalhos de solicitação para
negociação de conteúdo, também conhecido como “MIME, algum dia, talvez”.
Tony continuou:
gosto muito de adicionar mais funcionalidades à tag <A> , mas a ideia aqui é manter a compatibilidade com os
navegadores que não pode respeitar o parâmetro INCLUDE . A intenção é que os navegadores que entendem
INCLUDE substituam o texto âncora (neste caso “Ver foto”) pelo documento incluído (imagem), enquanto
navegadores mais antigos ou mais burros ignorem completamente a tag INCLUDE .
Esta proposta nunca foi implementada, embora a ideia de fornecer texto caso falte uma imagem seja
uma importante técnica de acessibilidade isso estava faltando na proposta inicial de Marc <IMG> .
Muitos anos depois, esse recurso foi implementado como o <img alt> atributo, que o Netscape
prontamente quebrou ao tratá-lo erroneamente como uma dica de ferramenta.
Poucas horas depois de Tony postar sua mensagem, Tim Berners-Lee respondeu:
Observe que você pode ter várias combinações destes e, se o navegador não suportar nenhum deles, ele não
falha.
[Eu] vejo que usar isso como um método para ícones selecionáveis significa aninhar âncoras. Hmmm.
Mas eu não queria uma etiqueta especial.
Esta proposta nunca foi implementada, mas o atributo rel ainda existe (veja “Amigos e Relações (Link)” na página 36).
Seria bom se houvesse uma maneira de especificar o tipo de conteúdo, por exemplo
estou totalmente disposto a aceitar a exigência de especificar o tipo de conteúdo por extensão de
arquivo.
Esta proposta nunca foi implementada, mas a Netscape adicionou posteriormente suporte para incorporação arbitrária de
objetos de mídia com o elemento <embed> .
Embora as imagens estejam no topo da minha lista de tipos de mídia desejados em um navegador
WWW, não acho que devamos adicionar ganchos idiossincráticos para a mídia, um de cada vez. O
que aconteceu com o entusiasmo pelo uso do mecanismo de digitação MIME?
Isto não substitui o futuro uso do MIME como mecanismo de documento padrão; isso fornece uma
implementação necessária e simples de funcionalidades independentemente do MIME.
Vamos esquecer temporariamente o MIME, se isso atrapalhar o problema. A minha objecção foi à
discussão de “como vamos apoiar imagens incorporadas” em vez de “como vamos apoiar objecções
incorporadas em vários meios de comunicação”.
Caso contrário, na próxima semana alguém irá sugerir “vamos colocar uma nova tag <AUD SRC="file://
foobar.com/foo/bar/blargh.snd">” para áudio.
Não deveria haver muito custo em optar por algo que generaliza.
Olhando retrospectivamente, parece que as preocupações de Jay eram bem fundamentadas. Demorou um pouco mais de
uma semana, mas o HTML5 finalmente adicionou um novo <video> e <áudio> elementos.
Quero considerar toda uma gama de possíveis tipos de imagem/arte de linha, juntamente com a possibilidade
de negociação de formato. A observação de Tim sobre o suporte a áreas clicáveis nas imagens também é
importante.
Mais tarde, em 1993, Dave HTML+ proposto como uma evolução do padrão HTML. A proposta nunca foi implementada e
foi substituída pelo HTML 2.0. HTML 2.0 era uma “especificação retro”, o que significa que formalizava recursos já de uso
comum: “Esta especificação reúne, esclarece e formaliza um conjunto de recursos isso corresponde aproximadamente às
capacidades do HTML de uso comum antes de junho de 1994.”
Mais tarde, Dave escreveu HTML 3.0, baseado em seu rascunho HTML+ anterior. Fora da implementação
de referência do próprio W3C, Arena, HTML 3.0 nunca foi implementado. Foi substituído pelo HTML
3.2, que também era uma “especificação retro”: “HTML 3.2 adiciona recursos amplamente implantados
como tabelas, miniaplicativos e fluxo de texto em torno de imagens, ao mesmo tempo que fornece
compatibilidade retroativa total com o padrão existente HTML 2.0.
Mais tarde, Dave foi coautor do HTML 4.0, desenvolveu HTML Tidy, e passou a ajudar com XHTML,
XForms, MathML e outras especificações modernas do W3C.
Na verdade, talvez devêssemos pensar em uma linguagem gráfica processual de uso geral, na qual
possamos incorporar hiperlinks arbitrários anexados a ícones, imagens, texto ou qualquer coisa.
Alguém mais viu as capacidades da Intermedia em relação a isso?
Intermediário foi um projeto de hipertexto da Brown University. Foi desenvolvido de 1985 a 1991 e
funcionou em A/UX, um sistema operacional semelhante ao Unix para os primeiros computadores Macintosh.
Outros sistemas que possuem essa noção (bastante valiosa) são Andrew e Slate.
Andrew é construído com _insets_, cada um dos quais possui algum tipo interessante, como texto,
bitmap, desenho, animação, mensagem, planilha, etc. A noção de incorporação recursiva arbitrária
está presente, de modo que uma inserção de qualquer tipo pode ser incorporada em qualquer outro
tipo que suporte incorporação. Por exemplo, uma inserção pode ser incorporada em qualquer ponto do
texto do widget de texto, ou em qualquer área retangular do widget de desenho, ou em qualquer célula
da planilha.
“Andrew” é uma referência ao Sistema de Interface de Usuário Andrew, embora naquela época fosse
conhecido simplesmente como Projeto Andrew.
Aqui está minha opinião. A melhor maneira de fazer imagens na WWW é usando MIME. Tenho certeza
de que o postscript já é um subtipo suportado no MIME e lida muito bem com a mistura de texto e
gráficos.
Mas não é clicável, você diz? Sim, você está certo. Suspeito que já exista uma resposta para isso no
display postscript. Mesmo que não haja adição ao postscript padrão, é trivial.
Defina um comando âncora que especifique a URL e use o caminho atual como uma região fechada
para o botão. Como o postscript lida muito bem com caminhos, isso torna triviais os formatos arbitrários
de botões.
Exibir PostScript foi uma tecnologia de renderização na tela desenvolvida em conjunto pela Adobe e
NeXT.
Esta proposta nunca foi implementada, mas a ideia de que a melhor maneira de corrigir o HTML é
substituí-lo por algo completamente diferente ainda surge de vez em quando.
HTTP2 permite que um documento contenha qualquer tipo que o usuário disse que pode manipular, não
apenas tipos MIME registrados. Portanto, pode-se experimentar. Sim, acho que há um caso para
postscript com hipertexto. Não sei se o display postscript é suficiente. Eu sei que a Adobe está tentando
estabelecer seu próprio “PDF” baseado em postscript, que terá links e poderá ser lido por sua marca
proprietária de visualizadores.
Achei que uma linguagem genérica de sobreposição para âncoras (baseada em HyTime?) permitiria que
o hipertexto e os padrões gráficos/vídeo evoluíssem separadamente, o que ajudaria ambos.
Deixe a tag IMG ser INCLUDE e faça referência a um tipo de documento arbitrário. Ou EMBED se
INCLUDE soar como um cpp include que as pessoas esperam fornecer o código-fonte SGML para ser
analisado inline - não o que se pretendia.
HyTime foi um dos primeiros sistemas de documentos de hipertexto baseado em SGML. Ele teve grande importância em
muitas das primeiras discussões sobre HTML e, posteriormente, sobre XML.
A proposta de Tim para uma tag <INCLUDE> nunca foi implementada, embora você possa ver ecos dela em
<object>, <embed> e no elemento <iframe>.
De volta ao tópico de imagens embutidas novamente - estou chegando perto de lançar o Mosaic v0.10,
que oferecerá suporte a imagens/bitmaps GIF e XBM embutidos, conforme mencionado anteriormente. [...]
Não estamos preparados para apoiar INCLUDE/EMBED neste momento. [...] Então provavelmente iremos
usar <IMG SRC="url"> (não ICON, já que nem todas as imagens embutidas podem ser chamadas de
ícones de forma significativa). Por enquanto, as imagens embutidas não serão explicitamente digitadas
por conteúdo; no futuro, planejamos apoiar isso (juntamente com a adaptação geral do MIME). Na
verdade, as rotinas de leitura de imagens que usamos atualmente descobrem o formato da imagem na
hora, então a extensão do nome do arquivo nem será significativa.
Estou extraordinariamente fascinado por todos os aspectos desta conversa de quase 17 anos que levou à criação de
um elemento HTML que foi usado em praticamente todas as páginas da web já publicadas. Considere isto:
• O HTTP ainda existe. Ele evoluiu com sucesso de 0.9 para 1.0 e posteriormente para 1.1, e ainda
ele evolui.
• HTML ainda existe. Esse formato de dados rudimentar (nem suportava imagens inline!) evoluiu com sucesso
para 2.0, 3.2 e 4.0. HTML é uma linha contínua. Uma linha retorcida, nodosa e emaranhada, com certeza –
havia muitos “galhos mortos” na árvore evolucionária, lugares onde as pessoas com mentalidade padronizada
se adiantavam (e à frente dos autores e implementadores) – mas ainda assim, aqui nós são em 2010, e as
páginas da web de 1990 ainda são renderizadas em navegadores modernos. Acabei de carregar um no
navegador do meu celular Android de última geração e nem fui solicitado a “aguarde enquanto importa o
formato legado...”
• HTML sempre foi uma conversa entre criadores de navegadores, autores, especialistas em padrões e outras
pessoas que simplesmente apareciam e gostavam de falar sobre colchetes angulares. A maioria das versões
bem-sucedidas do HTML foram “especificações retroativas”, alcançando o mundo e, ao mesmo tempo,
tentando empurrá-lo na direção certa.
Qualquer um que lhe diga que o HTML deve ser mantido “puro” (presumivelmente ignorando os fabricantes
de navegadores, ou ignorando os autores, ou ambos) está simplesmente mal informado. O HTML nunca foi
puro e todas as tentativas de purificá-lo foram fracassos espetaculares, só igualados pelas tentativas de
substituí-lo.
• Nenhum dos navegadores em uso em 1993 ainda existe em qualquer forma reconhecível. O Netscape
Navigator foi abandonado em 1998 e reescrito do zero para criar o Mozilla Suite, que foi então bifurcado para
criar o Firefox. O Internet Explorer teve seu “começo” humilde no “Microsoft Plus! para Windows 95”, onde
veio com alguns temas de desktop e um jogo de pinball; mas é claro que esse navegador também pode ser
rastreado.
• Alguns dos sistemas operacionais de 1993 ainda existem, mas nenhum deles é relevante para a Web moderna.
A maioria das pessoas hoje que “experimentam” a Web o fazem em um PC com Windows 2000 ou posterior,
um Mac com Mac OS X, um PC com alguma versão do Linux ou um dispositivo portátil como um iPhone. Em
1993, o Windows estava na versão 3.1 (e competia com o OS/2), os Macs rodavam o System 7 e o Linux
era distribuído via Usenet. (Quer se divertir? Encontre um homem de barba grisalha e sussurre “Trumpet
Winsock” ou “MacPPP”.) • Algumas das mesmas pessoas ainda estão por aí e ainda envolvidas no que hoje
chamamos simplesmente de “padrões da web”.
Isso depois de quase 20 anos. E alguns estiveram envolvidos em antecessores do HTML, desde a década de
1980 e antes.
• Falando em antecessores... Com a eventual popularidade do HTML e da Web, é fácil esquecer os formatos e
sistemas contemporâneos que influenciaram seu design. Antes de ler este capítulo, você já tinha ouvido
falar de André? Intermediário?
HyTime? E o HyTime não era um projeto de pesquisa acadêmica vulgar; era um padrão ISO aprovado para
uso militar. Foi um grande negócio. E você mesmo pode ler sobre isso em http://www.sgmlsource.com/history/
hthist.htm.
Mas nada disso responde à pergunta original: por que temos um elemento <img>? Por que não um elemento
<icon>? Ou um elemento <include>? Por que não um hiperlink com um atributo include ou alguma combinação de
valores rel? Por que um elemento <img>? Simplesmente, porque Marc Andreessen enviou um e o código de envio
vence.
Isso não quer dizer que todos os códigos de envio vencem; afinal, Andrew, Intermedia e HyTime também enviaram
código. O código é necessário, mas não suficiente para o sucesso. E certamente não quero dizer que o código
de envio antes de um padrão produzirá a melhor solução. O elemento <img> de Marc não exigia um formato
gráfico comum; não definia como o texto fluía em torno dele; não suportava alternativas de texto ou conteúdo
alternativo para navegadores mais antigos. E 17 anos depois, ainda estamos lutando contra a detecção de
conteúdo, e isso ainda é uma fonte de vulnerabilidades de segurança malucas. Você pode rastrear isso através do
Grande
Browser Wars, desde 25 de fevereiro de 1993, quando Marc Andreessen comentou espontaneamente:
“MIME, algum dia, talvez”, e então enviou seu código de qualquer maneira.
Em dezembro de 1997, o World Wide Web Consortium (W3C) publicou o HTML 4.0 e imediatamente
encerrou o Grupo de Trabalho HTML. Menos de dois meses depois, um grupo de trabalho separado do
W3C publicou o XML 1.0. Apenas três meses depois disso, o W3C realizou um workshop chamado
“Moldando o Futuro do HTML” para responder à pergunta: “O W3C desistiu do HTML?” Esta foi a resposta:
Nas discussões, foi acordado que seria difícil estender ainda mais o HTML 4.0, assim como
converter o 4.0 em um aplicativo XML. A maneira proposta de se libertar dessas restrições é
começar do zero com a próxima geração de HTML baseada em um conjunto de conjuntos de
tags XML.
O W3C reorganizou o Grupo de Trabalho HTML para criar este “conjunto de conjuntos de tags XML”. O
primeiro passo dos membros, em dezembro de 1998, foi redigir uma especificação provisória que
simplesmente reformulasse o HTML em XML sem adicionar quaisquer novos elementos ou atributos. Esta
especificação mais tarde ficou conhecida como “XHTML 1.0”. Ele definiu um novo tipo MIME para
documentos XHTML, application/xhtml+xml. No entanto, para facilitar a migração de páginas HTML 4
existentes, também incluiu o Apêndice C, que “resume as diretrizes de design para autores que desejam
que seus documentos XHTML sejam renderizados em agentes de usuário HTML existentes”. O Apêndice C
dizia que você tinha permissão para criar as chamadas páginas “XHTML”, mas ainda assim servi-las com o
tipo MIME text/html.
O próximo alvo foram os formulários da web. Em agosto de 1999, o mesmo Grupo de Trabalho HTML
publicou um primeiro rascunho do XHTML Extended Forms. Os seus membros estabeleceram as
expectativas logo nas primeiras frases deste projecto de documento:
Após cuidadosa consideração, o Grupo de Trabalho HTML decidiu que os objetivos para a
próxima geração de formulários são incompatíveis com a preservação da compatibilidade
retroativa com navegadores projetados para versões anteriores de HTML. Nosso objetivo é
fornecer um novo modelo de formulários limpo (“XHTML Extended Forms”) baseado em um
conjunto de requisitos bem definidos. Os requisitos descritos neste documento baseiam-se na
experiência com um amplo espectro de aplicações de formulários.
Alguns meses depois, “XHTML Extended Forms” foi renomeado como “XForms” e transferido para seu
próprio Grupo de Trabalho. Esse grupo trabalhou em paralelo com o HTML Working Group e finalmente
publicou a primeira edição do XForms 1.0 em outubro de 2003.
Enquanto isso, com a transição para XML concluída, os membros do Grupo de Trabalho HTML decidiram
criar “a próxima geração de HTML”. Em maio de 2001, eles publicaram a primeira edição do XHTML 1.1,
que adicionou apenas alguns recursos menores ao XHTML 1.0, mas eliminou a lacuna do “Apêndice C”. A
partir da versão 1.1, todos os documentos XHTML deveriam ser servidos com um tipo MIME de application/
xhtml+xml.
Por que os tipos MIME são importantes? Por que continuo voltando para eles? Três palavras: tratamento
draconiano de erros. Os navegadores sempre foram “clementes” com o HTML. Se você criar uma página HTML,
mas esquecer de atribuir um <title> a ela, os navegadores exibirão a página de qualquer maneira, mesmo que o
elemento <title> sempre tenha sido obrigatório em todas as versões do HTML. Certas tags não são permitidas em
outras tags, mas se você criar uma página que as coloque dentro de qualquer maneira, os navegadores
simplesmente lidarão com isso (de alguma forma) e seguirão em frente sem exibir uma mensagem de erro.
Como seria de esperar, o fato de a marcação HTML “quebrada” ainda funcionar em navegadores da Web levou
os autores a criar páginas HTML quebradas. Muitas páginas quebradas. Segundo algumas estimativas, mais de
99% das páginas HTML na Web hoje apresentam pelo menos um erro. Mas como esses erros não fazem com que
os navegadores exibam mensagens de erro visíveis, ninguém os corrige.
MIME application/xhtml+xml estariam sujeitos a um tratamento draconiano de erros. Se houvesse um único erro
em sua página XHTML, os navegadores da web não teriam escolha a não ser interromper o processamento e
exibir uma mensagem de erro ao usuário final.
Essa ideia não era universalmente popular. Com uma taxa de erro estimada em 99% nas páginas existentes, a
sempre presente possibilidade de exibir erros ao usuário final e a escassez de novos recursos em XHTML 1.0 e
1.1 para justificar o custo, os autores da web basicamente ignoraram application/xhtml+xml . Mas isso não significa
que eles ignoraram completamente o XHTML. Ah, definitivamente não. O Apêndice C da especificação XHTML
1.0 deu aos autores da web de todo o mundo uma brecha: “Use algo que se pareça com a sintaxe XHTML, mas
continue servindo-o com o tipo MIME text/html.” E foi exatamente isso que milhares de desenvolvedores web
fizeram: eles “atualizaram” para a sintaxe XHTML, mas continuaram servindo-a com um tipo MIME text/html.
Ainda hoje, embora muitas páginas da web afirmem ser XHTML, elas começam com o doctype XHTML na primeira
linha, usam nomes de tags em minúsculas, usam aspas em torno de valores de atributos e adicionam uma barra
final após elementos vazios como <br /> e <hr /> — apenas uma pequena fração dessas páginas é servida com o
tipo MIME application/xhtml+xml que acionaria o tratamento draconiano de erros do XML. Qualquer página
veiculada com um tipo MIME de texto/html, independentemente de seu tipo de documento, sintaxe ou estilo de
codificação, será analisada usando um “perdoador”
Analisador de HTML, ignorando silenciosamente quaisquer erros de marcação e nunca alertando os usuários finais (ou
qualquer outra pessoa), mesmo que a página esteja tecnicamente quebrada.
O XHTML 1.0 incluía essa brecha, mas o XHTML 1.1 a fechou, e o XHTML 2.0, nunca finalizado, continuou a tradição de exigir
tratamento draconiano de erros. E é por isso que existem bilhões de páginas que afirmam ser XHTML 1.0, e apenas algumas
que afirmam ser XHTML 1.1 (ou XHTML 2.0). Então, você está realmente usando XHTML? Verifique seu tipo MIME. (Na
verdade, se você não sabe que tipo MIME está usando, posso garantir que ainda está usando text/html.) A menos que você
esteja servindo suas páginas com um tipo MIME de application/xhtml+xml , o chamado “XHTML” é XML apenas no nome.
Em junho de 2004, o W3C realizou o Workshop sobre Aplicações Web e Documentos Compostos. Estiveram presentes neste
workshop representantes de vários fornecedores de navegadores, empresas de desenvolvimento web e outros membros do
W3C. Um grupo de partes interessadas, incluindo a Mozilla Foundation e a Opera Software, fizeram uma apresentação sobre
suas visões concorrentes do futuro da Web: uma evolução do padrão HTML 4 existente para incluir novos recursos para
desenvolvedores de aplicações web modernas:
Os sete princípios a seguir representam o que acreditamos serem os requisitos mais críticos para este trabalho:
Os recursos básicos de aplicativos da Web devem ser implementáveis usando comportamentos, scripts e
folhas de estilo no IE6 hoje, para que os autores tenham um caminho de migração claro. Qualquer solução
que não possa ser usada com o atual agente de usuário de alta participação de mercado sem a necessidade
de plug-ins binários tem grande probabilidade de não ser bem-sucedida.
Os casos de uso devem preferencialmente ser baseados em sites reais onde os autores usaram
anteriormente uma solução ruim para contornar a limitação.
Numa enquete, os participantes do workshop foram questionados: “O W3C deveria desenvolver extensões
declarativas para HTML e CSS e extensões imperativas para DOM, para atender aos requisitos de aplicações Web
de nível médio, em oposição a APIs sofisticadas e completas em nível de sistema operacional?” A votação foi de
11 a 8 contra. No resumo do workshop, os membros do W3C escreveram: “Atualmente, o W3C não pretende
colocar quaisquer recursos no terceiro tópico da pesquisa: extensões para HTML e CSS para aplicações Web,
além das tecnologias que estão sendo desenvolvidas sob o estatuto dos atuais grupos de trabalho do W3C.”
Diante dessa decisão, as pessoas que propuseram a evolução dos formulários HTML e HTML tinham apenas duas
opções: desistir ou continuar seu trabalho fora do W3C. Eles escolheram este último, registraram o domínio
whatwg.org e, em junho de 2004, nasceu o Grupo de Trabalho WHAT.
O que diabos é o QUE Grupo de Trabalho? Vou deixar que explique por si:
O Grupo de Trabalho de Tecnologia de Aplicações de Hipertexto da Web é uma colaboração livre, não
oficial e aberta de fabricantes de navegadores da Web e partes interessadas. O grupo pretende
desenvolver especificações baseadas em HTML e tecnologias relacionadas para facilitar a implantação
de aplicações Web interoperáveis, com a intenção de submeter os resultados a uma organização de
normalização. Esta submissão formaria então a base do trabalho de extensão formal do HTML na trilha
de padrões.
A criação deste fórum decorre de vários meses de trabalho por e-mail privado sobre especificações
para tais tecnologias. O foco principal até agora tem sido estender os Formulários HTML4 para suportar
recursos solicitados pelos autores, sem quebrar a compatibilidade retroativa com o conteúdo existente.
Este grupo foi criado para garantir que o desenvolvimento futuro destas especificações será
completamente aberto, através de uma lista de discussão aberta e arquivada publicamente.
A frase-chave aqui é “sem quebrar a compatibilidade com versões anteriores”. XHTML (sem a lacuna do Apêndice
C) não é compatível com versões anteriores de HTML. Requer um tipo MIME totalmente novo e exige um tratamento
draconiano de erros para todo o conteúdo servido com esse tipo MIME. XForms não é compatível com versões
anteriores de formulários HTML, porque só pode ser usado em documentos que são servidos com o novo tipo
XHTML MIME, o que significa que XForms também exige tratamento draconiano de erros. Todos os caminhos
levam ao MIME.
Em vez de descartar o investimento de mais de uma década em HTML e inutilizar 99% das páginas da Web
existentes, o Grupo de Trabalho O QUE decidiu adotar uma abordagem diferente: documentar os algoritmos
“complacentes” de tratamento de erros que os navegadores realmente usavam. Os navegadores da Web
sempre perdoaram os erros de HTML, mas ninguém jamais se preocupou em escrever exatamente como eles
faziam isso. O NCSA Mosaic tinha seus próprios algoritmos para lidar com páginas quebradas e a Netscape
tentou combiná-los. Então o Internet Explorer tentou igualar o Netscape. Então o Opera e o Firefox tentaram
igualar o Internet Explorer. Então o Safari tentou igualar o Firefox. E assim por diante, até os dias atuais. Ao
longo do caminho, os desenvolvedores gastaram milhares e milhares de horas tentando tornar seus produtos
compatíveis com os de seus concorrentes.
Se isso parece uma quantidade absurda de trabalho, é porque é. Ou melhor, foi. Demorou vários anos, mas
(módulo de alguns casos extremos obscuros) o Grupo de Trabalho O QUE documentou com sucesso como
analisar HTML de uma forma que seja compatível com o conteúdo da web existente. Em nenhum lugar do
algoritmo final existe uma etapa que determina que o consumidor HTML pare o processamento e exiba uma
mensagem de erro ao usuário final.
Enquanto toda aquela engenharia reversa acontecia, o Grupo de Trabalho O QUE também trabalhava
discretamente em algumas outras coisas. Uma delas foi uma especificação, inicialmente chamada de Web
Forms 2.0, que adicionou novos tipos de controles aos formulários HTML. (Você aprenderá mais sobre
formulários web no Capítulo 9.) Outra foi um rascunho de especificação chamado “Aplicativos Web 1.0” que
incluía novos recursos importantes, como uma tela de desenho em modo direto (veja o Capítulo 4) e suporte
nativo para áudio e vídeo. sem plug-ins (veja o Capítulo 5).
De volta ao W3C
Durante vários anos, o W3C e o Grupo de Trabalho WHAT ignoraram-se em grande parte.
Enquanto o Grupo de Trabalho O QUE se concentrava em formulários web e novos recursos HTML, o Grupo
de Trabalho HTML do W3C estava ocupado com a Versão 2.0 do XHTML. Mas em outubro de 2006, ficou claro
que o Grupo de Trabalho O QUE havia ganhado um grande impulso, enquanto o XHTML 2 ainda estava
definhando na forma de rascunho, não implementado por nenhum grande navegador. Em outubro de 2006, Tim
Berners-Lee, o fundador do próprio W3C, anunciou que o W3C trabalharia em conjunto com o Grupo de
Trabalho WHAT para evoluir o HTML: Algumas coisas ficam mais claras em retrospectiva de vários anos. É
necessário evoluir o HTML de forma incremental. A tentativa de fazer com que o mundo mudasse
para XML, incluindo aspas em torno de valores de atributos e barras em tags e namespaces vazios
de uma só vez, não funcionou. O grande público gerador de HTML não se mexeu, em grande parte
porque os navegadores não reclamaram. Algumas comunidades grandes mudaram e estão a colher
os frutos de sistemas bem formados, mas não todas. É importante manter o HTML de forma
incremental, bem como continuar a transição para um mundo bem formado e desenvolver mais
poder nesse mundo.
O plano é fundar um grupo HTML completamente novo. Ao contrário do anterior, este será destinado
a fazer melhorias incrementais no HTML, e também no XHTML paralelo. Terá um presidente e
contato de equipe diferentes. Funcionará em HTML e XHTML juntos. Temos um forte apoio a este
grupo, vindo de muitas pessoas com quem conversamos, incluindo fabricantes de navegadores.
De volta ao W3C | 13
Também haverá trabalho em formulários. Esta é uma área complexa, pois os formulários HTML e
XForms existentes são linguagens de formulários. Os formulários HTML são implantados de forma
onipresente e há muitas implementações e usuários de XForms. Enquanto isso, o envio de
Webforms sugeriu extensões sensatas para formulários HTML. O plano é, informado pela
Webforms, estender os formulários HTML.
Uma das primeiras coisas que o recém-reformado Grupo de Trabalho HTML do W3C decidiu foi
renomear “Aplicações Web 1.0” para “HTML5”. E aqui estamos, mergulhando no HTML5.
Pós-escrito
Em outubro de 2009, o W3C encerrou o Grupo de Trabalho XHTML 2 e emitiu esta declaração
para explicar a decisão:
Quando o W3C anunciou os Grupos de Trabalho HTML e XHTML 2 em março de 2007,
indicamos que continuaríamos monitorando o mercado de XHTML 2. O W3C reconhece
a importância de um sinal claro para a comunidade sobre o futuro do HTML.
Embora reconheçamos o valor das contribuições do Grupo de Trabalho XHTML 2 ao longo
dos anos, após discussão com os participantes, a administração do W3C decidiu permitir
que o estatuto do Grupo de Trabalho expirasse no final de 2009 e não renová-lo.
Leitura adicional
CAPÍTULO 2
Mergulhando
Você pode perguntar: “Como posso começar a usar HTML5 se navegadores mais antigos não o suportam?”
Mas a questão em si é enganosa. HTML5 não é grande coisa; é uma coleção de recursos individuais.
Portanto, você não pode detectar “suporte HTML5”, porque isso não faz sentido. Mas você pode detectar
suporte para recursos individuais, como tela, vídeo ou geolocalização.
Técnicas de detecção
Quando seu navegador renderiza uma página da web, ele constrói um Document Object Model (DOM), uma
coleção de objetos que representam os elementos HTML da página. Cada elemento – cada <p>, cada
<div>, cada <span> – é representado no DOM por um objeto diferente. (Existem também objetos globais,
como janela e documento, que não estão vinculados a elementos específicos.)
Todos os objetos DOM compartilham um conjunto de propriedades comuns, mas alguns objetos possuem
mais que outros. Em navegadores que suportam recursos HTML5, determinados objetos terão propriedades
exclusivas. Uma rápida olhada no DOM lhe dirá quais recursos são suportados.
Existem quatro técnicas básicas para detectar se um navegador oferece suporte a um recurso específico.
Do mais simples ao mais complexo:
Para obter um exemplo de teste de suporte ao canvas, consulte “Canvas” na página 16.
3. Crie um elemento, verifique se existe um determinado método naquele elemento, depois chame o
método e verifique o valor que ele retorna.
15
Para obter um exemplo de teste de quais formatos de vídeo são suportados, consulte “Formatos
de vídeo” na página 19.
4. Crie um elemento, defina uma propriedade com um determinado valor e verifique se a propriedade
manteve seu valor.
Para obter um exemplo de teste de quais tipos de <input> são suportados, consulte “Tipos de
entrada” na página 25.
Tela
HTML5 define o elemento <canvas> como “uma tela de bitmap dependente de resolução que pode ser
usada para renderizar gráficos, gráficos de jogos ou outras imagens visuais em tempo real”. Uma tela é
um retângulo em sua página dentro do qual você pode usar JavaScript para desenhar o que quiser.
HTML5 define um conjunto de funções (“API canvas”) para desenhar formas, definir caminhos, criar
gradientes e aplicar transformações.
A verificação do suporte da API canvas usa a técnica de detecção nº 2 (consulte “Técnicas de detecção”
na página 15). Se o seu navegador suportar a API canvas, o objeto DOM que ele cria
para representar um elemento <canvas> terá um método getContext() (veja “Formas Simples” na página 58). Se o
seu navegador não suportar a API canvas, o objeto DOM criado para um elemento <canvas> terá apenas o conjunto
de propriedades comuns, e não qualquer coisa específica do canvas. Você pode verificar o suporte ao canvas
usando esta função:
document.createElement('canvas').getContext;
Este elemento nunca é anexado à sua página, portanto ninguém o verá. Está apenas flutuando na memória, indo a
lugar nenhum e sem fazer nada, como uma canoa em um rio lento.
Assim que você cria o elemento fictício <canvas>, você testa a presença de um método getContext(). Este método
só existirá se o seu navegador suportar a API canvas:
return !!document.createElement('canvas').getContext;
Finalmente, você usa o truque da dupla negativa para forçar o resultado a um valor booleano (verdadeiro ou falso):
return !!document.createElement('canvas').getContext;
Esta função detectará suporte para a maior parte da API canvas, incluindo formas (consulte “Formas simples” na
página 58), caminhos (consulte “Caminhos” na página 61), gradientes (consulte “Gradientes” na página 67) e
padrões . Ele não detectará a biblioteca explorercanvas de terceiros (consulte “E quanto ao IE?” na página 73) que
implementa a API canvas no Microsoft Internet Explorer.
Em vez de escrever essa função você mesmo, você pode usar o Modernizr (introduzido na seção anterior) para
detectar suporte para a API canvas:
if (Modernizr.canvas) {
// vamos desenhar algumas
formas! }
else { // não há suporte nativo para canvas
disponível :( }
Texto em tela
Mesmo que o seu navegador suporte a API canvas, ele pode não oferecer suporte à API canvas text.
A API canvas cresceu com o tempo e as funções de texto foram adicionadas mais tarde no jogo.
Alguns navegadores foram fornecidos com suporte a canvas antes da conclusão da API de texto.
A verificação do suporte da API de texto de tela novamente usa a técnica de detecção nº 2 (consulte “Técnicas de
detecção” na página 15). Se o seu navegador suportar a API canvas, o objeto DOM criado para representar um
elemento <canvas> terá o método getContext() (veja “Simples
Texto em tela | 17
Formas” na página 58). Se o seu navegador não suportar a API canvas, o objeto DOM criado para um
elemento <canvas> terá apenas o conjunto de propriedades comuns, e não qualquer coisa específica
do canvas. Você pode verificar o suporte ao texto da tela usando esta função:
função support_canvas_text() { if (!
supports_canvas()) { return false; } var
dummy_canvas = document.createElement('canvas'); var
contexto = dummy_canvas.getContext('2d'); return
typeof context.fillText == 'função'; }
Se o seu navegador não suporta a API canvas, certamente não suportará a API canvas text!
Em seguida, você cria um elemento <canvas> fictício e obtém seu contexto de desenho. É garantido
que isso funcione, porque a função support_canvas() já verificou se o método getContext() existe em
todos os objetos canvas:
var dummy_canvas = document.createElement('canvas');
var contexto = dummy_canvas.getContext('2d');
Finalmente, você verifica se o contexto do desenho possui uma função fillText(). Se isso acontecer, a
API de texto da tela estará disponível:
Em vez de escrever esta função você mesmo, você pode usar o Modernizr (veja “Modernizr: Um
Biblioteca de detecção HTML5” na página 16) para detectar suporte para a API de texto de tela:
if (Modernizr.canvastext) { //
vamos desenhar um
texto! }
else { // nenhum suporte de texto de tela nativo
disponível :( }
Vídeo
HTML5 define um novo elemento chamado <video> para incorporar vídeo em suas páginas da web.
Incorporar vídeo costumava ser impossível sem plug-ins de terceiros, como Apple QuickTime ou Adobe
Flash.
O elemento <video> foi projetado para ser usado sem nenhum script de detecção. Você pode
especificar vários arquivos de vídeo, e os navegadores que suportam vídeo HTML5 escolherão um
com base nos formatos de vídeo que suportam.*
Os navegadores que não suportam vídeo HTML5 ignorarão o elemento <video> completamente,
mas você pode usar isso a seu favor e peça para eles reproduzirem o vídeo por meio de um plug-in
de terceiros. Kroc Camen projetou uma solução chamada Video for Everybody! que usa vídeo HTML5
quando disponível, mas recorre ao QuickTime ou Flash em navegadores mais antigos. Esta solução
não usa nenhum JavaScript e funciona em praticamente todos os navegadores, incluindo navegadores
móveis.
Se quiser fazer mais com o vídeo do que colocá-lo em sua página e reproduzi-lo, você precisará usar
JavaScript. A verificação de suporte de vídeo usa a técnica de detecção nº 2 (consulte “Técnicas de
detecção” na página 15). Se o seu navegador suportar vídeo HTML5, o objeto DOM criado para
representar um elemento <video> terá um método canPlayType(). Se o seu navegador não suportar
vídeo HTML5, o objeto DOM criado para um elemento <video> terá apenas o conjunto de
propriedades comuns a todos os elementos. Você pode verificar o suporte de vídeo usando esta
função: function support_video()
{ return !!
document.createElement('video').canPlayType; }
Em vez de escrever esta função você mesmo, você pode usar o Modernizr (veja “Modernizr: Um
Biblioteca de detecção de HTML5” na página 16) para detectar suporte para vídeo HTML5:
if (Modernizr.video) { //
vamos reproduzir um
vídeo! }
else { // nenhum suporte de vídeo nativo
disponível :( // talvez verifique se há QuickTime ou
Flash }
Existe um teste separado para detectar quais formatos de vídeo seu navegador pode reproduzir, que
demonstrarei a seguir.
Formatos de vídeo
Os formatos de vídeo são como linguagens escritas. Um jornal inglês pode transmitir a mesma
informação que um jornal espanhol, mas se você só consegue ler em inglês, apenas um deles lhe
será útil! Para reproduzir um vídeo, seu navegador precisa entender o “idioma” em que o vídeo foi
escrito.
* Consulte “Uma introdução suave à codificação de vídeo, parte 1: formatos de contêiner” e “parte 2: codecs de vídeo com perdas” para
aprender sobre os diferentes formatos de vídeo.
Formatos de vídeo | 19
A “linguagem” de um vídeo é chamada de “codec” – este é o algoritmo usado para codificar o vídeo
em um fluxo de bits. Existem dezenas de codecs em uso em todo o mundo. Qual você deve usar?
A triste realidade do vídeo HTML5 é que os navegadores não conseguem chegar a um acordo sobre
um único codec. No entanto, eles parecem ter reduzido para dois. Um codec custa dinheiro (devido
ao licenciamento de patentes), mas funciona no Safari e no iPhone. (Este também funciona em
Adobe Flash, se você usar uma solução como Video for Everybody!.) O outro codec é gratuito e
funciona em navegadores de código aberto como Chromium e Mozilla Firefox.
Esta função verifica o formato com patente suportada por Macs e iPhones:
função support_h264_baseline_video() { if (!
supports_video()) { return false; } var v =
document.createElement("vídeo"); retornar
v.canPlayType('vídeo/mp4; codecs="avc1.42E01E, mp4a.40.2"'); }
A função começa verificando o suporte a vídeo HTML5, usando a função support_video() da seção
anterior:
if (!supports_video()) { return falso; }
Se o seu navegador não suporta vídeo HTML5, certamente não suportará nenhum formato de vídeo!
Em seguida, a função cria um elemento <video> fictício (mas não o anexa à página, portanto não
ficará visível) e chama o método canPlayType(). É garantido que este método esteja lá, porque a
função support_video() acabou de verificar:
var v = document.createElement("vídeo");
retornar v.canPlayType('vídeo/mp4; codecs="avc1.42E01E, mp4a.40.2"');
"provavelmente"
† Explicarei o que tudo isso significa no Capítulo 5. Você também pode estar interessado em ler “Uma introdução suave à
codificação de vídeo”.
"talvez"
Se o navegador achar que pode reproduzir este formato "" (uma string vazia)
Esta segunda função verifica o formato de vídeo aberto suportado pelo Mozilla Firefox e outros navegadores de
código aberto. O processo é exatamente o mesmo; a única diferença é a string que você passa para a função
canPlayType(). Em termos técnicos, você está perguntando ao navegador se ele pode reproduzir vídeo Theora e
áudio Vorbis em um contêiner Ogg:
função support_ogg_theora_video() {
if (!supports_video()) { return falso; } var v =
document.createElement("vídeo"); return
v.canPlayType('video/ogg; codecs="theora, vorbis"'); }
Finalmente, WebM é um codec de vídeo de código aberto (e sem patente) que será incluído na próxima versão dos
principais navegadores, incluindo Chrome, Firefox e Opera. Você pode usar a mesma técnica para detectar suporte
para vídeo WebM aberto:
função support_webm_video() { if (!
supports_video()) { return false; } var v =
document.createElement("vídeo"); retornar
v.canPlayType('video/webm; codecs="vp8, vorbis"'); }
Em vez de escrever esta função sozinho, você pode usar o Modernizr para detectar suporte para vários formatos
de vídeo HTML5 diferentes (observe que o Modernizr ainda não tem suporte para detectar suporte para o formato
de vídeo WebM aberto): if (Modernizr.video) { // vamos reproduza algum
MP4 } }
Armazenamento local
O armazenamento HTML5 fornece uma maneira para os sites armazenarem informações em seu computador e
recuperá-las posteriormente. O conceito é semelhante ao dos cookies, mas foi concebido para grandes quantidades
de informação. Os cookies têm tamanho limitado e seu navegador os envia de volta ao servidor da web sempre
que solicita uma nova página (o que exige mais tempo e largura de banda preciosa). O armazenamento HTML5
permanece no seu computador e os sites podem acessá-lo com JavaScript após o carregamento da página.
Armazenamento local | 21
P: O armazenamento local é realmente parte do HTML5? Por que está em uma especificação separada?
R: A resposta curta é sim, o armazenamento local faz parte do HTML5. A resposta um pouco mais longa é que o
armazenamento local costumava fazer parte da especificação principal do HTML5, mas foi dividido em uma
especificação separada porque algumas pessoas do Grupo de Trabalho do HTML5 reclamaram que o HTML5 era
muito grande. Se isso soa como cortar uma torta em mais pedaços para reduzir o número total de calorias... bem,
bem-vindo ao mundo maluco dos padrões.
A verificação do suporte ao armazenamento HTML5 usa a técnica de detecção nº 1 (consulte “Técnicas de detecção” na
página 15). Se o seu navegador suportar armazenamento HTML5, haverá uma propriedade localStorage no objeto de janela
global. Se o seu navegador não suportar armazenamento HTML5, a propriedade localStorage será indefinida. Você pode
verificar o suporte de armazenamento local usando esta função:
Em vez de escrever esta função você mesmo, você pode usar o Modernizr (veja “Modernizr: Um
Biblioteca de detecção HTML5” na página 16) para detectar suporte para armazenamento local HTML5:
if (Modernizr.localstorage) { //
window.localStorage está disponível! } else { //
sem
suporte nativo para armazenamento local :( // talvez tente
o Gears ou outra solução de terceiros }
Observe que o JavaScript diferencia maiúsculas de minúsculas. O atributo Modernizr é chamado localstorage (tudo em letras
minúsculas), mas a propriedade DOM é chamada window.localStorage (maiúsculas e minúsculas).
P: Quão seguro é meu banco de dados de armazenamento HTML5? Alguém pode ler?
R: Qualquer pessoa que tenha acesso físico ao seu computador provavelmente poderá consultar (ou até mesmo
alterar) seu banco de dados de armazenamento HTML5. No seu navegador, qualquer site pode ler e modificar seus
próprios valores, mas os sites não podem acessar valores armazenados por outros sites. Isso é chamado de restrição
de mesma origem.
Trabalhadores da Web
Web workers fornecem uma maneira padrão para os navegadores executarem JavaScript em segundo plano.
Com web workers, você pode gerar vários “threads” que são executados ao mesmo tempo, mais ou menos. (Pense
em como seu computador pode executar vários aplicativos ao mesmo tempo, e você estará quase lá.) Esses “threads
de segundo plano” podem fazer cálculos matemáticos complexos, fazer solicitações de rede ou acessar armazenamento
local enquanto a página principal da web responde à rolagem, clique ou digitação do usuário.
A verificação de web workers usa a técnica de detecção nº 1 (consulte “Técnicas de detecção” na página 15). Se o
seu navegador suportar a API Web Worker, haverá uma propriedade Worker no objeto de janela global. Se o seu
navegador não suportar a API Web Worker, a propriedade Worker será indefinida. Esta função verifica o suporte do
web trabalhador:
função support_web_workers()
{ return !!window.Worker; }
Em vez de escrever esta função você mesmo, você pode usar o Modernizr (veja “Modernizr: Um
Biblioteca de detecção HTML5” na página 16) para detectar suporte para web workers:
if (Modernizr.webworkers) {
// window.Worker está
Observe que o JavaScript diferencia maiúsculas de minúsculas. O atributo Modernizr é chamado de webworkers (tudo
em letras minúsculas), mas o objeto DOM é chamado de window.Worker (com “W” maiúsculo em “Worker”).
Ler páginas da web estáticas off-line é fácil: conecte-se à Internet, carregue uma página da web, desconecte-se da
Internet, dirija até uma cabana isolada e leia a página da web quando quiser. (Para economizar tempo, você pode
pular a etapa da cabine.) Mas que tal usar aplicativos da web como Gmail ou Google Docs quando estiver off-line?
Graças ao HTML5, qualquer pessoa (não apenas o Google!) pode construir uma aplicação web que funcione offline.
Os aplicativos da web offline começam como aplicativos da web online. Na primeira vez que você visita um site
habilitado para off-line, o servidor da web informa ao seu navegador quais arquivos ele precisa para funcionar off-line.
Esses arquivos podem ser qualquer coisa: HTML, JavaScript, imagens e até vídeos (consulte “Vídeo” na página 18).
Depois que seu navegador baixar todos os arquivos necessários, você poderá revisitar o site mesmo se não estiver
conectado à Internet. Seu navegador notará que você está offline e usará os arquivos já baixados. Quando você voltar
a ficar on-line, todas as alterações feitas poderão ser carregadas no servidor web remoto.
A verificação de suporte off-line usa a técnica de detecção nº 1 (consulte “Técnicas de detecção” na página 15). Se o
seu navegador suportar aplicativos da web offline, haverá uma propriedade applicationCache no objeto de janela global.
Se o seu navegador não suportar aplicativos da Web offline, a propriedade applicationCache será indefinida. Você pode
verificar o suporte offline com a seguinte função:
função support_offline() {
retornar !!window.applicationCache; }
Em vez de escrever esta função você mesmo, você pode usar o Modernizr (veja “Modernizr: Um
Biblioteca de detecção HTML5” na página 16) para detectar suporte para aplicativos da web offline:
if (Modernizr.applicationcache) { //
window.applicationCache está disponível! } else { //
sem
suporte nativo para off-line :( // talvez tente o
Gears ou outra solução de terceiros }
Observe que o JavaScript diferencia maiúsculas de minúsculas. O atributo Modernizr é chamado applicationc ache
(tudo em letras minúsculas), mas o objeto DOM é chamado window.applicationCache (maiúsculas e minúsculas).
Geolocalização
Geolocalização é a arte de descobrir onde você está no mundo e (opcionalmente) compartilhar essa informação com
pessoas em quem você confia. Há muitas maneiras de descobrir onde você está: seu endereço IP, sua conexão de
rede sem fio, com qual torre de celular seu telefone está se comunicando ou hardware GPS dedicado que recebe
informações de latitude e longitude de satélites no céu.
P: A geolocalização faz parte do HTML5? Por que você está falando sobre isso?
R: O suporte à geolocalização está sendo adicionado aos navegadores agora, junto com o suporte para novos
recursos do HTML5. A rigor, a geolocalização está sendo padronizada pelo Grupo de Trabalho de
Geolocalização, que é separado do Grupo de Trabalho HTML5. Mas vou falar sobre geolocalização neste livro
de qualquer maneira, porque faz parte da evolução da Web que está acontecendo agora.
Em vez de escrever esta função você mesmo, você pode usar o Modernizr (veja “Modernizr: Um
Biblioteca de detecção HTML5” na página 16) para detectar suporte para a API de geolocalização:
if (Modernizr.geolocalização) {
// vamos descobrir onde você está! }
else { //
nenhum suporte nativo de geolocalização disponível :
( // talvez tente o Gears ou outra solução de terceiros }
Se o seu navegador não oferece suporte nativo à API de geolocalização, ainda há esperança.
Gears é um plug-in de navegador de código aberto do Google que funciona em Windows, Mac, Linux,
Windows Mobile e Android. Ele fornece vários recursos para navegadores mais antigos que não suportam
todas as novidades sofisticadas que discutimos neste capítulo.
Um dos recursos que o Gears oferece é uma API de geolocalização. Não é o mesmo que a API
navigator.geolocation, mas tem o mesmo propósito.
O Capítulo 6 entrará em detalhes excruciantes sobre como usar todas essas APIs diferentes.
Tipos de entrada
Você sabe tudo sobre formulários web, certo? Faça um <form>, adicione alguns elementos <input type="text">
e talvez um <input type="password">, e finalize com um botão <input type="submit">.
Você não sabe nem metade disso. HTML5 define mais de uma dúzia de novos tipos de entrada que você
pode usar em seus formulários:
<input type="search">
Consulte http://bit.ly/9mQt5C para caixas de
pesquisa <input
type="number"> Consulte http://bit.ly/aPZHjD para caixas giratórias
<input type="range">
Consulte http://bit.ly/dmLiRr para controles
deslizantes <input
type="color"> Consulte http://bit.ly/bwRcMO para
telefone <input
type="url"> Consulte http://bit.ly/cjKb3a para endereços da web
Tipos de entrada | 25
<input type="email">
Consulte http://bit.ly/aaDrgS para endereços de e-
mail <input type="date">
Consulte http://bit.ly/c8hL58 para seletores de datas do
calendário <input
type="month" > Consulte http://bit.ly/cDgHRI
para meses <input
type="week"> Consulte http://bit.ly/
bR3r58 para semanas
<input type="time"> Consulte http://bit.ly/ bfMCMn
para carimbos de data e hora
<input type="datetime"> Consulte http://bit.ly/c46zVW para datas/carimbos de data e hora precisos e absolutos
<input type="datetime-local"> Consulte
http://bit.ly/aziNkE para datas e horários locais
A verificação de tipos de entrada HTML5 usa a técnica de detecção nº 4 (consulte “Técnicas de detecção”
na página 15). Primeiro, você cria um elemento <input> fictício na memória:
var i = document.createElement("entrada");
O tipo de entrada padrão para todos os elementos <input> é "texto". Isto provará ser de vital importância.
Em seguida, defina o atributo type no elemento fictício <input> para o tipo de entrada que você deseja
detectar:
i.setAttribute("tipo", "cor");
Se o seu navegador suportar esse tipo de entrada específico, a propriedade type manterá o valor que
você definiu. Se o seu navegador não suportar esse tipo de entrada específico, ele irá ignorar o valor que
você definiu e a propriedade type ainda será "texto":
return i.type !== "texto";
Em vez de escrever você mesmo 13 funções separadas, você pode usar o Modernizr (consulte “Mod
ernizr: uma biblioteca de detecção de HTML5” na página 16) para detectar suporte para todos os novos
tipos de entrada definidos em HTML5. O Modernizr reutiliza um único elemento <input> para detectar
com eficiência o suporte para todos os 13 tipos de entrada. Em seguida, ele cria um hash chamado tipos
Modernizr.input, que contém 13 chaves (os atributos do tipo HTML5) e 13 valores booleanos (verdadeiro
se suportado, falso se não):
if (!Modernizr.inputtypes.date) { // sem
suporte nativo para <input type="date"> :( // talvez você
mesmo construa um com // Dojo //
ou
jQueryUI }
Além dos novos tipos de entrada, o HTML5 inclui vários pequenos ajustes nos formulários existentes. Uma
melhoria é a capacidade de definir texto de espaço reservado em um campo de entrada. O texto do espaço
reservado é exibido dentro do campo de entrada enquanto o campo estiver vazio e sem foco. Assim que você
clica (ou tabula) no campo de entrada, o texto do espaço reservado desaparece. “Texto de espaço reservado” na
página 147 contém capturas de tela caso você esteja tendo problemas para visualizá-lo.
A verificação do suporte de espaço reservado utiliza a técnica de detecção nº 2 (consulte “Técnicas de detecção”
na página 15). Se o seu navegador suportar texto de espaço reservado em campos de entrada, o objeto DOM
criado para representar um elemento <input> terá uma propriedade de espaço reservado (mesmo se você não
incluir um atributo de espaço reservado em seu HTML). Se o seu navegador não suportar texto de espaço
reservado, o objeto DOM criado para um elemento <input> não terá uma propriedade de espaço reservado . Veja
como verificar o suporte ao espaço reservado:
função support_input_placeholder() {
var i = document.createElement('input');
retorne 'espaço reservado'
em i; }
Em vez de escrever esta função sozinho, você pode usar o Modernizr (consulte “Modernizr: uma biblioteca de
detecção HTML5” na página 16) para detectar suporte para texto de espaço reservado: if
(Modernizr.input.placeholder) {
// seu texto de espaço reservado já deve estar visível! }
else { //
sem suporte de espaço
reservado :( // volta para uma solução
com script }
Muitos sites usam JavaScript para focar automaticamente o primeiro campo de entrada de um formulário da web.
Por exemplo, a página inicial do Google.com focará automaticamente a caixa de entrada para que você possa
digitar as palavras-chave de pesquisa sem precisar posicionar o cursor na caixa de pesquisa.
Embora isso seja conveniente para a maioria das pessoas, pode ser irritante para usuários avançados ou pessoas
com necessidades especiais. Se você pressionar a barra de espaço esperando rolar a página, a página não
rolará porque o foco já está em um campo de entrada do formulário. (Em vez disso, você digitará um espaço no
campo.) Se você focar em um campo de entrada diferente enquanto a página ainda está carregando, o script de
foco automático do site pode “útil” mover o foco de volta para o campo de entrada original após a conclusão,
interrompendo seu fluir e fazer com que você digite no lugar errado.
Como o foco automático é feito com JavaScript, pode ser complicado lidar com todos esses casos extremos, e
há poucos recursos para pessoas que não desejam que uma página da Web “roube” o foco.
Para resolver esse problema, o HTML5 introduz um atributo autofocus em todos os controles de formulário da web.
O atributo autofocus faz exatamente o que diz na lata: move o foco para um campo de entrada específico. Mas como
se trata apenas de uma marcação em vez de um script, o comportamento será consistente em todos os sites. Além
disso, os fornecedores de navegadores (ou autores de extensões) podem oferecer aos usuários uma maneira de
desativar o comportamento de foco automático.
A verificação do suporte ao foco automático usa a técnica de detecção nº 2 (consulte “Técnicas de detecção” na
página 15). Se o seu navegador suportar controles de formulário da web com foco automático, o objeto DOM criado
para representar um elemento <input> terá uma propriedade autofocus (mesmo se você não incluir o atributo
autofocus em seu HTML). Se o seu navegador não suportar controles de formulário da web com foco automático, o
objeto DOM criado para um elemento <input> não terá uma propriedade autofocus . Você pode detectar suporte para
foco automático com esta função:
função support_input_autofocus() {
var i = document.createElement('input'); retorne
'foco automático' em i; }
Em vez de escrever esta função você mesmo, você pode usar o Modernizr (veja “Modernizr: Um
Biblioteca de detecção HTML5” na página 16) para detectar suporte para campos de formulário com foco automático:
if (Modernizr.input.autofocus) { // o
foco automático
funciona! }
else { // sem suporte para foco
automático :( // volta para uma solução
com script }
Microdados
Microdados é uma forma padronizada de fornecer semântica adicional em suas páginas da web.
Por exemplo, você pode usar microdados para declarar que uma fotografia está disponível sob uma licença Creative
Commons específica. Como você verá no Capítulo 10, você também pode usar microdados para marcar uma página
“Sobre mim”. Navegadores, extensões de navegador e mecanismos de pesquisa podem converter sua marcação de
microdados HTML5 em um vCard, um formato padrão para compartilhar informações de contato. Você também pode
definir seus próprios vocabulários de microdados.
O padrão de microdados HTML5 inclui marcação HTML (principalmente para mecanismos de pesquisa) e um
conjunto de funções DOM (principalmente para navegadores). Não há mal nenhum em incluir marcação de
microdados em suas páginas da web; nada mais é do que alguns atributos bem posicionados, e os mecanismos de
pesquisa que não entendem os atributos de microdados simplesmente os ignorarão. Mas se precisar acessar ou
manipular microdados por meio do DOM, você precisará verificar se o navegador oferece suporte à API DOM de
microdados.
A verificação do suporte da API de microdados HTML5 usa a técnica de detecção nº 1 (consulte “Técnicas
de detecção” na página 15). Se o seu navegador suportar a API de microdados HTML5, haverá uma função
getItems() no objeto de documento global . Se o seu navegador não suportar microdados, a função
getItems() será indefinida. Você pode verificar o suporte da seguinte maneira:
função support_microdata_api()
{ return !!document.getItems; }
O Modernizr ainda não oferece suporte à verificação da API de microdados, então você precisará usar uma
função como esta.
Leitura adicional
Especificações e padrões:
• O elemento <canvas>
• O elemento <video>
• tipos de <entrada>
• O atributo <espaço reservado de entrada> •
Armazenamento HTML5
• Trabalhadores da Web
API de geolocalização
Bibliotecas JavaScript:
deste livro
Leitura adicional | 29
CAPÍTULO 3
Mergulhando
Este capítulo pegará uma página HTML que não tem absolutamente nada de errado e a melhorará.
Partes dele ficarão mais curtas. As peças ficarão mais longas. Tudo isso se tornará mais semântico.
Vai ser incrível.
O tipo de documento
Do topo:
<!DOCTYPE
html PUBLIC "-//W3C//DTD XHTML 1.0
Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
Isso é chamado de tipo de documento. Há uma longa história – e uma arte negra – por trás do doctype.
Durante o desenvolvimento do Internet Explorer 5 para Mac, a Microsoft se deparou com um problema
surpreendente. A próxima versão de seu navegador melhorou tanto o suporte aos padrões que as
páginas mais antigas não eram mais renderizadas corretamente. Ou melhor, eles foram renderizados
corretamente (de acordo com as especificações), mas as pessoas esperavam que eles fossem
renderizados de maneira inadequada. As próprias páginas foram criadas com base nas peculiaridades
dos navegadores dominantes da época, principalmente Netscape 4 e Internet Explorer 4. O IE5/Mac
era tão avançado que realmente quebrou a Web.
A Microsoft apresentou uma solução inovadora. Antes de renderizar uma página, o IE5/Mac olhou para o
“doctype”, que normalmente é a primeira linha do código-fonte HTML (mesmo antes do elemento <html>).
Páginas mais antigas (que dependiam das peculiaridades de renderização de navegadores mais antigos)
geralmente não tinham nenhum tipo de documento. O IE5/Mac renderizou essas páginas como os
navegadores mais antigos. Para “ativar” o suporte aos novos padrões, os autores das páginas web tiveram
que optar por fornecer o tipo de documento correto antes do elemento <html>.
31
Essa ideia se espalhou rapidamente e logo todos os principais navegadores tinham dois modos: “modo peculiaridades”
e “modo padrão”. É claro que, sendo esta a Web, as coisas rapidamente saíram do controle. Quando a Mozilla
tentou lançar a versão 1.1 de seu navegador, descobriu que havia páginas sendo renderizadas no modo padrão
que, na verdade, dependiam de uma peculiaridade específica. A Mozilla tinha acabado de consertar seu mecanismo
de renderização para eliminar essa peculiaridade e milhares de páginas quebraram de uma só vez. Assim foi criado
– e não estou inventando isso – o “ modo quase padrão”.
Em seu trabalho seminal, “Ativando Modos de Navegador com Doctype”, Henri Sivonen resume os diferentes
modos:
Modo Quirks No
modo Quirks, os navegadores violam as especificações contemporâneas de formato da Web para evitar
“quebrar” páginas criadas de acordo com práticas que eram predominantes no final da década de 1990.
Modo Padrões No
modo Padrões, os navegadores tentam dar aos documentos em conformidade o tratamento correto em termos
de especificação, na medida em que são implementados em um navegador específico.
O HTML5 chama esse modo de “modo sem peculiaridades”.
Modo quase padrão
Firefox, Safari, Chrome, Opera (desde 7.5) e IE8 também possuem um modo conhecido como “modo Quase
Padrões”, que implementa o dimensionamento vertical das células da tabela de forma tradicional e não
rigorosa de acordo com a especificação CSS2. O HTML5 chama esse modo de “modo de peculiaridades
limitadas”.
Você deveria ler o resto do artigo de Henri, porque estou simplificando imensamente
aqui. Mesmo no IE5/Mac, havia alguns tipos de documentos mais antigos que não
contavam para a opção de suporte a padrões. Com o tempo, a lista de peculiaridades
cresceu, assim como a lista de doctypes que acionaram o modo quirks.
A última vez que tentei contar, havia 5 doctypes que acionavam o modo quase padrão
e 73 que acionavam o modo quirks. Mas provavelmente perdi alguns, e nem vou falar
sobre as coisas que o Internet Explorer 8 faz para alternar entre seus quatro – quatro!
– modos de renderização diferentes. Há um fluxograma em http:// hsivonen.iki.fi/ doctype/
ie8-mode .png. Mate isso. Matá-lo com fogo.
Este é um dos 15 doctypes que acionam o modo padrão em todos os navegadores modernos. Não há nada de
errado com isso. Se você gostar, pode ficar com ele. Ou você pode alterá-lo para o tipo de documento HTML5, que
é mais curto e mais agradável e também aciona o modo padrão em todos os navegadores modernos.
É isso. Apenas 15 caracteres. É tão fácil que você pode digitar à mão e não estragar tudo.
tipo de documento precisa estar na primeira linha do seu arquivo HTML. Se houver mais alguma coisa antes
dela - mesmo que seja uma única linha em branco - certos navegadores tratarão sua página como se ela
não tivesse nenhum tipo de documento. Sem um doctype, o navegador renderizará sua página no modo quirks.
Este pode ser um erro muito difícil de detectar. Espaços em branco extras geralmente não importam em
HTML, então meus olhos tendem a ignorá-los, mas neste caso são muito importantes!
O elemento raiz
Uma página HTML é uma série de elementos aninhados. Toda a estrutura da página é como uma árvore.
Alguns elementos são “irmãos”, como dois galhos que se estendem do mesmo tronco de árvore. Alguns
elementos podem ser “filhos” de outros elementos, como um galho menor que se estende de um galho
maior. (Funciona de outra maneira também; um elemento que contém outros elementos é chamado de nó
“pai” de seus elementos filhos imediatos e de “ancestral” de seus netos.) Elementos que não têm filhos são
chamados de nós “folha”.
O elemento mais externo, que é o ancestral de todos os outros elementos da página, é chamado de
“elemento raiz”. O elemento raiz de uma página HTML é sempre <html>.
<html xmlns="http://www.w3.org/1999/xhtml"
lang="en"
xml:lang="en">
Não há nada de errado com essa marcação. Novamente, se você gostar, você pode mantê-lo. É HTML5
válido. Mas partes dele não são mais necessárias no HTML5, então você pode economizar alguns bytes
removendo-os.
A primeira coisa a discutir é o atributo xmlns . Este é um vestígio do XHTML 1.0. Diz que os elementos
desta página estão no namespace XHTML, http://www.w3.org/1999/xhtml. Mas os elementos no HTML5
estão sempre neste namespace, então você não precisa mais declará-lo explicitamente. Sua página HTML5
funcionará exatamente da mesma forma em todos os navegadores modernos, esteja este atributo presente
ou não.
O elemento raiz | 33
Os dois atributos aqui, lang e xml:lang, definem o idioma desta página HTML. en significa “Inglês”.* Por
que dois atributos para a mesma coisa? Novamente, este é um vestígio de XHTML. Somente o atributo
lang tem efeito no HTML5. Você pode manter o atributo xml:lang se quiser, mas se quiser, você precisa
garantir que ele contenha o mesmo valor que o atributo lang :
Para facilitar a migração de e para XHTML, os autores podem especificar um atributo em nenhum espaço
de nome, sem prefixo e com o nome local literal “xml:lang” em elementos HTML em documentos HTML, mas
tais atributos só devem ser especificados se um atributo lang em nenhum namespace também é especificado
e ambos os atributos devem ter o mesmo valor quando comparados de maneira ASCII sem distinção entre
maiúsculas e minúsculas. O atributo sem namespace, sem prefixo e com o nome local literal “xml:lang” não
tem efeito no processamento da linguagem.
Você está pronto para abandoná-lo? Está tudo bem, apenas deixe para lá. Indo indo Foi! Isso nos deixa
com este elemento raiz:
<html lang="pt">
O elemento <head>
O primeiro filho do elemento raiz geralmente é o elemento <head> . O elemento <head> contém metadados
– informações sobre a página, em vez do corpo da página em si.
(O corpo da página está, sem surpresa, contido no elemento <body> .) O elemento <head> em si é
bastante chato e não mudou de nenhuma maneira interessante no HTML5. O bom é o que está dentro do
elemento <head> . E para isso, voltamos mais uma vez à nossa página de exemplo:
<cabeça>
*
Não está escrevendo em inglês? Encontre o código do seu idioma em http:// www.w3.org/ International/ questions/ qa-choosing
-language-tags.
Codificação de caracteres
Quando você pensa em “texto”, provavelmente pensa em “caracteres e símbolos que vejo na tela do meu
computador”. Mas os computadores não lidam com caracteres e símbolos; eles lidam com bits e bytes.
Cada pedaço de texto que você já viu na tela de um computador é, na verdade, armazenado em uma
codificação de caracteres específica. Existem muitas codificações de caracteres diferentes, algumas
otimizadas para idiomas específicos, como russo, chinês ou inglês, e outras que podem ser usadas para
vários idiomas. Grosso modo, a codificação de caracteres fornece um mapeamento entre o que você vê
na tela e o que seu computador realmente armazena na memória e no disco.
Na realidade, é mais complicado que isso. Muitos caracteres são comuns a múltiplas codificações, mas
cada codificação pode usar uma sequência diferente de bytes para armazenar esses caracteres na
memória ou no disco. Portanto, você pode pensar na codificação de caracteres como uma espécie de
chave de descriptografia do texto. Sempre que alguém fornece uma sequência de bytes e afirma que é
“texto”, você precisa saber qual codificação de caracteres ele usou para poder decodificar os bytes em
caracteres e exibi-los (ou processá-los, ou qualquer outra coisa).
Então, como seu navegador realmente determina a codificação de caracteres do fluxo de bytes que um
servidor web envia? Estou feliz que você perguntou. Se você estiver familiarizado com cabeçalhos HTTP,
talvez já tenha visto um cabeçalho como este:
Resumidamente, isso indica que o servidor web pensa que está enviando um documento HTML e que o
documento usa a codificação de caracteres UTF-8 . Infelizmente, em toda a magnífica sopa da World
Wide Web, poucos autores realmente têm controle sobre seus servidores HTTP. Pense no Blogger: o
conteúdo é fornecido por indivíduos, mas os servidores são administrados pelo Google. Portanto, o HTML
4 forneceu uma maneira de especificar a codificação de caracteres no próprio documento HTML. Você
provavelmente já viu isso também:
Resumidamente, isso indica que o autor da web pensa ter criado um documento HTML usando a
codificação de caracteres UTF-8 .
Ambas as técnicas ainda funcionam em HTML5. O cabeçalho HTTP é o método preferido e substitui a
tag <meta> , se presente. Mas nem todos podem definir cabeçalhos HTTP, então a tag <meta> ainda
existe. Na verdade, ficou um pouco mais fácil no HTML5. Agora fica assim:
O elemento <head> | 35
Isso funciona em todos os navegadores. Como surgiu essa sintaxe abreviada? Aqui está a melhor
explicação que pude encontrar:
A justificativa para a combinação de atributos <meta charset=""> é que os UAs já a implementam, porque
as pessoas tendem a deixar coisas sem aspas, como:
Existem até alguns casos de teste <meta charset> , se você não acredita que os navegadores já fazem
isso.
P: Eu nunca uso personagens engraçados. Ainda preciso declarar minha codificação de caracteres?
R: Sim! Você deve sempre especificar uma codificação de caracteres em cada página HTML que você veicula.
Não especificar uma codificação pode levar a vulnerabilidades de segurança.
Resumindo: a codificação de caracteres é complicada e não foi facilitada por várias décadas de
software mal escrito usado por autores com formação em copiar e colar.
Você deve sempre especificar uma codificação de caracteres em cada documento HTML, ou coisas
ruins acontecerão. Você pode fazer isso com o cabeçalho HTTP Content-Type , a declaração <meta
http equiv> ou a declaração <meta charset> mais curta , mas faça isso. A Web agradece.
Links regulares (<a href>) simplesmente apontam para outra página. As relações de link são uma forma
de explicar por que você está apontando para outra página. Eles terminam a frase “Estou apontando
para esta outra página porque...”
• ...é uma folha de estilo contendo regras CSS que seu navegador deve aplicar a este
documento.
• ...é um feed que contém o mesmo conteúdo desta página, mas em um sub padrão
formato rabiscável.
• ...é uma tradução desta página para outro idioma. • ...é o mesmo
conteúdo desta página, mas em formato PDF. • ...é o próximo capítulo
de um livro online do qual esta página também faz parte.
Duas categorias de links podem ser criadas usando o elemento link. Links para recursos externos são
links para recursos que serão usados para aumentar o documento atual, e links de hiperlink são links para
outros documentos. [...]
O comportamento exato dos links para recursos externos depende do relacionamento exato, conforme
definido para o tipo de link relevante.
Dos exemplos que acabei de dar, apenas o primeiro (rel="stylesheet") é um link para um recurso externo. O restante
são hiperlinks para outros documentos. Você pode querer seguir esses links ou não, mas eles não são necessários
para visualizar a página atual.
Na maioria das vezes, as relações de link são vistas em elementos <link> dentro do <head> de uma página.
Algumas relações de link também podem ser usadas em elementos <a> , mas isso é incomum mesmo quando
permitido. HTML5 também permite algumas relações em elementos <area> , mas isso é ainda menos comum.
(HTML 4 não permitia um atributo rel em elementos <area> .) Veja o gráfico completo de relações de link para
verificar onde você pode usar valores rel específicos .
Pergunte ao Professor
Esta é a relação de link usada com mais frequência no mundo (literalmente). <link rel="style sheet"> serve para
apontar para regras CSS que são armazenadas em um arquivo separado. Uma pequena otimização que você pode
fazer no HTML5 é eliminar o atributo type . Existe apenas uma linguagem de folha de estilo para a Web, CSS, então
esse é o valor padrão para o atributo type :
Isso funciona em todos os navegadores. (Suponho que algum dia alguém poderia inventar uma nova linguagem de
folha de estilo, mas se isso acontecer, você pode simplesmente adicionar o atributo type de volta.)
rel = alternativo
<link rel="alternativo"
type="application/atom+xml"
title="Meu feed do blog"
href="/feed/" />
Essa relação de link também é bastante comum. <link rel="alternate">, combinado com o tipo de mídia RSS ou Atom
no atributo type , permite algo chamado “feed au todiscovery”. Ele permite leitores de feeds distribuídos como o
Google Reader descobrir que um site possui um feed de notícias com os artigos mais recentes. A maioria dos
navegadores também oferece suporte à descoberta automática de feeds, exibindo um ícone especial próximo ao
URL. (Ao contrário de rel="stylesheet", o atributo type é importante aqui. Não o deixe cair!)
O elemento <head> | 37
A relação de link rel="alternate" sempre foi um estranho híbrido de casos de uso, mesmo
em HTML 4. No HTML5, sua definição foi esclarecida e ampliada para descrever com mais precisão o
conteúdo da web existente. Como você acabou de ver, usar rel="alternate" em conjunto com
type=application/atom+xml indica um feed Atom para a página atual.
Mas você também pode usar rel="alternate" em conjunto com outros atributos de tipo para indicar o
mesmo conteúdo em outro formato, como PDF.
O HTML5 também acaba com uma confusão de longa data sobre como vincular traduções de documentos.
HTML 4 diz para usar o atributo lang em conjunto com rel="alter
nate" para especificar o idioma do documento vinculado, mas isso está incorreto. O HTML
4 Erratas lista quatro erros completos nas especificações do HTML 4 (junto com vários detalhes editoriais);
um desses erros flagrantes é como especificar o idioma de um documento vinculado a
rel="alternativo". (A maneira correta, descrita no documento HTML 4 Errata e
agora em HTML5, é usar o atributo hreflang .) Infelizmente, essas erratas nunca foram
reintegrado na especificação HTML 4, porque ninguém no Grupo de Trabalho HTML do W3C
estava mais trabalhando em HTML.
rel="arquivos"
(http:// bit.ly/ clzlyG) “indica que o documento referenciado descreve uma coleção
de registros, documentos ou outros materiais de interesse histórico. A página de índice de um blog
poderia vincular a um índice de postagens anteriores do blog com rel="archives".”
rel="autor"
é usado para vincular informações sobre o autor da página. Este pode ser um mailto:
endereço, embora não precise ser. Poderia simplesmente vincular a um formulário de contato ou
página “sobre o autor”.
rel="externo"
(http:// bit.ly/ dBVO09) “indica que o link leva a um documento que não é
parte do site do qual o documento atual faz parte.” acredito que foi o primeiro
popularizado pelo WordPress, que o utiliza em links deixados por comentaristas.
compatibilidade), bem como rel="last" (o último de uma série, espelhando rel="first") e rel="up".
A melhor maneira de pensar em rel="up" é observar sua navegação estrutural (ou pelo menos
imaginá-la). Sua página inicial é provavelmente a primeira página na localização atual, e a
página atual está no final. rel="up" aponta para a penúltima página na localização atual.
rel="ícone"
(http:// bit.ly/ diAJUP) é a segunda relação de link mais popular, depois de rel="folha de estilo".
Geralmente é encontrado junto com o atalho, assim:
rel="noreferrer" (http://
bit.ly/ cQMSJg) “indica que nenhuma informação de referência será vazada ao seguir o link.”
Nenhum navegador de remessa atualmente oferece suporte para isso, mas o suporte foi
adicionado recentemente às noites do WebKit, então eventualmente aparecerá no Safari,
Google Chrome e outros navegadores baseados em WebKit. Você pode encontrar um caso de
teste rel="noreferrer" em http:// wearehugh.com/ public/ 2009/04/ rel-
noreferrer.html.
rel="pingback" (http://bit.ly/ cIAGXB) especifica o endereço de um servidor “pingback”. Conforme
explicado na especificação Pingback, “O sistema de pingback é uma forma de um blog ser
notificado automaticamente quando outros sites possuem links para ele. [...] Permite a vinculação
reversa - uma forma de voltar a subir uma cadeia de elos, em vez de apenas aprofundar. Os
sistemas de blog, principalmente o WordPress, implementam o mecanismo de pingback para
notificar os autores de que você criou um link para eles ao criar uma nova postagem no blog.
O elemento <head> | 39
rel="pré-busca" (http://
bit.ly/ 9o0nMS) “indica que a busca preventiva e o armazenamento em cache do recurso especificado
provavelmente serão benéficos, pois é altamente provável que o usuário precise desse recurso.” Às vezes,
os mecanismos de pesquisa adicionam <link rel="prefetch" href="<empha sis>URL DO PRINCIPAL
RESULTADO DE PESQUISA</emphasis>"> à página de resultados de pesquisa se acharem que o
resultado principal é muito mais popular do que qualquer outro. Por exemplo: usando Fire fox, pesquise
CNN no Google, visualize o código-fonte da página e pesquise a pré-busca de palavra-chave. Mozilla Firefox
é o único navegador atual que suporta rel="prefetch".
rel="pesquisar"
(http:// bit.ly/ aApkaP) “indica que o documento referenciado fornece uma interface específica para pesquisar
o documento e seus recursos relacionados.” Especificamente, se você quiser que rel="search" faça algo
útil, ele deve apontar para uma pesquisa aberta documento que descreve como um navegador pode
construir uma URL para pesquisar uma determinada palavra-chave no site atual. OpenSearch (e links
rel="search" que apontam para documentos de descrição do OpenSearch) tem suporte no Microsoft Internet
Explorer desde a versão 7 e no Mozilla Firefox desde a versão 2.
rel="barra lateral"
(http:// bit.ly/ azTA9D) “indica que o documento referenciado, se recuperado, tende a ser mostrado em um
contexto de navegação secundário (se possível), em vez de no contexto de navegação atual.” O que isso
significa? No Opera e no Mozilla Firefox, significa “quando clico neste link, solicita ao usuário que crie um
marcador que, quando selecionado no menu Marcadores, abre o documento vinculado na barra lateral do
navegador”. (Na verdade, o Opera o chama de “painel” em vez de “barra lateral”.) Internet Explorer, Safari
e Chrome ignoram rel="sidebar" e tratam-no apenas como um link normal.
Você pode encontrar um caso de teste rel="sidebar" em http:// wearehugh.com/ public/ 2009/04/ rel
-sidebar.html.
rel="tag" (http://
bit.ly/ 9bYlfa) “indica que a tag que o documento referenciado representa se aplica ao documento atual.” A
marcação de “tags” (palavras-chave de categoria) com o atributo rel foi inventada pela Technorati para
ajudar na categorização das postagens do blog. Os primeiros blogs e tutoriais referiam-se a eles como “tags
Technorati”.
(Você leu certo: uma empresa comercial convenceu o mundo inteiro a adicionar metadados que facilitaram
o trabalho da empresa. Bom trabalho, se você conseguir!) A sintaxe foi posteriormente padronizada na
comunidade de microformatos, onde foi simplesmente chamado de rel="tag". A maioria dos sistemas de
blog que permitem associar categorias, palavras-chave ou tags a postagens individuais irá marcá-las com
links rel="tag" .
Os navegadores não fazem nada de especial com eles; eles são realmente projetados para serem usados
pelos mecanismos de pesquisa como um sinal do assunto da página.
O HTML5 não se trata apenas de tornar a marcação existente mais curta (embora faça bastante disso). Também define uma série de novos elementos
<section> O elemento de seção representa uma seção genérica de um documento ou aplicativo. Uma seção, neste contexto, é um agrupamento temático
de conteúdo, normalmente com um título. Exemplos de seções seriam os capítulos, as diversas páginas com guias em uma caixa de
diálogo com guias ou as seções numeradas de uma tese. A página inicial de um site pode ser dividida em diferentes seções para
<nenhum> O elemento nav representa uma seção de uma página vinculada a outras páginas ou a partes da página: uma seção com links de
navegação. Nem todos os grupos de links em uma página precisam estar em um elemento nav – somente seções que consistem em
blocos de navegação principais são apropriadas para o elemento nav. Em particular, é comum que os rodapés tenham uma pequena
lista de links para várias páginas de um site, como termos de serviço, página inicial e página de direitos autorais. O elemento footer
sozinho é suficiente para tais casos, sem um elemento nav.
<article> O elemento article representa uma composição independente em um documento, página, aplicativo ou site que se destina a ser distribuído de
forma independente ou reutilizável, por exemplo, em distribuição. Pode ser uma postagem em um fórum, um artigo de revista ou
jornal, uma entrada de blog, um comentário enviado por um usuário, um widget ou gadget interativo ou qualquer outro item de
conteúdo independente.
<à parte> O elemento aparte representa uma seção de uma página que consiste em conteúdo tangencialmente relacionado ao conteúdo ao
redor do elemento aparte e que pode ser considerado separado desse conteúdo. Essas seções são frequentemente representadas
como barras laterais na tipografia impressa. O elemento pode ser usado para efeitos tipográficos, como citações ou barras laterais,
para publicidade, para grupos de elementos de navegação e para outros conteúdos considerados separados do conteúdo principal
da página.
<hgrupo> O elemento hgroup representa o título de uma seção. O elemento é usado para agrupar um conjunto de elementos h1–h6 quando o
<cabeçalho> O elemento header representa um grupo de auxílios introdutórios ou de navegação. Um elemento de cabeçalho geralmente contém
o título da seção (um elemento h1–h6 ou um elemento hgroup), mas isso não é obrigatório.
O elemento header também pode ser usado para agrupar o índice de uma seção, um formulário de pesquisa ou qualquer logotipo relevante.
<rodapé> O elemento footer representa um rodapé para seu conteúdo de seccionamento ancestral mais próximo ou elemento raiz de seccionamento.
Um rodapé normalmente contém informações sobre sua seção, como quem o escreveu, links para documentos relacionados,
dados de direitos autorais e assim por diante. Os rodapés não precisam necessariamente aparecer no final de uma seção, embora
normalmente apareçam. Quando o elemento de rodapé contém seções inteiras, eles representam apêndices, índices, colofões
<tempo> O elemento de tempo representa uma hora em um relógio de 24 horas ou uma data precisa no calendário gregoriano proléptico,
<marca> O elemento mark representa uma sequência de texto em um documento marcado ou destacado para fins de referência.
Sei que você está ansioso para começar a usar esses novos elementos, ou não estaria lendo este capítulo. Mas primeiro precisamos fazer um pequeno desvio.
Cada navegador possui uma lista mestra de elementos HTML que suporta. Por exemplo, a lista do
Mozilla Firefox é armazenada em nsElementTable.cpp. Os elementos que não estão nesta lista são
tratados como “elementos desconhecidos”. Existem duas questões fundamentais em relação a
elementos desconhecidos:
A primeira pergunta deve ser relativamente simples de responder: não dê nenhum estilo especial a
elementos desconhecidos. Apenas deixe-os herdar quaisquer propriedades CSS em vigor onde quer
que apareçam na página e deixe o autor da página especificar todos os estilos com CSS.
Infelizmente, o Internet Explorer (anterior à versão 9) não permite estilização de elementos
desconhecidos. Por exemplo, se você tivesse esta marcação:
<style type="texto/css">
artigo {exibição: bloco; borda: 1px vermelho sólido }
</style>
...
<article>
<h1>Bem-vindo à Initech</
h1> <p>Este é seu <span>primeiro dia.</p>
</article>
O Internet Explorer (até IE 8 inclusive) não colocará uma borda vermelha ao redor do artigo.
Enquanto escrevo isto, o Internet Explorer 9 ainda está na versão beta, mas a Microsoft declarou (e
os desenvolvedores verificaram) que o Internet Explorer 9 não terá esse problema.
O segundo problema é o DOM que os navegadores criam quando encontram elementos desconhecidos.
Novamente, o navegador mais problemático é o Internet Explorer. Se o IE não reconhecer
explicitamente o nome do elemento, ele inserirá o elemento no DOM como um nó vazio sem filhos.
Todos os elementos que você esperaria que fossem filhos diretos do elemento desconhecido serão,
na verdade, inseridos como irmãos.
Aqui está alguma arte ASCII para mostrar a diferença. Este é o DOM que o HTML5 dita:
artigo |
span | | |
+--
text node "primeiro dia" | +--text
node "."
node
Existe uma solução maravilhosa para esse problema. Se você criar um <article> fictício elemento
com JavaScript antes de usá-lo em sua página, o Internet Explorer reconhecerá magicamente o
elemento <article> e permitirá que você o estilize com CSS. Não há necessidade de inserir o
elemento fictício no DOM. Simplesmente criar o elemento uma vez (por página) é suficiente para
ensinar o IE a estilizar o elemento que ele não reconhece. Por exemplo:
<html>
<cabeça>
<estilo>
artigo {display: bloco; borda: 1px vermelho sólido } </style>
<script>document.createElement("article");</script> </head>
<body>
<article>
<h1>Bem-
vindo ao Initech</h1> <p>Este é
seu <span>primeiro dia.</p> </article> </body> </html>
Uma longa digressão sobre como os navegadores lidam com elementos desconhecidos | 43
Isso funciona em todas as versões do Internet Explorer, desde o IE 6! Podemos estender essa
técnica para criar cópias fictícias de todos os novos elementos HTML5 de uma só vez - novamente,
eles nunca são inseridos no DOM, então você nunca verá esses elementos fictícios - e então
começar a usá-los sem se preocupar também muito sobre navegadores não compatíveis com
HTML5.
Remy Sharp fez exatamente isso, com seu apropriadamente chamado “script de ativação HTML5”.
O script passou por diversas revisões, mas esta é a ideia básica:
<!--[if lt IE 9]>
<script>
var e = ("abbr,article,aside,audio,canvas,datalist,details," +
"figure,footer,header,hgroup,mark,menu,meter, nav,saída,"
+ "progresso,seção,tempo,vídeo").split(',');
for (var i = 0; i < e.length; i++)
{ document.createElement(e[i]); }
</script>
<![endif]-->
Os bits <!--[if lt IE 9]> e <![endif]--> são comentários condicionais. O Internet Explorer os interpreta
como uma instrução if : “se o navegador atual for uma versão do Internet Explorer inferior à versão
9, execute este bloco”. Todos os outros navegadores tratarão o bloco inteiro como um comentário
HTML. O resultado líquido é que o Internet Explorer (até a versão 8 inclusive) executará esse script,
mas outros navegadores o ignorarão completamente. Isso faz com que sua página carregue mais
rápido em navegadores que não precisam desse hack.
Essa parte “mais tarde” é importante. Este script precisa estar no topo da sua página – de
preferência no elemento <head> – e não na parte inferior. Dessa forma, o Internet Explorer
executará o script antes de analisar suas tags e atributos. Se você colocar esse script no final da
sua página, será tarde demais. O Internet Explorer já terá interpretado mal sua marcação e
construído o DOM errado, e não irá voltar atrás e ajustá-lo apenas por causa deste script.
Remy Sharp “minificou” este script e o hospedou no Google Project Hosting. (Caso você esteja se
perguntando, o script em si é de código aberto e licenciado pelo MIT, então você pode usá-lo em
qualquer projeto.) Se desejar, você pode até fazer um “hotlink” do script apontando diretamente
para a versão hospedada, como este :
<head> <meta
charset="utf-8" />
<title>Meu blog</
title> <!--[if lt IE 9]> <script src="http://html5shiv.googlecode.com/svn /trunk/html5.js"></script>
<![endif]--> </
head>
Agora estamos prontos para começar a usar os novos elementos semânticos no HTML5.
Cabeçalhos
...
<div class="entrada">
<h2>Dia de viagem</
h2> </div>
...
<div class="entry">
<h2>Vou para Praga!</h2> </div>
Não há nada de errado com essa marcação. Se você gostar, pode ficar com ele. É HTML5 válido. Mas o
HTML5 fornece alguns elementos semânticos adicionais para cabeçalhos e seções.
Primeiro, vamos nos livrar disso <div id="header">. Este é um padrão muito comum, mas não significa nada.
O elemento div não possui semântica definida e o atributo id não possui semântica definida. (Os agentes do
usuário não têm permissão para inferir qualquer significado do valor do atributo id .) Você poderia mudar
isso para <div id="shazbot"> e teria o mesmo valor semântico, ou seja, nada.
HTML5 define um elemento <header> para essa finalidade. A especificação HTML5 tem vários exemplos
do mundo real de usar o elemento <header> . Aqui está como ficaria em nossa página de exemplo:
<cabeçalho>
<h1>Meu blog</h1>
<p class="tagline">Muito esforço foi feito para tornar isso fácil.</p>
...
</header>
Isso é bom. Diz a quem quiser saber que se trata de um cabeçalho. Mas e quanto a esse slogan? Outro
padrão comum, que até agora não tinha marcação padrão.
É uma coisa difícil de marcar. Um slogan é como um subtítulo, mas está “anexado” ao título principal. Ou
seja, é um subtítulo que não cria seção própria.
Cabeçalhos | 45
Elementos de cabeçalho como <h1> e <h2> fornecem a estrutura da sua página. Juntos, eles criam
um esboço que você pode usar para visualizar (ou navegar) em sua página. Os leitores de tela usam
contornos de documentos para ajudar usuários cegos a navegar pela sua página. Existem
ferramentas online e extensões de navegador que pode ajudá-lo a visualizar o esboço do seu documento.
+--Dia de viagem
Tudo bem, mas significa que não há como marcar o slogan “Muito esforço foi feito para tornar isso
fácil”. Se tentássemos marcá-lo como <h2>, adicionaríamos um nó fantasma ao esboço do
documento:
+--Muito esforço foi feito para tornar isso fácil. (h2) | +--Dia de viagem
Mas essa não é a estrutura do documento. O slogan não representa uma seção; é apenas um
subtítulo.
Talvez pudéssemos marcar o slogan como <h2> e marcar cada título de artigo como <h3>? Não,
isso é ainda pior: Meu Weblog
(h1) | +--Muito
| +--Dia de viagem
Agora ainda temos um nó fantasma em nosso esboço do documento, mas ele “roubou” os filhos que
pertencem por direito ao nó raiz. E é aqui que reside o problema: o HTML 4 não fornece uma maneira
de marcar um subtítulo sem adicioná-lo ao esboço do documento. Não importa o quanto tentemos
mudar as coisas, “muito esforço foi feito para tornar isso fácil” vai acabar naquele gráfico. E é por
isso que acabamos com uma marcação semanticamente sem sentido como <p class="tagline">.
HTML5 fornece uma solução para isso: o elemento <hgroup> . O elemento <hgroup> atua como um
wrapper para dois ou mais elementos de cabeçalho relacionados . O que significa “relacionado”?
Isso significa que, em conjunto, eles criam um único nó no esboço do documento.
<header>
<hgroup>
<h1>Meu blog</h1>
<h2> Muito esforço foi feito para tornar isso fácil.</h2> </hgroup>
...
</header>
...
<div class="entrada">
<h2>Dia de viagem</
h2> </div>
...
<div class="entry">
<h2>Vou para Praga!</h2> </div>
| +--Dia de viagem
Você pode testar suas próprias páginas no HTML5 Outliner para garantir que você está usando os
elementos de título corretamente.
Artigos
Continuando com nossa página de exemplo, vamos ver o que podemos fazer sobre essa marcação:
<div class="entrada">
<p class="post-date">22 de outubro de 2009</p>
<h2>
<a href="#"
rel="bookmark"
title="link para esta postagem">
Dia de viagem
</a>
</h2>
...
</div>
Novamente, este é HTML5 válido. Mas o HTML5 fornece um elemento mais específico para o caso comum
de marcação de um artigo em uma página – o elemento <article> apropriadamente chamado:
<article>
<p class="post-date">22 de outubro de 2009</
p>
<h2> <a
href="#" rel="bookmark"
Artigos | 47
Ah, mas não é tão simples assim. Há mais uma mudança que você deve fazer. Vou mostrar para você
primeiro e depois explicar:
<article>
<header>
<p class="post-date">22 de outubro de 2009</p>
<h1> <a
href="#"
rel="bookmark" title="link para esta postagem">
Dia de
viagem
</a> </h1> </header>
...
</artigo>
Você percebeu isso? Mudei o elemento <h2> para um <h1> e coloquei-o dentro de um elemento
<header> . Você já viu o elemento <header> em ação. Sua finalidade é agrupar todos os elementos
que formam o cabeçalho do artigo (neste caso, a data de publicação e o título do artigo).
Mas...mas...mas...você não deveria ter apenas um <h1> por documento? Isso não vai estragar o
esboço do documento? Não, mas para entender por que não, precisamos recuar um passo.
No HTML 4, a única maneira de criar um esboço de documento era com os elementos <h1>–<h6> .
Se você quisesse apenas um nó raiz em seu esboço, teria que se limitar a um <h1> em sua marcação.
Mas a especificação HTML5 define um algoritmo para gerar um esboço de documento que incorpora
os novos elementos semânticos do HTML5. O algoritmo HTML5 diz que um elemento <article> cria
uma nova seção, ou seja, um novo nó no esboço do documento. E no HTML5, cada seção pode ter
seu próprio elemento <h1> .
Esta é uma mudança drástica em relação ao HTML 4 e é por isso que é uma coisa boa. Muitas páginas
da web são realmente geradas por modelos. Um pouco do conteúdo é retirado de uma fonte e inserido
na página aqui em cima; um pouco do conteúdo é retirado de outra fonte e inserido na página ali
embaixo. Muitos tutoriais são estruturados da mesma maneira. “Aqui estão algumas marcações HTML.
Basta copiá-lo e colá-lo em sua página.” Isso é bom para pequenos pedaços de conteúdo, mas e se a
marcação que você está colando for uma seção inteira? Nesse caso, o tutorial será mais ou menos
assim: “Aqui estão algumas marcações HTML. Basta copiá-lo, colá-lo em um editor de texto e corrigir
as tags de título para que correspondam ao nível de aninhamento das tags de título correspondentes
na página em que você está colando.”
Deixe-me explicar de outra forma. HTML 4 não possui elemento de título genérico . Possui seis
elementos de título estritamente numerados, <h1>–<h6>, que devem ser aninhados exatamente nessa ordem.
Isso é uma droga, especialmente se sua página for “montada” em vez de “de autoria”. E este é o
problema que o HTML5 resolve com os novos elementos de seccionamento e as novas regras para
os elementos de título existentes. Se você estiver usando os novos elementos de seccionamento,
posso fornecer esta marcação:
<article>
<header>
<h1>Uma postagem distribuída</
h1> </
header> <p>Lorem ipsum blá blá...</
p> </article>
e você pode copiá-lo e colá-lo em qualquer lugar da sua página sem modificação. O fato de conter
um elemento <h1> não é um problema, porque tudo está contido em um <article>. O elemento
<article> define um nó independente no esboço do documento, o elemento <h1> fornece o título
para esse nó do esboço e todos os outros elementos de seccionamento na página permanecerão
em qualquer nível de aninhamento em que estavam antes.
acontece com todas as coisas na Web, a realidade é um pouco mais complicada do que estou deixando transparecer.
Datas e horários
Isso é emocionante, certo? Quero dizer, não é emocionante “esquiar nu no Monte Everest enquanto
recita o Star Spangled Banner de trás para frente”, mas é muito emocionante no que diz respeito à
marcação semântica. Vamos continuar com nossa página de exemplo. A próxima linha que quero
destacar é esta:
<div class="entrada">
<p class="post-date">22 de outubro de 2009</
p> <h2>Dia da viagem</
h2> </div>
A mesma velha história, certo? Um padrão comum – designando a data de publicação de um artigo
– que não possui marcação semântica para apoiá-lo, então os autores recorrem à marcação genérica
com atributos de classe personalizados . Novamente, este é HTML5 válido. Você não é obrigado a
alterá-lo. Mas o HTML5 fornece uma solução específica para este caso – o elemento <time> :
<time datetime="2009-10-22" pubdate>22 de outubro de 2009</time>
Datas e horários | 49
Neste exemplo, o atributo datetime especifica apenas uma data, não uma hora. O formato é um ano de quatro dígitos, um mês
de dois dígitos e um dia de dois dígitos, separados por travessões: <time datetime="2009-10-22" pubdate>22
de outubro de 2009</time>
Se você quiser incluir uma hora também, adicione a letra T após a data, depois a hora no formato de 24 horas e,
em seguida, um deslocamento de fuso horário:
O formato de data/hora é bastante flexível. A especificação HTML5 contém vários exemplos de strings de data/
hora válidas.
Observe que alterei o conteúdo do texto — o que está entre <time> e </time> — para corresponder ao carimbo de
data/hora legível por máquina. Na verdade, isso não é necessário. O conteúdo do texto pode ser o que você
quiser, desde que você forneça uma data/carimbo de data/hora legível por máquina no atributo datetime . Portanto,
este é HTML5 válido:
<hora datetime="2009-10-22"></hora>
A peça final do quebra-cabeça aqui é o atributo pubdate . É um atributo booleano, então basta adicioná-lo se
precisar, assim:
O que significa o atributo pubdate ? Significa uma de duas coisas. Se o elemento <time> estiver em um elemento
<article> , significa que este carimbo de data/hora é a data de publicação do artigo. Se o elemento <time> não
estiver em um elemento <article> , significa que este carimbo de data/hora é a data de publicação de todo o
documento.
<artigo>
<cabeçalho>
<hora datetime="2009-10-22" pubdate>
22 de outubro de 2009
</time>
<h1>
<a href="#"
rel="favorito"
title="link para esta postagem">
Dia de viagem
</
a> </
h1> </
header> <p>A dor em si é importante...</
p> </article>
Navegação
Uma das partes mais importantes de qualquer site é a barra de navegação. CNN.com tem “guias” na parte
superior de cada página com links para diferentes seções de notícias – “Tecnologia”,
“Saúde”, “Esportes” etc. As páginas de resultados de pesquisa do Google têm uma faixa semelhante na
parte superior da página, permitindo que você tente sua pesquisa em diferentes serviços do Google - “Imagens”,
“Vídeo”, “Mapas” etc. E nossa página de exemplo tem uma barra de navegação no cabeçalho que inclui
links para diferentes seções de nosso site hipotético – “página inicial”, “blog”, “galeria” e “sobre”.
Novamente, este é HTML5 válido. Mas embora esteja marcada como uma lista de quatro itens, não há nada
na lista que diga que ela faz parte da navegação do site. Visualmente, você pode adivinhar isso pelo fato de
fazer parte do cabeçalho da página e pela leitura do texto dos links. Mas semanticamente, não há nada que
distinga esta lista de links de qualquer outra.
Quem se importa com a semântica da navegação no site? Por um lado, pessoas com deficiência.
Por que é que? Considere este cenário: seu movimento é limitado e usar o mouse é difícil ou impossível.
Para compensar, você pode usar um complemento do navegador que permite pular para (ou pular) os
principais links de navegação. Ou considere o seguinte: sua visão é limitada e você usa um programa
dedicado chamado “leitor de tela”, que usa conversão de texto em fala para falar e resumir páginas da web.
Depois de passar pelo título da página, as próximas informações importantes sobre uma página são os
principais links de navegação. Se quiser navegar rapidamente, você dirá ao leitor de tela para ir até a barra
de navegação e começar a ler. Se quiser navegar rapidamente, você pode dizer ao seu leitor de tela para
pular a barra de navegação e começar a ler o conteúdo principal. De qualquer forma, é importante ser capaz
de determinar links de navegação programaticamente.
Portanto, embora não haja nada de errado em usar <div id="nav"> para marcar a navegação do seu site,
também não há nada particularmente certo nisso. É abaixo do ideal de uma forma que afeta pessoas reais.
HTML5 fornece uma maneira semântica de marcar seções de navegação — o elemento <nav> :
Navegação | 51
<nav>
<ul>
<li><a href="#">página inicial</a></
li> <li><a href="#">blog</a></li>
<li>< uma href="#">galeria</a></li>
<li><a href="#">sobre</a></li> </ul>
</
nav>
Pergunte ao Professor
Markup P: Os links são ignorados? compatível com o elemento <nav> ? Ainda preciso pular links em HTML5?
R: Links para pular permitem que os leitores pulem as seções de navegação. Eles são úteis para
usuários com deficiência que usam software de terceiros para ler uma página da web em voz alta e
navegar nela sem o mouse. Saiba como e por que fornecer links para pular em http:// www.webaim.org/
techniques/ skipnav .
Depois que os leitores de tela forem atualizados para reconhecer o elemento <nav> , os links para
pular se tornarão obsoletos, uma vez que o software leitor de tela será capaz de oferecer
automaticamente para pular uma seção de navegação marcada com o elemento <nav> . No entanto,
levará um tempo até que todos os usuários deficientes na Web atualizem para um software leitor de
tela compatível com HTML5, portanto, você deve continuar a fornecer seus próprios links de pular para
pular as seções <nav> .
Rodapés
Finalmente chegamos ao final da nossa página de exemplo. A última coisa que quero falar é a última
coisa da página: o rodapé. O rodapé foi originalmente marcado assim:
<div id="footer">
<p>§</p>
<p>© 2001–9 <a href="#">Marco Peregrino</a></p> </
div>
Este é HTML5 válido. Se você gostar, pode ficar com ele. Mas o HTML5 fornece um elemento mais
específico para isso — o elemento <footer> :
<footer>
<p>§</p>
<p>© 2001–9 <a href="#">Mark Pilgrim</a></p> </
footer>
O que é apropriado colocar em um elemento <footer> ? Provavelmente o que você está colocando
em um <div id="footer"> agora. OK, essa é uma resposta circular. Mas realmente, é isso. A
especificação HTML5 diz: “Um rodapé normalmente contém informações sobre sua seção, como
quem o escreveu, links para documentos relacionados, dados de direitos autorais e assim por
diante”. Isso é o que está no rodapé desta página de exemplo: uma breve declaração de direitos
autorais e um link para uma página sobre o autor. Olhando em alguns sites populares, vejo muito potencial no rodapé:
• CNN tem um rodapé que contém uma declaração de direitos autorais, links para traduções e links para
termos de serviço, privacidade, páginas “sobre nós”, “entre em contato” e “ajuda”. Todo material
<footer> totalmente apropriado. • Google tem
uma página inicial notoriamente esparsa, mas na parte inferior dela há links para “Programas de
publicidade”, “Soluções empresariais” e “Sobre o Google”; uma declaração de direitos autorais; e um
link para a política de privacidade do Google. Tudo isso poderia ser agrupado em um <footer>.
• Meu blog tem um rodapé com links para meus outros sites, além de uma declaração de direitos autorais.
Definitivamente apropriado para um elemento <footer> . (Observe que os links em si não devem ser
agrupados em um elemento <nav> , porque não são links de navegação de site; são apenas uma
coleção de links para meus outros projetos em outros sites.)
Rodapés gordos estão na moda hoje em dia. Dê uma olhada no rodapé do site W3C. Ele contém três
colunas, denominadas “Navegação”, “Entre em contato com o W3C” e “Atualizações do W3C”.
A marcação fica assim, mais ou menos:
<div id="w3c_footer">
<div class="w3c_footer-nav">
<h3>Navegação</h3>
<ul>
<li><a href="/">Página inicial</
a></li> <li><a href="/standards/">Padrões</a></
li> <li><a href=" /participate/">Participar</a></li> <li><a
href="/Consortium/membership">Associação</a></li> <li><a
href="/Consortium/"> Sobre o W3C</a></li> </ul>
</
div>
<div class="w3c_footer-nav">
<h3>Entre em contato
com
o W3C</h3> <ul> <li><a href="/Consortium /
contact">Contato</a></li> <li><a href="/
Help/">Ajuda e perguntas frequentes</a></li>
<li><a href="/Consortium/sup" >Doe</a></li> <li><a href="/
Consortium/siteindex">Mapa
do site</a></li> </ul>
</
div> <div class="w3c_footer-nav "> <h3>Atualizações do
W3C</h3> <ul> <li><a href="http://twitter.com/W3C">Twitter</
a></
li>
<li><a href=" http://identi.ca/w3c">Identi.ca</a></
li> </ul> </div> <p class="copyright">Copyright © 2009 W3C</p> </div>
Rodapés | 53
• Converta os cabeçalhos <h3> em <h1>, já que cada um estará agora dentro de um elemento de seccionamento. O
elemento <nav> cria uma seção no esboço do documento, assim como o elemento <article> (veja “Artigos” na
página 47).
<h1>Navegação</h1>
<ul>
<li><a href="/">Página inicial</a></li>
<li><a href="/standards/">Padrões</a>< /li> <li><a href="/
participate/">Participar</a></li> <li><a href="/Consortium/
membership">Associação</a></li> <li ><a href="/Consortium/">Sobre o
W3C</a></li> </ul> </nav> <nav> <h1>Entre em contato
com o
W3C</
h1>
<ul> <li><a href ="/
<h1>Atualizações W3C</
h1> <ul>
<li><a href="http://twitter.com/W3C">Twitter</a></li> <li><a href="http://
identi.ca/w3c">Identi.ca </a></li> </ul> </section> <p
Leitura adicional
(HTML5)
Na codificação de caracteres:
• “O mínimo absoluto que todo desenvolvedor de software deve saber absolutamente e positivamente sobre Unicode
e conjuntos de caracteres (sem desculpas!)”, por Joel Spolsky • “Sobre os benefícios do Unicode”,
• “Ativando modos de navegador com Doctype”, por Henri Sivonen. Este é o único artigo que você deve ler sobre o
assunto. Existem muitos outros artigos, mas estão desatualizados, incompletos ou errados.
Leitura adicional | 55
CAPÍTULO 4
Mergulhando
HTML5 define o elemento <canvas> como “uma tela de bitmap dependente de resolução que
pode ser usado para renderizar gráficos, gráficos de jogos ou outras imagens visuais em tempo real.” A
canvas é um retângulo em sua página no qual você pode usar JavaScript para desenhar qualquer coisa
você quer. A tabela a seguir mostra quais navegadores oferecem suporte básico a canvas no
momento desta redação:
Então, como é uma tela? Nada realmente. Um elemento <canvas> não tem conteúdo
e nenhuma fronteira própria. A marcação fica assim:
A Figura 4-1 mostra a tela com uma borda pontilhada para que possamos ver com o que estamos lidando.
Você pode ter vários elementos <canvas> na mesma página. Cada tela aparecerá
no DOM, e cada canvas mantém seu próprio estado. Se você der um ID para cada tela
atributo, você pode acessá-los como faria com qualquer outro elemento.
57
Formas Simples
Cada tela começa em branco. Isto é chato! Vamos desenhar algo. Você pode usar o
manipulador onclick para chamar uma função que desenha um retângulo (veja http:// diveintohtml5.org/
tela.html para um exemplo interativo):
função desenhar_b() {
var b_canvas = document.getElementById("b");
var b_context = b_canvas.getContext("2d");
b_context.fillRect(50, 25, 150, 100);
}
A primeira linha da função não tem nada de especial; apenas encontra o elemento <canvas> no
DOM. A segunda linha é onde fica mais interessante. Cada tela tem um desenho
contexto, que é onde toda a diversão acontece. Depois de encontrar um elemento <canvas>
no DOM (usando document.getElementById() ou qualquer outro método de sua preferência), você
pode chamar seu método getContext() . Você deve passar a string "2d" para getContext()
método:
função desenhar_b() {
var b_canvas = document.getElementById("b");
var b_context = b_canvas.getContext("2d");
b_context.fillRect(50, 25, 150, 100);
}
R: Ainda não. Fornecedores individuais experimentaram suas próprias APIs de tela tridimensionais,
mas nenhuma foi padronizada. A especificação HTML5 observa: “Uma versão futura desta
especificação provavelmente definirá um contexto 3D”.
Então, você tem um elemento <canvas> e seu contexto de desenho. O contexto do desenho é
onde todos os métodos e propriedades do desenho são definidos. Há todo um grupo de
propriedades e métodos dedicados ao desenho de retângulos:
• A propriedade fillStyle pode ser uma cor CSS, um padrão ou um gradiente. (Mais sobre
gradientes em breve.) O fillStyle padrão é preto sólido, mas você pode configurá-lo como
quiser. Cada contexto de desenho lembra suas próprias propriedades enquanto a página
estiver aberta, a menos que você faça algo para redefini-la.
• fillRect(x, y, width, height) desenha um retângulo preenchido com o estilo de preenchimento
atual. • A propriedade strokeStyle é como fillStyle — pode ser uma cor CSS, um padrão ou um
gradiente.
• strokeRect(x, y, width, height) desenha um retângulo com o estilo de traço atual. strokeRect
não preenche o meio; apenas desenha as bordas.
• clearRect(x, y, width, height) limpa os pixels no retângulo especificado.
R: Sim. Definir a largura ou altura de um elemento <canvas> apagará seu conteúdo e redefinirá
todas as propriedades de seu contexto de desenho para seus valores padrão. Você nem precisa
alterar a largura; você pode simplesmente configurá-lo para seu valor atual, assim:
Formas Simples | 59
Coordenadas da tela
A tela é uma grade bidimensional. A coordenada (0, 0) está no canto superior esquerdo da tela. Ao
longo do eixo x, os valores aumentam em direção à borda direita da tela.
Ao longo do eixo y, os valores aumentam em direção à borda inferior da tela.
O diagrama de coordenadas na Figura 4-2 foi desenhado com um elemento <canvas> . Compreende:
• Um conjunto de linhas verticais esbranquiçadas
• A letra “y” • O
texto “(0, 0)” próximo ao canto superior esquerdo • O
texto “(500, 375)” próximo ao canto inferior direito • Um ponto
no canto superior esquerdo e outro no canto inferior direito
Nas seções a seguir, exploraremos como criar o efeito mostrado nesta figura.
Primeiro, precisamos definir o próprio elemento <canvas> . O elemento <canvas> define o
largura e altura do retângulo, e o id para que possamos encontrá-lo mais tarde:
Então precisamos de um script para encontrar o elemento <canvas> no DOM e obter seu desenho
contexto:
Caminhos
Imagine que você está desenhando uma imagem com tinta. Você não quer simplesmente mergulhar e
começar a desenhar, porque pode cometer um erro. Em vez disso, você esboça as linhas e curvas com
um lápis e, quando estiver satisfeito com ele, você traça seu esboço com tinta.
Cada tela tem um caminho. Definir o caminho é como desenhar com um lápis. Você pode desenhar
o que você quiser, mas não fará parte do produto final até que você pegue o
pena e trace seu caminho com tinta.
Para desenhar linhas retas a lápis, você usa os dois métodos a seguir:
Quanto mais você chama moveTo() e lineTo(), maior fica o caminho. Estes são “lápis”
métodos - você pode chamá-los quantas vezes quiser, mas não verá nada no
canvas até você chamar um dos métodos “ink”.
Caminhos | 61
Todos esses eram métodos de “lápis”. Na verdade, nada foi desenhado na tela ainda.
Precisamos de um método de “tinta” para torná-lo permanente:
context.strokeStyle = "#eee";
contexto.stroke();
acidente vascular cerebral() é um dos métodos de “tinta”. Ele pega o caminho complexo que você definiu
com todas as chamadas moveTo() e lineTo() e realmente o desenha na tela. O strokeStyle controla a cor
das linhas. A Figura 4-3 mostra o resultado.
R: Imagine cada pixel como um grande quadrado. As coordenadas de números inteiros (0, 1, 2...) são as
arestas dos quadrados. Se você desenhar uma linha de uma unidade de largura entre coordenadas de
números inteiros, ela se sobreporá aos lados opostos do quadrado de pixels e a linha resultante será
desenhada com dois pixels de largura. Para desenhar uma linha com apenas um pixel de largura, você
precisa deslocar as coordenadas em 0,5 perpendicularmente à direção da linha.
Agora vamos desenhar a seta horizontal. Todas as linhas e curvas em um caminho são desenhadas
a mesma cor (ou gradiente – sim, falaremos disso em breve). Queremos desenhar a seta
em uma tinta de cor diferente – preta em vez de esbranquiçada – então precisamos iniciar um novo caminho:
context.beginPath();
contexto.moveTo(0, 40);
contexto.lineTo(240, 40);
contexto.moveTo(260, 40);
contexto.lineTo(500, 40);
contexto.moveTo(495, 35);
contexto.lineTo(500, 40);
contexto.lineTo(495, 45);
A seta vertical parece praticamente a mesma. Como a seta vertical é da mesma cor que
seta horizontal, não precisamos iniciar outro novo caminho. As duas setas irão
fazer parte do mesmo caminho:
contexto.moveTo(60, 0);
contexto.lineTo(60, 153);
contexto.moveTo(60, 173);
contexto.lineTo(60, 375);
contexto.moveTo(65, 370);
contexto.lineTo(60, 375);
contexto.lineTo(55, 370);
Eu disse que essas setas seriam pretas, mas o strokeStyle ainda está esbranquiçado. (O
fillStyle e strokeStyle não são redefinidos quando você inicia um novo caminho.) Tudo bem,
porque acabamos de executar uma série de métodos “lápis”. Mas antes de desenhá-lo de verdade, em
“ink”, precisamos definir o strokeStyle como preto. Caso contrário, essas duas setas ficarão esbranquiçadas e
dificilmente conseguiremos vê-las! As linhas a seguir mudam a cor para
preto e desenhe as linhas na tela:
context.strokeStyle = "#000";
contexto.stroke();
Texto
Além de desenhar linhas em uma tela, você também pode desenhar texto em uma tela. Diferente
texto na página da web ao redor, não há modelo de caixa. Isso significa que nenhum dos
técnicas familiares de layout CSS estão disponíveis: sem pontos flutuantes, sem margens, sem preenchimento, sem
quebra de palavras. (Talvez você ache que isso é uma coisa boa!) Você pode definir alguns atributos de fonte e,
em seguida, escolher um ponto na tela e desenhar seu texto ali.
Texto | 63
• fonte pode ser qualquer coisa que você colocaria em uma regra de fonte CSS . Isso inclui estilo de fonte,
variante da fonte, espessura da fonte, tamanho da fonte, altura da linha e família da fonte.
• textAlign controla o alinhamento do texto. É semelhante (mas não idêntico) a uma regra de
alinhamento de texto CSS . Os valores possíveis são início, fim, esquerda, direita
e centro. • textBaseline controla onde o texto é desenhado em relação ao ponto inicial. Os
valores possíveis são superior, suspenso, intermediário, alfabético, ideográfico e inferior.
textBaseline é complicado, porque o texto é complicado. (Bem, o texto em inglês não é complicado, mas você pode
desenhar qualquer caractere Unicode que desejar em uma tela, e o Unicode é complicado.) A especificação HTML5
explica as diferentes linhas de base do texto:*
A parte superior do quadrado em está aproximadamente no topo dos glifos em uma fonte, a linha de base suspensa é onde alguns
glifos como estão ancorados, o meio está a meio caminho entre o topo do quadrado em e a parte inferior do quadrado em, a linha de
base alfabética é onde caracteres como Á, ÿ, f e ÿ estão ancorados, a linha de base ideográfica é onde glifos como ÿ e ÿ estão
ancorados, e a parte inferior do quadrado em está aproximadamente na parte inferior dos glifos em uma fonte. A parte superior e
inferior da caixa delimitadora podem estar distantes dessas linhas de base, devido aos glifos que se estendem muito além do
quadrado em (veja a Figura 4-5 ).
Para alfabetos simples como o inglês, você pode usar com segurança o topo, o meio ou o fundo para
a propriedade textBaseline .
Vamos desenhar um texto! O texto desenhado dentro da tela herda o tamanho e o estilo da fonte
o próprio elemento <canvas> , mas você pode substituir isso definindo a propriedade font como
o contexto do desenho:
context.font = "negrito 12px sem
serifa"; context.fillText("x", 248, 43);
context.fillText("o", 58, 165);
P: Posso usar tamanhos de fonte relativos para desenhar texto em uma tela?
R: Sim. Como qualquer outro elemento HTML da sua página, o próprio elemento <canvas> possui
um tamanho de fonte calculado com base nas regras CSS da sua página. Se você definir a propriedade context.font
para um tamanho de fonte relativo como 1,5em ou 150%, seu navegador multiplicará isso pelo tamanho de fonte
calculado do próprio elemento <canvas> .
Para o texto no canto superior esquerdo, digamos que queremos que o topo do texto esteja em y=5. Mas
somos preguiçosos – não queremos medir a altura do texto e calcular a linha de base.
Em vez disso, podemos definir textBaseline como top e passar a coordenada superior esquerda do
caixa delimitadora do texto:
context.textBaseline = "topo";
context.fillText("(0 0)", 8,, 5);
Texto | 65
Agora, para o texto no canto inferior direito. Digamos que queremos o canto inferior direito
do texto esteja nas coordenadas (492.370) - a apenas alguns pixels do canto inferior direito da tela -
mas, novamente, não queremos medir a largura ou a altura
do texto. Podemos definir textAlign como right e textBaseline como bottom e então chamar
fillText() pelas coordenadas inferiores direitas da caixa delimitadora do texto:
context.textAlign = "direita";
context.textBaseline = "inferior";
, 492, 370);
context.fillText("(500 375)",
Ops! Esquecemos os pontos nos cantos. Veremos como desenhar círculos um pouco mais tarde; para
agora vamos trapacear um pouco e desenhá-los como retângulos (veja “Formas Simples” na página 58):
contexto.fillRect(0, 0, 3, 3);
contexto.fillRect(497, 372, 3, 3);
E foi tudo o que ela escreveu! A Figura 4-7 mostra o produto final.
Gradientes
Anteriormente neste capítulo, você aprendeu como desenhar um retângulo preenchido com uma cor sólida (veja
“Formas Simples” na página 58), depois uma linha traçada com uma cor sólida (consulte
“Caminhos” na página 61). Mas as formas e linhas não se limitam às cores sólidas. Você pode fazer tudo
tipos de magia com gradientes. A Figura 4-8 mostra um exemplo.
Gradientes | 67
gradientes: • createLinearGradient(x0, y0, x1, y1) pinta ao longo de uma linha de (x0, y0) até
(x1, y1).
• createRadialGradient(x0, y0, r0, x1, y1, r1) pinta ao longo de um cone entre dois círculos.
Os três primeiros parâmetros representam o círculo inicial, com origem (x0, y0) e raio
r0. Os últimos três parâmetros representam o círculo final, com origem (x1, y1) e raio
r1.
Vamos fazer um gradiente linear. Os gradientes podem ter qualquer tamanho, mas faremos esse gradiente com
300 pixels de largura, como a tela:
Como os valores de y (o segundo e o quarto parâmetros) são ambos 0, esse gradiente será sombreado
uniformemente da esquerda para a direita.
Assim que tivermos um objeto gradiente, podemos definir as cores do gradiente. Um gradiente tem duas ou
mais interrupções de cor. As paradas de cor podem estar em qualquer lugar ao longo do gradiente. Para
adicionar uma parada de cor, você precisa especificar sua posição ao longo do gradiente. As posições do
gradiente podem estar em qualquer lugar entre 0 e 1.
my_gradient.addColorStop(0, "preto");
my_gradient.addColorStop(1, "branco");
Definir um gradiente não desenha nada na tela. É apenas um objeto guardado em algum lugar na memória.
Para desenhar um gradiente, você define fillStyle como gradiente e desenha uma forma, como um retângulo ou
uma linha:
context.fillStyle = meu_gradiente;
contexto.fillRect(0, 0, 300, 225);
Suponha que você queira um gradiente que sombreie de cima para baixo. Ao criar o objeto
gradiente, mantenha os valores x (o primeiro e o terceiro parâmetros) constantes e faça os valores
y (o segundo e o quarto parâmetros) variarem de 0 até a altura da tela:
var meu_gradiente = context.createLinearGradient(0, 0, 0, 225);
my_gradient.addColorStop(0, "preto");
my_gradient.addColorStop(1, "branco");
context.fillStyle = meu_gradiente;
contexto.fillRect(0, 0, 300, 225);
Gradientes | 69
Você também pode criar gradientes ao longo de uma diagonal. Por exemplo:
Imagens
O contexto de desenho da tela define vários métodos para desenhar uma imagem em uma tela: •
drawImage(image, dx, dy) pega uma imagem e a desenha na tela. As coordenadas fornecidas (dx,
dy) serão o canto superior esquerdo da imagem. As coordenadas (0, 0) desenhariam a imagem
no canto superior esquerdo da tela.
• drawImage(image, dx, dy, dw, dh) pega uma imagem, dimensiona-a para uma largura de dw e um
altura de dh e desenha-o na tela nas coordenadas (dx, dy).
• drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) pega uma imagem, recorta-a no retângulo (sx,
sy, sw, sh), dimensiona-a para dimensões (dw, dh), e desenha na tela nas coordenadas (dx, dy).
Para desenhar uma imagem em uma tela, você precisa de uma imagem. A imagem pode ser um
elemento <img> existente ou você pode criar um objeto Image com JavaScript. De qualquer forma,
você precisa garantir que a imagem esteja totalmente carregada antes de desenhá-la na tela.
Se estiver usando um elemento <img> existente , você pode desenhá-lo com segurança na tela
durante o evento window.onload :
0); }; </script>
Imagens | 71
Figura 4-14. Como drawImage() mapeia uma imagem para uma tela
Se você estiver criando o objeto de imagem inteiramente em JavaScript, poderá desenhar a imagem
com segurança na tela durante o evento Image.onload :
<canvas id="e" width="177" height="113"></canvas>
<script>
var canvas = document.getElementById("e");
var contexto = canvas.getContext("2d");
var gato = nova
imagem(); cat.src = "imagens/
cat.png"; cat.onload =
function() { context.drawImage(cat,
0, 0); }; </script>
uma única tela: Aqui está o script que produz o efeito “multicat”:
cat.onload = function() { for
(var x = 0, y = 0; x <
500 && y < 375; x
+= 50, y += 37)
{ context.drawImage(cat, x, y, 88 , 56);
} };
Todo esse esforço levanta uma questão legítima: por que você iria querer desenhar uma imagem
em uma tela? O que a complexidade extra traz para você em relação a um elemento <img> e
algumas regras CSS? Até mesmo o efeito “multicat” poderia ser replicado com 10 elementos
<img> sobrepostos .
A resposta simples é que você faria isso pelo mesmo motivo pelo qual deseja desenhar texto
em uma tela (consulte “Texto” na página 63). Nosso diagrama de coordenadas da tela (consulte
“Coordenadas da tela” na página 60) incluía texto, linhas e formas; o elemento texto em tela era
apenas uma parte de um trabalho maior. Um diagrama mais complexo poderia facilmente usar
drawImage() para incluir ícones, sprites ou outros gráficos.
E quanto ao IE?
O Microsoft Internet Explorer (até a versão 8 inclusive, a versão atual no momento em que este
artigo foi escrito) não oferece suporte à API canvas. No entanto, o Internet Explorer suporta uma
tecnologia proprietária da Microsoft chamada VML, que pode fazer muitas das mesmas coisas
que o elemento <canvas> . E assim nasceu o excanvas.js .
E quanto ao IE? | 73
ExplorerCanvas — excanvas.js — é uma biblioteca JavaScript de código aberto licenciada pelo Apache
que implementa a API canvas no Internet Explorer. Para usá-lo, inclua o seguinte elemento <script>
no topo da sua página:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Mergulhe no HTML 5</title>
<!--[if IE]>
<script src="excanvas.js"></script> <!
[endif]- -> </
head>
<body>
...
</body>
</html>
Os bits <!--[if IE]> e <![endif]--> são comentários condicionais. O Internet Explorer os interpreta como
uma instrução if : “se o navegador atual for qualquer versão do Internet Explorer, execute este bloco”.
Todos os outros navegadores tratarão o bloco inteiro como um comentário HTML. O resultado líquido
é que o Internet Explorer baixará o script excan vas.js e o executará, mas outros navegadores irão
ignorar o script completamente (não baixá-lo, não executá-lo, nada). Isso faz com que sua página
carregue mais rápido em navegadores que implementam a API canvas nativamente.
Depois de incluir o script excanvas.js no <head> da sua página, você não precisa fazer mais nada
para acomodar o Internet Explorer. Você pode simplesmente adicionar elementos <canvas> à sua
marcação ou criá-los dinamicamente com JavaScript. Siga as instruções deste capítulo para obter o
contexto de desenho de um elemento <canvas> e você poderá desenhar formas, texto e padrões.
• Gradientes (consulte “Gradientes” na página 67) só podem ser lineares. Gradientes radiais não são
suportado. •
Os padrões devem se repetir em ambas as direções. •
Regiões de recorte não são suportados. •
Escala não uniforme não dimensiona corretamente os traços. • É
lento. Isso não deveria ser um grande choque para ninguém, já que o analisador de JavaScript do
Internet Explorer é mais lento do que o de outros navegadores, para começar. Quando você
começa a desenhar formas complexas por meio de uma biblioteca JavaScript que traduz
comandos para uma tecnologia completamente diferente, as coisas ficam paralisadas. Você não
notará a degradação do desempenho em exemplos simples, como desenhar algumas linhas e
transformar uma imagem, mas verá isso imediatamente quando começar a fazer animações
baseadas em tela e outras coisas malucas.
Há mais uma ressalva sobre o uso do excanvas.js, e é um problema que encontrei ao criar os exemplos
neste capítulo. ExplorerCanvas inicializa sua própria interface de tela falsa automaticamente sempre que
você inclui o script excanvas.js em sua página HTML. Mas isso não significa que o Internet Explorer esteja
pronto para usá-lo imediatamente.
Em certas situações, você pode entrar em uma condição de corrida em que a interface de tela falsa está
quase, mas não totalmente, pronta para uso. O principal sintoma desse estado é que o Internet Explorer
reclamará que “o objeto não suporta esta propriedade ou método” sempre que você tentar fazer qualquer
coisa com um elemento <canvas> , como obter seu contexto de desenho.
A solução mais fácil para isso é adiar toda a manipulação relacionada ao canvas até que o evento onload
seja acionado. Isso pode demorar um pouco – se sua página tiver muitas imagens ou vídeos, eles atrasarão
o evento onload – mas dará ao ExplorerCanvas tempo para fazer sua mágica.
jogo de tabuleiro centenário. Existem muitas variações. Neste exemplo, criei uma versão solitária do Halma
com nove peças em um tabuleiro 9 × 9. No início do jogo, as peças formam um quadrado 3 × 3 no canto
inferior esquerdo do tabuleiro. O objetivo do jogo é mover todas as peças de forma que formem um quadrado
3 × 3 no canto superior direito do tabuleiro, no menor número possível de movimentos.
• Pegue uma peça e mova-a para qualquer quadrado vazio adjacente. Um quadrado “vazio” é aquele que
atualmente não contém nenhuma peça. Um quadrado “adjacente” está imediatamente ao norte, sul,
leste, oeste, noroeste, nordeste, sudoeste ou sudeste da posição atual da peça. (O tabuleiro não gira
de um lado para o outro. Se uma peça estiver na coluna mais à esquerda, ela não poderá se mover
para oeste, noroeste ou sudoeste. Se uma peça estiver na linha inferior, ela não poderá se mover para
sul, sudeste ou sudoeste. sudoeste.)
• Pegue uma peça e pule sobre uma peça adjacente e, possivelmente, repita. Ou seja, se você pular uma
peça adjacente e depois pular outra peça adjacente à sua nova posição, isso contará como um único
movimento. Na verdade, qualquer número de saltos ainda conta como um único movimento. (Como o
objetivo é minimizar o número total de movimentos, ter um bom desempenho no Halma envolve construir
e depois usar longas cadeias de peças escalonadas para que outras peças possam pular sobre elas
em longas sequências.)
A Figura 4-16 é uma captura de tela do jogo em si; você também pode jogar online se você quiser mexer
nisso com as ferramentas de desenvolvedor do seu navegador.
Então, como isso funciona? Estou tão feliz que você perguntou. Não mostrarei todo o código aqui (você pode
vê-lo em http:// diveintohtml5.org/ examples/ halma.js). Irei pular a maior parte do código do jogo em si, mas
quero destacar algumas partes do código que tratam do desenho na tela e da resposta aos cliques do mouse
no elemento <canvas> .
Um exemplo completo | 75
gCanvasElement.width = kPixelWidth;
gCanvasElement.height = kPixelHeight;
gDrawingContext = gCanvasElement.getContext("2d");
Em seguida, fazemos algo que você ainda não viu: adicionamos um ouvinte de evento ao elemento
<canvas> para escutar eventos de clique:
A função halmaOnClick() é chamada quando o usuário clica em qualquer lugar da tela. Seu argumento
é um objeto MouseEvent que contém informações sobre onde o usuário clicou:
função halmaOnClick(e)
{ var célula = getCursorPosition(e);
} clickOnEmptyCell(célula);
}
A próxima etapa é pegar o objeto MouseEvent e calcular qual quadrado do quadro Halma acabou de
ser clicado. O quadro Halma ocupa toda a tela, então cada clique ocorre em algum lugar do quadro. Só
precisamos descobrir onde. Isso é complicado porque os eventos do mouse são implementados de
maneira diferente em praticamente todos os navegadores:
function getCursorPosition(e) { var
x;
variar;
if (e.páginaX || e.páginaY)
{x=
e.páginaX; y
=
e.páginaY; } else { x = e.clientX +
document.body.scrollLeft +
document.documentElement.scrollLeft; y =
e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
Neste ponto, temos coordenadas xey relativas ao documento (ou seja, a página HTML inteira). Mas
queremos coordenadas relativas à tela. Podemos obtê-los da seguinte forma:
x -= gCanvasElement.offsetLeft; y
-= gCanvasElement.offsetTop;
Agora temos coordenadas x e y relativas à tela (consulte “Coordenadas da tela” na página 60). Ou
seja, se x for 0 e y for 0 neste ponto, sabemos que o usuário acabou de clicar no pixel superior esquerdo
da tela.
A partir daqui, podemos calcular em qual quadrado Halma o usuário clicou e agir de acordo:
Uau! Eventos de mouse são difíceis. Mas você pode usar a mesma lógica (na verdade, esse código
exato) em todos os seus próprios aplicativos baseados em canvas. Lembre-se: clique do
mouseÿcoordenadas relativas do documentoÿcoordenadas relativas à telaÿcódigo específico do aplicativo.
OK, vamos dar uma olhada na rotina principal de desenho. Como os gráficos são tão simples, optei por
limpar e redesenhar o tabuleiro por completo sempre que alguma coisa mudar no jogo. Isto não é
estritamente necessário. O contexto de desenho da tela manterá tudo o que
Um exemplo completo | 77
você já desenhou nela, mesmo que o usuário role a tela para fora da visualização ou mude para outra
guia e volte mais tarde. Se estiver desenvolvendo um aplicativo baseado em tela com gráficos mais
complicados (como um jogo de arcade), você poderá otimizar o desempenho rastreando quais regiões
da tela estão “sujas” e redesenhando apenas as regiões sujas. Mas isso está fora do escopo deste livro.
Aqui está o código de compensação do quadro:
gDrawingContext.clearRect(0, 0, kPixelWidth, kPixelHeight);
A rotina de desenho do quadro deve parecer familiar. É muito semelhante ao modo como desenhamos
o diagrama de coordenadas do canvas (veja “Coordenadas do Canvas” na página
60): gDrawingContext.beginPath();
/* linhas verticais */
for (var x = 0; x <= kPixelWidth; x += kPieceWidth)
{ gDrawingContext.moveTo(0.5 + x,
0); gDrawingContext.lineTo(0,5 + x, kPixelHeight);
}
/* linhas horizontais */
for (var y = 0; y <= kPixelHeight; y += kPieceHeight)
{ gDrawingContext.moveTo(0, 0.5 +
y); gDrawingContext.lineTo(kPixelWidth, 0,5 + y);
}
/* desenhe
isso! */ gDrawingContext.strokeStyle =
"#ccc"; gDrawingContext.stroke();
A verdadeira diversão começa quando vamos desenhar cada uma das peças individuais. Uma peça é
um círculo, algo que não desenhamos antes. Além disso, se o usuário selecionar uma peça antes de
movê-la, desejaremos desenhar essa peça como um círculo preenchido. Aqui, o argumento p representa
uma peça, que possui propriedades de linha e coluna que indicam a localização atual da peça no
tabuleiro. Usamos algumas constantes do jogo para traduzir (coluna, linha) em coordenadas relativas à
tela (x, y) , depois desenhamos um círculo e (se a peça estiver selecionada) preenchemos
no círculo com uma cor sólida:
função drawPiece (p, selecionado)
{ var coluna = p.coluna;
var linha = p.linha;
var x = (coluna * kPieceWidth) + (kPieceWidth/2); var
y = (linha * kPieceHeight) + (kPieceHeight/2); var raio
= (kPieceWidth/2) - (kPieceWidth/10);
Esse é o fim da lógica específica do jogo. Agora temos coordenadas (x, y) , relativas à tela, para o centro
do círculo que queremos desenhar. Não existe um método circle() na API canvas, mas existe um método
arc() . E realmente, o que é um círculo senão um arco que percorre toda a volta? Você se lembra da sua
geometria básica? O método arc() usa um ponto central (x, y), um raio, um ângulo inicial e final (em
radianos) e um sinalizador de direção (falso para sentido horário, verdadeiro para sentido anti-horário).
Podemos usar o módulo Math integrado ao JavaScript para calcular radianos:
gDrawingContext.beginPath();
gDrawingContext.arc(x, y, raio, 0, Math.PI * 2, falso);
gDrawingContext.closePath();
Mas espere! Nada foi desenhado ainda. Assim como moveTo() e lineTo(), o método arc() é um
método “lápis” (consulte “Caminhos” na página 61). Para realmente desenhar o círculo, precisamos
definir o StrokeStyle e chamar Stroke() para traçá-lo em “ink”:
gDrawingContext.strokeStyle = "#000";
gDrawingContext.stroke();
E se a peça for selecionada? Podemos reutilizar o mesmo caminho que criamos para desenhar o
contorno da peça e preencher o círculo com uma cor sólida:
if (selecionado)
{ gDrawingContext.fillStyle = "#000";
gDrawingContext.fill();
}
E isso é... bem, é basicamente isso. O resto do programa é uma lógica específica do jogo – distinguir
entre movimentos válidos e inválidos, acompanhar o número de movimentos, detectar se o jogo
acabou. Com nove círculos, algumas linhas retas e um manipulador onclick , criamos um jogo inteiro
em <canvas>. Huzah!
Leitura adicional
• Tutorial de tela no Mozilla Developer Center • “HTML5
canvas – o básico”, por Mihai Sucan • Demonstrações
de telas: demonstrações, ferramentas e tutoriais para o elemento HTML <canvas> • “O
elemento canvas ” no rascunho do padrão HTML5
Leitura adicional | 79
CAPÍTULO 5
Vídeo na Web
Mergulhando
Qualquer pessoa que tenha visitado o YouTube.com nos últimos quatro anos sabe que é possível incorporar
vídeo em uma página da web. Mas antes do HTML5, não havia uma maneira baseada em padrões de fazer isso.
Praticamente todos os vídeos que você já assistiu “na Web” foram canalizados
um plug-in de terceiros – talvez QuickTime, talvez RealPlayer, talvez Flash. (YouTube
usa Flash.) Esses plug-ins se integram ao seu navegador bem o suficiente para que você não
até mesmo esteja ciente de que você os está usando - até tentar assistir a um vídeo em uma plataforma
isso não suporta esse plug-in, claro.
HTML5 define uma forma padrão de incorporar vídeo em uma página web, usando um elemento <video> .
O suporte para o elemento <video> ainda está evoluindo, o que é uma forma educada de dizer que não.
ainda funciona (pelo menos não funciona em todos os lugares). Mas não se desespere! Existem alternativas
e substitutos e opções em abundância. A Tabela 5-1 mostra quais navegadores suportam o
Elemento <video> no momento da escrita.
IE9 IE8 IE7 Raposa de fogo Raposa de fogo Safári 4 Safári 3 cromada Ópera
3.5 3,0
ÿ · · ÿ · ÿ ÿ ÿ ÿ
O suporte para o elemento <video> em si é apenas uma pequena parte da história. Antes de nós
Para falar sobre vídeo HTML5, primeiro você precisa entender um pouco sobre o vídeo em si.
(Se você já conhece o vídeo, pode pular para “O que funciona no
Web” na página 88.)
Contêineres de vídeo
Você pode pensar nos arquivos de vídeo como “arquivos AVI” ou “arquivos MP4”. Na realidade, “AVI” e “MP4”
são apenas formatos de contêiner. Assim como um arquivo ZIP pode conter qualquer tipo de arquivo, o vídeo
81
os formatos de contêiner definem apenas como armazenar coisas dentro deles, não que tipo de dados
são armazenados. (É um pouco mais complicado do que isso, porque nem todos os streams de vídeo
são compatíveis com todos os formatos de contêiner, mas não importa por enquanto.)
Um arquivo de vídeo geralmente contém múltiplas trilhas: uma trilha de vídeo (sem áudio), mais uma ou
mais trilhas de áudio (sem vídeo). As faixas geralmente estão inter-relacionadas. Uma trilha de áudio
contém marcadores para ajudar a sincronizar o áudio com o vídeo. Trilhas individuais podem ter
metadados, como a proporção de uma trilha de vídeo ou o idioma de uma trilha de áudio. Os contêineres
também podem ter metadados, como o título do vídeo em si, a capa do vídeo, os números dos episódios
(para programas de televisão) e assim por diante.
Existem muitos formatos de contêiner de vídeo. Alguns dos mais populares incluem:
MPEG-4
Geralmente com extensão .mp4 ou .m4v . O contêiner MPEG-4 é baseado no contêiner QuickTime
mais antigo da Apple (.mov). Trailers de filmes no site da Apple ainda usa o contêiner QuickTime
mais antigo, mas os filmes que você aluga no iTunes são entregues em um contêiner MPEG-4.
Vídeo instantâneo
Geralmente com uma extensão .flv . Flash Video é, sem surpresa, usado pelo Adobe Flash.
Antes do Flash 9.0.60.184 (também conhecido como Flash Player 9 Update 3), esse era o único
formato de contêiner compatível com o Flash. Versões mais recentes do Flash também suportam
o contêiner MPEG-4.
Ogg
Geralmente com extensão .ogv . Ogg é um padrão aberto, compatível com código aberto e livre de
quaisquer patentes conhecidas. Firefox 3.5, Chrome 4 e Opera 10.5 oferecem suporte nativo, sem
plug-ins específicos de plataforma, para o formato contêiner Ogg, vídeo Ogg (chamado “Theora”)
e áudio Ogg (chamado “Vorbis”).
No desktop, o Ogg é compatível com todas as principais distribuições Linux, e você pode usá-lo
no Mac e no Windows instalando os componentes do QuickTime . ou filtros DirectShow,
respectivamente. Também é jogável com o excelente VLC em todas as plataformas.
WebM
Com uma extensão .webm . WebM é um novo formato de contêiner tecnicamente muito semelhante
a outro formato chamado Matroska. WebM foi anunciado no Google I/O 2010. Ele foi projetado
para ser usado exclusivamente com o codec de vídeo VP8 e o codec de áudio Vorbis. (Mais sobre
isso em um minuto.) Ele terá suporte nativo, sem plug-ins específicos de plataforma, nas próximas
versões do Chromium, Google Chrome, Mozilla Firefox e Opera. A Adobe também anunciou que a
próxima versão do Flash suportará vídeo WebM.
Intercalação de áudio e
vídeo Geralmente com uma extensão .avi . O formato contêiner AVI foi inventado pela Micro soft
em uma época mais simples, quando o fato de os computadores poderem reproduzir vídeo era
considerado incrível. Ele não suporta oficialmente muitos dos recursos do
formatos de contêiner mais recentes. Não oferece suporte oficial a nenhum tipo de metadado de
vídeo. Ele nem sequer oferece suporte oficial à maioria dos codecs modernos de vídeo e áudio em
uso atualmente. Com o tempo, várias empresas tentaram estendê-lo de maneiras geralmente
incompatíveis para suportar isto ou aquilo, e ainda é o formato de contêiner padrão para codificadores
populares como o MEncoder.
Codecs de vídeo
Quando você fala em “assistir a um vídeo”, provavelmente está falando sobre uma combinação de um
fluxo de vídeo e um fluxo de áudio. Mas você não tem dois arquivos diferentes; você só tem “o vídeo”.
Talvez seja um arquivo AVI ou MP4. Conforme descrito na seção anterior, esses são apenas formatos
de contêiner, como um arquivo ZIP que contém vários tipos de arquivos. O formato contêiner define como
armazenar os fluxos de vídeo e áudio em um único arquivo.
Quando você “assiste a um vídeo”, seu player de vídeo faz várias coisas ao mesmo tempo:
• Interpretar o formato do contêiner para descobrir quais faixas de vídeo e áudio estão disponíveis e
como elas são armazenadas no arquivo para que ele possa encontrar os dados necessários para
decodificar em seguida
• Decodificar o fluxo de vídeo e exibir uma série de imagens na tela • Decodificar o fluxo de
áudio e enviar o som para seus alto-falantes
Um codec de vídeo é um algoritmo pelo qual um fluxo de vídeo é codificado. Ou seja, especifica como
fazer o item 2 acima. (A palavra “codec” é uma mala de viagem, uma combinação das palavras
“codificador” e “decodificador”.) Seu reprodutor de vídeo decodifica o fluxo de vídeo de acordo com o
codec de vídeo e, em seguida, exibe uma série de imagens, ou “quadros”, na tela. A maioria dos codecs
de vídeo modernos usa todos os tipos de truques para minimizar a quantidade de informações necessárias
para exibir um quadro após o outro. Por exemplo, em vez de armazenar cada quadro individual (como
capturas de tela), eles armazenam apenas as diferenças entre os quadros. A maioria dos vídeos não
muda muito de um quadro para outro, então isso permite altas taxas de compactação, o que resulta em
tamanhos de arquivo menores.
Existem codecs de vídeo com e sem perdas . O vídeo sem perdas é grande demais para ser útil na Web,
então vou me concentrar nos codecs com perdas. Com um codec de vídeo com perdas, as informações
são irremediavelmente perdidas durante a codificação. Assim como copiar uma fita cassete de áudio,
toda vez que você codifica, você perde informações sobre o vídeo de origem e degrada a qualidade.
Em vez do “silvo” de uma fita cassete, um vídeo re-recodificado pode parecer bloqueado, especialmente
durante cenas com muito movimento. (Na verdade, isso pode acontecer mesmo se você codificar
diretamente da fonte original, se você escolher um codec de vídeo ruim ou passar o conjunto errado de
parâmetros.) Pelo lado positivo, os codecs de vídeo com perdas podem oferecer taxas de compactação
incríveis e muitos oferecem maneiras para “trapacear” e suavizar esse bloqueio durante a reprodução
para tornar a perda menos perceptível ao olho humano.
Codecs de vídeo | 83
Existem muitos codecs de vídeo. Os três codecs mais relevantes são H.264, Theora e VP8.
H.264
H.264 também é conhecido como “MPEG-4 parte 10”, também conhecido como “MPEG-4 AVC”, também
conhecido como “MPEG-4 Advanced Video Coding”. H.264 foi desenvolvido pelo grupo MPEG e
padronizado em 2003. Tem como objetivo fornecer um codec único para dispositivos de baixa largura de
banda e baixa CPU (telefones celulares); dispositivos de alta largura de banda e alta CPU (computadores
desktop modernos); e tudo mais. Para conseguir isso, o padrão H.264 é dividido em “perfis”, cada um
definindo um conjunto de recursos opcionais que trocam complexidade por tamanho de arquivo. Perfis
mais altos usam mais recursos opcionais, oferecem melhor qualidade visual em arquivos menores,
demoram mais para codificar e exigem mais potência da CPU para decodificar em tempo real.
Para lhe dar uma ideia aproximada da variedade de perfis, o iPhone da Apple suporta o perfil Baseline, o
decodificador AppleTV suporta os perfis Baseline e Main, e o Adobe Flash em um PC desktop oferece
suporte aos perfis Baseline, Main e High. O YouTube (de propriedade do Google, meu empregador)
agora usa H.264 para codificar vídeos de alta definição jogável através do Adobe Flash; O YouTube
também fornece vídeo codificado em H.264 para dispositivos móveis, incluindo o iPhone da Apple e
telefones que executam o sistema operacional móvel Android do Google . Além disso, H.264 é um dos
codecs de vídeo exigidos pela especificação Blu-ray; Os discos Blu-ray que o utilizam geralmente usam
o perfil Alto.
A maioria dos dispositivos não PC que reproduzem vídeo H.264 (incluindo iPhones e reprodutores Blu-
ray independentes) na verdade fazem a decodificação em um chip dedicado, já que suas CPUs principais
não são nem de longe poderosas o suficiente para decodificar o vídeo em tempo real. Muitas placas
gráficas de desktop também suportam decodificação H.264 em hardware. Existem vários codificadores
H.264 concorrentes, incluindo a biblioteca x264 de código aberto. O padrão H.264 está protegido por
patente; o licenciamento é intermediado pelo grupo MPEG LA. O vídeo H.264 pode ser incorporado nos
formatos de contêiner mais populares (consulte “Contêineres de vídeo” na página 81), incluindo MP4
(usado principalmente pela iTunes Store da Apple) e MKV (usado principalmente por entusiastas de
vídeos não comerciais).
Teoria
Teora evoluiu do codec VP3 e foi posteriormente desenvolvido pela Fundação Xiph.org. Theora é um
codec livre de royalties e não está sobrecarregado por nenhuma patente conhecida além das patentes
VP3 originais, que foram licenciadas sem royalties.
Embora o padrão esteja “congelado” desde 2004, o projeto Theora (que inclui um codificador e
decodificador de referência de código aberto) só lançou a versão 1.0 em novembro de 2008. e Versão
1.1 em setembro de 2009.
O vídeo Theora pode ser incorporado em qualquer formato de contêiner, embora seja mais frequentemente
visto em um contêiner Ogg. Todas as principais distribuições Linux suportam Theora imediatamente, e o
Mozilla Firefox 3.5 inclui suporte nativo para vídeo Theora em um contêiner Ogg. Por
“nativo”, quero dizer, “disponível em todas as plataformas sem plug-ins específicos da plataforma”. Você também
pode reproduzir vídeo Theora no Windows ou no Mac OS X após instalar o software decodificador de código aberto
da Xiph.org.
VP8
VP8 é outro codec de vídeo da On2, a mesma empresa que desenvolveu originalmente o VP3 (mais tarde Theora).
Tecnicamente, é semelhante em qualidade ao H.264 Baseline, com muito potencial para melhorias futuras.
Em 2010, o Google adquiriu a On2 e publicou a especificação do codec de vídeo e um exemplo de codificador e
decodificador como código aberto. Como parte disso, o Google também “abriu” todas as patentes que a On2 havia
registrado no VP8, licenciando-as sem royalties. (Isso é o melhor que você pode esperar com patentes – você não
pode realmente “liberá-las” ou anulá-las depois de terem sido emitidas. Para torná-las compatíveis com o código
aberto, você as licencia sem royalties e então qualquer pessoa pode usá-las. as tecnologias que as patentes
cobrem sem pagar nada ou negociar licenças de patente.) Em 19 de maio de 2010, VP8 é um codec moderno e
isento de royalties e não está onerado por nenhuma patente conhecida, exceto as patentes que On2 (agora
Google) já licenciou sem royalties.
Codecs de áudio
A menos que você se limite a filmes feitos antes de 1927 ou algo assim, você vai querer uma trilha de áudio em
seu vídeo. Assim como os codecs de vídeo, os codecs de áudio são algoritmos de codificação, neste caso usados
para fluxos de áudio. Tal como acontece com os codecs de vídeo, existem codecs de áudio com e sem perdas . E
assim como o vídeo sem perdas, o áudio sem perdas é realmente grande demais para ser colocado na Web, então
vou me concentrar nos codecs de áudio com perdas.
Na verdade, podemos restringir ainda mais o foco, porque existem diferentes categorias de codecs de áudio com
perdas. O áudio é usado em muitos lugares onde o vídeo não é (telefonia, por exemplo), e há toda uma categoria
de codecs de áudio otimizados para codificação de voz. Você não copiaria um CD de música com esses codecs,
porque o resultado soaria como uma criança de quatro anos cantando no viva-voz. Mas você os usaria em um
Asterisk PBX, porque a largura de banda é preciosa e esses codecs podem compactar a fala humana em uma
fração do tamanho dos codecs de uso geral. No entanto, devido à falta de suporte em navegadores nativos e plug-
ins de terceiros, os codecs de áudio otimizados para fala nunca decolaram na Web. Portanto, vou me concentrar
nos codecs de áudio com perdas de uso geral.
Como mencionei em “Codecs de vídeo” na página 83, quando você “assiste a um vídeo”, seu computador está
fazendo várias coisas ao mesmo tempo:
Codecs de áudio | 85
O codec de áudio especifica como fazer o número 3: decodificar o fluxo de áudio e transformá-lo em
formas de onda digitais que seus alto-falantes transformam em som. Tal como acontece com os codecs
de vídeo, existem vários truques para minimizar a quantidade de informações armazenadas no fluxo de áudio.
E como estamos falando de codecs de áudio com perdas , as informações são perdidas durante o ciclo
de vida de gravaçãoÿcodificaçãoÿdecodificaçãoÿaudição. Diferentes codecs de áudio jogam fora coisas
diferentes, mas todos têm o mesmo propósito: enganar seus ouvidos para que não percebam as partes
que estão faltando.
Um conceito que o áudio tem e o vídeo não é o de canais. Estamos enviando som para seus alto-falantes,
certo? Bem, quantos alto-falantes você tem? Se você estiver sentado em frente ao computador, poderá
ter apenas dois: um à esquerda e outro à direita. Minha área de trabalho tem três: esquerda, direita e
mais uma no chão. O chamado “som surround” os sistemas podem ter seis ou mais alto-falantes,
estrategicamente posicionados pela sala. Cada alto-falante é alimentado por um canal específico da
gravação original. A teoria é que você pode sentar-se no meio dos seis alto-falantes, literalmente cercado
por seis canais separados de som, e seu cérebro os sintetiza e faz você se sentir como se estivesse no
meio da ação.
Funciona? Uma indústria multibilionária parece pensar assim.
A maioria dos codecs de áudio de uso geral pode lidar com dois canais de som. Durante a gravação, o
som é dividido nos canais esquerdo e direito; durante a codificação, ambos os canais são armazenados
no mesmo fluxo de áudio; e durante a decodificação, ambos os canais são decodificados e cada um é
enviado ao alto-falante apropriado. Alguns codecs de áudio podem lidar com mais de dois canais e
controlam qual canal é qual, para que o player possa enviar o som certo para o alto-falante certo.
Existem muitos codecs de áudio. Eu disse que havia muitos codecs de vídeo? Esqueça isso.
Existem muitos codecs de áudio, mas na Web, existem apenas três que você precisa conhecer: MP3,
AAC e Vorbis.
MPEG-1 Camada de Áudio 3 é coloquialmente conhecido como “MP3”. Se você ainda não ouviu falar de
MP3, não sei o que fazer com você. Walmart vende tocadores de música portáteis e os chama de
“leitores de MP3”. Walmart. De qualquer forma...
Os MP3s podem conter até dois canais de som. Eles podem ser codificados em diferentes taxas de bits:
64 kbps, 128 kbps, 192 kbps e uma variedade de outras, de 32 a 320. Taxas de bits mais altas significam
tamanhos de arquivo maiores e áudio de melhor qualidade, embora a relação entre qualidade de áudio e
taxa de bits não seja linear. (128 kbps soa duas vezes melhor que 64 kbps, mas 256 kbps não soa duas
vezes melhor que 128 kbps.) Além disso, o formato MP3 (padronizado em 1991) permite codificação de
taxa de bits variável, o que significa que algumas partes do o fluxo codificado é compactado mais do que
outros. Por exemplo, o silêncio entre as notas pode ser codificado em uma taxa de bits muito baixa e, em
seguida, a taxa de bits pode aumentar um momento depois, quando vários instrumentos começarem a
tocar um acorde complexo. Os MP3s também podem ser codificados com uma taxa de bits constante,
que, sem surpresa, é chamada de codificação de taxa de bits constante.
O padrão MP3 não define exatamente como codificar MP3s (embora defina exatamente como decodificá-
los); diferentes codificadores usam diferentes modelos psicoacústicos que produzem resultados totalmente
diferentes, mas são todos decodificáveis pelos mesmos jogadores. O projeto LAME de código aberto é o
melhor codificador gratuito e, sem dúvida, o melhor codificador, ponto final, para todas as taxas de bits,
exceto as mais baixas.
O formato MP3 é protegido por patente, o que explica por que o Linux não consegue reproduzir arquivos
MP3 imediatamente. Praticamente todos os reprodutores de música portáteis suportam arquivos MP3
independentes, e os fluxos de áudio MP3 podem ser incorporados em qualquer contêiner de vídeo. O
Adobe Flash pode reproduzir arquivos MP3 independentes e fluxos de áudio MP3 em um contêiner de vídeo MP4.
Codificação de áudio avançada é carinhosamente conhecido como “AAC”. Padronizado em 1997, ganhou
destaque quando a Apple o escolheu como formato padrão para a iTunes Store.
Originalmente, todos os arquivos AAC “comprados” na iTunes Store eram criptografados com o esquema
DRM proprietário da Apple, chamado FairPlay. Muitas músicas na iTunes Store agora estão disponíveis
como arquivos AAC desprotegidos, que a Apple chama de “iTunes Plus” porque soa muito melhor do que
chamar todo o resto de “iTunes Minus”. O formato AAC está protegido por patente; as taxas de
licenciamento estão disponíveis online.
O AAC foi projetado para fornecer melhor qualidade de som do que o MP3 na mesma taxa de bits e pode
codificar áudio em qualquer taxa de bits. (O MP3 é limitado a um número fixo de taxas de bits, com um
limite superior de 320 kbps.) O AAC pode codificar até 48 canais de som, embora na prática ninguém faça
isso. O formato AAC também difere do MP3 na definição de múltiplos perfis, da mesma forma que o H.264,
e pelas mesmas razões. O perfil de “baixa complexidade” foi projetado para ser reproduzido em tempo
real em dispositivos com potência de CPU limitada, enquanto perfis mais altos oferecem melhor qualidade
de som na mesma taxa de bits, às custas de codificação e decodificação mais lentas.
Todos os produtos atuais da Apple, incluindo iPods, AppleTV e QuickTime, suportam determinados perfis
de AAC em arquivos de áudio independentes e em fluxos de áudio em um contêiner de vídeo MP4. Adobe
Flash suporta todos os perfis de AAC em MP4, assim como os reprodutores de vídeo MPlayer e VLC de
código aberto. Para codificação, a biblioteca FAAC é a opção de código aberto; o suporte para isso é uma
opção de tempo de compilação no mencoder e ffmpeg.
Vorbis
Vorbis é frequentemente chamado de “Ogg Vorbis”, embora isso seja tecnicamente incorreto – “Ogg” é
apenas um formato de contêiner (consulte “Contêineres de vídeo” na página 81), e os fluxos de áudio
Vorbis podem ser incorporados em outros contêineres. Vorbis não está sobrecarregado por nenhuma
patente conhecida e, portanto, é suportado imediatamente por todas as principais distribuições Linux e
por dispositivos portáteis que executam o Rockbox de código aberto. firmware. Mozilla Firefox 3.5 suporta
arquivos de áudio Vorbis em um contêiner Ogg ou vídeos Ogg com uma trilha de áudio Vorbis. Um andróide
telefones celulares também podem reproduzir arquivos de áudio Vorbis independentes. Fluxos de áudio Vorbis
Codecs de áudio | 87
geralmente são incorporados em um contêiner Ogg ou WebM, mas também podem ser incorporados em um MP4
ou MKV container, ou, com algum hacking, em AVI. Vorbis suporta um número arbitrário de canais de som.
No momento em que este livro foi escrito, este é o cenário do vídeo HTML5:
• Opera (10.5 e posterior) suporta vídeo Theora e áudio Vorbis em formato Ogg
recipiente.
• Google Chrome (3.0 e posterior) suporta vídeo Theora e áudio Vorbis em um contêiner Ogg. Ele também
suporta vídeo H.264 (todos os perfis) e áudio AAC (todos os perfis) em um contêiner MP4.
• No momento em que este livro foi escrito (9 de junho de 2010), o “canal de desenvolvimento” do Google
Chrome, compilações noturnas do Chromium, compilações noturnas do Mozilla Firefox, e versões
experimentais do Opera todos suportam vídeo VP8 e áudio Vorbis em um contêiner WebM. (Visite webm
project.org para obter informações mais atualizadas e links de download para navegadores compatíveis
com WebM.)
• O Safari em Macs e PCs com Windows (3.0 e posteriores) suportará tudo o que o Quick Time suportar. Em
teoria, você poderia exigir que seus usuários instalassem plug-ins Quick Time de terceiros. Na prática,
poucos usuários farão isso. Então você fica com os formatos que o QuickTime suporta “prontos para usar”.
Esta é uma lista longa, mas não inclui vídeo Theora, áudio Vorbis ou contêiner Ogg. No entanto, QuickTime
suporta vídeo H.264 (perfil principal) e áudio AAC em um contêiner MP4.
• Dispositivos móveis como o iPhone da Apple e os telefones Android do Google suportam vídeo H.264 (perfil
de linha de base) e áudio AAC (perfil de baixa complexidade) em um contêiner MP4.
• Adobe Flash (9.0.60.184 e posterior) suporta vídeo H.264 (todos os perfis) e AAC
• O Internet Explorer 9 suportará alguns perfis de vídeo H.264 ainda não especificados
e áudio AAC em um contêiner MP4.
• O Internet Explorer 8 não tem suporte para vídeo HTML5, mas praticamente todos os recursos da Internet
Os usuários do Explorer terão o plug-in Adobe Flash. Mais adiante neste capítulo, mostrarei
você como você pode usar vídeo HTML5, mas voltar ao Flash.
A Tabela 5-2 fornece as informações acima de uma forma mais fácil de digerir.
WebM · · · · · · ·
Daqui a um ano, o cenário parecerá significativamente diferente: o WebM será implementado em vários navegadores, esses navegadores
fornecerão versões não experimentais habilitadas para WebM e os usuários atualizarão para essas novas versões. O codec esperado
· · b
WebM 9,0+a 4,0+ 6,0+ 11,0+
a
O Internet Explorer 9 só suportará WebM “quando o usuário tiver instalado um codec VP8”, o que implica que a Microsoft não enviará
o próprio codec.
b
O Google se comprometeu a apoiar o WebM “em uma versão futura” do Android, mas ainda não há um cronograma definido.
E agora o nocaute....
Não existe uma combinação única de contêineres e codecs que funcione em todos os HTML5
navegadores.
Para tornar seu vídeo assistido em todos esses dispositivos e plataformas, você vai
precisar codificar seu vídeo mais de uma vez.
Para obter compatibilidade máxima, veja como será o fluxo de trabalho do seu vídeo:
1. Faça uma versão que use vídeo Theora e áudio Vorbis em um contêiner Ogg.
2. Faça outra versão que utilize WebM (VP8 + Vorbis).
3. Faça outra versão que use vídeo H.264 Baseline e AAC de baixa complexidade
áudio em um contêiner MP4.
4. Vincule todos os três arquivos de vídeo a partir de um único elemento <video> e volte para um player de
vídeo baseado em Flash.
Antes de continuarmos, preciso ressaltar que há um custo para codificar seus vídeos duas vezes. Ou seja,
além do custo óbvio – que você precisa codificar seus vídeos duas vezes, o que leva mais computadores e
mais tempo do que apenas fazer isso uma vez – há outro custo muito real associado ao vídeo H.264: taxas de
licenciamento.
Lembra quando expliquei pela primeira vez o vídeo H.264 (veja “H.264” na página 84) e mencionei que o
codec de vídeo estava sujeito a patentes e o licenciamento era intermediado pelo consórcio MPEG LA? Isso
acaba sendo importante. Para entender por que isso é importante, direciono você para o Labirinto de
Licenciamento H.264:*
A MPEG LA divide o portfólio de licenças H.264 em duas sublicenças: uma para fabricantes de
codificadores ou decodificadores e outra para distribuidores de conteúdo. [...]
A sublicença no lado da distribuição é dividida em quatro subcategorias principais, duas das quais
(assinatura e compra título por título ou uso pago) estão vinculadas ao fato de o usuário final pagar
diretamente pelos serviços de vídeo, e duas das quais (“ televisão gratuita e transmissão pela
Internet) estão vinculados à remuneração de outras fontes que não o telespectador final. [...]
A taxa de licenciamento para televisão “gratuita” baseia-se numa de duas opções de royalties. O
primeiro é um pagamento único de US$ 2.500 por codificador de transmissão AVC, que cobre um
codificador AVC “usado por ou em nome de um Licenciado na transmissão de vídeo AVC para o
Usuário Final”, que o decodificará e visualizará. Se você está se perguntando se esta é uma
cobrança dupla, a resposta é sim: uma taxa de licença já foi cobrada do fabricante do codificador e
a emissora, por sua vez, pagará uma das duas opções de royalties.
A segunda taxa de licenciamento é uma taxa anual de transmissão. [...] [A] taxa anual de transmissão
é dividida por tamanho de audiência:
• US$ 2.500 por ano civil por mercados de transmissão de 100.000 a 499.999 televisões
famílias
• US$ 5.000 por ano civil por mercado de transmissão de 500.000 a 999.999 televisões
famílias
• US$ 10.000 por ano civil por mercado de transmissão de 1.000.000 ou mais de televisão
famílias
[...] Com todas as questões em torno da televisão “gratuita”, por que alguém envolvido na distribuição não
transmitida deveria se preocupar? Como mencionei antes, as taxas de participação aplicam-se a qualquer entrega
de conteúdo. Depois de definir que televisão “gratuita” significava mais do que apenas [over-the-air], a MPEG LA
passou a definir taxas de participação para transmissão pela Internet como “vídeo AVC que é entregue através da
Internet mundial a um usuário final para o qual o usuário final não não pagar remuneração pelo direito de receber
ou visualizar.” Em outras palavras, qualquer transmissão pública, seja ela [over-the-air], cabo, satélite ou Internet,
está sujeita a taxas de participação. [...]
As taxas são potencialmente um pouco mais elevadas para transmissões pela Internet, talvez assumindo que a
distribuição pela Internet crescerá muito mais rapidamente do que a OTA ou a televisão “gratuita” via cabo ou satélite.
Adicionando a taxa do mercado de transmissão de “televisão gratuita” juntamente com uma taxa adicional, a MPEG
LA concede uma espécie de indulto durante o primeiro período de licença, que termina em 31 de dezembro de
2010, e observa que “após o primeiro período, o royalty será não mais do que o equivalente económico dos
royalties devidos durante o mesmo período pela televisão gratuita.”
A última parte – sobre a estrutura de taxas para transmissões pela Internet – já foi alterada. A MPEG
LA anunciou recentemente esse streaming gratuito pela Internet seria estendido até 31 de dezembro
de 2015. E depois disso... quem sabe?
Firefogg é uma extensão do Firefox de código aberto e licenciada pela GPL para codificação de vídeo
Ogg. Para usá-lo, você precisará instalar o Mozilla Firefox 3.5 ou posterior, visite o site do Firefogg,
mostrado na Figura 5-1.
Clique em “Instalar Firefogg”. O Firefox perguntará se você realmente deseja permitir que o site instale
uma extensão. Clique em “Permitir” para continuar (Figura 5-2).
O Firefox apresentará a janela padrão de instalação do software. Clique em “Instalar agora” para
continuar (Figura 5-3).
Assim que o Firefox for reiniciado, o site do Firefogg confirmará que o Firefogg foi instalado com
sucesso (Figura 5-5).
Clique em “Make Ogg Video” para iniciar o processo de codificação (Figura 5-6), depois clique em
“Select file” para selecionar o vídeo de origem (Figura 5-7).
Predefinições A predefinição padrão é “vídeo da web”, o que é adequado para nossos propósitos.
Faixa de codificação A
codificação de vídeo pode levar muito tempo. Ao começar, você pode querer codificar apenas parte do seu vídeo (digamos,
os primeiros 30 segundos) até encontrar uma combinação de configurações de sua preferência.
Metadados
Não vou abordar isso aqui, mas você pode adicionar metadados como título e autor ao seu vídeo codificado. Você
provavelmente adicionou metadados à sua coleção de músicas com o iTunes ou algum outro gerenciador de música. Esta é
a mesma ideia.
Veremos apenas a aba “Controle básico de qualidade e resolução” (Figura 5-9), que contém todas as
opções importantes:
Qualidade de
vídeo É medida em uma escala de 0 (qualidade mais baixa) a 10 (qualidade mais alta). Números mais altos
significam tamanhos de arquivo maiores, então você precisará experimentar para determinar a melhor
relação tamanho/qualidade para suas necessidades.
Qualidade de áudio
É medida em uma escala de –1 (qualidade mais baixa) a 10 (qualidade mais alta). Números mais altos significam
tamanhos de arquivo maiores, assim como acontece com a configuração de qualidade de vídeo.
Codec de
vídeo Deve ser sempre “theora”.
Codec de áudio
Deve ser sempre “vorbis”.
Largura e altura do vídeo
O padrão é a largura e altura reais do vídeo de origem. Se quiser redimensionar o vídeo durante a
codificação, você pode alterar a largura ou altura aqui. O Firefogg ajustará automaticamente a
outra dimensão para manter as proporções originais, para que seu vídeo não fique amassado ou
esticado.
Na Figura 5-10, redimensiono o vídeo para metade da largura original. Observe como o Firefogg ajusta
automaticamente a altura para corresponder.
Depois de mexer em todos os botões, clique em “Salvar Ogg” para iniciar o processo de codificação real
(Figura 5-11). O Firefogg solicitará um nome de arquivo para o vídeo codificado.
O Firefogg mostrará uma bela barra de progresso enquanto codifica seu vídeo (Figura 5-12). Tudo que
você precisa fazer é esperar (e esperar e esperar)!
Existem vários codificadores offline para vídeo Ogg. Se você está pensando em codificar em lote muitos
arquivos de vídeo e deseja automatizar o processo, você definitivamente deveria dar uma olhada no
ffmpeg2theora. ffmpeg2theora
é um aplicativo de código aberto licenciado pela GPL para codificação de vídeo Ogg.
Binários pré-construídos estão disponíveis para Mac OS X, Windows e distribuições Linux modernas . Ele
pode receber praticamente qualquer arquivo de vídeo como entrada, incluindo o vídeo DV produzido por
muitas filmadoras de consumo.
Para usar o ffmpeg2theora, você precisa chamá-lo na linha de comando. (No Windows, vá para Menu
IniciarÿProgramasÿAcessóriosÿPrompt de Comando. No Mac OS X, abra AplicativosÿUtilitáriosÿTerminal.)
Portanto, aqui está como você pode codificar um vídeo com as mesmas configurações que
usamos na seção anterior (“Codificando vídeo Ogg com Firefogg” na página 91):
você@localhost$ ffmpeg2theora --videoquality
5 --audioquality
1 --max_size
320x240 pr6.dv
O vídeo codificado será salvo no mesmo diretório do vídeo original, com uma extensão .ogv
adicionada. Você pode especificar um local e/ou nome de arquivo diferente passando um
sinalizador de linha de comando --output=/ path/ to/ encoded/ video para ffmpeg2theora.
Deixando de lado as questões de licenciamento (consulte “Problemas de licenciamento com vídeo H.264” na
página 90), a maneira mais fácil de codificar vídeo H.264 é usando o HandBrake. HandBrake é um aplicativo
de código aberto licenciado pela GPL para codificação de vídeo H.264. (Ele costumava fazer outros formatos
de vídeo também, mas na versão mais recente os desenvolvedores abandonaram o suporte para a maioria dos
outros formatos e concentraram todos os seus esforços no vídeo H.264.) Binários pré-construídos estão
disponíveis para Windows , Mac OS X e sistemas modernos. Distribuições Linux.
O HandBrake vem em dois sabores: gráfico e linha de comando. Apresentarei primeiro a interface gráfica e
depois veremos como minhas configurações recomendadas se traduzem em
a versão da linha de comando.
Depois de abrir o aplicativo HandBrake, a primeira coisa a fazer é selecionar o vídeo de origem (Figura 5-13).
Clique em “Fonte” e escolha “Arquivo de vídeo” no menu suspenso para selecionar um arquivo. O HandBrake
pode receber praticamente qualquer arquivo de vídeo como entrada, incluindo vídeo DV produzido por muitas
filmadoras de consumo.
O HandBrake reclamará que você não definiu um diretório padrão para salvar seus vídeos
codificados (Figura 5-14). Você pode ignorar este aviso com segurança ou pode abrir a janela de
opções (no menu “Ferramentas”) e definir um diretório de saída padrão.
No lado direito está uma lista de predefinições. Selecionar a predefinição “iPhone e iPod Touch”,
como na Figura 5-15, definirá a maioria das opções necessárias.
Uma opção importante que está desativada por padrão é a opção “Otimizado para Web”.
Selecionar esta opção, conforme mostrado na Figura 5-16, reordena alguns dos metadados do
vídeo codificado para que você possa assistir ao início do vídeo enquanto o restante é baixado
em segundo plano. Eu recomendo sempre marcar esta opção. Isso não afeta a qualidade ou o
tamanho do arquivo do vídeo codificado, então não há razão para não fazê-lo.
Na aba “Imagem”, você pode definir a largura e altura máximas do vídeo codificado (Figura 5-17).
Você também deve selecionar a opção “Manter proporção de aspecto” para garantir que o
HandBrake não estique ou estique seu vídeo ao redimensioná-lo.
Na aba “Vídeo”, mostrada na Figura 5-18, você pode definir diversas opções importantes:
Codec de vídeo
Certifique-se de que seja “H.264 (x264)”.
Codificação de 2
passagens Se esta opção estiver marcada, o HandBrake executará o codificador de vídeo duas vezes.
Na primeira vez, ele apenas analisa o vídeo, procurando coisas como composição de cores, movimento
e quebras de cena. Na segunda vez, ele codifica o vídeo usando as informações que aprendeu durante
a primeira passagem. Como seria de esperar, isso leva cerca de duas vezes mais tempo que a
codificação de passagem única, mas resulta em um vídeo melhor sem aumentar o tamanho do arquivo.
Sempre habilito a codificação de duas passagens para vídeo H.264. A menos que você esteja construindo
o próximo YouTube e codificando vídeos 24 horas por dia, você provavelmente também deverá usar a
codificação em duas passagens.
Turbo First Pass
Quando você habilita a codificação de duas passagens, você pode recuperar um pouco de tempo
habilitando esta opção. Reduz a quantidade de trabalho realizado na primeira passagem (análise do
vídeo), ao mesmo tempo que degrada apenas ligeiramente a qualidade. Normalmente habilito esta
opção, mas se a qualidade é de extrema importância para você, deixe-a desabilitada.
Qualidade
Existem várias maneiras diferentes de especificar a “qualidade” do seu vídeo codificado.
Você pode definir um tamanho de arquivo de destino e o HandBrake fará o possível para garantir que o
vídeo codificado não seja maior do que isso. Você pode definir uma “taxa de bits” média, que é
R: Sim, mas devido a diferenças fundamentais no funcionamento do codificador, provavelmente não será
necessário. A codificação H.264 de duas passagens quase sempre resulta em vídeo de maior qualidade.
A codificação Ogg de duas passagens de vídeo Ogg só é útil se você estiver tentando fazer com que seu vídeo
codificado tenha um tamanho de arquivo específico. (Talvez isso seja algo em que você esteja interessado, mas
não é o que esses exemplos mostram e provavelmente não vale a pena gastar tempo extra para codificar vídeo da
web.) Para obter a melhor qualidade de vídeo Ogg, use as configurações de qualidade de vídeo e não se preocupe .
sobre codificação de duas passagens.
Neste exemplo, escolhi uma taxa de bits média de 600 kbps, que é bastante alta para um vídeo codificado em
320×240. Também habilitei a codificação de duas passagens com uma primeira passagem “turbo”.
Na aba “Áudio”, mostrada na Figura 5-19, você provavelmente não precisará alterar nada.
Se o seu vídeo de origem tiver várias trilhas de áudio, talvez seja necessário selecionar qual delas deseja no
vídeo codificado. Se o seu vídeo for principalmente uma pessoa falando (em oposição a música ou sons ambientais
em geral), você provavelmente poderá reduzir a taxa de bits do áudio para 96 kbps ou mais. Fora isso, os padrões
que você herdou da predefinição “iPhone” devem servir.
Em seguida, clique no botão “Browse” e escolha um diretório e nome de arquivo para salvar seu vídeo codificado
(Figura 5-20).
O HandBrake exibirá algumas estatísticas de progresso enquanto codifica seu vídeo (Figura 5-22).
Como mencionei na seção anterior, o HandBrake também vem em uma edição de linha de comando.
Tal como acontece com a edição gráfica, você deve baixar um instantâneo recente em http:// handbrake.fr/
downloads2.php.
Assim como o ffmpeg2theora (consulte “Codificação em lote de vídeo Ogg com ffmpeg2the ora” na
página 98), a edição de linha de comando do HandBrake oferece uma variedade estonteante de opções.
(Digite HandBrakeCLI --help em uma janela do Terminal ou em um prompt de comando para ler sobre
eles.) Vou me concentrar em apenas alguns:
• --preset "X", onde "X" é o nome de um preset do HandBrake (é importante colocar o nome entre
aspas). A predefinição que você deseja para o vídeo da web H.264 é chamada de “iPhone e iPod
Touch”.
Aqui está um exemplo de chamada do HandBrake na linha de comando, com sinalizadores de linha de
comando que correspondem às configurações que escolhemos com a versão gráfica do HandBrake:
De cima para baixo, este comando executa o HandBrake com o “iPhone e iPod Touch”
predefinido, redimensiona o vídeo para 320 × 240, define a taxa de bits média para 600 kbps, habilita a
codificação de duas passagens com uma primeira passagem turbo, lê o arquivo pr6.dv e o codifica como pr6.mp4.
Uau!
• libvp8 e uma versão especial do ffmpeg com patches adicionais (para conectá-lo com
libvp8) que ainda não fazem parte do repositório oficial do ffmpeg :
Preparar? OK. Na linha de comando, execute ffmpeg sem parâmetros e verifique se ele
foi compilado com suporte VP8:
você@localhost$ ffmpeg
Versão FFmpeg SVN-r23197, Copyright (c) 2000-2010 os desenvolvedores do FFmpeg
construído em 19 de maio de 2010 22:32:20 com gcc 4.4.3
configuração: --enable-gpl --enable-version3 --enable-nonfree --enable-postproc --enable-pthreads --enable-
libfaac --enable-libfaad --enable-libmp3lame --enable-libopencore-amrnb - -enable-libopencore-
amrwb --enable-libtheora --enable-libx264 --enable-libxvid --enable-x11grab --enable-libvpx-vp8
Se você não vir as palavras mágicas --enable-libvpx-vp8, você não tem a versão correta
do ffmpeg. (Se você jura que compilou corretamente, verifique se você tem dois
versões instaladas. Tudo bem, eles não entrarão em conflito um com o outro - você só precisará
use o caminho completo da versão do ffmpeg habilitada para VP8.)
Vou mostrar como fazer uma codificação em duas passagens (veja “Codificando vídeo H.264 com
HandBrake” na página 100). A primeira passagem apenas examina o arquivo de vídeo de entrada
(-i pr6.dv) e escreve algumas estatísticas em um arquivo de log (que será nomeado automaticamente
pr6.dv-0.log). Você especifica o codec de vídeo com o parâmetro -vcodec :
você @ localhost $ ffmpeg -pass 1 -passlogfile pr6.dv -threads 16 -token_partitions 4 -altref 1 -lag 16
-keyint_min 0 -g 250 -mb_static_threshold 0 -skip_threshold 0 -qmin 1 -qmax
51 -i pr6.dv -vcodec libvpx_vp8 -an -f rawvideo -y NUL
A maior parte da linha de comando do ffmpeg não tem nada a ver com VP8 ou WebM. libvp8 suporta uma
série de opções específicas do VP8 que você pode passar para o ffmpeg, mas ainda não sei como nenhuma
delas funciona. Assim que encontrar uma boa explicação sobre essas opções, fornecerei um link no site
deste livro.
Para a segunda passagem, o ffmpeg lerá as estatísticas que escreveu durante a primeira passagem e
realmente fará a codificação do vídeo e do áudio. Ele gravará um arquivo MKV, que converteremos
posteriormente em um arquivo WebM. (Eventualmente, o ffmpeg será capaz de gravar arquivos WebM
diretamente, mas essa funcionalidade está atualmente quebrada de maneira sutil e perniciosa.)
Aqui está a linha de comando para a segunda passagem:
-vcodec libvpx_vp8
Especifica que estamos codificando com o codec de vídeo VP8. WebM sempre usa vídeo VP8.
-b 614400
Especifica a taxa de bits. Ao contrário de outros formatos, o libvp8 espera a taxa de bits em bits reais,
não em kilobits. Se você quiser um vídeo de 600 kbps, multiplique 600 por 1.024 para obter 614.400.
-s 320x240
Especifica o tamanho do destino, largura por altura.
-aspecto 4:3
Especifica a proporção do vídeo. O vídeo de definição padrão geralmente é 4:3, mas a maioria dos
vídeos de alta definição é 16:9 ou 16:10. Em meus testes, descobri que precisava especificar isso
explicitamente na linha de comando, em vez de confiar no ffmpeg para detectá-lo automaticamente.
-acodec vobis
Especifica que estamos codificando com o codec de áudio Vorbis. WebM sempre usa áudio Vorbis.
Agora temos um arquivo MKV com vídeo VP8 e áudio Vorbis. Isso está muito próximo do que queremos. O
formato de contêiner do WebM é tecnicamente muito semelhante ao MKV. Na verdade, é um subconjunto
adequado. Precisamos apenas mexer alguns bits para criar nosso arquivo de vídeo WebM final, usando o
utilitário mkclean Mencionei anteriormente:
HTML5 oferece duas maneiras de incluir vídeo em sua página da web. Ambos envolvem o elemento
<video> . Se você tiver apenas um arquivo de vídeo, poderá simplesmente vinculá-lo em um atributo
src . Isso é notavelmente semelhante a incluir uma imagem com uma tag <img src="..."> .
<video src="pr6.webm"></video>
Tecnicamente, isso é tudo que você precisa. Mas assim como em uma tag <img> , você deve sempre
incluir atributos de largura e altura em suas tags <video> . Os atributos de largura e altura podem ser
iguais à largura e altura máximas especificadas durante o processo de codificação:
Não se preocupe se uma dimensão do vídeo for um pouco menor que isso. Seu navegador
centralizará o vídeo dentro da caixa definida pela tag <video> . Nunca será esmagado ou esticado
fora de proporção.
Por padrão, o elemento <video> não exporá nenhum tipo de controle do player. Você pode criar
seus próprios controles com HTML, CSS e JavaScript simples e antigos. O elemento <video>
possui métodos como play() e pause() e uma propriedade de leitura/gravação chamada hora
atual . Também há volume de leitura/gravação e silenciado propriedades. Então você realmente
tem tudo o que precisa para construir sua própria interface.
Se não quiser criar sua própria interface, você pode instruir o navegador a exibir um conjunto
integrado de controles. Para fazer isso, basta incluir o atributo controles na sua tag <video> :
Existem dois outros atributos opcionais que quero mencionar antes de prosseguirmos: pré-
carregamento e reprodução automática. Não atire no mensageiro; deixe-me explicar por que eles são úteis.
O atributo preload informa ao navegador que você gostaria que ele iniciasse o download do arquivo
de vídeo assim que a página carregasse. Isso faz sentido se o objetivo da página for visualizar o
vídeo. Por outro lado, se for apenas material suplementar que apenas alguns visitantes assistirão,
você poderá definir o pré-carregamento como nenhum para informar ao navegador para minimizar o
tráfego de rede.
Aqui está um exemplo de vídeo que começará a ser baixado (mas não será reproduzido) assim que
a página carregar:
<video src="pr6.webm" width="320" height="240" preload></video>
E aqui está um exemplo de vídeo que não inicia o download assim que a página carrega:
O atributo autoplay faz exatamente o que parece: informa ao navegador que você gostaria que ele
iniciasse o download do arquivo de vídeo assim que a página carregasse e que desejasse que ele
começasse a reproduzir o vídeo automaticamente o mais rápido possível. Algumas pessoas adoram
isso; algumas pessoas odeiam isso. Mas deixe-me explicar por que é importante ter um atributo como
este no HTML5. Algumas pessoas vão querer que seus vídeos sejam reproduzidos automaticamente,
mesmo que isso irrite os visitantes. Se o HTML5 não definisse uma forma padrão de reprodução
automática de vídeos, as pessoas recorreriam a hacks de JavaScript para fazer isso de qualquer
maneira, por exemplo, chamando o método play() do vídeo durante o evento de carregamento da
janela . Isso seria muito mais difícil para os visitantes neutralizarem. Por outro lado, é simples adicionar
uma extensão ao seu navegador (ou escrever uma, se necessário) que permita dizer “ignore o atributo
de reprodução automática , nunca quero que os vídeos sejam reproduzidos automaticamente”.
Aqui está um exemplo de vídeo que começará a ser baixado e reproduzido assim que possível após o
carregamento da página:
<video src="pr6.webm" width="320" height="240" reprodução automática></video>
E aqui está um Greasemonkey script que você pode instalar em sua cópia local do Firefox que impede
a reprodução automática de vídeos HTML5. Ele usa o atributo DOM de reprodução automática definido
pelo HTML5, que é o equivalente JavaScript do atributo de reprodução automática em sua marcação
HTML: // ==UserScript== //
@name //
Desativar a reprodução automática
@namespace // de vídeo http://diveintomark.org/projects/greasemonkey/ Garante que
@description // os elementos de vídeo HTML5 não sejam reproduzidos automaticamente
@include // *
==/UserScript==
Mas espere um segundo. Se você acompanhou todo este capítulo, sabe que não tem apenas um
arquivo de vídeo; você tem três. Um é um arquivo .ogv que você criou com Firefogg (consulte
“Codificação de vídeo Ogg com Firefogg” na página 91) ou ffmpeg2theora (consulte “Codificação em
lote de vídeo Ogg com ffmpeg2theora” na página 98). O segundo é um arquivo .mp4 que você criou
com HandBrake (consulte “Codificando vídeo H.264 com HandBrake” na página 100). O terceiro é um
arquivo .webm que você criou com ffmpeg (consulte “Codificando vídeo WebM com ffmpeg” na página
108). HTML5 fornece uma maneira de vincular todos os três: o elemento <source> . Cada elemento
<video> pode conter quantos elementos <source> você precisar. Seu navegador percorrerá a lista de
fontes de vídeo, em ordem, e reproduzirá a primeira que for capaz de reproduzir.
Isso levanta outra questão: como o navegador sabe qual vídeo pode reproduzir? Na pior das hipóteses,
ele carrega cada um dos vídeos e tenta reproduzi-los. Isso é um grande
desperdício de largura de banda, no entanto. Você economizará muito tráfego de rede se informar
antecipadamente ao navegador sobre cada vídeo. Você faz isso com o atributo type no elemento <source> .
Vamos decompô-lo. O elemento <video> especifica a largura e a altura do vídeo, mas na verdade não
vincula a um arquivo de vídeo. Dentro do elemento <video> estão dois elementos <source> . Cada elemento
<source> vincula-se a um único arquivo de vídeo (com o atributo src ) e fornece informações sobre o
formato do vídeo (no atributo type ).
O atributo type parece complicado – caramba, é complicado. Ele contém três informações: o formato do
contêiner (consulte “Contêineres de vídeo” na página 81), o codec de vídeo (consulte “Codecs de vídeo” na
página 83) e o codec de áudio (consulte “Codecs de áudio” na página 85) . Vamos começar de baixo. Para
o arquivo de vídeo .ogv , o formato do contêiner é Ogg, representado aqui como video/ogg. (Tecnicamente
falando, esse é o tipo MIME para arquivos de vídeo Ogg.) O codec de vídeo é Theora e o codec de áudio é
Vorbis.
Isso é bastante simples, exceto que o formato do valor do atributo é um pouco complicado. O próprio valor
dos codecs deve incluir aspas, o que significa que você precisará usar um tipo diferente de aspas para
delimitar todo o valor do tipo : <source src="pr6.ogv" type='video/ogg;
codecs="theora, vorbis"'>
O elemento <source> para o arquivo WebM é praticamente o mesmo, mas com um tipo MIME diferente
(video/webm em vez de video/ogg) e um codec de vídeo diferente (vp8 em vez de theora) listado no
parâmetro codecs :
O elemento <source> do arquivo H.264 é ainda mais complicado. Lembra quando eu disse que tanto o
vídeo H.264 (consulte “H.264” na página 84) quanto o áudio AAC (consulte “Codificação de áudio avançada”
na página 87) podem vir em “perfis” diferentes? Codificamos com o perfil H.264 Baseline e o perfil AAC de
baixa complexidade e, em seguida, agrupamos tudo em um contêiner MPEG-4. Todas essas informações
estão incluídas no atributo type :
A vantagem de enfrentar todo esse problema é que o navegador será capaz de verificar primeiro o atributo
type para ver se pode reproduzir um arquivo de vídeo específico. Se um navegador decidir que não pode
reproduzir um vídeo específico, ele não fará o download do arquivo. Nem mesmo parte do arquivo. Você
economizará largura de banda e seus visitantes verão o vídeo que procuram com mais rapidez.
Se você seguir as instruções deste capítulo para codificar seus vídeos, poderá simplesmente copiar os
valores do atributo type deste exemplo. Caso contrário, você mesmo precisará definir os parâmetros de
tipo .
momento em que este artigo foi escrito (20 de maio de 2010), o iPad tinha um bug que o impedia de perceber
qualquer coisa além da primeira fonte de vídeo listada. Infelizmente, isso significa que você precisará listar
primeiro o arquivo MP4, seguido pelos formatos de vídeo gratuitos. Suspirar.
Há tantas peças no quebra-cabeça do vídeo que hesito até mesmo em mencionar isso. Mas é
importante, porque um servidor web mal configurado pode levar a uma frustração sem fim enquanto
você tenta depurar por que seus vídeos são reproduzidos em seu computador local, mas não são
reproduzidos quando você os implanta em seu site de produção. Se você se deparar com esse
problema, a causa raiz provavelmente são os tipos MIME.
Mencionei os tipos MIME no Capítulo 1 (veja “Tipos MIME” na página 1), mas você provavelmente
não percebeu isso e não percebeu o significado. Então aqui está em letras maiúsculas.
Qual é o tipo MIME adequado? Você já viu; faz parte do valor do atributo type de um elemento
<source> . Mas definir o atributo type na sua marcação HTML não é suficiente. Você também
precisa garantir que seu servidor web inclua o tipo MIME adequado no cabeçalho HTTP Content-
Type .
Se você estiver usando o servidor web Apache ou algum derivado do Apache, você pode usar
diretivas Add Type no httpd.conf de todo o site ou em um arquivo .htaccess no diretório onde você
armazena seus arquivos de vídeo. (Se você usar algum outro servidor web, consulte a documentação
do seu servidor sobre como definir o cabeçalho HTTP Content-Type para tipos de arquivo específicos.)
As diretivas AddType que você precisará incluir são:
AddType vídeo/ogg .ogv
AddType vídeo/mp4 .mp4
AddType vídeo/webm .webm
A primeira linha é para vídeos em um contêiner Ogg. A segunda linha é para vídeos em um
contêiner MPEG-4. O terceiro é para WebM. Defina-os uma vez e esqueça-os. Caso contrário, seus
vídeos não serão reproduzidos em alguns navegadores, mesmo se você incluir o tipo MIME no
atributo type em sua marcação HTML.
Para obter detalhes ainda mais sangrentos sobre como configurar seu servidor web, direciono sua
atenção para um excelente artigo do Mozilla Developer Center, “Configurando servidores para Ogg
me dia”. (O conselho desse artigo também se aplica a vídeos MP4 e WebM.)
E quanto ao IE?
Enquanto escrevo isto, a Microsoft lançou uma “visualização para desenvolvedores” do Internet
Explorer 9. Ele ainda não oferece suporte ao elemento HTML5 <video> , mas a Microsoft prometeu
publicamente que a versão final do IE 9 suportará vídeo H.264 e áudio AAC em um contêiner
MPEG-4, assim como o Safari em Macs desktop e o Mobile Safari no iOS.
Mas e as versões mais antigas do Internet Explorer? Tipo, você sabe, todas as versões disponíveis
até o IE 8, inclusive? A maioria das pessoas que usa o Internet Explorer também possui o plug-in
Adobe Flash instalado. Versões modernas do Adobe Flash (começando com 9.0.60.184) suportam
vídeo H.264 e áudio AAC em um contêiner MPEG-4. Depois de codificar seu vídeo H.264 para
Safari (consulte “Codificando vídeo H.264 com freio de mão” na página 100), você poderá
reproduzi-lo em um player de vídeo baseado em Flash se detectar que seu visitante não possui um
navegador compatível com HTML5.
FlowPlayer é um reprodutor de vídeo de código aberto, licenciado pela GPL e baseado em Flash.
(Licenças comerciais também estão disponíveis; consulte http:// flowplayer.org/ download/.)
FlowPlayer não sabe nada sobre o elemento <video> . Ele não transformará magicamente uma tag
<video> em um objeto Flash. Mas o HTML5 é bem projetado para lidar com isso, porque você pode
aninhar um elemento <object> dentro de um elemento <video> . Os navegadores que não suportam
vídeo HTML5 ignorarão o elemento <video> e simplesmente renderizarão o <object> aninhado , o
que invocará o plug-in Flash e reproduzirá o filme por meio do FlowPlayer. Os navegadores que
suportam vídeo HTML5 encontrarão uma fonte de vídeo que possam reproduzir e reproduzir, e
ignorarão completamente o elemento <object> aninhado.
Essa última parte é a chave para todo o quebra-cabeça: HTML5 especifica que todos os elementos
(exceto os elementos <source> ) que são filhos de um elemento <video> devem ser ignorados
completamente. Isso permite que você use vídeo HTML5 em navegadores mais recentes e volte
ao Flash normalmente em navegadores mais antigos, sem a necessidade de hacks sofisticados de
JavaScript. Você pode ler mais sobre essa técnica no Vídeo para Todos! site.
Um exemplo completo
Vejamos um exemplo que usa essas técnicas. Estendi o vídeo para todos! código para incluir um
vídeo formatado em WebM. Usando esses comandos, codifiquei o mesmo vídeo de origem em três
formatos:
## Theora/Vorbis/Ogg
you@localhost$ ffmpeg2theora --videobitrate 200 --max_size 320x240 --output pr6.ogv
pr6.dv
## H.264/AAC/
MP4 you@localhost$ HandBrakeCLI --preset "iPhone e iPod Touch" --vb 200 --width 320
--duas passagens --turbo --optimize --input pr6.dv --output pr6.mp4
## VP8/Vorbis/
WebM you@localhost$ ffmpeg -pass 1 -passlogfile pr6.dv -threads 16 -token_partitions
4 -altref 1 -lag 16 -keyint_min 0 -g 250 -mb_static_threshold 0
A marcação final usa um elemento <video> para vídeo HTML5, com um elemento <object>
aninhado para substituto do Flash:
Com a combinação de HTML5 e Flash, você poderá assistir a este vídeo em praticamente
qualquer navegador e dispositivo.
Leitura adicional
• “O elemento <video> ” na especificação HTML5 • Vídeo
para todos! • “Uma
introdução suave à codificação de vídeo” • “Theora
1.1 foi lançado – o que você precisa saber”, por Christopher Blizzard • “Configurando
servidores para mídia Ogg” • “Codificação
com o codec x264 ” • “Parâmetros de
tipo de vídeo” • Zencoder
Vídeo JS, controles personalizados para vídeo HTML5 • “Tudo
o que você precisa saber sobre áudio e vídeo HTML5”, por Simon Pieters
CAPÍTULO 6
Mergulhando
Geolocalização é a arte de descobrir onde você está no mundo e (opcionalmente) compartilhar essa
informação com pessoas em quem você confia. Há muitas maneiras de descobrir onde você está: seu
endereço IP, sua conexão de rede sem fio, com qual torre de celular seu telefone está se comunicando
ou hardware GPS dedicado que recebe informações de latitude e longitude de satélites no céu.
R: A privacidade é uma preocupação óbvia quando se trata de compartilhar sua localização física com um
servidor web remoto. A API de geolocalização afirma explicitamente: “Os User Agents não devem enviar
informações de localização para sites sem a permissão expressa do usuário.” Em outras palavras, se você
não quiser compartilhar sua localização, não é necessário.
A API de geolocalização
A API de geolocalização permite que você compartilhe sua localização com sites confiáveis. A latitude
e a longitude estão disponíveis para JavaScript na página, que por sua vez pode enviar essas
informações de volta ao servidor web remoto e realizar tarefas sofisticadas de reconhecimento de
localização, como encontrar empresas locais ou mostrar sua localização em um mapa.
Como você pode ver na Tabela 6-1, a API de geolocalização é suportada em vários dos principais
navegadores em desktops e dispositivos móveis. Além disso, alguns navegadores e dispositivos mais
antigos podem ser suportados por bibliotecas wrapper, como veremos mais adiante neste capítulo.
117
Juntamente com o suporte para a API de geolocalização padrão, há uma infinidade de APIs específicas de
dispositivos em outras plataformas móveis. Abordarei tudo isso mais adiante neste capítulo.
Mostre-me o código
A API de geolocalização gira em torno de uma nova propriedade no objeto navegador global :
navegador.geolocalização.
O uso mais simples da API de geolocalização é assim:
função get_location() {
navigator.geolocation.getCurrentPosition(show_map);
}
função get_location() {
if (Modernizr.geolocation)
{navigator.geolocation.getCurrentPosition(show_map);
} outro {
// sem suporte nativo; talvez tente o Gears?
}
}
O que você faz sem suporte de geolocalização depende de você. Vou explicar o substituto do Gears
opção em um minuto, mas primeiro quero falar sobre o que acontece durante aquela ligação para
getCurrentPosition(). Como mencionei no início deste capítulo, o suporte de geolocalização
é opt-in. Isso significa que seu navegador nunca irá forçá-lo a revelar seu endereço físico atual.
local para um servidor remoto. A experiência do usuário difere de navegador para navegador. Em
Mozilla Firefox, chamar a função getCurrentPosition() da API de geolocalização irá
fazer com que o navegador exiba uma “barra de informações” na parte superior da janela do navegador. A barra de informações
se parece com a Figura 6-1.
• São informados de que um site deseja saber sua localização • São informados
de qual site deseja saber sua localização • Podem clicar na página de ajuda
navegador para lembrar sua escolha (compartilhar ou não compartilhar) para que você nunca mais veja esta barra de
informações neste site
• Não modal, portanto não impedirá que você mude para outra janela do navegador ou
aba
• Específico da guia, portanto ele desaparecerá se você mudar para outra janela ou guia do navegador e reaparecerá
quando você voltar para a guia original • Incondicional, então não há como um
site ignorá-lo • Bloqueio, então não há nenhuma chance que o site pode determinar sua
localização enquanto
está esperando sua resposta
Você acabou de ver o código JavaScript que faz com que esta barra de informações apareça. É uma única chamada de
função que recebe uma função de retorno de chamada (que chamei de show_map()). A chamada para getCurrent Position()
retornará imediatamente, mas isso não significa que você tenha acesso à localização do usuário. A primeira vez que você
terá informações de localização garantidas será na função de retorno de chamada. A função de retorno de chamada fica
assim:
A função callback será chamada com um único parâmetro, um objeto com duas propriedades: coordenadas e carimbo de
data/hora. O carimbo de data/hora é apenas isso, a data e hora em que o local foi calculado. (Como tudo isso está
acontecendo de forma assíncrona, você não pode realmente saber quando isso acontecerá com antecedência. Pode levar
algum tempo para o usuário ler a barra de informações e concordar em compartilhar sua localização, dispositivos com
hardware GPS dedicado podem levar mais algum tempo para conectar-se a um satélite GPS e assim por diante.) O objeto
coords possui propriedades como latitude e longitude que representam exatamente o que parecem: a localização física do
usuário no mundo. As propriedades do objeto posição estão listadas na Tabela 6-2.
coordenadas.latitude dobro
Graus decimais
coordenadas.longitude dobro
Graus decimais
coordenadas.altitude
double ou null Metros acima do elipsóide de referência
Tratamento de erros
A geolocalização é complicada. Tantas coisas podem dar errado. Mencionei o “usuário
consentimento” já. Se o seu aplicativo da web deseja a localização do usuário, mas o usuário
não quer dar isso a você, você está ferrado. O usuário sempre ganha. Mas o que faz
isso parece no código? Parece o segundo argumento para getCurrentPosition()
function – uma função de retorno de chamada de tratamento de erros:
navegador.geolocation.getCurrentPosition(
show_map, handle_error)
Se algo der errado, sua função de retorno de chamada de erro será chamada com um
Objeto PositionError . Possui as propriedades listadas na Tabela 6-3.
• TIMEOUT (3) se a rede estiver ativa, mas demorar muito para calcular a posição do usuário.
Quanto tempo é “muito longo”? Mostrarei como definir isso na próxima seção.
• UNKNOWN_ERROR (0) se algo der errado.
Por exemplo:
function handle_error(err) { if (err.code
== 1) { // o usuário disse não!
}}
Pergunte ao Professor
Markup P: A API de geolocalização funciona na Estação Espacial Internacional, na Lua
ou em outros planetas?
O segundo método, na verdade, usa hardware GPS dedicado em seu dispositivo para se
comunicar com satélites de posicionamento GPS dedicados que estão orbitando a Terra. O GPS
geralmente pode apontar sua localização em poucos metros. A desvantagem é que o chip GPS
dedicado do seu dispositivo consome muita energia, então telefones e outros dispositivos móveis
de uso geral geralmente desligam o chip até que seja necessário. Isso significa que haverá um
atraso na inicialização enquanto o chip inicializa sua conexão com os satélites GPS no céu. Se
você já usou o Google Maps em um iPhone ou outro smartphone, viu os dois métodos em ação.
Primeiro você vê um círculo grande que se aproxima da sua posição (encontrando a torre de
celular mais próxima), depois um círculo menor (triangulando com outras torres de celular) e, em
seguida, um único ponto com uma posição exata (fornecida por satélites GPS).
Mencionei isso porque, dependendo do seu aplicativo da web, você pode não precisar de alta
precisão. Por exemplo, se você estiver procurando listas de filmes próximos, um valor “baixo
tempo esgotado
longo (nenhum padrão) Em milissegundos
A propriedade timeout especifica o número de milissegundos que seu aplicativo da web fica
disposto a esperar por uma posição. Este cronômetro não inicia a contagem regressiva até depois do
o usuário dá permissão para tentar calcular sua posição. Você não está cronometrando o usuário;
você está cronometrando a rede.
A propriedade MaximumAge permite que o dispositivo responda imediatamente com uma posição em cache. Por
exemplo, digamos que você chame getCurrentPosition() pela primeira vez, o
consentimento do usuário, e sua função de retorno de chamada de sucesso é chamada com uma posição que foi
calculado exatamente às 10h. Então suponha que exatamente um minuto depois, às 10h01
AM, você chama getCurrentPosition() novamente com uma propriedade maximaAge de 75000:
navegador.geolocation.getCurrentPosition(
sucesso_callback, erro_callback, {maximumAge: 75000});
O que você está dizendo é que não precisa necessariamente da localização atual do usuário . Você
ficaria satisfeito em saber onde ele estava há 75 segundos (75.000 milissegundos).
Nesse caso, o dispositivo sabe onde o usuário estava há 60 segundos (60.000 milissegundos),
porque calculou a localização na primeira vez que você chamou getCurrentPosition(). Desde
isso está dentro da janela especificada, o dispositivo não se preocupa em recalcular o usuário
localização atual. Ele apenas retorna exatamente as mesmas informações que retornou da primeira vez:
a mesma latitude e longitude, precisão e carimbo de data/hora (10h).
location mais de uma vez, você deve pensar em quantos anos as informações podem ter e ainda
serem úteis, e definir a idade máxima de acordo. Se você precisa encontrar a localização do usuário
continuamente, getCurrentPosition() não é para você. Você precisa atualizar para watchPosition().
A função watchPosition() tem a mesma estrutura que getCurrentPosition(). São necessárias duas
funções de retorno de chamada – uma obrigatória para sucesso e outra opcional para condições
de erro – e também pode usar um objeto PositionOptions opcional que possui todas as mesmas
propriedades que você acabou de aprender. A diferença é que sua função de retorno de chamada
será chamada sempre que a localização do usuário mudar. Não há necessidade de pesquisar
ativamente a posição. O dispositivo determinará o intervalo de pesquisa ideal e chamará sua
função de retorno de chamada sempre que determinar que a posição do usuário mudou. Você
pode usar isso para atualizar um marcador visível em um mapa, fornecer instruções sobre onde ir
em seguida ou o que quiser. Depende inteiramente de você.
A própria função watchPosition() retorna um número. Você provavelmente deveria armazenar esse
número em algum lugar. Se você quiser parar de observar as mudanças de localização do usuário,
você pode chamar o método clearWatch() e passar esse número para ele, e o dispositivo irá parar
de chamar sua função de retorno de chamada. Se você já usou as funções setInterval() e
clearInterval() em JavaScript, isso funciona da mesma maneira.
E quanto ao IE?
O Internet Explorer não oferece suporte à API de geolocalização W3C que acabei de descrever
(consulte “A API de geolocalização” na página 117). Mas não se desespere! Engrenagens é um
plug-in de navegador de código aberto do Google que funciona nas plataformas Windows, Mac,
Linux, Windows Mobile e Android. Ele fornece vários recursos para navegadores mais antigos,
incluindo uma API de geolocalização. Não é exatamente igual à API de geolocalização do W3C,
mas serve ao mesmo propósito.
Já que estamos falando de plataformas legadas, devo salientar que há uma série de APIs de
geolocalização específicas de dispositivos em plataformas de telefonia móvel. Amora, Nokia,
Palma, e OMTP BONDI todos fornecem suas próprias APIs de geolocalização. Claro, todos eles
funcionam de forma diferente do Gears, que por sua vez funciona de forma diferente da API de
geolocalização W3C. Uau!
O primeiro script é gears_init.js, que inicializa o Gears se estiver instalado. O segundo script é geo.js.
Você pode incluí-los em sua página usando um código como este:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Mergulhe no HTML 5</title>
</head>
<body>
...
<script src="gears_init.js"></script> <script
src="geo.js"></script> </body> </
html>
Agora você está pronto para usar qualquer API de geolocalização instalada: if
(geo_position_js.init()) {
geo_position_js.getCurrentPosition(geo_success, geo_error); }
Vamos dar um passo de cada vez. Primeiro, você precisa chamar explicitamente uma função init().
A função init() retorna true se uma API de geolocalização compatível estiver disponível:
if (geo_position_js.init()) {
Chamar a função init() na verdade não encontra a localização do usuário; apenas verifica se é possível
encontrar o local. Para realmente encontrar a localização do usuário, você precisa chamar a função
getCurrentPosition():
geo_position_js.getCurrentPosition(geo_success, geo_error);
A função getCurrentPosition() fará com que o navegador peça permissão para encontrar e compartilhar
a localização do usuário. Se a geolocalização estiver sendo fornecida pelo Gears, será exibida uma caixa
de diálogo perguntando se o usuário confia no site para usar o Gears. Se o navegador suportar
nativamente a API de geolocalização, a caixa de diálogo terá uma aparência diferente. Por exemplo, o
Firefox 3.5 exibirá uma barra de informações no topo da página perguntando se o usuário deseja
compartilhar sua localização com o seu site.
A função de retorno de chamada de sucesso recebe um único argumento, que contém as informações
de posição:
Se a função getCurrentPosition() não conseguir encontrar a localização do usuário — seja porque ele
se recusou a dar permissão ou porque a API de geolocalização falhou por algum motivo — ela chamará
a função passada como segundo argumento. Neste exemplo, a função de retorno de chamada de
falha é chamada geo_error:
geo_position_js.getCurrentPosition(geo_success, geo_error);
Um exemplo completo
Vamos trabalhar com um exemplo de uso de geo.js para tentar obter a localização do usuário e exibir
um mapa do entorno imediato.
Se o usuário der consentimento para rastrear sua localização e o serviço de back-end for realmente
capaz de determinar essa localização, geo.js chamará a primeira função de retorno de chamada,
show_map(), com um único argumento, loc. O objeto loc possui uma propriedade coords que contém
informações de latitude, longitude e precisão. (Este exemplo não usa informações de precisão.) O
restante da função show_map() usa a API do Google Maps para configurar um mapa incorporado:
função show_map(loc) { $
("#geo-wrapper").css({'largura':'320px','altura':'350px'}); var mapa = new
GMap2(document.getElementById("geo-wrapper")); var centro = novo
GLatLng(loc.coords.latitude, loc.coords.longitude); map.setCenter(centro, 14);
map.addControl(novo
GSmallMapControl()); map.addControl(novo
GMapTypeControl()); map.addOverlay(new
GMarker(center, {draggable: false, title: "Você está aqui (mais ou
menos)"}));
}
Se geo.js não conseguir determinar a localização, ele chama a segunda função de retorno de chamada,
show_map_error():
função show_map_error() {
$("#live-geolocation").html('Não foi possível determinar sua localização.'); }
Leitura adicional
• API de geolocalização W3C •
Engrenagens
CAPÍTULO 7
Mergulhando
O armazenamento local persistente é uma das áreas onde os aplicativos clientes nativos têm
tradicionalmente mantido uma vantagem sobre os aplicativos web. Para aplicativos nativos, o sistema
operacional normalmente fornece uma camada de abstração para armazenar e recuperar dados específicos
do aplicativo, como preferências ou estado de tempo de execução. Esses valores podem ser armazenados
no registro, em arquivos INI, em arquivos XML ou em algum outro local, conforme convenção da plataforma.
Se seu aplicativo cliente nativo precisar de armazenamento local além dos pares chave/valor, você poderá
incorporar seu próprio banco de dados, inventar seu próprio formato de arquivo ou implementar inúmeras
outras soluções.
Historicamente, os aplicativos da Web não tiveram nenhum desses luxos. Os cookies foram inventados no
início da história da Web e, na verdade, podem ser usados para armazenamento local persistente de
pequenas quantidades de dados. Mas eles têm várias desvantagens potencialmente prejudiciais:
• Os cookies são incluídos em todas as solicitações HTTP, tornando assim a sua aplicação web mais
lenta ao transmitir desnecessariamente os mesmos dados repetidas vezes.
• Os cookies são incluídos em todas as solicitações HTTP, enviando assim dados não criptografados pela
Internet (a menos que todo o seu aplicativo da Web seja servido por SSL). • Os cookies
são limitados a cerca de 4 KB de dados, o suficiente para tornar seu aplicativo mais lento
(veja acima), mas não o suficiente para ser terrivelmente útil.
• Muito espaço de
• armazenamento... no cliente...
127
Houve uma série de tentativas para conseguir isso, todas insatisfatórias de diferentes maneiras.
No início existia apenas o Internet Explorer. Ou pelo menos era isso que a Microsoft queria que o mundo
pensasse. Para esse fim, durante a primeira das Grandes Guerras dos Navegadores, A Microsoft
inventou muitas coisas e as incluiu em sua guerra de navegadores, o Internet Explorer. Uma dessas
coisas foi chamada de Comportamentos DHTML, e um desses comportamentos foi chamado userData.
userData permite que páginas da web armazenem até 64 KB de dados por domínio, em uma estrutura
hierárquica baseada em XML. (Domínios confiáveis, como sites de intranet, podem armazenar 10 vezes
essa quantidade. E, ei, 640 KB devem ser suficientes para qualquer pessoa!) O IE não apresenta
nenhuma forma de caixa de diálogo de permissões e não há permissão para aumentar a quantidade de
armazenamento disponível.
Em 2002, a Adobe introduziu um recurso no Flash 6 que ganhou o infeliz e equivocado nome de
“cookies Flash”. No ambiente Flash, o recurso é conhecido como Local Shared Objects, ou LSOs.
Resumidamente, permite que objetos Flash armazenem até 100 KB de dados por domínio. Em 2005,
Brad Neuberg desenvolveu um protótipo inicial de uma ponte Flash para JavaScript chamada AJAX
Massive Storage System, ou AMASS, mas foi limitado por algumas peculiaridades de design do Flash.
Em 2006, com o advento do ExternalInterface no Flash 8, acessar LSOs a partir de JavaScript tornou-
se muito mais fácil e rápido. Brad reescreveu o AMASS e integrou-o ao popular Dojo Toolkit sob o
apelido dojox.storage. Com esta solução, cada domínio recebe os habituais 100 KB de armazenamento
“de graça”. Além disso, ele solicita ao usuário cada aumento de ordem de magnitude no armazenamento
de dados (1 MB, 10 MB e assim por diante).
Então, em 2007, o Google lançou o Gears, um plug-in de navegador de código aberto destinado a
fornecer recursos adicionais em navegadores. (Já discutimos anteriormente o Gears no contexto do
fornecimento de uma API de geolocalização no Internet Explorer (consulte “E quanto ao IE?” na página
123). O Gears fornece uma API para um banco de dados SQL incorporado baseado em SQLite. Depois
de obter permissão do usuário uma vez, o Gears pode armazenar quantidades ilimitadas de dados por
domínio em tabelas de banco de dados SQL.
Enquanto isso, Brad Neuberg e outros continuaram a hackear o dojox.storage para fornecer uma
interface unificada para todos esses plug-ins e APIs diferentes. Em 2009, o dojox.storage poderia
detectar automaticamente (e fornecer uma interface unificada sobre) Adobe Flash, Gears, Adobe AIR e
um protótipo inicial de armazenamento HTML5 que só foi implementado em versões mais antigas do
Firefox.
À medida que você examina essas soluções, surge um padrão: todas elas são específicas de um único
navegador ou dependem de um plug-in de terceiros. Apesar dos esforços heróicos para encobrir as
diferenças (no dojox.storage), todos eles expõem interfaces radicalmente diferentes, têm limitações de
armazenamento diferentes e apresentam experiências de usuário diferentes. Então este é o
128 | Capítulo 7: O passado, o presente e o futuro do armazenamento local para aplicativos da Web
problema que o HTML5 se propôs a resolver: fornecer uma API padronizada, implementada
de forma nativa e consistente em vários navegadores, sem precisar depender de terceiros
plug-ins.
O que chamo de “Armazenamento HTML5” é na verdade uma especificação chamada Web Storage.
Isso já fez parte da especificação HTML5 propriamente dita, mas foi dividido em seu
próprias especificações por razões políticas desinteressantes. Certos fornecedores de navegadores também se referem
a ele como “Armazenamento local” ou “Armazenamento DOM”. A situação de nomenclatura torna-se ainda mais
complicado por alguns padrões emergentes relacionados e com nomes semelhantes que discutirei mais tarde
neste capítulo.
Então, o que é armazenamento HTML5? Simplificando, é uma forma de as páginas da web armazenarem chaves nomeadas/
pares de valores localmente, no navegador da web do cliente. Tal como os dados armazenados em cookies, este
os dados persistem mesmo depois que você sai do site, fecha a guia do navegador,
saia do seu navegador ou o que quer que seja. Mas, diferentemente dos cookies, esses dados nunca são transmitidos
para o servidor web remoto (a menos que você faça o possível para enviá-los manualmente).
E ao contrário de todas as tentativas anteriores de fornecer armazenamento local persistente (descritas no
seção anterior), ele é implementado nativamente em navegadores web, portanto está disponível mesmo
quando plug-ins de navegador de terceiros não o são.
Quais navegadores? Como mostra a Tabela 7-1 , o HTML5 é suportado pelas versões mais recentes do
praticamente todos os navegadores...até mesmo o Internet Explorer!
A partir do seu código JavaScript, você acessará o armazenamento HTML5 por meio do localStorage
objeto no objeto de janela global . Antes de poder usá-lo, você deve detectar se
o navegador suporta (consulte “Armazenamento local” na página 21):
função support_html5_storage() {
return ('localStorage' na janela) && window['localStorage'] !== null;
}
Ou, em vez de escrever esta função você mesmo, você pode usar o Modernizr (veja “Modernizr:
Uma biblioteca de detecção HTML5” na página 16) para detectar suporte para armazenamento HTML5:
if (Modernizr.localstorage) {
// window.localStorage está disponível!
} outro {
// sem suporte nativo para armazenamento HTML5 :(
// talvez tente dojox.storage ou uma solução de terceiros
}
O armazenamento HTML5 é baseado em pares chave/valor nomeados. Você armazena dados com
base em uma chave nomeada e pode recuperá-los com a mesma chave:
interface Storage { getter
qualquer getItem (na chave DOMString); criador do
setter void setItem (na chave DOMString, em qualquer dado); };
A chave nomeada é uma string. Os dados podem ser de qualquer tipo suportado por JavaScript,
incluindo strings, booleanos, inteiros ou flutuantes. No entanto, os dados são armazenados como uma
string. Se você estiver armazenando e recuperando algo diferente de strings, precisará usar funções
como parseInt() ou parseFloat() para forçar seus dados recuperados no tipo de dados Java Script
esperado.
Chamar setItem() com uma chave nomeada que já existe substituirá silenciosamente o valor anterior.
Chamar getItem() com uma chave inexistente retornará nulo em vez de lançar uma exceção.
Como outros objetos JavaScript, você pode tratar o objeto localStorage como um array associativo. Em vez de usar os métodos
getItem() e setItem() , você pode simplesmente usar colchetes. Por exemplo, este trecho de código: var foo =
localStorage.getItem("bar"); // ... localStorage.setItem("bar",
foo);
localStorage["bar"] = foo;
Existem também métodos para remover o valor de uma determinada chave nomeada e limpar toda a
área de armazenamento (ou seja, excluir todas as chaves e valores de uma vez):
interface Armazenamento {
deleter void removeItem (na chave DOMString); vazio
claro(); };
Finalmente, existe uma propriedade para obter o número total de valores na área de armazenamento
e iterar por todas as chaves por índice (para obter o nome de cada chave):
interface Storage {
atributo readonly de comprimento longo sem sinal; chave
getter DOMString (em índice longo não assinado); };
Se você chamar key() com um índice que não esteja entre 0 e (comprimento –1), a função retornará
nulo.
130 | Capítulo 7: O passado, o presente e o futuro do armazenamento local para aplicativos da Web
if (window.addEventListener) {
window.addEventListener("armazenamento", handle_storage, false);
} outro {
window.attachEvent("onstorage", handle_storage);
};
A função de retorno de chamada handle_storage() será chamada com um objeto StorageEvent , exceto no Internet
Explorer, onde o objeto de evento é armazenado em window.event:
função handle_storage(e) {
if (!e) { e = janela.event; }
}
Neste ponto, a variável e será um objeto StorageEvent , que possui as propriedades úteis listadas na Tabela 7-2.
chave oldValue Qualquer O valor anterior (agora substituído) ou nulo se um novo item foi adicionado
gritar Corda A página que chamou o método que acionou essa alteração
a
A propriedade url foi originalmente chamada de uri. Alguns navegadores foram fornecidos com essa propriedade antes da alteração da especificação. Para máximo
compatibilidade, você deve verificar se a propriedade url existe e, caso contrário, verifique a propriedade uri .
O evento de armazenamento não é cancelável. De dentro da função de retorno de chamada handle_storage() , não
há como impedir que a mudança ocorra. É simplesmente uma forma do navegador
para lhe dizer: “Ei, isso acabou de acontecer. Não há nada que você possa fazer sobre isso agora; Eu acabei de
queria que você soubesse.
Por padrão, cada origem obtém 5 MB de espaço de armazenamento. Isso é surpreendentemente consistente em
todos os navegadores, embora seja formulado como nada mais do que uma sugestão na especificação de
armazenamento HTML5. Uma coisa a ter em mente é que você está armazenando strings, e não dados em seu
formato original. Se você estiver armazenando muitos inteiros ou números flutuantes, a diferença na representação
pode realmente aumentar: cada dígito nesse número flutuante está sendo armazenado como um caractere, não na
representação usual de um número de ponto flutuante.
Se você exceder sua cota de armazenamento, uma exceção QUOTA_EXCEEDED_ERR será lançada. “Não” é a
resposta à próxima pergunta óbvia: “Posso pedir ao usuário mais espaço de armazenamento?”
No momento em que este artigo foi escrito, nenhum navegador suportava qualquer mecanismo para que os
desenvolvedores da Web solicitassem mais espaço de armazenamento. Alguns navegadores, como o Opera,
permitem que o usuário controle a cota de armazenamento de cada site, mas é puramente uma ação iniciada pelo
usuário, e não algo que você, como desenvolvedor web, possa incorporar em seu aplicativo web.
Vejamos um exemplo de armazenamento HTML5 em ação. Pense no jogo Halma que construímos no Capítulo 4
(veja “Um exemplo completo” na página 75). Há um pequeno problema com o jogo: se você fechar a janela do
navegador no meio do jogo, perderá seu progresso. Mas com o armazenamento HTML5, podemos salvar o progresso
localmente, dentro do próprio navegador. Você pode ver uma demonstração ao vivo em http:// diveintohtml5.org/
examples/ localstor age-halma.html. Faça alguns movimentos, feche a guia do navegador e reabra-a. Se o seu
navegador suportar armazenamento HTML5, a página de demonstração deverá lembrar magicamente sua posição
exata no jogo, incluindo o número de movimentos que você fez, as posições de cada uma das peças no tabuleiro e
até mesmo se uma peça específica está selecionada .
Como funciona? Cada vez que ocorre uma mudança no jogo, chamamos esta função:
function saveGameState()
{ if (!supportsLocalStorage()) { return false; }
localStorage["halma.game.in.progress"] = gGameInProgress;
for (var i = 0; i < kNumPieces; i++) {
localStorage["halma.piece." + i + ".row"] = gPieces[i].row;
localStorage["halma.piece." + i + ".coluna"] = gPieces[i].coluna; }
localStorage["halma.selectedpiece"] = gSelectedPieceIndex;
localStorage["halma.selectedpiecehasmoved"] gSelectedPieceHasMoved;
localStorage["halma.movecount"] = gMoveCount;
retornar verdadeiro;
}
132 | Capítulo 7: O passado, o presente e o futuro do armazenamento local para aplicativos da Web
Como você pode ver, ele usa o objeto localStorage para salvar se há um jogo em andamento
(gGameInProgress, um booleano). Nesse caso, ele itera pelas peças (gPieces, um array JavaScript ) e
salva o número da linha e da coluna de cada peça. Em seguida, ele salva algum estado adicional do
jogo, incluindo qual peça está selecionada (gSelectedPieceIndex, um número inteiro), se a peça está no
meio de uma série potencialmente longa de saltos (gSelectedPieceHasMoved, um booleano) e o número
total de movimentos feitos até agora (gMoveCount, um número inteiro).
No carregamento da página, em vez de chamar automaticamente uma função newGame() que redefiniria
essas variáveis para valores codificados, chamamos uma função resumeGame() . Usando o
armazenamento HTML5, a função resumeGame() verifica se algum estado sobre um jogo em andamento
está armazenado localmente. Nesse caso, ele restaura esses valores usando o objeto localStorage :
function resumeGame()
{ if (!supportsLocalStorage()) { return false; }
gGameInProgress = (localStorage["halma.game.in.progress"] == "true"); if (!
gGameInProgress) { retornar falso; }
gPieces = new Array(kNumPieces);
for (var i = 0; i < kNumPieces; i++) { var
row = parseInt(localStorage["halma.piece." + i + ".row"]); var coluna
= parseInt(localStorage["halma.piece." + i + ".column"]); gPieces[i] = new
Cell(linha, coluna); } gNumPieces =
kNumPieces;
gSelectedPieceIndex = parseInt(localStorage["halma.selectedpiece"]);
gSelectedPieceHasMoved = localStorage["halma.selectedpiecehasmoved"] == "true";
gMoveCount = parseInt(localStorage["halma.movecount"]);
drawBoard();
retornar verdadeiro;
}
A parte mais importante desta função é a advertência que mencionei anteriormente neste capítulo, que
repetirei aqui: Os dados são armazenados como strings. Se você estiver armazenando algo diferente de
uma string, você mesmo precisará coagi-lo ao recuperá-lo. Por exemplo, o sinalizador para saber se há
um jogo em andamento (gGameInProgress) é um booleano. Na função saveGameState() , apenas
armazenamos e não nos preocupamos com o tipo de dados:
localStorage["halma.game.in.progress"] = gGameInProgress;
Mas na função resumeGame() , precisamos tratar o valor que obtivemos da área de armazenamento
local como uma string e construir manualmente o valor booleano adequado:
localStorage["halma.movecount"] = gMoveCount;
Mas na função resumeGame() , precisamos forçar o valor para um número inteiro, usando a função
parseInt() incorporada ao JavaScript: gMoveCount
= parseInt(localStorage["halma.movecount"]);
Embora o passado esteja repleto de hacks e soluções alternativas (veja “Uma Breve História do Local
Hacks de armazenamento antes do HTML5” na página 128), a condição atual do armazenamento HTML5
é surpreendentemente róseo. Uma nova API foi padronizada e implementada em todos os principais
navegadores, plataformas e dispositivos. Como desenvolvedor web, isso não é algo que você
vejo todos os dias, não é? Mas a vida é mais do que 5 MB de pares chave/valor nomeados, e
o futuro do armazenamento local persistente é... como posso dizer? Bem, há uma série de
visões concorrentes.
Uma visão é um acrônimo que você provavelmente já conhece: SQL. Em 2007, Google
lançou o Gears, um plug-in de código aberto para vários navegadores que incluía uma base de dados incorporada baseada
em SQLite. Este protótipo inicial influenciou mais tarde a criação da Web
Especificação do banco de dados SQL. O Banco de Dados SQL da Web (anteriormente conhecido como “WebDB”) fornece
um wrapper fino em torno de um banco de dados SQL, permitindo que você faça coisas como esta a partir de
JavaScript:
Como você pode ver, a maior parte da ação reside na string que você passa para executeSql()
método. Esta string pode ser qualquer instrução SQL suportada, incluindo SELECT, UPDATE,
INSERIR e EXCLUIR. É como programar banco de dados back-end, exceto que você está fazendo
isso em JavaScript! Ah, alegria!
A Tabela 7-3 mostra quais navegadores implementaram o Banco de Dados Web SQL
especificação.
Claro, se você usou mais de um produto de banco de dados em sua vida, você sabe
que “SQL” é mais um termo de marketing do que um padrão rígido e rápido. (Alguns gostariam
diga o mesmo de “HTML5”, mas não importa isso.) Claro, existe um SQL real
especificação - é chamada SQL-92 - mas não há nenhum servidor de banco de dados no mundo que
está em conformidade com essa e somente essa especificação. Existe o SQL da Oracle, o SQL da Microsoft,
SQL do MySQL, SQL do PostgreSQL e SQL do SQLite. E cada um desses produtos acrescenta
novos recursos SQL ao longo do tempo, portanto, mesmo dizer “SQL do SQLite” não é suficiente para fixar
exatamente o que você está falando - você precisa dizer “a versão do SQL que
enviado com SQLite versão XYZ”
134 | Capítulo 7: O passado, o presente e o futuro do armazenamento local para aplicativos da Web
Tudo isso nos leva à seguinte isenção de responsabilidade, atualmente presente no topo da lista
Especificação do banco de dados SQL da Web:
É nesse contexto que apresentarei outra visão concorrente para armazenamento local avançado e persistente para aplicações
web: a API de banco de dados indexado, anteriormente conhecido como “WebSimpleDB”, agora carinhosamente conhecido
como “IndexedDB”.
A API do banco de dados indexado expõe o que é chamado de armazenamento de objetos. Um armazenamento de objetos
compartilha muitos conceitos com um banco de dados SQL. Existem “bancos de dados” com “registros” e cada registro possui
um número definido de “campos”. Cada campo possui um tipo de dados específico, que é definido quando o banco de dados é
criado. Você pode selecionar um subconjunto de registros e enumerá-los com um “cursor”. As alterações no armazenamento
Se você já programou algum banco de dados SQL, esses termos provavelmente lhe parecem familiares.
A principal diferença é que o armazenamento de objetos não possui linguagem de consulta estruturada. Você não constrói uma
instrução como "SELECT * from USERS where ACTIVE = 'Y'". Em vez disso, você usa métodos fornecidos pelo armazenamento
de objetos para abrir um cursor no banco de dados chamado USERS, enumerar os registros, filtrar registros de usuários
inativos e usar métodos de acesso para obter os valores de cada campo nos registros restantes. O primeiro passo a passo do
IndexedDB é um bom tutorial sobre como o IndexedDB funciona, fornecendo comparações lado a lado do IndexedDB e do
banco de dados SQL da Web.
No momento em que este artigo foi escrito, o IndexedDB não foi implementado em nenhum navegador importante. No início de
junho de 2010, a Mozilla disse que “teria algumas compilações de teste nas próximas semanas”, mas ainda não há informações
se ele será lançado no Firefox 4. (Por outro lado, a Mozilla declarou que nunca implementará o banco de dados SQL da Web.)
O Google declarou que está considerando o suporte ao IndexedDB, e até a Microsoft disse que o IndexedDB “é uma ótima
solução para a Web”.
Então, o que você, como desenvolvedor web, pode fazer com o IndexedDB? No momento, absolutamente nada. Daqui a um
ano? Talvez alguma coisa. Verifique a seção “Leitura adicional” para obter links para alguns bons tutoriais para você começar.
Leitura adicional
Armazenamento HTML5:
Web: armazenamento de dados do lado do cliente mais fácil e poderoso”, por Shwetank Dixit
• “Introdução ao armazenamento DOM” no Mozilla Developer Center. (Nota: a maior parte desta página
é dedicada ao protótipo de implementação do objeto globalStorage no Firefox, um precursor não
padrão do localStorage. A Mozilla adicionou suporte para a interface localStorage padrão no Firefox
3.5.)
• “Desbloqueie o armazenamento local para aplicativos Web móveis com HTML 5”, um tutorial sobre
IBM DeveloperWorks
• “Internet Explorer tem suporte nativo para persistência?!?!”, sobre os dados do usuário
objeto no IE
• Armazenamento Dojo, parte de um tutorial maior sobre a (agora extinta) biblioteca Dojo Offline •
referência da API dojox.storage.manager •
• persistência.js, um “ORM JavaScript assíncrono” construído sobre base de dados Web SQL e Gears
136 | Capítulo 7: O passado, o presente e o futuro do armazenamento local para aplicativos da Web
CAPÍTULO 8
Mergulhando
Na sua forma mais simples, uma aplicação web offline é apenas uma lista de URLs apontando para HTML, CSS,
ou arquivos JavaScript, imagens ou quaisquer outros tipos de recursos que possam estar presentes. O
página inicial do aplicativo da web off-line aponta para esta lista, chamada de arquivo de manifesto, que
é apenas um arquivo de texto localizado em outro lugar no servidor web. Um navegador web que implementa
Os aplicativos offline HTML5 lerão a lista de URLs do arquivo de manifesto, farão o download
os recursos, armazená-los em cache localmente e manter automaticamente as cópias locais atualizadas
à medida que eles mudam. Quando você tenta acessar o aplicativo da web sem uma conexão de rede, seu
navegador da web mudará automaticamente para as cópias locais.
A partir daí, a maior parte do trabalho depende de você, como desenvolvedor web. Há uma bandeira no
DOM que lhe dirá se você está online ou offline, e há eventos que disparam
quando seu status muda (um minuto você está off-line e no minuto seguinte você está on-line,
ou vice-versa). Mas é basicamente isso. Se seu aplicativo criar dados ou salvar estado,
cabe a você armazenar esses dados localmente (veja o Capítulo 7) enquanto estiver offline e sincronizá-los
com o servidor remoto quando estiver online novamente. Em outras palavras, HTML5
pode colocar seu aplicativo da web off-line, mas o que você fará quando estiver lá depende de você.
A Tabela 8-1 mostra quais navegadores suportam aplicações web offline.
137
O Manifesto de Cache
Um aplicativo da web offline gira em torno de um arquivo de manifesto de cache. Como já mencionei, o arquivo de
manifesto é uma lista de todos os recursos que seu aplicativo Web pode precisar acessar enquanto estiver
desconectado da rede. Para iniciar o processo de download e armazenamento em cache desses recursos, você
precisa apontar para o arquivo manifesto, usando o atributo manifest no seu elemento <html>:
<!DOCTYPE
HTML> <html manifest="/
cache.manifest"> <body>
...
</body>
</html>
Seu arquivo de manifesto de cache pode estar localizado em qualquer lugar do seu servidor web, mas deve ser
servido com o tipo de conteúdo text/cache-manifest. Se você estiver executando um servidor web baseado em
Apache, provavelmente poderá simplesmente colocar uma diretiva AddType no arquivo .htaccess na raiz do seu
diretório web:
Em seguida, certifique-se de que o nome do arquivo de manifesto do cache termine com .manifest. Se você usar um
servidor web diferente ou uma configuração diferente do Apache, consulte a documentação do seu servidor sobre
como controlar o cabeçalho Content-Type.
P: Minha aplicação web abrange diversas páginas. Preciso de um atributo de manifesto em cada página ou
posso simplesmente colocá-lo na página inicial?
R: Cada página do seu aplicativo da web precisa de um atributo de manifesto que aponte para o manifesto
de cache de todo o aplicativo.
OK, então cada uma de suas páginas HTML aponta para o arquivo de manifesto de cache, e seu arquivo de manifesto
de cache está sendo servido com o cabeçalho Content-Type adequado. Mas o que está no arquivo de manifesto? É
onde as coisas começam a ficar interessantes.
Depois disso, todos os arquivos de manifesto são divididos em três partes: a seção “explícita”, a seção “substituta” e
a seção “lista de permissões online”. Cada seção possui um cabeçalho, em sua própria linha. Se o arquivo de
manifesto não tiver nenhum cabeçalho de seção, todos os recursos listados estarão implicitamente na seção
“explícita”. Tente não se preocupar com a terminologia, para que sua cabeça não exploda.
Aqui está um arquivo de manifesto válido. Ele lista três recursos – um arquivo CSS, um arquivo JavaScript e
uma imagem JPEG:
MANIFESTO DE
CACHE /
clock.css /
clock.js /clock-face.jpg
Este arquivo de manifesto de cache não possui cabeçalhos de seção, portanto, todos os recursos listados estão
na seção “explícita” por padrão. Os recursos na seção “explícita” serão baixados e armazenados em cache
localmente e serão usados no lugar de suas contrapartes online sempre que você estiver desconectado da rede.
Assim, ao carregar este arquivo de manifesto de cache, seu navegador baixará clock.css, clock.js e clock-
face.jpg do diretório raiz do seu servidor web. Você pode então desconectar o cabo de rede e atualizar a página,
e todos esses recursos estarão disponíveis offline.
R: Sim e não. Se todo o seu aplicativo da web estiver contido em uma única página, certifique-se de que
a página aponte para o manifesto do cache usando o atributo manifest. Quando você navega para uma
página HTML com um atributo de manifesto, presume-se que a própria página faça parte do aplicativo
Web, portanto, não é necessário listá-la no próprio arquivo de manifesto. Entretanto, se seu aplicativo
Web abranger diversas páginas, você deverá listar todas as páginas HTML no arquivo de manifesto;
caso contrário, o navegador não saberá que existem outras páginas HTML que precisam ser baixadas e
armazenadas em cache.
Seções de rede
Aqui está um exemplo um pouco mais complicado. Suponha que você queira que seu aplicativo de relógio
rastreie visitantes, usando um script tracking.cgi que é carregado dinamicamente a partir de um atributo <img
src>. Armazenar esse recurso em cache anularia o propósito de rastreamento, portanto, esse recurso nunca
deve ser armazenado em cache e nunca estar disponível off-line. Aqui está como você faz isso:
MANIFESTO DE CACHE
REDE:
/tracking.cgi
CACHE: /
clock.css /
clock.js /clock-face.jpg
Este arquivo de manifesto de cache inclui cabeçalhos de seção. A linha marcada NETWORK: é o início da
seção “lista branca online”. Os recursos nesta seção nunca são armazenados em cache e não estão disponíveis
offline. (Tentar carregá-los off-line resultará em erro.)
A linha marcada CACHE: é o início da seção “explícita”. O restante do arquivo de manifesto do cache é igual ao
exemplo anterior. Cada um dos três recursos listados será armazenado em cache e estará disponível offline.
Seções substitutas
Há mais um tipo de seção em um arquivo de manifesto de cache: uma seção substituta. Em uma seção de
fallback, você pode definir substituições para recursos online que, por qualquer motivo, não podem ser
armazenados em cache ou não foram armazenados em cache com êxito. A especificação HTML5 oferece
este exemplo inteligente de uso de uma seção substituta:
CACHE
MANIFEST
FALLBACK: //
offline.html REDE:
*
O que isso faz? Primeiro, considere um site que contém milhões de páginas, como o Wikipédia. Você não
poderia baixar o site inteiro, nem gostaria de fazer isso. Mas suponha que você pudesse disponibilizar
parte dele off-line. Como você decidiria quais páginas armazenar em cache? Que tal isto: cada página que
você já viu em uma hipotética Wikipédia off-line seria baixada e armazenada em cache. Isso incluiria cada
entrada da enciclopédia que você já visitou, cada página de discussão (onde você pode ter discussões
improvisadas sobre uma entrada específica da enciclopédia) e cada página de edição (onde você pode
realmente fazer alterações naquela entrada específica).
É isso que este manifesto de cache faz. Suponha que todas as páginas HTML da Wikipedia (entrada,
página de discussão, página de edição, página de histórico) apontassem para este arquivo de manifesto
de cache. Quando você visita qualquer página que aponta para um manifesto de cache, seu navegador diz:
“Ei, esta página faz parte de um aplicativo da web offline, eu conheço algum?” Se o seu navegador nunca
tiver baixado esse arquivo de manifesto de cache específico, ele configurará um novo “appcache” offline
(abreviação de “cache de aplicativo”), baixará todos os recursos listados no manifesto de cache e, em
seguida, adicionará a página atual para o appcache. Se o seu navegador souber sobre esse manifesto de
cache, ele simplesmente adicionará a página atual ao appcache existente. De qualquer forma, a página
que você acabou de visitar acaba no appcache. Isso é importante. Isso significa que você pode ter um
aplicativo da web offline que adiciona páginas “preguiçosamente” conforme você as visita. Você não precisa
listar cada uma de suas páginas HTML no manifesto de cache.
Agora olhe para a seção alternativa. A seção de fallback neste manifesto de cache contém apenas uma
linha. A primeira parte da linha (antes do espaço) não é uma URL. É realmente um padrão de URL. O
caractere único (/) corresponderá a qualquer página do seu site, não apenas à página inicial. Quando você
tenta visitar uma página enquanto está offline, seu navegador irá procurá-la no appcache. Se o seu
navegador encontrar a página no appcache (porque você a visitou enquanto estava online e a página foi
adicionada implicitamente ao appcache naquele momento), ele exibirá a cópia em cache da página. Se o
seu navegador não encontrar a página no appc ache, em vez de exibir uma mensagem de erro, ele exibirá
a página /offline.html, conforme especificado na segunda metade da linha na seção de fallback.
Finalmente, vamos examinar a seção de rede. A seção de rede neste manifesto de cache também possui
apenas uma linha, que contém apenas um caractere (*). Este caractere tem um significado especial em
uma seção de rede. É chamado de “sinalizador curinga da lista de permissões online”.
Essa é uma maneira elegante de dizer que qualquer coisa que não esteja no appcache ainda pode ser
baixado do endereço da web original, desde que você tenha uma conexão com a Internet.
Isso é importante para um aplicativo da web off-line “aberto”. Continuando com nosso exemplo, isso significa que
enquanto você navega nesta hipotética Wikipédia on-line habilitada para off-line, seu navegador buscará
imagens, vídeos e outros recursos incorporados normalmente, mesmo que estejam em um domínio diferente.
(Isso é muito comum em sites grandes, mesmo que não façam parte de um aplicativo da Web off-line: as páginas
HTML são geradas e veiculadas localmente, enquanto as imagens e os vídeos são veiculados a partir de um
CDN em outro domínio.)
Sem esse sinalizador curinga, nossa hipotética Wikipedia habilitada para off-line se comportaria de maneira
estranha quando você estivesse on-line - especificamente, ela não carregaria nenhuma imagem ou vídeo
hospedado externamente!
Este exemplo está completo? Não. A Wikipédia é mais do que apenas arquivos HTML; ele usa CSS, JavaScript
e imagens comuns em cada página. Cada um desses recursos precisaria ser listado explicitamente na seção
CACHE: do arquivo de manifesto para que as páginas fossem exibidas e se comportassem adequadamente off-
line. Mas o objetivo da seção alternativa é que você pode ter um aplicativo da Web off-line “aberto” que se estende
além dos recursos listados explicitamente no arquivo de manifesto.
O Fluxo de Eventos
Até agora, falei sobre aplicativos web off-line, o manifesto de cache e o cache de aplicativos off-line (“appcache”)
em termos vagos e semimágicos. As coisas são baixadas, os navegadores tomam decisões e tudo “simplesmente
funciona”. Você sabe melhor do que isso, certo? Quero dizer, é de desenvolvimento web que estamos falando.
Nada nunca “simplesmente funciona”.
Primeiro, vamos falar sobre o fluxo de eventos, especificamente eventos DOM. Quando seu navegador visita uma
página que aponta para um manifesto de cache, ele dispara uma série de eventos no objeto
window.applicationCache, conforme descrevo abaixo. Eu sei que isso parece complicado, mas acredite em mim,
esta é a versão mais simples que consegui e que não deixou de fora informações importantes. Aqui está o
processo:
1. Assim que notar um atributo manifesto no elemento <html>, seu navegador dispara um evento de verificação.
(Todos os eventos listados aqui são acionados no objeto de cache window.applicationC.) O evento de
verificação é sempre acionado, independentemente de você ter visitado esta página anteriormente ou
qualquer outra página que aponte para o mesmo manifesto de cache.
• Ele disparará um evento de download e, em seguida, iniciará o download dos recursos listados no
manifesto do cache.
• Durante o download, seu navegador disparará periodicamente eventos de progresso, que contêm
informações sobre quantos arquivos já foram baixados e quantos arquivos ainda estão na fila para
download.
• Após o download completo de todos os recursos listados no manifesto de cache, o navegador dispara
O aplicativo da web está totalmente armazenado em cache e pronto para ser usado offline. É isso; Você
Terminou.
3. Por outro lado, se você já visitou esta página ou qualquer outra página que aponte para o mesmo manifesto de
cache, seu navegador já conhece esse manifesto de cache e pode já ter alguns recursos no appcache. Na
verdade, ele pode ter todo o aplicativo da web offline funcionando no appcache. Então agora a questão é: o
manifesto do cache mudou desde a última vez que seu navegador o verificou? • Se a resposta for não, o
manifesto do cache não foi alterado. Nesse caso, seu navegador disparará imediatamente um evento
noupdate. É isso; Você Terminou. • Se a resposta for sim, o manifesto do cache foi alterado. Nesse caso, seu
navegador disparará um evento de download e começará a baixar novamente cada recurso
Durante o download, seu navegador disparará periodicamente eventos de progresso, que contêm informações
sobre quantos arquivos já foram baixados e quantos arquivos ainda estão na fila para download.
Depois que todos os recursos listados no manifesto do cache forem baixados novamente com sucesso, o
navegador disparará um evento final, updateready. Este é o seu sinal de que a nova versão do seu aplicativo
da web offline está totalmente armazenada em cache e pronta para ser usada offline. A nova versão ainda não
está em uso. Para fazer “hot-swap” para a nova versão sem forçar o usuário a recarregar a página, você pode
chamar manualmente a função window.applicationC ache.swapCache().
Se, em qualquer ponto deste processo, algo der terrivelmente errado, seu navegador disparará um evento de erro e
parará. Aqui está uma lista irremediavelmente abreviada de coisas que podem dar errado:
• O manifesto do cache retornou um HTTP 404 (Página não encontrada) ou 410 (Permanentemente
Desaparecido) erro.
• O manifesto do cache foi encontrado e não foi alterado, mas a página HTML que apontava para o manifesto não
foi baixada corretamente. • O manifesto do cache foi encontrado e
alterado, mas o navegador não conseguiu baixar um dos recursos listados no manifesto do cache.
A Bela Arte da Depuração, também conhecida como “Kill Me! Me mate agora!"
Quero destacar dois pontos importantes aqui. O primeiro é algo que você acabou de ler, mas provavelmente não
entendeu, então aqui está novamente: se mesmo um único recurso listado em seu arquivo de manifesto de cache
falhar no download corretamente, todo o processo de armazenamento em cache de seu aplicativo da web offline
falhará . Seu navegador disparará o evento de erro, mas não haverá indicação de qual era o problema real. Isso
pode tornar a depuração de aplicativos da Web off-line extremamente frustrante.
O segundo ponto importante é algo que não é, tecnicamente falando, um erro, mas parecerá um
bug grave do navegador até você perceber o que está acontecendo. Tem a ver exatamente com a
forma como o seu navegador verifica se um arquivo de manifesto de cache foi alterado.
Este é um processo de três fases. Isso é chato, mas importante, então preste atenção. Aqui está o
procedimento:
1. Através da semântica HTTP normal, seu navegador verificará se o manifesto do cache expirou.
Assim como acontece com qualquer outro arquivo servido por HTTP, seu servidor web
normalmente incluirá metainformações sobre o arquivo nos cabeçalhos de resposta HTTP.
Alguns desses cabeçalhos HTTP (Expires e Cache-Control) informam ao seu navegador como
é permitido armazenar o arquivo em cache sem nunca perguntar ao servidor se ele foi alterado.
Esse tipo de cache não tem nada a ver com aplicativos da web offline. Isso acontece com
praticamente todas as páginas HTML, folhas de estilo, scripts, imagens ou outros recursos no
a teia.
2. Se o manifesto do cache expirou (de acordo com seus cabeçalhos HTTP), seu navegador
perguntará ao servidor se existe uma nova versão e, em caso afirmativo, fará o download dela.
Para fazer isso, seu navegador emite uma solicitação HTTP que inclui a data da última
modificação do arquivo de manifesto de cache, que seu servidor web incluiu nos cabeçalhos
de resposta HTTP na última vez que seu navegador baixou o arquivo. Se o servidor web
determinar que o arquivo de manifesto não foi alterado desde aquela data, ele simplesmente
retornará um código de status 304 (Não Modificado). Novamente, nada disso é específico para
aplicações web off-line. Isso acontece com praticamente todos os recursos da Web.
3. Se o servidor web achar que o arquivo de manifesto foi alterado desde aquela data, ele retornará
um código de status HTTP 200 (OK), seguido pelo conteúdo do novo arquivo junto com os
novos cabeçalhos Cache-Control e uma nova data da última modificação . Isso garante que as
etapas 1 e 2 funcionarão corretamente na próxima vez. (HTTP é legal; os servidores web estão
sempre planejando o futuro. Se o seu servidor web realmente precisa enviar um arquivo para
você, ele faz tudo o que pode para garantir que não precise enviá-lo duas vezes sem motivo.)
Depois de baixado o novo arquivo de manifesto de cache, seu navegador verificará o conteúdo
em relação à cópia baixada da última vez. Se o conteúdo do arquivo de manifesto de cache for
o mesmo da última vez, seu navegador não baixará novamente nenhum dos recursos listados
no manifesto.
Qualquer uma dessas etapas pode atrapalhar você enquanto desenvolve e testa seu aplicativo da
web offline. Por exemplo, digamos que você implemente uma versão do seu arquivo de manifesto
de cache e, 10 minutos depois, perceba que precisa adicionar outro recurso a ele. Não tem problema,
certo? Basta adicionar outra linha e reimplantar. Bzzt. Aqui está o que vai acontecer: você recarrega
a página, seu navegador percebe o atributo manifesto, aciona o evento de verificação e então...
nada. Seu navegador insiste teimosamente que o arquivo de manifesto do cache não foi alterado.
Por que? Porque, por padrão, seu servidor web provavelmente está configurado para instruir os
navegadores a armazenar arquivos estáticos em cache por algumas horas (via semântica HTTP,
usando cabeçalhos Cache-Control). Isso significa que seu navegador nunca passará da etapa 1
desse processo de três fases. Claro, o servidor web sabe que o arquivo foi alterado, mas seu
navegador nem sequer pergunta ao servidor web. Por que? Porque a última vez
A Bela Arte da Depuração, também conhecida como “Kill Me! Me mate agora!" | 143
seu navegador baixou o manifesto do cache, o servidor da web disse para ele armazenar o recurso em cache por algumas
horas (via semântica HTTP, usando cabeçalhos Cache-Control). E agora, 10 minutos depois, é exatamente isso que o seu
navegador está fazendo.
Para ser claro, isso não é um bug, é um recurso. Tudo está funcionando exatamente como deveria. Se os servidores web não
tivessem uma maneira de dizer aos navegadores (e proxies intermediários) para armazenar coisas em cache, a web entraria
em colapso da noite para o dia. Mas isso não é nenhum conforto depois de passar algumas horas tentando descobrir por que
seu navegador não notará o manifesto de cache atualizado. (E melhor ainda, se você esperar o suficiente, ele começará a
funcionar misteriosamente novamente! Porque o cache HTTP expirou! Exatamente como deveria! Mate-me!
Me mate agora!)
Então, aqui está uma coisa que você absolutamente deve fazer: reconfigurar seu servidor web para que seu arquivo de
manifesto de cache não possa ser armazenado em cache pela semântica HTTP. Se você estiver executando um servidor web
baseado em Apache, estas duas linhas em seu arquivo .htaccess resolverão o problema:
Expira Ativo em
Expira o "acesso" padrão
Na verdade, isso desativará o cache para todos os arquivos nesse diretório e em todos os subdiretórios.
Provavelmente não é isso que você deseja na produção, então você deve qualificar isso com uma diretiva <Files> para que
afete apenas o arquivo de manifesto de cache ou criar um subdiretório que contenha nada além deste arquivo .htaccess e seu
arquivo de manifesto de cache. Como de costume, os detalhes de configuração variam de acordo com o servidor web, portanto
consulte a documentação do seu servidor para saber como controlar os cabeçalhos de cache HTTP.
No entanto, desabilitar o cache HTTP no arquivo de manifesto do cache não resolverá todos os seus problemas. Você ainda
terá momentos em que alterou um dos recursos no appcache, mas ele ainda estará na mesma URL em seu servidor web. Aqui,
a etapa 2 do processo trifásico vai ferrar você. Se o seu arquivo de manifesto de cache não tiver sido alterado, o navegador
nunca notará que um dos recursos armazenados em cache anteriormente foi alterado. Considere o seguinte exemplo:
MANIFESTO DE CACHE
# rev 42
relógio.js
relógio.css
Se você alterar clock.css e reimplantá-lo, não verá as alterações, porque o arquivo de manifesto do cache em si não foi alterado.
Cada vez que você fizer uma alteração em um dos recursos do seu aplicativo Web offline, será necessário alterar o próprio
arquivo de manifesto de cache. Isso pode ser tão simples quanto alterar um único caractere. A maneira mais fácil que encontrei
de fazer isso é incluir uma linha de comentário com um número de revisão no arquivo de manifesto. Sempre que você alterar
um dos recursos, altere o número da revisão no comentário. O servidor web retornará o arquivo de manifesto de cache recém-
alterado, seu navegador notará que o conteúdo do arquivo foi alterado e iniciará o processo para baixar novamente todos os
recursos listados no manifesto:
MANIFESTO DE
CACHE # rev 43
relógio.js
relógio.css
Lembra-se do jogo Halma que apresentamos no Capítulo 4 (veja “Um exemplo completo” na página 75) e
posteriormente melhorado salvando o estado com armazenamento local persistente (veja “Armazenamento
HTML5 em ação” na página 132)? Vamos colocar nosso jogo Halma offline.
Para fazer isso, precisamos de um manifesto que liste todos os recursos de que o jogo precisa. Bem, há a
página HTML principal, um único arquivo JavaScript que contém todo o código do jogo e... é isso. Não há
imagens, porque todo o desenho é feito programaticamente através da API canvas (veja o Capítulo 4), e
todos os estilos CSS necessários estão em um elemento <style> no topo da página HTML. Então, este é o
nosso manifesto de cache:
MANIFESTO DE
CACHE halma.html
../halma-localstorage.js
Uma palavra sobre caminhos. Criei um subdiretório offline/ no diretório exemplos/ e esse arquivo de manifesto
de cache fica dentro do subdiretório. Como a página HTML precisará de uma pequena adição para funcionar
off-line (mais sobre isso em um minuto), criei uma cópia separada do arquivo HTML, que também fica no
subdiretório offline/. Mas como não há alterações no código JavaScript em si desde que adicionamos suporte
ao armazenamento local (consulte “Armazenamento HTML5 em ação” na página 132), estou literalmente
reutilizando o mesmo arquivo .js, que fica no diretório pai (exemplos/ ). Ao todo, os arquivos ficam assim: /
examples/localstorage-halma.html /examples/halma-localstorage.js /examples/offline/halma.manifest /
examples/offline/halma.html
Agora, no arquivo HTML, precisamos adicionar o atributo manifest que aponta para o arquivo de manifesto do
cache:
<!DOCTYPE
html> <html lang="en" manifest="halma.manifest">
E é isso! Quando um navegador com capacidade off-line carrega pela primeira vez a página
HTML habilitada para off-line, ele baixa o arquivo de manifesto do cache vinculado e começa a
baixar todos os recursos referenciados e a armazená-los no cache do aplicativo off-line. A partir
de então, o algoritmo do aplicativo offline assumirá o controle sempre que você revisitar a página.
Você pode jogar offline e, como ele se lembra de seu estado localmente, você pode sair e voltar
quantas vezes quiser.
Leitura adicional
Padrões:
• “Gmail for Mobile HTML5 Series: Using Appcache to Launch Offline - part 1”, por
Andrew Grieve
• “Gmail for Mobile HTML5 Series: Using Appcache to Launch Offline - part 2”, por
Andrew Grieve
• “Gmail for Mobile HTML5 Series: Usando Appcache para iniciar off-line - parte 3”, por
Andrew Grieve
• “Depurando cache de aplicativos offline HTML 5”, por Jonathan Stark • “Um
aplicativo de upload e editor de imagens offline HTML5”, por Paul Rouget
CAPÍTULO 9
Mergulhando
Todo mundo conhece formulários web, certo? Faça um <form>, adicione alguns elementos <input type="text"> e talvez
uma <input type="password">, finalize com um botão <input type="submit"> e pronto .
Você não sabe nem metade disso. HTML5 define mais de uma dúzia de novos tipos de entrada que você pode usar em
seus formulários. E quando digo “usar”, quero dizer que você pode usá-los agora mesmo, sem quaisquer correções, hacks
ou soluções alternativas. Agora não fique muito animado; Não quero dizer que todos esses novos recursos interessantes
sejam realmente suportados em todos os navegadores.
Oh meu Deus, não, não quero dizer isso de jeito nenhum. Nos navegadores modernos, sim, seus formulários vão arrasar
com todo tipo de bunda. Em navegadores legados, seus formulários ainda funcionarão, mas com menos agressões.
O que quer dizer que todos esses recursos são degradados normalmente em todos os navegadores. Até mesmo o IE 6.
A primeira melhoria que o HTML5 traz aos formulários da web é a capacidade de definir texto de espaço reservado em um
campo de entrada. O texto do espaço reservado é exibido dentro do campo de entrada enquanto o campo estiver vazio e
sem foco. Assim que você clica (ou tabula) no campo de entrada, o texto do espaço reservado desaparece.
Você provavelmente já viu texto de espaço reservado antes. Por exemplo, o Mozilla Firefox 3.5 agora inclui texto de espaço
reservado na barra de localização que diz “Marcadores e histórico de pesquisa”, conforme mostrado na Figura 9-1.
147
Quando você clica (ou tabula) na barra de localização, o texto do espaço reservado desaparece
(Figura 9-2).
Ironicamente, o Firefox 3.5 não suporta a adição de texto de espaço reservado aos seus próprios formulários web.
É a vida. O suporte do navegador para espaços reservados é mostrado na Tabela 9-1.
Veja como você pode incluir texto de espaço reservado em seus próprios formulários da web:
<formulário>
Os navegadores que não suportam o atributo placeholder irão simplesmente ignorá-lo. Nenhum dano,
nenhuma falta.
P: Posso usar marcação HTML no atributo placeholder ? Quero inserir uma imagem ou
talvez mude as cores.
Muitos sites usam JavaScript para focar automaticamente o primeiro campo de entrada de um formulário da web.
Por exemplo, a página inicial do Google.com focará automaticamente a caixa de entrada para que você possa
digite as palavras-chave de pesquisa sem precisar posicionar o cursor na caixa de pesquisa.
Embora isso seja conveniente para a maioria das pessoas, pode ser irritante para usuários avançados ou pessoas
com necessidades especiais. Se você pressionar a barra de espaço esperando rolar a página, a página irá
não role porque o foco já está em um campo de entrada de formulário. Em vez disso, você digitará um espaço
no campo. Se você focar em um campo de entrada diferente enquanto a página ainda está carregando, o site
O script de foco automático pode “útil” mover o foco de volta para o campo de entrada original após
conclusão, interrompendo seu fluxo e fazendo com que você digite no lugar errado.
Como o foco automático é feito com JavaScript, pode ser complicado lidar com tudo isso
casos extremos, e há poucos recursos para pessoas que não querem que uma página da web seja “roubada”
o foco.
Para resolver esse problema, o HTML5 introduz um atributo autofocus em todos os formulários da web.
trolls. O atributo autofocus faz exatamente o que diz na lata: assim que a página
carrega, ele move o foco de entrada para um campo de entrada específico. Mas porque é apenas marcação
em vez de script, o comportamento será consistente em todos os sites. Além disso, os fornecedores de navegadores (ou
autores de extensões) podem oferecer aos usuários uma maneira de desativar o comportamento de foco automático.
A Tabela 9-2 mostra quais navegadores suportam foco automático.
Veja como você pode definir um campo de formulário para foco automático:
<formulário>
O que é isso? Você diz que deseja que seus campos de foco automático funcionem em todos os navegadores, não apenas
esses navegadores HTML5 sofisticados? Você pode manter seu script de foco automático atual. Apenas
faça duas pequenas alterações:
2. Detecte se o navegador suporta o atributo autofocus (consulte “Formulário de foco automático” na página 27) e
execute seu próprio script de foco automático somente se o navegador não suportar.
suporta foco automático nativamente:
<nome do formulário="f">
muitas páginas da web esperam até que window.onload seja acionado para definir o foco. Mas o
evento window.onload não é acionado até que todas as suas imagens sejam carregadas. Se a sua
página tiver muitas imagens, um script tão ingênuo poderá reorientar o campo depois que o usuário
começar a interagir com outra parte da sua página. (É por isso que usuários avançados odeiam
scripts de foco automático.) O exemplo anterior coloca o script de foco automático imediatamente
após o campo de formulário ao qual ele faz referência, mas seus sistemas de back-end podem não
ser tão flexíveis. Se você não conseguir inserir um script no meio da sua página, você deve definir o
foco durante um evento personalizado como $(document).ready() do jQuery em vez de window.onload.
Endereço de e-mail
Durante mais de uma década, os formulários web incluíram apenas alguns tipos de campos – os mais comuns
estão listados na Tabela 9-3.
Caixa de seleção
<input type="checkbox"> Pode ser ativado ou
Botao de radio desativado <input type="radio"> Pode ser agrupado com outras entradas
Campo de senha <input type="password"> Ecoa pontos em vez de caracteres conforme o usuário digita
Seletor de arquivos <input type="arquivo"> Abre uma caixa de diálogo “abrir arquivo”
Texto simples
<input type="texto"> O atributo type pode ser omitido
Todos esses tipos de entrada ainda funcionam em HTML5. Se você estiver “atualizando para HTML5” (talvez
alterando seu tipo de documento; consulte “O tipo de documento” na página 31), não será necessário fazer
nenhuma alteração em seus formulários da web. Viva a compatibilidade com versões anteriores!
No entanto, o HTML5 define vários novos tipos de campos e, por motivos que ficarão claros em breve, não há
razão para não começar a usá-los.
O primeiro desses novos tipos de entrada é para endereços de email. Se parece com isso:
<formulário>
Eu estava prestes a escrever uma frase que começava com “Em navegadores que não suportam type="email"...”,
mas me contive. Por que? Porque não tenho certeza do que significaria dizer que um navegador não suporta
type = "email". Todos os navegadores “suportam” type="email". Eles podem não fazer nada de especial com
isso (você verá alguns exemplos de
tratamento especial em breve), mas navegadores que não reconhecem type="email" irão tratá-lo como
type="text" e renderizá-lo como um campo de texto simples.
Não consigo enfatizar o suficiente o quão importante isso é. A Web possui milhões de formulários que
solicitam que você insira um endereço de e-mail, e todos eles usam <input type="text">. Você vê uma caixa
de texto, digita seu endereço de e-mail na caixa de texto e pronto. Depois vem o HTML5, que define
type="email". Os navegadores enlouquecem? Não. Todos os navegadores do planeta tratam um atributo de
tipo desconhecido como type="text" — até mesmo o IE 6. Assim, você pode “atualizar” seus formulários
web para usar type="email" agora mesmo.
O que significaria dizer que um navegador suporta type ="email"? Bem, isso pode significar uma série de
coisas. A especificação HTML5 não exige nenhuma interface de usuário específica para os novos tipos de
entrada. O Opera estiliza o campo do formulário com um pequeno ícone de e-mail.
Outros navegadores HTML5, como Safari e Chrome, simplesmente o renderizam como uma caixa de texto
— exatamente como type="text" — para que seus usuários nunca saibam a diferença (a menos que
visualizem o código-fonte da página).
E depois há o iPhone.
O iPhone não possui teclado físico. Toda a “digitação” é feita tocando em um teclado na tela que aparece
nos momentos apropriados, como quando você foca um campo de formulário em uma página da web. A
Apple fez algo muito inteligente no navegador do iPhone: ele reconhece vários dos novos tipos de entrada
HTML5 e altera dinamicamente o teclado na tela para otimizar esse tipo de entrada.
Por exemplo, endereços de e-mail são texto, certo? Claro, mas são um tipo especial de texto.
Ou seja, praticamente todos os endereços de e-mail contêm o sinal @ e pelo menos um ponto final (.), mas
é improvável que contenham espaços. Portanto, quando um usuário do iPhone se concentra em um
elemento <input type="email"> , ele obtém um teclado na tela que contém uma barra de espaço menor que
o normal, além de teclas dedicadas para @ e . caracteres, conforme mostrado na Figura 9-3.
Endereços da Web
Endereços da Web – conhecidos por muitos como URLs e por alguns pedantes como URIs – são outro tipo
de texto especializado. A sintaxe de um endereço web é limitada pelos padrões relevantes da Internet. Se
alguém solicitar que você insira um endereço da web em um formulário, ele estará esperando algo como
http://www.google.com, e não “125 Farwood Road”. Barras e pontos são comuns, mas espaços são
proibidos. E todo endereço da web tem um sufixo de domínio como “.com” ou “.org”.
Eis...(rufar os tambores, por favor)...<input type="url">. No iPhone, parece com a Figura 9-4.
Assim como acontece com os campos de endereço de e-mail, o iPhone oferece um teclado virtual especial
otimizado para endereços da web. A barra de espaço foi completamente substituída por três teclas virtuais: um
ponto final, uma barra e um botão “.com”. Você pode manter pressionado o botão “.com” para escolher outros
sufixos comuns, como “.org” ou “.net”.
Os navegadores que não suportam HTML5 tratarão type="url" exatamente como type="text", portanto não há
nenhuma desvantagem em usá-lo para todas as suas necessidades de inserção de endereços da web.
A seguir: números. Pedir um número é, em muitos aspectos, mais complicado do que pedir um e-mail ou endereço
da web. Em primeiro lugar, os números são mais complicados do que você imagina.
Rápido: escolha um número. –1? Não, eu quis dizer um número entre 1 e 10. 7½? Não, não, nem uma fração,
bobo. ÿ? Agora você está apenas sendo irracional.
O que quero dizer é que você não costuma pedir “apenas um número”. É mais provável que você solicite um
número em um intervalo específico e queira apenas certos tipos de números dentro desse intervalo - talvez
números inteiros, mas não frações ou decimais, ou algo mais esotérico, como números divisíveis por 10. HTML5
tem você cobriu. Vejamos um exemplo:
<input type="número"
min="0"
max="10"
passo="2"
valor="6">
Vamos pegar um atributo de cada vez (você pode acompanhar com um exemplo ao vivo se você gostar):
especifica o valor mínimo aceitável para este campo. • max="10" é o valor máximo
números aceitáveis no
intervalo: 0, 2, 4 e assim por diante, até o valor máximo .
• valor="6" é o valor padrão. Isso deve parecer familiar. É o mesmo nome de atributo que você sempre usou
para especificar valores para campos de formulário. (Mencionei isso aqui para deixar claro que o HTML5 se
baseia em versões anteriores do HTML. Você não precisa reaprender como fazer coisas que já está fazendo.)
Esse é o lado da marcação de um campo numérico. Lembre-se de que todos esses atributos são opcionais. Se
você tiver um mínimo, mas não um máximo, poderá especificar um atributo min , mas nenhum atributo max . O
valor da etapa padrão é 1 e você pode omitir o atributo step , a menos que precise de um valor de etapa diferente.
Se não houver valor padrão, o atributo value pode ser uma string vazia ou até mesmo omitido por completo.
Mas o HTML5 não para por aí. Pelo mesmo preço baixo e gratuito, você também obtém estes
métodos JavaScript úteis:
entrada.stepUp(n)
Aumenta o valor do campo em n
input.stepDown(n)
Diminui o valor do campo em n
input.valueAsNumber
Retorna o valor atual como um número de ponto flutuante (a propriedade input.value é
sempre uma string)
Está tendo problemas para visualizá-lo? Bem, a interface exata de um controle numérico depende
do seu navegador, e diferentes fornecedores de navegadores implementaram suporte de maneiras
diferentes. No iPhone, onde a entrada é difícil no início, o navegador mais uma vez otimiza o
teclado virtual para entrada numérica, conforme mostrado na Figura 9-5.
O Opera respeita os atributos min, max e step , então você sempre terá um valor numérico aceitável.
Se você aumentar o valor até o máximo, a seta para cima na caixa giratória ficará acinzentada (Figura
9-7).
Tal como acontece com todos os outros tipos de entrada que discuti neste capítulo, os navegadores
que não suportam type="number" irão tratá-lo como type="text". O valor padrão aparecerá no campo (já
que está armazenado no atributo value ), mas os outros atributos, como min e max, serão ignorados.
Você está livre para implementá-los sozinho ou pode reutilizar uma das muitas estruturas JavaScript
que já implementaram controles de spinbox. Basta verificar primeiro o suporte nativo ao HTML5 (consulte
“Tipos de entrada” na página 25) , assim: if (!Modernizr.inputtypes.number) { // sem suporte nativo
para campos type="number" // talvez
tente Dojo ou alguma outra estrutura JavaScript }
As caixas giratórias, discutidas na seção anterior, não são a única maneira de representar entradas
numéricas. Você provavelmente também já viu controles “deslizantes” semelhantes aos da Figura 9-8.
Agora você também pode ter controles deslizantes em seus formulários da web. A marcação parece estranhamente
semelhante ao dos controles spinbox:
<input type="intervalo"
min="0"
máximo="10"
passo = "2"
valor="6">
Seletores de data
O HTML 4 não incluía um controle de seleção de data. Vários frameworks JavaScript têm
pegou a folga - por exemplo, Dojo, interface do usuário jQuery, YUI, e Closure Library - mas de
É claro que cada uma dessas soluções exige “aderir” à estrutura em que a data
selecionador é construído.
O HTML5 finalmente define uma maneira de incluir um controle nativo de seleção de data sem precisar
para fazer o script você mesmo. Na verdade, ele define seis: data, mês, semana, hora, data + hora e
data + hora – fuso horário.
9,0+ •
type="data"
9,0+ •
type="mês"
9,0+ •
type="semana"
9,0+ •
tipo = "tempo"
9,0+ •
tipo = "datahora"
•
type="datahora-local" 9.0+
Se você precisar de um horário para definir essa data, o Opera também suporta <input type="date
tempo">, conforme mostrado na Figura 9-10.
Se você precisar apenas de um mês e um ano (talvez a data de validade do cartão de crédito), o Opera pode
renderizar um <input type="mês">, conforme mostrado na Figura 9-11.
Menos comum, mas também disponível, é a capacidade de escolher uma semana específica do ano com <input
type="week">; veja a Figura 9-12.
Por último, mas não menos importante, você pode escolher um horário com <input type="time">, conforme mostrado
na Figura 9-13.
É provável que outros navegadores eventualmente suportem esses tipos de entrada. Enquanto
isso, assim como type="email" (veja “Endereços de e-mail” na página 150) e os outros tipos de
entrada, esses campos de formulário serão renderizados como caixas de texto simples em
navegadores que não reconhecem type="date" e as outras variantes. Se quiser, você pode
simplesmente usar <input type="date"> e amigos, deixar os usuários do Opera felizes e esperar
que outros navegadores o atualizem. Alternativamente, você pode usar <input type="date">,
detectar se o navegador tem suporte nativo para seletores de data (veja “Tipos de entrada” na
página 25) e recorrer a uma solução de script de sua escolha:
<formulário>
<input type="data">
</form>
...
<script>
var i = document.createElement("input");
i.setAttribute("tipo", "data"); if
(i.type == "text") { // Sem
suporte nativo para seletor de data :
( // Use Dojo/jQueryUI/YUI/Closure/alguma outra solução para criar
uma, // então substitua dinamicamente esse elemento
<input>. } </script>
Caixas de pesquisa
OK, este é sutil. Bem, a ideia é bastante simples, mas as implementações podem exigir alguma
explicação. Aqui vai....
Procurar. Não apenas a Pesquisa Google ou o Yahoo! Procurar. (Bem, esses também.) Pense em qualquer caixa de
pesquisa, em qualquer página, em qualquer site. Amazon tem uma caixa de pesquisa. Newegg tem uma caixa de pesquisa.
A maioria dos blogs possui uma caixa de pesquisa. Como eles são marcados? <input type="text">, assim como qualquer
outra caixa de texto na Web. Com HTML5, podemos consertar isso:
<formulário>
Em alguns navegadores, você não notará nenhuma diferença em relação a uma caixa de texto normal. Mas se você
estiver usando o Safari no Mac OS X, será semelhante à Figura 9.14.
Você pode ver a diferença? A caixa de entrada tem cantos arredondados! Eu sei, eu sei, você mal consegue conter sua
excitação. Mas espere, tem mais! Quando você começa a digitar na caixa type="search" , o Safari insere um pequeno
botão “x” no lado direito da caixa. Clicar no “x” limpa o conteúdo do campo. (O Google Chrome, que compartilha muita
tecnologia com o Safari, também exibe esse comportamento.) Esses dois pequenos ajustes são feitos para corresponder
à aparência das caixas de pesquisa nativas no iTunes e em outros aplicativos clientes do Mac OS X (Figura 9- 15).
A maçã website usa <input type="search"> em sua caixa de pesquisa de site, para ajudar a dar ao site uma sensação
“semelhante ao Mac”. Mas não há nada específico do Mac nisso. É apenas marcação, então cada navegador em cada
plataforma pode optar por renderizar a caixa de pesquisa de acordo com convenções específicas da plataforma. Tal
como acontece com todos os outros novos tipos de entrada, os navegadores que não reconhecem type="search" irão
tratá-lo como type="text", então não há absolutamente nenhuma razão para não começar a usar type="search" para
todas as suas caixas de pesquisa hoje.
Seletores de cores
HTML5 também define <input type="color">, que permite escolher uma cor e retornar a representação
hexadecimal dessa cor. Nenhum navegador oferece suporte ainda, o que é uma pena, porque sempre
adorei o seletor de cores do Mac OS. Talvez algum dia.
Sério, você vai entender errado. Determinar se uma sequência aleatória de caracteres é um endereço
de e-mail válido é incrivelmente complicado. Quanto mais você olha, mais complicado fica. Eu
mencionei que é muito, muito complicado? Não seria mais fácil descarregar toda a dor de cabeça no
seu navegador?
A captura de tela na Figura 9-16 é do Opera 10, embora a funcionalidade esteja presente desde o
Opera 9. A única marcação envolvida é definir o atributo type como "email" (consulte “Endereços de e-
mail” na página 150). Quando um usuário do Opera tenta enviar um formulário com um campo <input
type="email"> , o Opera oferece automaticamente validação de e-mail compatível com RFC, mesmo
se o script estiver desabilitado.
O Opera também oferece validação de endereços da web inseridos em campos <input type="url"> e
números em campos <input type="number"> . A validação dos números leva em consideração até
mesmo os atributos min e max , portanto o Opera não permitirá que os usuários enviem o formulário se
inserirem um número muito grande (Figura 9-17).
Infelizmente, nenhum outro navegador oferece suporte à validação automática de formulários HTML5
ainda, então você ficará preso a substitutos baseados em script por um tempo.
Leitura adicional
Especificações e padrões:
• tipos de <entrada>
• O atributo <espaço reservado de entrada>
• O atributo <input autofocus>
Bibliotecas JavaScript:
CAPÍTULO 10
“Distribuído”, “Extensibilidade” e
Mergulhando
Existem mais de 100 elementos em HTML5. Alguns são puramente semânticos (veja o Capítulo
3) e outros são apenas contêineres para APIs com script (veja o Capítulo 4). Ao longo da
história do HTML (veja o Capítulo 1), especialistas em padrões discutiram sobre quais elementos
deveriam ser incluídos na linguagem. O HTML deve incluir um elemento <figure>? Um
elemento <person>? Que tal um elemento <rant>? Decisões são tomadas, especificações são
escritas, autores criam, implementadores implementam e a Web avança cada vez mais.
É claro que o HTML não agrada a todos. Nenhum padrão pode. Algumas ideias não dão certo. Por
exemplo, não há elemento <person> em HTML5. (Também não há elemento <rant>, caramba!) Não
há nada que impeça você de incluir um elemento <person> em uma página da web, mas ele não será
validado, não funcionará de forma consistente em todos os navegadores (consulte “Uma longa
digressão em Como os navegadores tratam elementos desconhecidos” na página 42) e poderá entrar
em conflito com futuras especificações HTML se for adicionado posteriormente.
Então, se criar seus próprios elementos não é a resposta, o que um autor da web com
inclinação semantica deve fazer? Houve tentativas de estender versões anteriores do HTML.
O método mais popular é com microformatos, que usam os atributos class e rel no HTML
4. Outra opção é o RDFa, que foi originalmente projetado para ser usado em XHTML
(veja “Postscript” na página 14), mas agora está sendo portado para HTML como bem.
Tanto os microformatos quanto o RDFa têm seus pontos fortes e fracos. Eles adotam abordagens
radicalmente diferentes em direção ao mesmo objetivo: estender páginas da Web com semântica
adicional que não faz parte da linguagem HTML central. Não pretendo transformar este capítulo em
um formato de guerra de chamas. (Isso definitivamente exigiria um elemento <rant>!) Em vez disso,
quero me concentrar em uma terceira opção que faz parte e está totalmente integrada ao próprio
HTML5: microdados.
163
Agora, o que isso significa? Vamos começar do fim e trabalhar de trás para frente. Os microdados giram em
torno de vocabulários personalizados. Pense no “conjunto de todos os elementos HTML5” como um
vocabulário. Este vocabulário inclui elementos para representar uma seção ou um artigo (veja “Novos
Elementos Semânticos em HTML5” na página 41), mas não inclui elementos para representar uma pessoa
ou um evento. Se quiser representar uma pessoa em uma página da web, você precisará definir seu próprio
vocabulário. Microdados permitem que você faça isso. Qualquer pessoa pode definir um vocabulário de
microdados e começar a incorporar propriedades personalizadas em suas próprias páginas da web.
A próxima coisa a saber sobre microdados é que eles funcionam com pares nome/ valor. Cada vocabulário
de microdados define um conjunto de propriedades nomeadas. Por exemplo, um vocabulário de Pessoa
poderia definir propriedades como nome e foto. Para incluir uma propriedade de microdados específica em
sua página da web, forneça o nome da propriedade em um local específico. Dependendo de onde você
declara o nome da propriedade, os microdados possuem regras sobre como extrair o valor da propriedade.
(Mais sobre isso na próxima seção.)
Já mencionei o DOM, mas deixe-me explicar melhor. Microdados tratam da aplicação de semântica adicional
a dados que já estão visíveis em sua página da web. Os microdados não foram projetados para ser um
formato de dados independente. É um complemento ao HTML. Como você verá na próxima seção, os
microdados funcionam melhor quando você já está usando HTML corretamente, mas o vocabulário HTML
não é suficientemente expressivo. Microdados são ótimos para ajustar a semântica dos dados que já estão
no DOM. Se os dados que você está
a semantificação não está no DOM, você deve recuar e reavaliar se os microdados são a solução certa.
A afirmação do Professor Markup faz mais sentido agora? Espero que sim. Vamos ver como isso
funciona em ação.
Definir seu próprio vocabulário de microdados é fácil. Primeiro você precisa de um namespace, que é
apenas uma URL. O URL do namespace pode apontar para uma página da Web em funcionamento,
embora isso não seja estritamente necessário. Digamos que eu queira criar um vocabulário de
microdados que descreva uma pessoa. Se eu possuir o domínio data-vocabulary.org , usarei a URL
http:// data-vocabulary.org/ Person como namespace para meu vocabulário de microdados. Essa é uma
maneira fácil de criar um identificador globalmente exclusivo: escolha um URL em um domínio que você controla.
Neste vocabulário, preciso definir algumas propriedades nomeadas. Vamos começar com três
propriedades básicas:
• nome (nome completo do
Duas dessas propriedades são URLs e a outra é texto simples. Cada um deles se presta a uma forma
natural de marcação, mesmo antes de você começar a pensar em microdados ou vocabulários. Imagine
que você tem uma página de perfil ou uma página “sobre”. Seu nome provavelmente está marcado
como um título, como um elemento <h1> . Sua foto provavelmente é um elemento <img> , pois você
deseja que as pessoas a vejam. E quaisquer URLs associados ao seu perfil provavelmente já estão
marcados como hiperlinks, porque você deseja que as pessoas possam clicar neles. Para fins de
discussão, digamos que todo o seu perfil também esteja envolvido em um elemento <section> para
separá-lo do restante do conteúdo da página. Por isso:
<section>
<h1>Mark Pilgrim</
h1> <p><img src="http://www.example.com/photo.jpg" alt="[eu sorrindo]"></
p> <p> <a href="http://diveintomark.org/">weblog</a></
p> </section>
Elemento Valor
<incorporar>
<iframe>
<img>
<fonte>
<vídeo>
<área>
<ligação>
atributo de dados
<objeto>
“Adicionar microdados” à sua página é uma questão de adicionar alguns atributos aos elementos
HTML que você já possui. A primeira coisa que você sempre faz é declarar qual vocabulário de
microdados você está usando, adicionando um atributo itemtype . A segunda coisa que você sempre
faz é declarar o escopo do vocabulário, usando um atributo itemscope . Neste exemplo, todos os
dados que queremos semantificar estão em um elemento <section> , então declararemos os atributos
itemtype e itemscope no elemento <section> :
<seção itemscope itemtype="http://data-vocabulary.org/Person">
Seu nome é o primeiro bit de dados dentro do elemento <section> . Está envolvido em um elemento
<h1> . O elemento <h1> não requer nenhum processamento especial, portanto ele se enquadra na
regra “todos os outros elementos” da Tabela 10-1, onde o valor da propriedade microdados é
simplesmente o conteúdo de texto de um elemento (isso funcionaria igualmente bem se seu nome foi
colocado em um elemento <p>, <div> ou <span> ):
<h1 itemprop="name">Marco Peregrino</h1>
A seguir está a propriedade da foto . Isto deveria ser um URL. De acordo com a Tabela 10-1, o
“valor” de um elemento <img> é seu atributo src . Ei, olha, o URL da sua foto de perfil já está em um
atributo <img src> ! Tudo que você precisa fazer é declarar que o elemento <img> é a propriedade
photo : <p><img itemprop="photo"
src="http://www.example.com/
photo.jpg" alt="[me sorrindo]"></p>
Finalmente, a propriedade url também é uma URL. De acordo com a Tabela 10-1, o “valor” de um
elemento <a> é seu atributo href . E mais uma vez, isso se ajusta perfeitamente à sua marcação
existente. Tudo que você precisa fazer é dizer que seu elemento <a> existente é a propriedade url :
<a itemprop="url" href="http://diveintomark.org/"> mergulhe na marca</a>
Em inglês, diz: “Aqui está a propriedade url do vocabulário http://data-vocabulary.org/ Person . O valor
da propriedade é http://diveintomark.org/.”
Claro, se a sua marcação parecer um pouco diferente, isso não será um problema. Você pode adicionar
propriedades e valores de microdados a qualquer marcação HTML, até mesmo a era realmente
complicada do século 20, tabelas para layout, oh-Deus-por que-concordei-em-manter-esta marcação.
Embora eu não recomende esse tipo de marcação, ela ainda é muito comum e você ainda pode
adicionar microdados a ela:
<TABELA>
<TR><TD>Nome<TD>Marco Peregrino
<TR><TD>Link<TD>
<A href=# onclick=goExternalLink()>http://diveintomark.org/</A> </TABLE>
Para marcar a propriedade name , basta adicionar um atributo itemprop na célula da tabela que contém
o nome. As células da tabela não possuem regras especiais na tabela de valores da propriedade de
microdados, portanto, elas obtêm o valor padrão, onde a propriedade de microdados é o conteúdo do texto:
<TR><TD>Nome<TD itemprop="name">Marca Peregrino
Adicionar a propriedade url parece mais complicado. Esta marcação não usa o elemento <a>
corretamente. Em vez de colocar o destino do link no atributo href , ele não tem nada de útil no atributo
href e usa JavaScript no atributo onclick para chamar uma função (não mostrada) que extrai a URL e
navega até ela. Para obter pontos extras do tipo “ah, merda, por favor, pare de fazer isso”, vamos fingir
que a função também abre o link em uma pequena janela pop-up sem barras de rolagem. A Internet não
foi divertida no século passado?
De qualquer forma, você ainda pode converter isso em uma propriedade de microdados; você só precisa
ser um pouco criativo. Usar o elemento <a> diretamente está fora de questão. O destino do link não está
no atributo href e não há como substituir a regra que diz “em um elemento <a> , procure o valor da
propriedade microdata no atributo href ”. Mas você pode adicionar um elemento wrapper em torno de
toda a bagunça e usá-lo para adicionar a propriedade url microdata:
<TABLE itemscope itemtype="http://data-vocabulary.org/Person">
<TR><TD>Nome<TD>Mark Pilgrim
<TR><TD>Link<TD>
<span itemprop="url">
<A href=# onclick=goExternalLink()>http://diveintomark.org/</A> </TABLE>
Como o elemento <span> não possui processamento especial, ele usa a regra padrão, “a propriedade
microdata é o conteúdo do texto”. “Conteúdo de texto” não significa “toda a marcação dentro deste
elemento” (como você faria com, digamos, a propriedade DOM innerHTML ). Significa “apenas o texto,
senhora”. Neste caso, http://diveintomark.org/ é o conteúdo de texto do elemento <a> dentro do elemento
<span> .
Resumindo: você pode adicionar propriedades de microdados a qualquer marcação. Você achará mais fácil
adicionar microdados se estiver usando HTML corretamente do que se sua marcação HTML for uma droga,
mas isso sempre pode ser feito.
Marcando pessoas
Os exemplos iniciais da seção anterior não foram completamente inventados. Existe realmente um vocabulário
de microdados para marcar informações sobre pessoas, e é realmente muito fácil. Vamos olhar mais de perto.
Vejamos primeiro a marcação bruta, antes de quaisquer propriedades de microdados serem adicionadas:
<seção>
<img largura="204" altura="250"
src="http://diveintohtml5.org/examples/2000_05_mark.jpg" alt="[Mark Pilgrim, por
volta de 2000]">
<dt>Nome</dt>
<dd>Mark Pilgrim</dd>
<dt>Posição</dt>
<dd>Defensor do desenvolvedor da Google, Inc.</dd>
</dd>
</dl>
<h1>Minhas pegadas digitais</h1> <ul>
<li><a
href="http://diveintomark.org/">weblog</a></li> <li ><a href="http://www.google.com/
profiles/pilgrim">Perfil do Google</a></li> <li><a href="http://www.reddit.com/user /MarkPilgrim">Perfil Reddit.com</
a></li> <li><a href="http://www.twitter.com/diveintomark">Twitter</a></li> </ul> </seção>
A primeira coisa que você sempre precisa fazer é declarar o vocabulário que está usando e o
escopo das propriedades que você deseja adicionar. Você faz isso adicionando o itemtype e
atributos itemscope no elemento mais externo que contém os outros elementos que
contêm os dados reais. Neste caso, é um elemento <section> :
Propriedade Descrição
nome Nome
apelido Apelido
Um link de imagem
foto
url Link para uma página da web, como a página inicial da pessoa
afiliação O nome de uma organização à qual a pessoa está associada (por exemplo, um empregador)
amigo Identifica uma relação social entre a pessoa descrita e outra pessoa
contato Identifica uma relação social entre a pessoa descrita e outra pessoa
conhecido Identifica uma relação social entre a pessoa descrita e outra pessoa
A primeira coisa neste exemplo de página “sobre” é uma foto minha. Naturalmente, está marcado
com um elemento <img> . Para declarar que este elemento <img> é minha foto de perfil, todos
o que precisamos fazer é adicionar itemprop="photo" a ele:
Onde está o valor da propriedade de microdados? Já está lá, no atributo src . Se você se lembra da Tabela
10-1, o “valor” de um elemento <img> é seu atributo src . Cada elemento <img> possui um atributo src —
caso contrário, seria apenas uma imagem quebrada — e o src é sempre uma URL. Ver? Se você estiver
usando HTML corretamente, microdados serão fáceis.
Além disso, este elemento <img> não está sozinho na página. É um elemento filho do elemento <section> ,
aquele que acabamos de declarar com o atributo itemscope . Os microdados reutilizam os relacionamentos
pai-filho dos elementos na página para definir o escopo das propriedades dos microdados. Em linguagem
simples, estamos dizendo: “Este elemento <section> representa uma pessoa. Quaisquer propriedades de
microdados que você possa encontrar nos filhos do elemento <section> são propriedades dessa pessoa.”
Se ajudar, você pode pensar no elemento <section> como o sujeito de uma frase. O atributo itemprop
representa o verbo da frase – algo como “é retratado em” – e o valor da propriedade microdata representa
o objeto da frase:
O assunto só precisa ser definido uma vez, colocando os atributos itemscope e itemtype no elemento
<section> mais externo . O verbo é definido colocando o atributo itemprop="photo" no elemento <img> . O
objeto da frase não precisa de nenhuma marcação especial, porque a Tabela 10-1 diz que o valor da
propriedade de um elemento <img> é seu atributo src .
Passando para a próxima parte da marcação, vemos um cabeçalho <h1> e o início de uma lista <dl> . Nem
o <h1> nem o <dl> precisam ser marcados com microdados. Nem todo pedaço de HTML precisa ser uma
propriedade de microdados. Os microdados tratam das propriedades em si, não da marcação ou dos
cabeçalhos que cercam as propriedades. Este <h1> não é uma propriedade; é apenas um cabeçalho. Da
mesma forma, o <dt> que diz “Nome” é apenas um rótulo, não uma propriedade:
<h1>Informações de contato</h1>
<dl>
<dt>Nome</dt>
<dd>Marco Peregrino</dd>
Então, onde está a informação real? Está no elemento <dd> , então é onde precisamos colocar o atributo
itemprop . Qual é a propriedade? É a propriedade do nome . Onde está o valor do imóvel? É o texto dentro
do elemento <dd> . Isso precisa ser marcado?
A Tabela 10-1 diz que não, os elementos <dd> não têm processamento especial, então o valor da
propriedade é apenas o texto dentro do elemento:
<dd itemprop="name">Marco Peregrino</dd>
O que acabamos de dizer em inglês? “O nome dessa pessoa é Mark Pilgrim.” Bem, ok então.
Avante.
Se você observar a definição do vocabulário Pessoa, o texto “Defensor do desenvolvedor do Google, Inc.”
na verdade, abrange duas propriedades: título (“Defensor do desenvolvedor”) e afiliação (“Google, Inc.”).
Como você pode expressar isso em microdados? A resposta curta é: você não pode. Os microdados não
têm como dividir trechos de texto em propriedades separadas. Você não pode dizer “os primeiros 18
caracteres deste texto são uma propriedade de microdados e os últimos 12 caracteres deste texto são
outra propriedade de microdados”.
Mas tudo não está perdido. Imagine que você deseja estilizar o texto “Defensor do desenvolvedor” em uma
fonte diferente do texto “Google, Inc.” CSS também não pode fazer isso. Então, o que você faria? Primeiro,
você precisaria agrupar os diferentes pedaços de texto em elementos fictícios, como <span>, e depois
aplicar regras CSS diferentes a cada elemento <span> .
Esta técnica também é útil para microdados. Existem duas informações distintas aqui: um título e uma
afiliação. Se você agrupar cada parte em um elemento <span> fictício , poderá declarar que cada <span>
é uma propriedade de microdados separada: <dt>Position</dt> <dd><span
itemprop="title">
Defensor do desenvolvedor</ span> para <span
itemprop="affiliation">Google, Inc.<span></dd>
Ta-da! Em inglês, diz: “O título desta pessoa é 'Defensor do desenvolvedor'. Esta pessoa é funcionária da
Google, Inc.” Duas frases, duas propriedades de microdados. Um pouco mais de marcação, mas uma troca
que vale a pena.
A mesma técnica é útil para marcar endereços. O vocabulário Person define uma
propriedade de endereço , que é um item de microdados. Isso significa que o endereço
tem seu próprio vocabulário (http:// data-vocabulary.org/ Address) e define suas
próprias propriedades: endereço, localidade, região, código postal e nome do país.
Se você é um programador, provavelmente está familiarizado com a notação de ponto para definir objetos
e suas propriedades. Pense no relacionamento assim:
• Pessoa
• Endereço.pessoa
• Pessoa.endereço.rua-endereço
• Pessoa.endereço.localidade •
Pessoa.endereço.região •
Pessoa.endereço.código postal •
Pessoa.endereço.nome do país
Neste exemplo, o endereço inteiro está contido em um único elemento <dd> . (Mais uma vez, o elemento
<dt> é apenas um rótulo, portanto não desempenha nenhum papel na adição de semântica com
<dt>Endereço para
correspondência</dt> <dd itemprop="address">
Mas lembre-se, a propriedade address é em si um item de microdados. Isso significa que precisamos
adicionar os atributos itemscope e itemtype também:
<dt>Endereço para
correspondência</dt> <dd itemprop="address"
itemscope itemtype="http://data-vocabulary.org/Address">
Já vimos tudo isso antes, mas apenas para itens de nível superior. Um elemento <section> define
itemtype e itemscope, e todos os elementos dentro do elemento <section> que definem propriedades
de microdados têm “escopo” dentro desse vocabulário específico. Mas esta é a primeira vez que
vemos escopos aninhados — definindo um novo itemtype e itemscope (no elemento <dd> ) dentro
de um já existente (no elemento <section> ). Este escopo aninhado funciona exatamente como o
HTML DOM. O elemento <dd> possui um certo número de elementos filhos, todos com escopo
definido para o vocabulário definido no elemento <dd> . Uma vez que o elemento <dd> é fechado
com uma tag </dd> correspondente , o escopo reverte para o vocabulário definido pelo elemento
pai (<section>, neste caso).
Em inglês: “Esta pessoa tem um endereço postal. A parte do endereço postal é '100 Main Street'. A
parte da localidade é 'Anytown'. A região é 'PA'. O código postal é '19999'. O nome do país é 'EUA'.”
Fácil.
R: Não. As propriedades do vocabulário Endereço são genéricas o suficiente para descrever a maioria dos
endereços de correspondência do mundo. Nem todos os endereços terão valores para todas as propriedades,
mas tudo bem. Alguns endereços podem exigir o ajuste de mais de uma “linha” em uma única propriedade,
mas tudo bem também. Por exemplo, se o seu endereço postal
Há mais uma coisa neste exemplo de página “sobre”: uma lista de URLs. O cabulário Person possui
uma propriedade para isso, chamada url. Uma propriedade de URL pode ser qualquer coisa, na verdade.
(Bem, tem que ser uma URL, mas você provavelmente adivinhou.) O que quero dizer é que a definição
da propriedade url é muito vaga. A propriedade pode ser qualquer tipo de URL que você queira associar
a uma Pessoa: um blog, uma galeria de fotos ou um perfil em outro site como Facebook ou Twitter.
A outra coisa importante a ser observada aqui é que uma única Pessoa pode ter várias propriedades
de URL . Tecnicamente, qualquer propriedade pode aparecer mais de uma vez, mas até agora não
aproveitamos isso. Por exemplo, você poderia ter duas propriedades de foto , cada uma apontando
para um URL de imagem diferente. Aqui, quero listar quatro URLs diferentes: meu weblog, minha
página de perfil do Google, meu perfil de usuário no Reddit e minha conta do Twitter.
Em HTML, é uma lista de links: quatro elementos <a> , cada um em seu próprio elemento <li> . Nos
microdados, cada elemento <a> recebe um atributo itemprop="url" :
<h1>Minhas pegadas digitais</h1>
<ul>
<li> <a href="http://diveintomark.org/"
itemprop="url"> weblog</a></li>
<li><a href="http://www.google.com/ profiles/pilgrim"
itemprop="url"> Perfil do Google</a></li>
<li> <a href="http://www.reddit.com/user/MarkPilgrim"
itemprop="url"> Reddit. com perfil</a></li> <li>
<a href="http://www.twitter.com/diveintomark"
itemprop="url"> Twitter</a></li>
</ul>
De acordo com a Tabela 10-1, os elementos <a> possuem processamento especial. O valor da
propriedade microdados é o atributo href , não o conteúdo de texto filho. O texto de cada link é
realmente ignorado por um processador de microdados. Assim, em inglês, diz: “Esta pessoa tem uma
URL em http:// diveintomark.org/. Esta pessoa tem outro URL em http:// www.google.com/ profiles/
pilgrim. Esta pessoa tem outro URL em http:// www.reddit.com/ user/ MarkPil sombrio. Essa pessoa
tem outro URL em http:// www.twitter.com/ diveintomark.”
Google, quero voltar por um momento e perguntar: “Por que estamos fazendo isso?” Estamos
adicionando semântica apenas por adicionar semântica? Não me interpretem mal; Gosto de mexer
com colchetes angulares tanto quanto qualquer outro webhead. Mas por que microdados? Porque se importar?
Existem duas classes principais de aplicativos que consomem HTML e, por extensão, microdados HTML5:
• Navegadores da Web
• Mecanismos de pesquisa
Para navegadores, HTML5 define um conjunto de APIs DOM para extrair itens de microdados, propriedades e
valores de propriedades de uma página da web. Enquanto escrevo isto, nenhum navegador oferece suporte a esta
API. Nem um único. Então isso é... meio que um beco sem saída, pelo menos até que os navegadores alcancem e
implementem as APIs do lado do cliente.
O outro grande consumidor de HTML são os motores de busca. O que um mecanismo de busca poderia fazer com
propriedades de microdados sobre uma pessoa? Imagine o seguinte: em vez de simplesmente exibir o título da
página e um trecho do texto, o mecanismo de busca poderia integrar algumas dessas informações estruturadas e
exibi-las. Nome completo, cargo, empregador, endereço, talvez até uma pequena miniatura de uma foto de perfil.
Isso chamaria sua atenção? Seria
pegue o meu.
O Google oferece suporte a microdados como parte de seu programa Rich Snippets. Quando o rastreador da Web
do Google analisa sua página e encontra propriedades de microdados que estão em conformidade com o vocabulário
http://data-vocabulary.org/Person , ele analisa essas propriedades e as armazena junto com o restante dos dados
da página. O Google ainda oferece uma ferramenta útil que mostra como o Google “vê” as propriedades de seus
microdados. Testando-o em nossa página “sobre” habilitada para microdados de amostra produz esta saída:
Tipo
de item : http://data-vocabulary.org/person
foto = http://diveintohtml5.org/examples/2000_05_mark.jpg nome =
Mark Pilgrim título =
Afiliação de defensor do
desenvolvedor = Google, Inc.
= http://diveintomark.org/
url = http://www.google.com/profiles/
pilgrim url = http://www.reddit.com/user/MarkPilgrim
url = http://www.twitter.com /mergulhar na marca
Item 1
Tipo: http://data-vocabulary.org/address street-
address = 100 Main Street localidade
= Anytown região =
PA código
postal = 19999 nome
do país = EUA
Está tudo lá: a propriedade photo do atributo <img src> , todos os quatro URLs da lista de
atributos <a href> e até mesmo o objeto de endereço (listado como “Item 1”) e todas as suas
cinco subpropriedades.
E como o Google usa todas essas informações? Depende. Não existem regras rígidas e rápidas
sobre como as propriedades dos microdados devem ser exibidas, quais devem ser exibidas ou
se devem ser exibidas. Se alguém pesquisar por “Mark Pilgrim” e o Google determinar que esta
página “sobre” deve ser classificada nos resultados, e o Google decidir que vale a pena exibir as
propriedades de microdados que ele encontrou originalmente naquela página, a listagem dos
resultados da pesquisa poderá ser semelhante à Figura 10-1.
Figura 10-1. Exemplo de resultado de pesquisa para uma listagem de pessoas aprimorada por microdados
A primeira linha, “Sobre Mark Pilgrim”, é na verdade o título da página, fornecido no elemento
<title> . Isso não é muito emocionante; O Google faz isso para todas as páginas. Mas a segunda
linha está repleta de informações retiradas diretamente das anotações de microdados que
adicionamos à página. “Anytown PA” fazia parte do endereço postal, marcado com o vocabulário
http://data-vocabulary.org/Address . “Defensor do desenvolvedor” e “Google, Inc.” eram duas
propriedades do vocabulário http://data-vocabulary.org/Person (título e afiliação, respectivamente).
Isso é realmente incrível. Você não precisa ser uma grande empresa fazendo acordos especiais
com fornecedores de mecanismos de pesquisa para personalizar suas listagens de resultados
de pesquisa. Reserve 10 minutos e adicione alguns atributos HTML para anotar os dados que
você já estava publicando.
P: Fiz tudo o que você disse, mas minha listagem de resultados de pesquisa no Google não parece diferente.
O que da?
R: “O Google não garante que a marcação em qualquer página ou site será usada na pesquisa
(http://www.google.com/support/webmasters/bin/answer.py?hl=pt-BR&answer=99170
resultados" ). Mas
mesmo que o Google decida não usar suas anotações de microdados, outro mecanismo de
busca poderá fazê-lo. Como o resto do HTML5, os microdados são um padrão aberto que
qualquer pessoa pode implementar. É seu trabalho fornecer o máximo de dados possível.
Deixe o resto do mundo decidir o que fazer com isso. Eles podem surpreendê-lo!
Marcando organizações
Os microdados não estão limitados a um único vocabulário. As páginas “Sobre” são legais, mas
provavelmente você só tem uma delas. Ainda está com fome de mais? Vamos aprender como marcar
organizações e negócios.
Curto e grosso. Todas as informações sobre a organização estão contidas no elemento <article> ,
então vamos começar por aí: <article
itemscope itemtype="http://data-vocabulary.org/Organization">
Assim como acontece com a marcação de pessoas, você precisa definir os atributos itemscope e
itemtype no elemento mais externo. Neste caso, o elemento mais externo é um elemento <article> .
O atributo itemtype declara o vocabulário de microdados que você está usando (neste caso, http:// data-
vocabulary.org/ Organization) e o atributo itemscope declara que todas as propriedades definidas em
elementos filhos estão relacionadas a esse vocabulário.
Então, o que há no vocabulário Organização? É muito simples e direto. Na verdade, algumas delas já
deveriam parecer familiares. A Tabela 10-3 lista as propriedades relevantes.
Propriedade Descrição
localização geográfica
As coordenadas geográficas do local. Sempre contém duas subpropriedades, latitude e longitude.
O primeiro bit de marcação dentro do elemento <article> mais externo é um <h1>. Este elemento <h1>
contém o nome de uma empresa, então colocaremos um atributo itemprop="name" diretamente nele:
De acordo com a Tabela 10-1, os elementos <h1> não precisam de nenhum processamento especial.
O valor da propriedade de microdados é simplesmente o conteúdo de texto do elemento <h1> . Em
inglês, dissemos apenas: “O nome da Organização é 'Google, Inc.'”
<p itemprop="address"
itemscope itemtype="http://data-vocabulary.org/Address">
Em inglês, dissemos apenas: “Esta organização tem um endereço. A parte do endereço é '1600
Amphitheatre Parkway'. A localidade é 'Mountain View'. A parte da região é 'CA'.
O código postal é '94043'. O nome do país é ‘EUA’.”
(Ei, caso você não tenha notado, o vocabulário Endereço saiu do escopo quando seu elemento <p>
foi fechado. Agora voltamos a definir propriedades no vocabulário Organização.)
Se quiser listar vários números de telefone – talvez um para clientes nos Estados Unidos e outro para
clientes internacionais – você pode fazer isso. Qualquer propriedade de microdados pode ser
repetido. Apenas certifique-se de que cada número de telefone esteja em seu próprio elemento HTML, separado
de qualquer rótulo que você possa fornecer:
<p>
Clientes dos EUA: <span itemprop="tel">650-253-0000<br>
Clientes do Reino Unido: <span itemprop="tel">00 + 1* + 6502530000 </p>
De acordo com a Tabela 10-1, nem o elemento <p> nem o elemento <span> possuem processamento especial. O
valor da propriedade tel de microdados é simplesmente o conteúdo do texto. O vocabulário de microdados da
Organização não tenta subdividir as diferentes partes de um número de telefone. Toda a propriedade tel é apenas
texto de formato livre. Se quiser colocar o código de área entre parênteses ou usar espaços em vez de travessões
para separar os números, você pode fazer isso. Se um cliente que consome microdados quiser analisar o número
de telefone, isso depende inteiramente dele.
A seguir, temos outra propriedade familiar: url. Assim como associar uma URL a uma Pessoa conforme descrito na
seção anterior, você pode associar uma URL a uma Organização.
Pode ser a página inicial da empresa, uma página de contato, uma página de produto ou qualquer outra coisa. Se
for um URL sobre, de ou pertencente à Organização, marque-o com um atributo itemprop="url" :
De acordo com a Tabela 10-1, o elemento <a> possui processamento especial. O valor da propriedade microdados
é o valor do atributo href , não o texto do link. Em inglês, diz: “Esta organização está associada ao URL http://
www.google.com/.” Não diz nada mais específico sobre a associação e não inclui o texto do link “Google.com”.
Por fim, quero falar sobre geolocalização. Não, não é a API de geolocalização do W3C (consulte o Capítulo 6).
Estou falando sobre como marcar a localização física de uma organização usando microdados.
Até o momento, todos os nossos exemplos se concentraram na marcação de dados visíveis . Ou seja, você tem um
<h1> com o nome de uma empresa, então você adiciona um atributo itemprop ao elemento <h1> para declarar que
o texto do cabeçalho (visível) é, de fato, o nome de uma Organização. Ou você tem um elemento <img> que aponta
para uma foto, então você adiciona um atributo itemprop ao elemento <img> para declarar que a imagem (visível)
é uma foto de uma Pessoa.
Neste exemplo, as informações de geolocalização não são assim. Não há nenhum texto visível que forneça a
latitude e longitude exatas (com quatro casas decimais!) da Organização. Na verdade, o exemplo de página da
organização sem microdados não tem nenhuma informação de geolocalização. Possui um link para o Google Maps,
mas mesmo o URL desse link não contém coordenadas de latitude e longitude. (Ele contém informações
semelhantes em um formato específico do Google.) Mesmo que tivéssemos um link para um hipotético serviço de
mapeamento on-line que usasse coordenadas de latitude e longitude como parâmetros de URL, os microdados não
teriam como separar as diferentes partes de um URL. . Você não pode declarar que a primeira consulta de URL
Para lidar com casos extremos como esse, o HTML5 fornece uma maneira de anotar dados invisíveis.
Esta técnica só deve ser usada como último recurso. Se houver uma maneira de exibir ou renderizar os
dados de seu interesse, você deverá fazê-lo. Dados invisíveis que apenas máquinas podem ler tendem
a “ficar obsoletos” muito rapidamente. Ou seja, é provável que alguém apareça mais tarde e atualize o
texto visível, mas esqueça de atualizar os dados invisíveis. Isso acontece com mais frequência do que
você pensa e acontecerá com você também.
Ainda assim, há casos em que os dados invisíveis são inevitáveis. Talvez seu chefe realmente queira
informações de geolocalização legíveis por máquina, mas não queira sobrecarregar a interface com
pares de números incompreensíveis de seis dígitos. Dados invisíveis são a única opção. A única graça
salvadora aqui é que você pode colocar os dados invisíveis imediatamente após o texto visível que eles
descrevem, o que pode ajudar a lembrar a pessoa que aparece mais tarde e atualiza o texto visível que
ela precisa atualizar os dados invisíveis logo após ele.
Neste exemplo, podemos criar um elemento <span> fictício dentro do mesmo elemento <article> que
todas as outras propriedades da Organização e, em seguida, colocar os dados de geolocalização
invisíveis dentro do elemento
<span>: <span itemprop="geo"
itemscope itemtype= "http://data-vocabulary.org/
Geo"> <meta itemprop="latitude" content="37.4149" /
> <meta itemprop="longitude" content="-122.078" /> </
article >
itemprop="geo"
Diz que este elemento representa a propriedade geográfica da organização circundante.
itemtype="http://data-vocabulary.org/Geo"
Diz a qual vocabulário de microdados as propriedades deste elemento estão em
conformidade. itemscope Diz que este elemento é o elemento envolvente para um item de microdados
com seu próprio vocabulário (fornecido no atributo itemtype). Todas as propriedades dentro deste
elemento são propriedades do vocabulário Geo (http://data-vocabulary.org/Geo), e não do
vocabulário da Organização circundante (http://data-vocabulary.org/Organization).
A próxima grande questão que este exemplo responde é: “Como você anota dados invisíveis?” Você faz
isso com o elemento <meta>. Nas versões anteriores do HTML, você só podia usar o elemento <meta>
dentro do <head> da sua página (consulte “O elemento <head>” na página 34). No HTML5, você pode
usar o elemento <meta> em qualquer lugar. E é exatamente isso que estamos fazendo aqui:
De acordo com a Tabela 10-1, o elemento <meta> possui processamento especial. O valor da propriedade
microdados é o atributo de conteúdo . Como esse atributo nunca é exibido de forma visível, temos a
configuração perfeita para quantidades ilimitadas de dados invisíveis. Com grandes poderes vem grandes
responsabilidades. Nesse caso, é sua responsabilidade garantir que esses dados invisíveis permaneçam
sincronizados com o texto visível ao seu redor.
Não há suporte direto para o vocabulário Organização nos Rich Snippets do Google, então não tenho nenhum
exemplo bonito de listagem de resultados de pesquisa para mostrar a você. Mas as organizações aparecem
fortemente nos próximos dois estudos de caso, eventos e análises, e são apoiados pelo Google Rich Snippets.
Marcando eventos
Coisas acontecem. Algumas coisas acontecem em horários predeterminados. Não seria bom se você pudesse
dizer aos mecanismos de pesquisa exatamente quando as coisas estavam para acontecer? Existe um colchete
angular para isso.
Centro de Congressos<br>
5th kvÿtna 65<br>
140 21 Praha 4<br>
República Tcheca
</p>
<p><a href="http://code.google.com/intl/cs/events/developerday/2009/home.html"> página inicial
do GDD/Praga</a></ p> </artigo>
Você pode acompanhar on-line as alterações feitas nesta seção. Antes: http://
diveintohtml5.org/ examples/ event.html; depois: http:// diveintohtml5.org/
examples/ event-plus-microdata.html.
Todas as informações sobre o evento estão contidas no elemento <article> , então isso é
onde precisamos colocar os atributos itemtype e itemscope :
<artigo itemscope itemtype="http://data-vocabulary.org/Event">
A URL para o vocabulário Evento é http:// data-vocabulary.org/ Event, que também contém um pequeno
gráfico que descreve as propriedades do vocabulário. E o que são
essas propriedades? A Tabela 10-4 os lista.
Propriedade Descrição
O nome do evento.
resumo
url Um link para a página de detalhes do evento.
localização O local ou local do evento. Opcionalmente, pode ser representado por uma organização aninhada (consulte “Marcando
tipo de evento A categoria do evento (por exemplo, “Concerto” ou “Palestra”). Esta é uma string de formato livre, não uma enumerada
atributo.
localização geográfica
As coordenadas geográficas do local. Sempre contém duas subpropriedades, latitude e
longitude.
O nome do Evento está em um elemento <h1> . De acordo com a Tabela 10-1, os elementos <h1> têm
nenhum processamento especial. O valor da propriedade microdados é simplesmente o conteúdo do texto do
elemento <h1> . Então, tudo o que precisamos fazer é adicionar o atributo itemprop para declarar que este
O elemento <h1> contém o nome do Evento:
Este anúncio de evento possui uma foto, que pode ser marcada com a propriedade da foto . Como
como seria de esperar, a foto já está marcada com um elemento <img> . Como
a propriedade photo no vocabulário Person (consulte “A propriedade de dados de microdados
Modelo” na página 166), a propriedade Foto do evento é uma URL. Como a Tabela 10-1 diz que
o valor da propriedade de um elemento <img> é seu atributo src , a única coisa que precisamos fazer
é adicionar o atributo itemprop ao elemento <img> :
<img itemprop="foto" largura="300" altura="200"
src="http://diveintohtml5.org/examples/gdd-2009-prague-pilgrim.jpg"
alt="[Marcar Peregrino no pódio]">
Em inglês, diz: “A foto deste evento está em http:// diveintohtml5.org/ examples/ gdd-2009-prague-
pilgrim.jpg .”
A seguir está uma descrição mais longa do Evento, que é apenas um parágrafo de texto de formato livre:
<p itemprop="description">Os Google Developer Days são uma oportunidade
de aprender sobre os produtos para desenvolvedores do Google com os engenheiros
que os desenvolveram. Esta conferência de um dia inclui seminários e "horário
comercial" sobre tecnologias da web como Google Maps, OpenSocial,
Android, APIs AJAX, Chrome e Google Web Toolkit.</p>
A próxima parte é algo novo. Os eventos geralmente ocorrem em datas específicas e começam e
terminam em horários específicos. No HTML5, datas e horas devem ser marcadas com o elemento
<time> (veja “Datas e Horas” na página 49), e já estamos fazendo isso aqui.
Então a questão é: como adicionamos propriedades de microdados a esses elementos <time> ?
Olhando novamente para a Tabela 10-1, vemos que o elemento <time> tem processamento especial. O
valor de uma propriedade de microdados em um elemento <time> é o valor do atributo datetime . E ei,
as propriedades startDate e endDate do vocabulário Event levam uma data no estilo ISO, assim como
a propriedade datetime de um elemento <time> .
Mais uma vez, a semântica do vocabulário HTML central se encaixa perfeitamente com a semântica do
nosso vocabulário personalizado de microdados. Marcar datas de início e término com microdados é tão
simples quanto:
1. Usar HTML corretamente em primeiro lugar (usar elementos <time> para marcar datas
e tempos)
<p>
<time itemprop="startDate" datetime="2009-11-06T08:30+01:00">2009 6 de novembro, 8h30</time>
–
<time itemprop="endDate" datetime="2009-11-06T20:30+01:00">20:30</time> </p>
Em inglês, diz: “Este evento começa em 6 de novembro de 2009, às 8h30 da manhã, e vai até 6 de
novembro de 2009, às 20h30 (horário local de Praga, GMT+1).”
A seguir está a propriedade location . A definição do vocabulário de eventos diz que pode ser uma
Organização ou um Endereço. Neste caso, o Evento será realizado num local especializado em
conferências, o Centro de Congressos de Praga. Marcar como Organização permite-nos incluir o nome
do local, bem como o seu endereço.
Primeiro, vamos declarar que o elemento <p> que contém o endereço é a propriedade location do Evento,
e que este elemento também é seu próprio item de microdados que está em conformidade com o
vocabulário http://data-vocabulary.org/Organization : < p
itemprop="localização" itemscope
itemtype="http://data-vocabulary.org/Organization">
Mais uma vez, queremos marcar cada parte do endereço como uma propriedade de microdados
separada, então precisamos de uma série de elementos <span> fictícios para pendurar nossos
atributos itemprop (se estou indo rápido demais para você aqui, volte e leia sobre como marcar o
endereço de uma Pessoa (consulte “Marcando Pessoas” na página 171) e como marcar o endereço de uma Pessoa.
Organização (consulte “Marcando organizações” na página 177)): <span
itemprop="street-address">5th kvÿtna 65<br> <span
itemprop="postal-code">140 21 <span
itemprop="locality">Praha 4<br> <span
itemprop="country-name"> República Tcheca
Não há mais propriedades do Endereço, então fechamos o elemento <span> que iniciou o escopo do
Endereço e abrimos a pilha:
Também não há mais propriedades da Organização, então fechamos o elemento <p> que iniciou o
escopo da Organização e abrimos a pilha novamente:
</p>
Agora voltamos a definir propriedades no Event. A próxima propriedade é geo, para representar a
localização física do Evento. Isso usa o mesmo vocabulário geográfico que usamos para marcar a
localização física de uma organização na seção anterior. Precisamos de um elemento <span> para
atuar como contêiner; ele obtém o itemtype e o itemscope nos tributos. Dentro desse elemento
<span> , precisamos de dois elementos <meta> , um para a propriedade latitude e outro para a
propriedade longitude :
<span itemprop="geo" itemscope itemtype="http://data-vocabulary.org/Geo">
<meta itemprop="latitude" content="50.047893" />
<meta itemprop="longitude" content="14.4491" />
Como fechamos o <span> que continha as propriedades Geo, voltamos a definir as propriedades do
Evento. A última propriedade é a propriedade url , que deve parecer familiar. Associar uma URL a um
Evento funciona da mesma maneira que associar uma URL a uma Pessoa (consulte “Marcando
Pessoas” na página 173) e associar uma URL a uma Organização (consulte “Marcando Organizações”
na página 178). Se você estiver usando HTML
corretamente (marcando hiperlinks com <a href>), declarar que o hiperlink é uma propriedade de url mi crodata é
simplesmente uma questão de adicionar o atributo itemprop :
artigo>
A página de evento de exemplo também lista um segundo evento, minha palestra na conferência ConFoo em
Montreal. Para ser breve, não vou passar por essa marcação linha por linha. É essencialmente o mesmo que o
evento em Praga: um item de evento com itens geográficos e de endereço aninhados. Menciono isso apenas de
passagem para reiterar que uma única página pode ter vários eventos, cada um marcado com microdados.
ID
do item:
__1 Tipo: http://data-vocabulary.org/Nome da organização
= Endereço do Centro de
Congressos = Item (__2)
Item
Id: __2
Tipo: http://data-vocabulary.org/Address street-
address = 5th kvÿtna 65 código postal
= 140 21 localidade =
Praha 4 nome do país
= República Tcheca
Item
Id: __3
Tipo: http://data-vocabulary.org/Geo
latitude = 50,047893
longitude = 14,4491
Como você pode ver, todas as informações que adicionamos nos microdados estão lá. Propriedades que são
itens de microdados separados recebem IDs internos (Item(__1), Item(__2) e assim por diante), mas isso não
faz parte da especificação de microdados. É apenas uma convenção que a ferramenta de teste do Google usa
para linearizar a saída da amostra e mostrar o agrupamento de itens aninhados e suas propriedades.
Então, como o Google poderia escolher representar esta página de exemplo em seus resultados de pesquisa?
(Novamente, devo começar com a isenção de responsabilidade de que este é apenas um exemplo; o Google
pode alterar o formato de seus resultados de pesquisa a qualquer momento e não há garantia de que o Google
prestará atenção à sua marcação de microdados.) Pode ser que isso aconteça. semelhante à Figura 10-2.
Figura 10-2. Exemplo de resultado da pesquisa para uma listagem de eventos aprimorada por microdados
Após o título da página e o texto do trecho gerado automaticamente, o Google começa a usar a marcação de
microdados que adicionamos à página para exibir uma pequena tabela de eventos. Observe o formato da data:
“Sexta-feira, 6 de novembro”. Essa não é uma string que apareceu em qualquer lugar de nossa marcação HTML
ou de microdados. Usamos duas strings totalmente qualificadas no formato ISO, 2009-11-06T08:30+01:00 e
2009-11-06T20:30+01:00. O Google pegou essas duas datas, descobriu que eram no mesmo dia e decidiu
exibir uma única data em um formato mais amigável.
Agora observe os endereços físicos. O Google optou por exibir apenas o nome
do local + localidade + país, não o endereço exato. Isso é possível porque
dividimos o endereço em cinco subpropriedades – nome, endereço, região,
localidade e nome do país – e marcamos cada parte do endereço como uma
propriedade de microdados diferente. O Google aproveita isso para mostrar um endereço abreviad
Outros consumidores da mesma marcação de microdados podem fazer escolhas diferentes sobre o que exibir
ou como exibi-lo. Não há escolha certa ou errada aqui. Cabe a você fornecer o máximo de dados possível, com
a maior precisão possível. Cabe ao resto do mundo interpretá-lo.
Marcando avaliações
Aqui está outro exemplo de como tornar a Web (e possivelmente as listagens de resultados de pesquisa) melhor
por meio de marcação: análises de empresas e produtos.
Esta é uma breve resenha que escrevi sobre minha pizzaria favorita perto da minha casa. (A propósito,
este é um restaurante de verdade. Se você estiver em Apex, NC, eu o recomendo fortemente.) Vejamos a
marcação original:
<article>
<h1>Anna's Pizzeria</h1>
<p>ÿÿÿÿÿ (4 estrelas de 5)</p> <p>Pizza
estilo nova-iorquino bem no centro histórico de Apex</p> <p > A
Você pode acompanhar on-line as alterações feitas nesta seção. Antes: http://
diveintohtml5.org/ examples/ review.html; depois: http:// diveintohtml5.org/
examples/ review-plus-microdata.html.
Esta revisão está contida em um elemento <article> , então é onde colocaremos os atributos itemtype e
itemscope . Aqui está o URL do namespace para este vocabulário:
Quais são as propriedades disponíveis no vocabulário Review? Estou feliz que você perguntou. Eles estão
listados na Tabela 10-5.
Descrição
Propriedade itemreviewed O nome do item que está sendo revisado. Pode ser um produto, serviço, negócio, etc.
avaliação Uma classificação numérica de qualidade para o item, em uma escala de 1 a 5. Também pode ser uma classificação
aninhada usando o vocabulário http://data-vocabulary.org/Rating para usar uma escala não padronizada.
As próximas duas propriedades também são diretas. A propriedade summary é uma breve
descrição do que você está revisando, e a propriedade description é o corpo da revisão:
As propriedades de localização e geográfica não são nada que não tenhamos abordado antes
(consulte as seções anteriores sobre marcação do endereço de uma Pessoa, marcação do
endereço de uma Organização e marcação de informações de geolocalização):
<p itemprop="location" itemscope
itemtype="http://data-vocabulary.org/Address">
<span itemprop="street-address"> Rua North Salem, 100<br> <span
itemprop=" localidade">Apex, <span
itemprop="region">NC <span
itemprop="postal-code">27502<br> <span
itemprop="country-name"> EUA </p>
<span itemprop="geo"
itemscope itemtype="http://data-
vocabulary.org/Geo"> <meta itemprop="latitude"
content="35.730796" /> <meta itemprop ="longitude"
content="-78.851426" />
A linha final apresenta um problema familiar: contém dois bits de informação em um elemento. O
nome do revisor é Mark Pilgrim e a data da revisão é 31 de março de 2010. Como marcamos
essas duas propriedades distintas? Como sempre, podemos envolvê-los em seus próprios
elementos (veja “Marcando Pessoas” na página 171) e colocar um atributo itemprop em cada
elemento. Na verdade, a data neste exemplo deveria ter sido marcada com um elemento <time>
em primeiro lugar, de modo que fornece um gancho natural para pendurar nosso atributo
itemprop . O nome do revisor pode ser simplesmente colocado em um elemento fictício <span> :
</p>
</artigo>
OK, vamos falar de classificações. A parte mais complicada de marcar uma avaliação é a classificação. Por
padrão, as classificações no vocabulário Revisão estão em uma escala de 1 a 5, sendo 1 “terrível” e 5
“incrível”. Se quiser usar uma escala diferente, você definitivamente pode fazer isso. Mas vamos falar primeiro
sobre a escala padrão:
Se você estiver usando a escala padrão de 1 a 5, a única propriedade que você precisa marcar é a própria
classificação (4, neste caso). Mas e se você quiser usar uma escala diferente? Você pode fazer isso; você só
precisa declarar os limites da escala que está usando. Por exemplo, se você quisesse usar uma escala de 0 a
10, ainda assim declararia a propriedade itemprop="rating" , mas em vez de fornecer o valor da classificação
diretamente, usaria uma classificação aninhada com o vocabulário de http:// data-vocabulary.org/Rating para
declarar os piores e melhores valores em sua escala personalizada e o valor real da classificação dentro dessa
escala:
<p itemprop="rating" itemscope
itemtype="http://data-vocabulary.org/Rating">
ÿÿÿÿÿÿÿÿÿÿ (<span
itemprop="value">9 em um escala de <span
itemprop="worst">0 a <span
itemprop="best">10) </p>
Em inglês, diz: “O produto que estou analisando tem uma classificação de 9 em uma escala de
0–10.”
Mencionei que os microdados de revisão podem afetar as listagens de resultados de pesquisa? Ah, sim, pode.
Aqui estão os “dados brutos” que a ferramenta Google Rich Snippets extraiu da minha análise aprimorada
de microdados:
Item
Tipo: http://data-vocabulary.org/Review
itemreviewed = Classificação da
Anna's
Pizzeria = 4 summary = Pizza estilo nova-iorquino bem no centro histórico
Descrição do Apex = A comida é de primeira qualidade. A atmosfera é
perfeita ... endereço =
Item (__1) geo =
Item (__2) revisor = Mark
Pilgrim dtreviewed = 31/03/2010
ID
do item:
__1 Tipo: http://data-vocabulary.org/Organization
endereço = 100 North Salem Street
localidade =
região Apex
= código postal NC =
27502 nome do país = EUA
Item
Id: __2
Tipo: http://data-vocabulary.org/Geo
latitude = 35,730796
longitude = -78,851426
A Figura 10-3 (módulo os caprichos do Google, a fase da lua e assim por diante) mostra como minha
avaliação ficaria em uma listagem de resultados de pesquisa.
Figura 10-3. Exemplo de resultado de pesquisa para uma listagem de revisão aprimorada por microdados
Os colchetes angulares não me impressionam muito, mas tenho que admitir, isso é muito legal.
Leitura adicional
Recursos de microdados:
• Playground de microdados ao
vivo • Especificação de microdados HTML5
• “Avaliar classificações”
• Ferramenta de teste de rich snippets do
Google • Dicas e truques para rich snippets do Google
APÊNDICE
Confuso? Leia o Capítulo 2 para uma introdução conceitual. Quer uma biblioteca multifuncional? Experimente o Modernizr.
Lista de Elementos
<áudio> http://bit.ly/cZxI7K
return !!document.createElement('audio').canPlayType;
var a = document.createElement('áudio');
return !!(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, ''));
var a = document.createElement('áudio');
return !!(a.canPlayType && a.canPlayType('audio/
ogg; codecs="vorbis"').replace(/no/, ''));
191
var a = document.createElement('áudio');
retornar !!(a.canPlayType && a.canPlayType('audio/
wav; codecs="1"').replace(/no/, ''));
var a = document.createElement('áudio');
retornar !!(a.canPlayType && a.canPlayType('audio/
mp4; codecs="mp4a.40.2"').replace(/no/, ''));
return !!document.createElement('canvas').getContext;
var c = document.createElement('canvas');
return c.getContext && typeof c.getContext('2d').fillText == 'função';
<comando> http://bit.ly/aQt2Fn
<detalhes> http://bit.ly/cO8mQy
<dispositivo> http://bit.ly/aaBeUy
var i = document.createElement('input');
i.setAttribute('tipo', 'cor');
return i.type !== 'texto';
var i = document.createElement('input');
i.setAttribute('tipo', 'e-mail');
return i.type !== 'texto';
var i = document.createElement('input');
i.setAttribute('tipo', 'número');
return i.type !== 'texto';
var i = document.createElement('input');
i.setAttribute('tipo', 'intervalo');
return i.type !== 'texto';
var i = document.createElement('input');
i.setAttribute('tipo', 'pesquisar');
return i.type !== 'texto';
var i = document.createElement('input');
i.setAttribute('tipo', 'tel'); return
i.type !== 'texto';
var i = document.createElement('input');
i.setAttribute('tipo', 'url'); return
i.type !== 'texto';
var i = document.createElement('input');
i.setAttribute('tipo', 'data');
return i.type !== 'texto';
var i = document.createElement('input');
i.setAttribute('tipo', 'hora');
return i.type !== 'texto';
var i = document.createElement('input');
i.setAttribute('tipo', 'datahora');
return i.type !== 'texto';
var i = document.createElement('input');
i.setAttribute('tipo', 'datahora-local);
return i.type !== 'texto';
var i = document.createElement('input');
i.setAttribute('tipo', 'mês');
return i.type !== 'texto';
var i = document.createElement('input');
i.setAttribute('tipo', 'semana');
return i.type !== 'texto';
<metro> http://bit.ly/c0pX0l
<saída> http://bit.ly/asJaqH
<progresso> http://bit.ly/bjDMy6
<hora> http://bit.ly/bI62jp
retornar !!document.createElement('video').canPlayType;
var v = document.createElement('vídeo');
retornar !!(v.canPlayType && v.canPlayType('video/webm; codecs="vp8,
vorbis"').replace(/no/, ''));
var v = document.createElement('vídeo');
retornar !!(v.canPlayType && v.canPlayType('video/mp4; codecs="avc1.42E01E,
mp4a.40.2"').replace(/no/, ''));
var v = document.createElement('vídeo');
retornar !!(v.canPlayType && v.canPlayType('video/ogg; codecs="theora,
vorbis"').replace(/no/, ''));
conteúdoEditável http://bit.ly/aLivbS
return !!window.postMessage;
return !!navigator.geolocalização;
História http://bit.ly/9JGAGB
Microdados http://bit.ly/dBGnqr
retornar !!document.getItems;
retornar !!window.applicationCache;
tentar {
return ('sessionStorage' na janela) && window['sessionStorage'] !== null;
} pegar(e) {
retorna falso;
}
SVG http://www.w3.org/TR/SVG/
var e = document.createElement('div');
e.innerHTML = '<svg></svg>';
retornar !!(window.SVGSVGElement && e.firstChild instanceof window.SVGSVGElement);
WebSimpleDB http://dev.w3.org/2006/webapi/WebSimpleDB/
retornar !!window.indexedDB;
retornar !!window.WebSocket;
retornar !!window.openDatabase;
retornar !!janela.Worker;
Desfazer http://bit.ly/bs6JFR
Leitura adicional
Especificações e padrões:
•HTML5
• Geolocalização
• Eventos enviados pelo servidor
• WebSimpleDB • Web
Sockets
• Armazenamento
na Web • Web Workers
Bibliotecas JavaScript:
Índice
Gostaríamos de ouvir suas sugestões para melhorar nossos índices. Envie um e-mail para index@oreilly.com.
201
202 | Índice
EU
armazenamento local
antes de Formato de endereço de
HTML5, 128 desenvolvimento de padrões, 2–7 correspondência M ,
XHTML, 10 XML, 10 HTML elemento de
marca 172, 41
microdados sobre, 28, modo de dados 164, 165–168
Suporte para áudio e vídeo do
visões concorrentes, 11 Microsoft Internet Explorer, 89
história de desenvolvimento, suporte para canvas e VML, 73 para
estrutura de 7 a 11 páginas, 33 geolocalização, 123
Grupo de Trabalho HTML, 9 para estilizar elementos desconhecidos,
Armazenamento HTML5, 127–136 42 para suporte a vídeo, 114
sobre, 21, 129 Navegador Midas, 3
futuro de, 134 Tipos MIME
Exemplo de jogo Halma, 132 sobre, 1
Índice | 203
139 nofollow, relação de link 39 origem, 112 caixas giratórias, números como, 153
P codificação de 17 caracteres, 35
desenhos, 63–66 texto
de espaço reservado, 27, 147
caminhos sobre,
Codec de vídeo Theora, 84
145 telas, 61–63
elementos de tempo,
pessoas, marcação, 168–175 relação de
41 horários e datas, 49
link de pingback, 39 texto de espaço
alterações de rastreamento na área de armazenamento HTML5,
reservado sobre, 27
131 traduções, links, 38
formulários
da web, 147 relação
EM
de link de pré-busca, 40 atributo de
pré-carregamento, 110 data de
publicação, 49 Microdados de URLs, 166
Vocabulário pessoal, 173
formulários da web, 151
P
Modo peculiaridades, 32
204 | Índice
EM
Índice | 205
Sobre o autor
Mark Pilgrim é um defensor sênior de desenvolvedores no Google, Inc. Ele é especialista em código aberto e
padrões abertos. Mark é autor de vários livros técnicos, incluindo Dive Into Python (APress) e Dive Into
Accessibility, um tutorial online gratuito sobre acessibilidade na web. Ele mora na Carolina do Norte com a
esposa, dois filhos e um cachorro grande e babão.
Colofão O
animal na capa do HTML5: Up and Running é uma camurça alpina (Rupicapra rupicapra), uma espécie
semelhante a uma cabra ou antílope nativa das cadeias montanhosas da Europa, incluindo os Cárpatos, os
Apeninos, os Tatras, os Balcãs, o Cau casus e os Alpes. A camurça alpina também pode ser encontrada na
Nova Zelândia, tendo sido introduzida lá em 1907 pelo imperador austríaco Franz Joseph I.
A camurça alpina vive em altitudes relativamente altas e se adaptou a terrenos íngremes, acidentados e
rochosos. Eles crescem até um tamanho de cerca de 75 centímetros de altura e pesam entre 20 e 30
quilogramas (embora os indivíduos na Nova Zelândia pesem frequentemente cerca de 20% menos do que os
seus irmãos europeus). Tanto os machos quanto as fêmeas apresentam chifres curtos que se curvam para trás
perto da ponta e pêlo que é marrom escuro durante o verão e cinza claro no inverno. Muitas camurças também
exibem rosto e garupa caracteristicamente brancos, com listras pretas sob os olhos e ao longo das costas.
As camurças machos adultos vivem principalmente vidas solitárias, reunindo-se apenas uma vez por ano para
competir pela atenção das fêmeas não acasaladas. As fêmeas, entretanto, vivem em rebanhos com seus filhotes.
Todas as variedades de camurças são animais de caça populares; sua carne é considerada saborosa e seu
couro é excepcionalmente macio e absorvente. Além disso, um tufo de cabelo retirado da nuca de uma camurça,
chamado gamsbart, é tradicionalmente usado como decoração de chapéu em todos os países alpinos. Esta
prática pode ser um pouco mais difícil nos tempos modernos, no entanto, uma vez que algumas subespécies de
camurça ganharam protecção da União Europeia. Em contrapartida, o Departamento de Conservação da Nova
Zelândia incentiva a caça da camurça alpina, na esperança de limitar o impacto do animal na flora nativa.
A imagem da capa é do Animate Creation de JG Wood. A fonte da capa é Adobe ITC Garamond. A fonte do
texto é Linotype Birka; a fonte do título é Adobe Myriad Con densa; e a fonte do código é TheSansMonoCondensed
da LucasFont.