CSS

10 nov, 2013

Escreva seu CSS com JavaScript

Publicidade

Às vezes, a programação está apenas usando a ferramenta certa. Esta pode ser um framework, uma biblioteca ou, como acontece no meu caso, pré-processamento CSS. Você provavelmente não percebe isso, mas LESS ou SASS têm um monte de restrições. Eu consegui mudar isso, escrevi meu próprio pré-processador CSS. Eu parei de escrever CSS e mudei tudo para o mundo JavaScript. Este artigo é sobre AbsurdJS: um pequeno módulo Node.js, que mudou completamente o meu fluxo de trabalho.

O conceito

css-1

Se você escreve um monte de CSS, você provavelmente usa pré-processador. Há dois populares – LESS e SASS. Ambas as ferramentas aceitam alguma coisa, que se parece com CSS, fazem um pouco de magia e exportação normal, CSS puro. O que eu fiz foi apenas substituir o instrumento e o formato de entrada. Eu não queria inventar uma nova linguagem ou sintaxe, porque isso está conectado com um monte de coisas, como análise e compilação. Felizmente, Node.js está aqui e eu decidi usá-lo. Além disso, eu tinha um monte de projetos do tipo LESS, o que significa que eu já uso Node.js para compilar meus estilos. Era muito mais fácil substituir um módulo em vez de adicionar algo completamente novo.

O input

css-2

Eu acho que a coisa mais próxima do formato CSS é JSON – é o que o AbsurdJS aceita. Claro que existem alguns contras dessa transformação. Você tem que colocar algumas propriedades entre aspas e, claro, os valores. Isso precisa de um pouco mais de tempo durante a escrita, mas como você verá a seguir vale a pena.

No princípio era… um arquivo JavaScript

Aqui está  como um simples arquivo LESS se parece:

.main-nav {
    background: #333;
    color: #000;
    font-weight: bold;
    p {
        font-size: 20px;
    }
}

E aqui está o seu equivalente AbsurdJS. É um módulo Node.js simples:

module.exports = function(api) {
    api.add({
        ".main-nav": {
            background: "#333",
            color: "#000",
            "font-weight": "bold",
            p: {
                "font-size": "20px"
            }
        }
    })
}

Você deve atribuir uma função para module.exports. Ele aceita uma referência à API, que tem vários métodos, mas o mais importante é add. Basta passar um objeto JSON e ele será convertido em CSS.

Para compilar o arquivo LESS, precisamos instalar o compilador LESS via npm install -g less e rodar

lessc .\css.less > styles.less.css

É quase o mesmo com AbsurdJS. A instalação é feita novamente via node package manager – npm install -g absurd.

absurd -s css.js -o styles.absurd.css

Ele aceita a fonte e a saída; o resultado é o mesmo.

A verdade

Você pode ter arquivos LESS ou SASS muito bonitos e de boa aparência ou arquivos SASS, mas o que importa é o CSS compilado final. Infelizmente, o resultado nem sempre é o melhor.

Combinando

Vamos ao exemplo a seguir:

.main-nav {
    background: #333;
}
.main-content {
    background: #333;
}

Se você passar isso para os pré-processadores atuais, você terá a mesma coisa no final. No entanto, se você usar AbsurdJS assim:

module.exports = function(api) {
    api.add({
        ".main-nav": {
            background: "#333"
        },
        ".main-content": {
            background: "#333"
        }
    })
}

Após a compilação você terá

.main-nav, .main-content {
    background: #333;
}

SASS tem um recurso chamado placeholders que faz a mesma coisa. No entanto, ele vem com seus próprios problemas. Os placeholders não podem aceitar parâmetros, e você deve repeti-los em cada seletor que você deseja combinar. Minha solução apenas analisa as regras e as combina. Vamos a um exemplo um pouco mais complexo:

{
    ".main-nav": {
        background: "#333",
        ".logo": {
            color: "#9f0000",
            margin: 0
        }
    },
    ".main-content": {
        background: "#333"
    },
    section: {
        color: "#9f0000",
        ".box": {
            margin: 0
        }
    }
}

O resultado é

.main-nav, .main-content {
    background: #333;
}
.main-nav .logo, section {
    color: #9f0000;
}
.main-nav .logo, section .box {
    margin: 0;
}
section .box {
    padding: 10px;
    font-size: 24px;
}

