Customização de LESS no Magento 2: _theme.less, _extend.less
Luma e Blank são estilizados com LESS em cima da UI library do Magento. O sistema é flexível, mas tem suas próprias convenções de nome de arquivo e regras de import, e se você não as seguir acaba com um tema que copia metade do Luma e quebra a cada upgrade.
Este artigo explica como o LESS é organizado num tema do Magento 2.4.8, qual arquivo mexer para cada tipo de mudança e como compilar rápido enquanto você trabalha.
Como os stylesheets são construídos
Um storefront baseado em Luma carrega dois arquivos CSS principais: styles-m.css para estilos mobile e comuns, e styles-l.css para estilos de desktop. Cada um vem de um arquivo raiz LESS no tema Blank, web/css/styles-m.less e web/css/styles-l.less. Esses arquivos importam, em ordem:
- A UI library de
lib/web/css/source/lib/, que fornece mixins e variáveis padrão. - As variáveis do tema.
- O
_module.lesse o_widgets.lessde cada módulo, pela diretiva especial//@magento_import. - O
_theme.lessdo tema. - Todo
_extend.less, de novo pela//@magento_import.
O //@magento_import parece um comentário mas é processado pelo Magento antes de o compilador LESS rodar. Ele coleta o arquivo com aquele nome de todos os módulos e da cadeia de fallback do tema. É por isso que os nomes de arquivo abaixo importam. Um arquivo com outro nome simplesmente nunca é importado.
Os arquivos que você deve editar
_theme.less: mudar variáveis
O web/css/source/_theme.less é onde você sobrescreve variáveis da UI library e do tema pai. Um child theme do Luma herda o _theme.less do Luma, mas se você criar seu próprio arquivo com o mesmo nome, ele substitui o do pai por completo em vez de acrescentar. Então comece copiando o conteúdo do arquivo do pai de vendor/magento/theme-frontend-luma/web/css/source/_theme.less para o seu tema, e depois mude ou acrescente variáveis:
// copied Luma variables above this line
@primary__color: #1a3c5e;
@link__color: #1a3c5e;
@link__hover__color: darken(#1a3c5e, 10%);
@font-family__base: 'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;
Esquecer o passo da cópia é o erro de LESS mais comum em child themes. Os valores do pai somem e partes da loja de repente voltam às cores do Blank. O custo da cópia é que você precisa comparar o arquivo com o do pai a cada upgrade, então mantenha suas mudanças no final, onde são fáceis de achar.
Antes de sobrescrever uma variável, procure por ela em lib/web/css/source/lib/variables/ e no tema pai. Mudar uma variável é a customização mais barata que existe, porque todo componente que a usa é atualizado de uma vez.
_extend.less: adicionar estilos
O web/css/source/_extend.less é para regras novas. Ele é importado depois de tudo, então vence em especificidade igual. Mantenha-o como um índice e divida o trabalho de verdade em partials:
@import 'components/_header.less';
@import 'components/_product-card.less';
@import 'components/_footer.less';
Use o _extend.less por padrão. Ele acrescenta ao tema pai em vez de substituí-lo, então as correções do pai continuam chegando depois de um upgrade.
Arquivos no nível do módulo
Cada pasta de módulo no tema pode ter seus próprios estilos, por exemplo Magento_Catalog/web/css/source/:
- O
_extend.lessnessa pasta adiciona estilos para aquele módulo. É pego pelo mesmo//@magento_importdo de nível de tema. - O
_module.lessnessa pasta substitui os estilos do tema pai para aquele módulo. Use só quando for reestilizar o módulo do zero.
Vejo muitos temas com um _module.less copiado onde só poucas linhas mudaram. É a versão em LESS de copiar um template para mudar uma linha, e tem o mesmo custo de upgrade.
Media queries do jeito Magento
Os estilos são divididos entre os dois arquivos CSS com mixins com guard. Regras para todos os tamanhos de tela vão num bloco com guard @media-common, e regras específicas de tela usam o mixin .media-width():
& when (@media-common = true) {
.product-card {
border: 1px solid @border-color__base;
padding: @indent__s;
}
}
.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
.product-card {
padding: @indent__base;
}
}
.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) {
.product-card {
padding: @indent__xs;
}
}
O Magento compila os breakpoints min de @screen__m para cima em styles-l.css, e o resto em styles-m.css. Se você escreve blocos @media comuns, as regras acabam duplicadas nos dois arquivos ou no arquivo errado. Escrever regras fora de um guard também as duplica, o que é um motivo comum para arquivos CSS que crescem sem nenhuma mudança visível.
As variáveis de breakpoint são @screen__xxs, @screen__xs, @screen__s, @screen__m, @screen__l e @screen__xl.
Compilando LESS durante o desenvolvimento
Há dois modos de compilação, definidos em Stores, Configuration, Advanced, Developer, Frontend Development Workflow (caminho de config dev/front_end_development_workflow/type):
- A compilação server side é o padrão e a única opção para produção. O Magento compila o LESS com uma biblioteca PHP quando o arquivo CSS é requisitado em developer mode, ou durante o static content deploy.
- A compilação client side compila no navegador com o less.js. É lenta e não recomendo.
No dia a dia, o Grunt é mais rápido e dá live reload. O Magento já traz os arquivos de que você precisa:
cp package.json.sample package.json
cp Gruntfile.js.sample Gruntfile.js
cp dev/tools/grunt/configs/themes.js dev/tools/grunt/configs/local-themes.js
npm install
Adicione seu tema ao local-themes.js:
module.exports = {
vendortheme: {
area: 'frontend',
name: 'Vendor/theme',
locale: 'en_US',
files: [
'css/styles-m',
'css/styles-l'
],
dsl: 'less'
}
};
Depois rode os três comandos abaixo. O primeiro publica os arquivos de origem como symlinks, o segundo compila, o terceiro observa as mudanças:
npx grunt exec:vendortheme
npx grunt less:vendortheme
npx grunt watch
Rode o exec de novo sempre que adicionar um arquivo LESS novo, porque os symlinks só cobrem arquivos que existiam quando ele rodou.
Quando os estilos não atualizam
CSS desatualizado é quase sempre problema de cache. Limpe os arquivos compilados do tema e as origens pré-processadas:
rm -rf pub/static/frontend/Vendor/theme var/view_preprocessed/pub/static/frontend/Vendor/theme
bin/magento cache:clean
Em production mode, nada muda até você rodar bin/magento setup:static-content:deploy para o tema e os locales. O artigo sobre estratégias de static content deploy mostra como manter essa etapa rápida.
Mantendo o CSS enxuto
O CSS do Luma é grande, e todo tema acrescenta a ele. Algumas regras ajudam:
- Mude variáveis antes de escrever regras novas.
- Evite aninhamento profundo. O LESS facilita escrever seletores com cinco níveis, o que prejudica tanto a especificidade quanto o tamanho do arquivo.
- Não importe fontes ou conjuntos de ícones que você não usa. Confira as declarações
@font-faceno arquivo compilado. - Considere critical CSS. O Magento pode inserir inline o
web/css/critical.cssdo seu tema e carregar o resto de forma assíncrona quando odev/css/use_css_critical_pathestá ativo. Você mesmo precisa escrever ou gerar esse arquivo.
Se você está planejando uma mudança visual maior, vale comparar o custo com abandonar o LESS de vez. O artigo de customização do Hyvä com Tailwind mostra como é o estilo desse outro lado. Para montar a pasta do tema em si, comece por criando um child theme.
FAQ
Devo colocar meus estilos no _theme.less ou no _extend.less?
Variáveis vão no _theme.less. Regras novas vão no _extend.less. Um _theme.less no seu tema substitui o arquivo do pai, então copie a versão do pai para ele primeiro.
Por que meu arquivo LESS não é compilado?
O Magento só importa arquivos com os nomes esperados, como _extend.less, _module.less e _theme.less, ou arquivos que você importa a partir deles. Um partial novo precisa ser importado por um desses, e com o Grunt você precisa rodar a task exec de novo.
Posso usar Sass em vez de LESS num tema Luma?
Não com o pipeline nativo. Alguns temas da comunidade trazem um port em Sass da UI library com ferramentas de build próprias, mas o Luma e o Blank do core são só LESS.
Por que minhas regras estão duplicadas no styles-m.css e no styles-l.css?
Foram escritas fora de um guard media-common ou dentro de media queries comuns. Envolva as regras comuns no guard media-common e use o mixin .media-width() para breakpoints.
Atendo como freelancer em Magento e Adobe Commerce, incluindo limpeza de tema Luma e performance de frontend. Se você precisa de ajuda com isso, fale comigo.
Artigos relacionados
Layout XML do Magento 2: guia prático para desenvolvedores
Como o layout XML do Magento 2 funciona: handles, containers, blocks, move e remove, arguments, view models e page layouts, com exemplos que valem no 2.4.8.
Como criar um child theme no Magento 2 passo a passo
Crie um child theme do Luma ou do Blank no Magento 2: theme.xml, registration.php, composer.json, view.xml, logo, override de templates, aplicação e deploy.
Core Web Vitals no Magento 2: como corrigir LCP, INP e CLS
Onde lojas Magento 2 com Luma perdem nos Core Web Vitals e como corrigir LCP, INP e CLS: resposta do servidor, CSS, fontes, imagens, galeria e scripts de terceiros.
Static content deploy no Magento 2: estratégias e opções
Acelere o setup:static-content:deploy no Magento 2: estratégias standard, quick e compact, jobs em paralelo, escopo de temas e locales e builds sem banco.