Melhorando seus layouts com 960 Grid System (para não designers como eu)
Em um post anterior expliquei como usar SiteMesh com Grails. Agora é hora de expor uma descoberta recente que fiz: o 960 Grid System (960gs), criado por Nathan Smith. Para aqueles que não conhecem, o 960gs é um framework CSS. Como não sou designer (apesar de tentar com toda a minha teimosia), o termo framework CSS é novidade pra mim também.
A definição do termo na Wikipédia é a seguinte: “trata-se de uma biblioteca pré-configurada cujo objetivo é facilitar a criação de layouts o mais próximo possível dos padrões web”. A definição Kiconiana é mais simples: “arquivos CSS prontos para que você possa criar layouts bacanas e dentro dos padrões web de forma rápida”.
Um sistema de grade (grid system) é uma técnica adotada em layouts para se organizar o conteúdo de uma página impressa. Por sorte, a técnica também é adotada com sucesso em aplicações web!
Idéia central
A idéia básica do sistema é fornecer uma grade aonde possamos organizar o conteúdo de forma consistente. No caso do 960gs, esta grade encontra-se sobreposta a uma área de 960 píxels de largura. Por que 960 pixels? Por que é a resolução mais comum dos navegadores atualmente, sendo assim resolveram adotar esta convenção. No caso do 960gs, ele já vêm pré-configurado com 3 possibilidades: 12,16 ou 24 colunas. Na imagem abaixo está um exemplo de layout usando 12 colunas:
Como pode ser observado, há 12 colunas de cor rosa, com um espaço entre elas. No padrão 960gs, cada coluna possui 10 pixels de margem tanto esquerda quanto direita.
Abaixo está um site que acabei de terminar usando o layout. Como você pode perceber, as áreas em vermelho encontram-se exatamente dentro do espaço delimitado pelas colunas.
Preparando o terreno
O primeiro passo para usar o 960gs é fazer o download no site oficial: http://960.gs. Trata-se de um arquivo zipado que, ao ser descompactado, irá apresentar a seguinte estrutura de diretórios:
code: o que nos interessa: são os arquvos .css
templates: arquivos de imagem para quem quiser fazer mockups usando algum editor gráfico como Gimp ou Photoshop
sketch_sheets: um arquivo no formato PDF que você pode imprimir e desenhar em cima
licenses: bla bla bla jurídico
Copie os arquivos 960.css, reset.css e text.css para o diretório da sua aplicação (seja ela feita em PHP, Grails, HTML puro ou qualquer outra coisa). Em seguida, dentro da tag <head> da sua página, inclua o código abaixo:
<link rel="stylesheet" href="css/reset.css" /> <link rel="stylesheet" href="css/text.css" /> <link rel="stylesheet" href="css/960.css" />
Lembre-se de referenciar os arquivos css de acordo com a sua localização dentro da aplicação.
Entendendo a lógica
A regra é a seguinte: o layout da sua aplicação será organizado em linhas e colunas. Cada linha deverá possuir n colunas, aonde n representa o padrão que você adotou ao usar o 960gs. É desnecessário, mas se você quiser saber a largura de uma coluna, use a fórmula abaixo:
largura da coluna = (960 / (número de colunas)) – (margem da coluna * 2)
Como mencionei acima, cada coluna possui duas margens (direita e esquerda), cada uma com 10 pixels de lado. Sendo assim, no nosso exemplo cada coluna terá 60 pixels de largura.
Pondo em prática
O 960gs é aplicado em um container. Sendo assim, escolha uma div dentro da sua página que conterá todas as demais e altere-a para que fique tal como no exemplo abaixo:
<div class="container_12"> ... </div>
A classe container_12 define que aquele elemento está adotando uma grade de 960 pixels com 12 colunas. Se quisesse usar uma grade com 16 colunas, bastaria usar a classe container_16.
A melhor maneira de explicar o funcionamento da técnica é visualmente. Sendo assim, observe a imagem abaixo, que é o exemplo fornecido com o framework:
Repare que é um layout composto por duas linhas. A primeira ocupa todas as 12 colunas, enquanto o segundo é dividido em dois grupos: um contendo uma coluna e outro contendo as 11 restantes. Para obter este resultado, escreve-se o código abaixo:
<div class="container_12"> // Primeira linha <div class="grid_12"></div> // Segunda linha <div class="grid_1"></div> <div class="grid_11"></div> </div>
A classe grid_[número de colunas] representa o número de colunas que o elemento deverá ocupar. Sendo assim, na primeira linha usamos a tag grid_12, pois queriamos que toda a largura fosse ocupada.
Já na segunda linha, como queriamos dividir a largura em dois blocos, definimos para o primeiro elemento a tag grid_1 (uma coluna) e grid_11 para o seguinte (11 colunas).
A regra se manteve: cada linha deve possuir 12 colunas.
Aumentando a flexibilidade
Agora, vamos aumentar a flexibilidade dos nossos layouts. E se quiséssemos apenas um componente que não ocupasse a página inteira, mas que ao mesmo tempo não estivesse próximo às margens da página, tal como no exemplo abaixo?
Agora entra em prática mais duas classes: prefix[colunas] e suffix[colunas] que representam respectivamente quantas colunas deverão vir antes do nosso componente e quantas depois. Reparou? Mantivemos aqui a regra de manter o número de colunas fixo!
Obteriamos o resultado acima portanto com o código abaixo:
<div class="grid_1 suffix_2 prefix_9"></div>
Duas colunas como sufixo e 9 como prefixo e uma coluna no meio. 2 + 9 + 1 = 12!
Aproveitando as margens laterais das colunas
É possível também aproveitar as margens direita e esquerda da coluna. Se quiser que seu componente ocupe a largura da margem esquerda, adicione a ele a classe alfa. Quer aproveitar a coluna da direita? Adicione a classe omega!
Simples assim!
Considerações finais: não interfira no trabalho do 960gs
No meu aprendizado observei o seguinte: como o objetivo do 960gs é dispor os elementos da sua página pra você, em momento algum o designer deverá definir em seus arquivos CSS o tamanho dos seus componentes. Isto irá interferir com o estilo definido pelo 960gs e, consequentemente, as coisas não sairão tão bacanas quanto gostaríamos.
Lembre-se: o objetivo do 960gs é resolver o problema da largura e disposição dos elementos da página. Tentar interferir neste processo é a mesma coisa que ir a um médico e começar a dar pitaco em seus diagnósticos, resumindo: não da certo (a não ser que você também seja um médico).
Você também deverá ignorar o atributo float: o 960gs já faz isto pra vocë. Defini-lo nestes componentes só irá anular o framework.
Indo além
E se você quiser um layout com menos ou mais de 960 pixels, ou mesmo um número de colunas diferente de 12, 16 ou 24? Como fazer? Neste caso você precisa de um sistema de grade variável. A SprySoft tem um gerador de grades customizados online e gratuito para você. Basta acessar este endereço: http://www.spry-soft.com/grids/
Grails: entendendo o SiteMesh
Ao aprender Grails um dos componentes que mais me confundiu foi o SiteMesh. Intuitivamente eu sabia o que estava acontecendo, mas toda vez que buscava escrever a respeito acabava me enrolando.
E acredite: você só conhece de fato algo se consegue descrevê-lo em palavras, por escrito. Trabalhando na última parte da minha série “Grails: do Groovy à Web” que está sendo publicada na Java Magazine tive a certeza de finalmente compreender de fato o que é o SiteMesh e como funciona. E a razão pela qual tinha tanta dificuldade é simples: estava viciado no Tiles.
Enquanto o Tiles é baseado no padrão composição (composite), o SiteMesh é baseado no padrão decorador (decorator). A diferença entre os dois é: no composite temos um layout central que contém uma série de espaços a serem preenchidos por templates.
Já o padrão decorator possui um layout central que também possui espaços a serem preenchidos: a diferença é que apenas os elementos ausentes serão preenchidos. Eu não preciso adicionar todos os componentes tal como estava acostumado na época do Struts 1/Tiles.
Bla bla bla demais, é hora de irmos à prática. No Grails, todos os layouts do SiteMesh ficam armazenados no diretório grails-app/views/layouts. Por padrão já há um layout pré-definido, cujo nome é main.gsp armazenado neste diretório. É importante lembrar que se trata de um arquivo GSP convencional, cujo código exponho abaixo:
<html>
<head>
<title><strong><g:layoutTitle default="Grails" /></strong></title>
<link rel="stylesheet" href="${resource(dir:’css’,file:’main.css’)}" />
<link rel="shortcut icon" href="${resource(dir:’images’,file:’favicon.ico’)}" type="image/x-icon" />
<strong><g:layoutHead /></strong>
<g:javascript library="application" />
</head>
<body>
<div id="spinner" style="display:none;">
<img src="${resource(dir:’images’,file:’spinner.gif’)}" alt="Spinner" />
</div>
<div id="grailsLogo"><a href="http://grails.org"><img src="${resource(dir:’images’,file:’grails_logo.png’)}" alt="Grails" border="0" /></a></div>
<strong><g:layoutBody /></strong>
</body>
</html>
A única diferença entre o arquvo GSP e uma view convencional é a presença de três tags: g:layoutTitle, g:layoutHead, g:layoutBody. Falarei delas logo a seguir, porém antes de continuar, vou expor a view mais idiota possível: algo que não exponha basicamente nada, e cujo código fonte é o seguinte:
<html> <head> <meta name="layout" content="main"/> </head> <body> </body> </html>
Colocando a aplicação para executar, e acessando-a, no entanto, é renderizado algo inicialmente inexperado:
De onde saiu este logotipo do Grails? Do layout main que defini anteriormente. No caso, eu instrui o Grails a usar o SiteMesh ao inserir a seguinte tag na minha view:
<meta name="layout" content="main"/>
Esta tag basicamente diz: “aplique o layout definido no arquivo grails-app/views/layouts/main.gsp a esta view”. E aqui entra a jusitificativa do mesh no nome SiteMesh: ao invés de incluir o conteúdo de um arquivo em outro, o que é feito na realidade é a fusão do conteúdo da view no corpo do layout!
Isto fica claro com a descrição das 3 tags que descrevi acima (consulte a primeira listagem para que fique claro):
g:layoutTitle – define qual será o conteúdo da tag title embutido na tag head. Repare qeu esta tag possui um atributo chamado “default”. Caso na view a tag title já esteja preenchida, será incluido no arquivo HTML final o conteúdo da tag title da view. Caso contrário, o conteúdo será aquele especificado no parâmetro default
g:layoutHead – o conteúdo da tag <head> da view será inserido no local do layout aonde a tag g:layoutHead se encontra.
g:layoutBody – o conteúdo da tag <body> da view será inserido no local do layout aonde a tag se encontra.
Resumindo: no SiteMesh não temos inclusão, mas sim fusão.
Espero que com esta descrição o recurso fique tão claro para vocês quanto pra mim.
Grande abraço e até a próxima!
Dica Groovy: simplificando seu código com ‘with’
Imagine que você tenha uma classe tal como a abaixo:
class Pessoa {
String nome
String sobrenome
}
Há duas maneiras de preencher suas propriedades: você poderia usar um construtor como o código abaixo:
new Pessoa(nome:"Henrique", sobrenome:"Lobo Weissmann")
que é bem bacana, mas também poderia escrever um código bem mais tedioso, como este:
def pessoa = new Pessoa() pessoa.nome = "Henrique" pessoa.sobrenome = "Lobo Weissmann"
Entra a instrução with, que é muito similar à que encontramos no Delphi:
def pessoa = new Pessoa()
pessoa.with {
nome = "Henrique"
sobrenome = "Lobo Weissmann"
}
Dica Groovy: o operador spread ( *. )
Um recurso muito bacana do Groovy é o operador spread, que é usado quando desejamos invocar um método em todos os objetos presentes em um objeto agregador (Collection).
Vamos supor que eu tenha uma classe tal como a implementada abaixo:
class DigaSeuNome {
String nome
void fale() {println nome}
}
E que eu tenha uma coleção populada tal como no código abaixo:
def lista = [new DigaSeuNome(nome:"Juca"), new DigaSeuNome(nome:"Zeca")]
Em Java, se eu quiser executar o método fale() em cada uma das minhas instâncias, eu faria algo como o código abaixo:
for (DigaSeuNome instancia : lista) {
instancia.fale()
}
E em Groovy? Assim:
lista*.fale() // Saida: // Primeiro seŕa impresso Juca e depois Zeca
Se o método a ser executado retornar um valor, o operador spread nos trás como retorno um vetor cujo conteúdo é justamente o resultado da operação do método. O código abaixo fala por si próprio:
def lista = ["aa", "bbb", "cccc"] assert lista*.size() == [2,3,4]
Muito legal.
Dica Groovy: parâmetros com valor default
Pouca gente sabe disto: Groovy aceita que criemos funções cujos parâmetros possam possuir valores opcionais.
O código abaixo fala por si mesmo:
// Repare: defini o valor default do parâmetro c igual a 3
def imprima(c = 3, d) {
println c
println d
}
// Saida:
// imprime 3 primeiro e 34 em seguida
imprima(d=34)
// Saida:
// Imprimirá 4 primeiro e 5 em seguida
imprima(4, 5)
// Saida:
// Imprimirá 3 e em seguida 55
imprima(55)
// Gera erro, pois o parâmetro d não possui valor default
imprima()
Grails e o plugin Tomcat
A partir da versão 1.2 do Grails o plugin de suporte ao Apache Tomcat passou a vir por default junto com o framework. Então, neste final de semana resolvi experimenta-lo para descobrir como funciona. Não foi surpresa descobrir que o deploy da aplicação pode ser muito mais fácil com ele.
Instalação do plugin
Se sua aplicação já é baseada na versão 1.2 do Grails, nada precisa ser feito. Caso contrário, basta executar o comando abaixo:
grails install-plugin tomcat
Este recurso só funciona para as versões 1.1 ou posteriores do framework.
Configuração do seu servidor tomcat
Verifique qual o usuário possui permissão para executar deploys no servidor. Isto pode ser feito lendo-se o arquivo tomcat-users.xml, que se encontra dentro do diretório conf da sua instalação do Tomcat. Somente usuários com o role manager podem executar esta tarefa.
Por padrão, o Tomcat não vêm com este usuário definido. Sendo assim, caso seu arquivo esteja ainda vazio, edite-o para ficar similar ao exemplo abaixo:
<role rolename="manager"/> <user username="admin" password="admin" roles="manager"/>
Configurando o seu projeto
Basta incluir no arquivo Config.groovy que se encontra no diretório grails-app/conf da sua aplicação as linhas abaixo:
// O usuário no Tomcat
tomcat.deploy.username=”admin”
// A senha de acesso deste usuário
tomcat.deploy.password=”admin”
Qual o endereço do servidor
tomcat.deploy.url=”http://localhost:8080/manager”
Atenção deve ser dada à linha tomcat.deploy.url, cuja sintaxe é a seguinte:
tomcat.deploy.url=”[endereço do servidor incluindo a porta]/manager”
A aplicação manager do Tomcat é a responsável por efetuar o deploy remoto, por isto deverá ser incluida no final do valor desta chave.
Finalmente, o deploy
Feito isto, o deploy não poderia ser mais simples: basta executar o seguinte comando dentro do diretório da sua aplicação:
grails tomcat deploy
Caso já exista uma aplicação com mesmo nome no seu servidor, o deploy será mal sucedido. Nestes casos, você terá de efetuar o undeploy para em seguida executar o deploy novamente. Como remover a aplicação do servidor?
Simples: basta executar o comando abaixo:
grails tomcat undeploy
Maiores informações podem ser obtidas na página do plugin: http://grails.org/plugin/tomcat
Grails: do Groovy à Web – Terceiro artigo publicado na Java Magazine 77
Acabou de sair a edição digital (a versão impressa deve estar para ser liberada nos próximos dias) da Java Magazine 77 na qual o meu terceiro artigo da série “Grails: do Groovy à Web” foi publicado.
Desta vez, o foco é a camada de controle do Grails. Veremos como funciona o mecanismo de requisições adotado pelo framework. Aguardo o retorno de vocês.
O próximo artigo, a ser publicado na edição de número 78 é sobre GORM, aonde exponho as entranhas do mecanismo de persistência do Grails.
Aguardo o feedback de vocês!
Grails é inegavelmente bonito
Hoje dei manutenção em um antigo projeto feito em JSF. Ao alterar o meu arquvo jsp para expor a data no formato que eu precisava, precisei escrever algo assim:
<h:outputText value="#{bean.data}">
<f:convertDateTime pattern="dd/MM/yyyy"/>
</h:outputText>
Ô saudade do Grails, aonde eu só preciso escrever:
<g:dateFormat date="${bean.data}" format="dd/MM/yyyy"/>
Divulgando os brasileiros que trabalham com Grails
Recentemente iniciei um novo projeto no Grails Brasil: o {Blogs}. Trata-se de um agregador de blogs escritos por brasileiros (ou em português) que trabalhem com Grails e curtem compartilhar suas experiências neste processo.
A razão de ter iniciado o projeto é simples: há profissionais excelentes no Brasil trabalhando com Grails, pessoas que ajudam demais a comunidade (seja em fórums ou publicando material em seus blogs) e cujo trabalho deve ser o mais divulgado possível, visto que são profissionais raros!
Além disto, é também um incentivo para que mais material seja publicado em português, tornando assim ainda mais conhecido o nosso framework favorito. Acredito que iniciativas como estas criam um ciclo que beneficia a todos: quem publica material o tem divulgado, e quem está aprendendo é incentivado a também escrever a respeito para que seja valorizado.
Infelizmente (ou seria felizmente?) este projeto não será bem sucedido se for executado por apenas uma entidade (itexto): sendo assim, gostaria de lhes pedir que me ajudassem de uma das formas abaixo:
- Possui um blog? Cadastre-o no Grails Brasil {Blogs}!
- Curte twitter? “Tuite” a respeito!
- Não gostou de algo no Grails Brasil {Blogs}? Meta o ferro! Envie-me um e-mail dizendo o que pode ser melhorado e eu o farei o mais rápido possível: kicolobo@itexto.net (se quiser pode comentar neste post também)
- Fale para os seus amigos a respeito
- E se quiser apoiar de outra forma, mande-me a sua idéia por e-mail!
Confesso estar bastante animado com o projeto, pois conheci alguns blogs que ainda não conhecia e tive a oportunidade de ler alguns posts que havia deixado escapar, e espero que a ferramenta lhe seja útil também.
Ah, e o endereço do site? http://blogs.grailsbrasil.com
PS: não é brasileiro mas escreve/lê em português? Seja bem vindo!
Não quer acessar o site toda hora? Tudo bem: assine o feed :)
Grails: detalhes pouco conhecidos dos ambientes de execução (environments)
Um dos recursos mais bacanas do Grails é a possibilidade de se possuir mais de um ambiente de execução (environment). A grosso modo, pode-se dizer que o environment representa uma configuração específica de banco de dados usada em determinada situação. Neste post não irei explicar como configurar seu acesso às suas bases de dados, mas sim alguns pontos pouco divulgados a respeito deste recurso.
Você pode ter quantos ambientes quiser!
Por padrão Grails nos fornece três ambientes: test, development e production que, respectivamente, são usados quando executamos nossos testes unitários/de integração, estamos programando e, finalmente, enviamos para o servidor de aplicações no qual o produto final do nosso trabalho será usado. O que poucos sabem é que na realidade podemos ter quantos ambientes de execução quisermos!
Para adicionar um novo ambiente de execução, basta adicionar mais um bloco de código dentro da seção environments como no exemplo abaixo:
environments {
development {
dataSource {
dbCreate = "update" // one of 'create', 'create-drop','update'
url = "jdbc:mysql://localhost/development"
}
}
test {
dataSource {
dbCreate = "update" // one of 'create', 'create-drop','update'
url = "jdbc:mysql://localhost/test"
}
}
production {
dataSource {
dbCreate = "update" // one of 'create', 'create-drop','update'
url = "jdbc:mysql://localhost/production"
}
}
meu_ambiente {
dataSource {
dbCreate = "update"
url = "jdbc:mysql://localhost/meu_BD_Louco"
}
}
}
Para usar estes ambientes de execução adicionais na linha de comando, basta usar a sintaxe abaixo:
grails [nome do ambiente] [comando]
Exemplo:
grails meu_ambiente run-app
Simples assim.
Descobrir qual o ambiente escolhido em tempo de execução
Grails só permite que um ambiente seja usado por vez. Sendo assim, esta é uma informação importante que podemos usar a nosso favor quando estamos programando. Suponhamos que seja interessante habilitar comportamentos apenas em alguns ambientes de execução. Como você faria? Assim:
import grails.util.Environmentswitch(Environment.current) {
case Environment.DEVELOPMENT:
"Apenas para desenvolvimento"
break
case Environment.PRODUCTION:
"Apenas para proução"
break
case "meu_environment"
"Olha o meu environment aqui!"
break
}
Environments na inicialização da aplicação
No arquivo grails-app/conf/Bootstrap.groovy incluimos o código que desejamos ser executado quando nossa aplicação é inicializada. Como tirar proveito dos ambientes de execução nesta situação? De novo, como no código abaixo:
def init = { ServletContext ctx ->
environments {
production {
// em produção
}
development {
// em desenvolvimento
}
}
ctx.setAttribute("foo", "bar")
}