Todos os estilos idênticos são combinados em uma única definição. Eu sei que os navegadores são muito rápidos hoje, e isso não é exatamente a otimização mais importante, mas poderia diminuir o tamanho do arquivo.

Overwriting

Você sabe que se você tiver dois seletores idênticos e que contêm a definição do mesmo estilo, o segundo faz um overwriting no primeiro. O código LESS/SASS permanece o mesmo:

.main-nav {
   font-size: 20px;
}
.main-nav {
   font-size: 30px;
}

No entanto, eu acho que isso deixa mais uma operação para o browser: ele tem que descobrir que há outra definição com o mesmo seletor e estilo e calcular o valor correto. Não é melhor evitar isso, e enviar diretamente:

.main-nav {
    font-size: 30px;
}

AbsurdJS se preocupa com isso e produz apenas uma definição. A entrada pode ser parecida com isto:

{
    ".main-nav": {
        "font-size": "20px"
    },
    ".main-nav": {
        "font-size": "30px"
    }
}

Ele também tornar processo de depuração mais fácil, porque não há nenhuma cadeia de substituições tão longa.

Flexibilidade

Ok, temos mixins, variáveis, placeholders, functions, mas uma vez que você começa a usá-los para escrever as coisas um pouco mais complexas você está preso. Vamos pegar os mixins. Eu quero criar um mixin, que define outro mixin. Isso não é possível atualmente em LESS, porque você não pode usar um mixin definido em outro mixin. Eu acho que é um problema de escopo. SASS tem algumas imperfeições em relação a interpolação das variáveis. Em geral, é difícil produzir boa arquitetura com menos código. Você tem que escrever muito e, mesmo assim, você não pode realmente alcançar seus objetivos. A principal razão por trás desses problemas é o fato de que ambos, LESS e SASS, têm que lidar com nova sintaxe, novas regras e, basicamente, inventar um novo compilador. No entanto, se usarmos JavaScript, não temos que pensar sobre essas questões.

AbsurdJS tem algo chamado de storage. Ele poderia salvar o que quiser e torná-lo disponível em outros arquivos. Por exemplo:

// B.js
module.exports = function(api) {
    api.storage("theme", function(type) {
        switch(type) {
            case "dark": return { color: "#333", "font-size": "20px" }; break;
            case "light": return { color: "#FFF", "font-size": "22px" }; break;
            default: return { color: "#999", "font-size": "18px" };
        }
    });
}

// A.js
module.exports = function(api) {
    api
    .import(__dirname + "/B.js")
    .add({
        ".main-nav": [
            {
                "font-size": "16px",
                padding: 0,
                margin: 0
            },
            api.storage("theme")("dark")
        ]
    });
}

No final você tem:

.main-nav {
    color: #333;
    font-size: 20px;
    padding: 0;
    margin: 0;
}

Usar o storage pode ser um pouco feio. Quero dizer, você precisa de um array atribuído ao seletor e, em seguida, chamar api.storage. Eu usei isso por um tempo, mas depois decidi implementar algo muito mais agradável. É um recurso que eu sempre quis – a capacidade de criar suas próprias propriedades e salvar toneladas de linhas. Por exemplo, vamos criar uma nova propriedade chamada theme e processar o seu valor.

// B.js - definition of the plugin 
module.exports = function(api) {
    api.plugin('theme', function(api, type) {
        switch(type) {
            case "dark": return { color: "#333", "font-size": "20px" }; break;
            case "light": return { color: "#FFF", "font-size": "22px" }; break;
            default: return { color: "#999", "font-size": "18px" };
        }
    });
}

// A.js - its usage
module.exports = function(api) {
    api
    .import(__dirname + "/B.js")
    .add({
        ".header": {
            theme: "light"
        }
    })
}

Mais uma vez, o resultado é semelhante:

.header {
    color: #FFF;
    font-size: 22px;
}

Conclusão

AbsurdJS é algo muito simples, mas evita o uso de pré-processadores CSS populares. Ele ainda tem a mesma característica de seletores aninhados, media queries, importação de arquivos, variáveis, mixins, e assim por diante. No entanto, ele traz uma maior flexibilidade, uma vez que é um JavaScript puro. Possui ainda suporte para GruntJS. Eu gostaria de obter algum feedback e vou ficar feliz se você fizer parte do projeto. O repositório oficial está disponível aqui: https://github.com/krasimir/absurd.

http://davidwalsh.name/write-css-javascript