
Lumos apporte trois gains majeurs par rapport à Client-First : un responsive sans breakpoints (breakpointless), un theming automatique par cascade de variables CSS, et un code CSS nettement plus léger sur les gros projets.
Client-First reste un excellent framework pour les projets de taille petite à moyenne. Sa force, c'est sa simplicité : des noms de classes lisibles, une documentation complète, une prise en main rapide. Mais Webflow a beaucoup évolué depuis la création de Client-First. Les variables natives, les variable modes, les composants, les container queries : autant de fonctionnalités que Lumos exploite pleinement, là où Client-First n'a pas reçu de mise à jour majeure depuis janvier 2024.
Quand on a migré nos builds vers Lumos chez Klyra, le premier constat a été la réduction du nombre de classes custom. En Client-First, chaque propriété CSS un peu spécifique nécessite une classe dédiée. Avec Lumos, le système d'utilitaires empilés (une classe composant + une classe utilitaire) et les variables globales permettent de réduire considérablement la feuille de style.
Sur un projet de 15+ pages, la différence est flagrante. Client-First a tendance à accumuler des classes custom et des couches HTML supplémentaires (page-padding, section-padding, etc.) qui alourdissent le code à mesure que le site grandit. Lumos, lui, centralise tout dans les variables : tu modifies une valeur, elle se répercute partout.
L'autre facteur, c'est l'accessibilité. Lumos est conçu dès le départ pour que les layouts s'adaptent quand un utilisateur augmente sa taille de police préférée. Les breakpoints en px de Webflow ne réagissent pas au zoom du navigateur. Les techniques Lumos (flexbox wrap, autofit grids, unités rem) résolvent ce problème nativement.
section_ et page-padding vs u-section et u-containerLa différence de structure entre les deux frameworks se voit dès la première section.
Client-First :
html
<section class="section_hero">
<div class="page-padding">
<div class="container-large">
<div class="padding-vertical padding-xxlarge">
<div class="hero_component">
<!-- contenu -->
</div>
</div>
</div>
</div>
</section>
Lumos :
html
<section class="hero_wrap u-section">
<div class="hero_contain u-container">
<div class="hero_layout">
<!-- contenu -->
</div>
</div>
</section>
En Client-First, tu empiles des divs de structure : page-padding pour les marges horizontales, container-large pour la largeur max, padding-vertical pour l'espacement vertical. En Lumos, tout ça est intégré dans deux classes utilitaires : u-section gère le padding vertical et les couleurs de fond, u-container gère la largeur max, les marges latérales et le container-type: inline-size.
La règle critique à retenir : ne jamais mettre de display: grid ou de grid-template-columns sur u-container. Parce que u-container a container-type: inline-size, il sert de contexte pour les container queries. Si tu mets un grid dessus, aucune container query ne pourra le changer. Le layout va toujours sur un enfant _layout :
css
/* CORRECT */
.hero_layout {
display: var(--flex-medium, grid);
flex-direction: column;
grid-template-columns: repeat(12, minmax(0, 1fr));
}
/* FAUX, ça casse les container queries */
.hero_contain {
display: grid;
grid-template-columns: repeat(12, minmax(0, 1fr));
}
Lumos utilise des underscores pour séparer les parties d'un nom de classe, limite la profondeur à 3 underscores maximum, et impose un préfixe u- pour toutes les classes utilitaires. Client-First utilise des tirets et n'a pas de préfixe obligatoire.
Voici le mapping direct des conventions :
ConceptClient-FirstLumosSéparateurTiret (hero-header_title)Underscore (hero_title)Titre_heading_titleParagraphe_paragraph_textImage_image_imgWrapper obligatoireNonOui (_wrap pour tout composant/sous-composant)UtilitairesPas de préfixe (text-size-large)Préfixe u- (u-text-style-large)Combo classes.is-large, .is-dark.is-reversed, .is-1, .is-activeMax profondeurPas de limite stricte3 underscores max
En Client-First, tu pourrais écrire home-hero_content-wrapper_heading. En Lumos, ce serait hero_content_title. Si tu dépasses 3 underscores, tu crées un nouveau sous-composant avec _wrap.
Le point clé : chaque élément HTML dans Lumos doit avoir une classe composant. Pas de <div> nu avec uniquement une classe utilitaire. La structure c'est toujours : classe composant en premier, puis utilitaire empilée. Par exemple : <h2 class="hero_title u-text-style-h2">.
Les mots composés gardent les tirets : hero_link_wrap, pas hero_link-wrap. Les underscores séparent les niveaux de composant, les tirets lient les mots d'un même niveau.
Lumos élimine les breakpoints Webflow en utilisant des variables CSS responsives qui flippent automatiquement entre des valeurs selon la taille du conteneur. Zéro @media queries : le browser décide quand le layout doit changer.
C'est le changement mental le plus important quand tu viens de Client-First. En CF, tu styles le desktop, puis tu ajustes sur tablet, mobile landscape, mobile portrait. Quatre breakpoints, quatre passages dans le designer.
Lumos fait l'inverse. Tu styles une seule fois sur desktop, et le responsive est géré par :
1. Des techniques CSS natives. Le wrapping automatique en flexbox, les grids autofit/autofill, et le flex-basis font que la majorité des layouts se plient naturellement aux petits écrans.
2. Des variables responsive. Lumos fournit des variables comme --flex-medium, --column-medium, --none-small qui changent de valeur selon la taille de l'écran. Tu les utilises comme fallback CSS :
css
/* Passe de grid à flex quand l'écran est medium ou plus petit */
display: var(--flex-medium, grid);
/* Passe de row à column */
flex-direction: var(--column-medium, row);
Les variables --_responsive---large, --_responsive---medium, --_responsive---small et --_responsive---xsmall valent 1 ou 0 selon le breakpoint actif. Tu peux les combiner dans des calc() pour des ajustements fins :
css
grid-template-columns: repeat(
calc(
var(--_responsive---large) * 4 +
var(--_responsive---medium) * 3 +
var(--_responsive---small) * 2 +
var(--_responsive---xsmall) * 1
),
minmax(0, 1fr)
);
3. Les container queries en dernier recours. Si les variables responsive ne suffisent pas (par exemple, réordonner des éléments complexes), tu utilises @container :
css
@container (width < 50em) {
.hero_layout {
display: flex;
}
}
L'avantage majeur : quand un utilisateur zoome dans son navigateur ou augmente sa police préférée, le layout s'adapte. Avec les breakpoints en px de Webflow, le texte déborde. Avec Lumos, le contenu reste lisible.
Client-First gère les couleurs avec des variables manuelles. Tu crées tes color variables dans Webflow, tu les appliques élément par élément, et si tu veux une section dark, tu surcharges chaque couleur à la main.
Lumos fonctionne par cascade. Tu appliques u-theme-dark sur une section, et toutes les variables de couleur se mettent à jour automatiquement : fond, texte, bordures, boutons, liens. Pas besoin de toucher aux enfants.
html
<!-- Section claire (par défaut) -->
<section class="about_wrap u-section u-theme-light">
<!-- Tout est automatiquement en couleurs claires -->
</section>
<!-- Section sombre -->
<section class="features_wrap u-section u-theme-dark">
<!-- Tout bascule en couleurs sombres -->
</section>
<!-- Section brand -->
<section class="cta_wrap u-section u-theme-brand">
<!-- Couleurs de marque appliquées partout -->
</section>
Les variables thématiques suivent une convention cohérente : --_theme---background, --_theme---text, --_theme---border, --_theme---heading-accent. Pour les boutons : --_theme---button-primary--background, --_theme---button-primary--text, etc.
Ce système facilite le dark mode. Avec Lumos, le recolorage d'une section ou d'une page entière se fait en changeant le nom d'une classe ou d'un attribut. C'est aussi ce qui rend les transitions de couleur au scroll (par exemple, une navbar qui change de thème selon la section visible) beaucoup plus simples à implémenter.
En Client-First, tu devrais créer des variantes de chaque composant pour chaque mode de couleur, ou empiler des override classes. Avec Lumos, la cascade fait le travail.
Le système trigger/state de Lumos remplace les sélecteurs descendants CSS par des variables CSS qui flippent entre 0 et 1. Les enfants réagissent en lisant la variable, sans jamais cibler un parent ou un état dans leur sélecteur.
En Client-First (ou en CSS classique), pour changer la couleur d'un texte au hover d'un bouton, tu écrirais :
css
/* Approche classique avec sélecteur descendant */
.button:hover .button_text {
color: white;
}
En Lumos, tu ne cibles jamais un état dans le sélecteur. Tu utilises data-trigger="hover focus" sur l'élément interactif, et les enfants lisent les variables --_trigger---on et --_trigger---off :
css
.hero_button {
background-color: color-mix(
in hsl,
var(--_theme---button-primary--background) calc(100% * var(--_trigger---on)),
var(--_theme---button-primary--background-hover) calc(100% * var(--_trigger---off))
);
transition: all 300ms;
}
Au repos, --_trigger---on vaut 1 et --_trigger---off vaut 0. Au hover, ça flip. Le color-mix() interpole entre les deux valeurs.
Pour les états (tabs actifs, accordéons ouverts), c'est le même principe avec --_state---true / --_state---false :
css
/* L'opacité change selon l'état actif */
.tabs_link_text {
opacity: var(--_state---false);
}
/* La barre de soulignement scale selon l'état */
.tabs_link_bar {
transform: scaleY(calc(var(--_state---false)));
transition: transform 300ms;
}
La règle d'or : true/on toujours en premier, false/off en second dans tes expressions. Et jamais, jamais de .is-active ou [data-state] dans un sélecteur CSS. Tu lis uniquement les valeurs des variables.
Après avoir accompagné plusieurs migrations chez Klyra, voici les pièges les plus fréquents.
1. Mettre un grid sur u-container. C'est le réflexe numéro un. En Client-First, tu mets ton layout directement dans le container. En Lumos, le container a container-type: inline-size : le layout doit aller sur un enfant _layout.
2. Utiliser des @media queries au lieu des variables responsive. Si tu écris @media (max-width: 768px), tu fais du Client-First dans Lumos. Utilise display: var(--flex-medium, grid) et flex-direction: var(--column-medium, row).
3. Utiliser des px au lieu de rem. Lumos interdit le px partout (sauf border-width qui utilise la variable --border-width--main). Les textes en max-width utilisent ch. Les breakpoints dans @container utilisent em. Tout le reste, c'est rem.
4. Mettre false/off avant true/on dans les expressions. Dans un color-mix() ou un calc(), l'ordre est toujours true/on d'abord. Si tu inverses, les valeurs ne correspondent plus aux états attendus.
5. Écrire des sélecteurs descendants. En Client-First, .nav_link.w--current .nav_link_text est normal. En Lumos, c'est interdit. Tu utilises data-state="current" sur le parent et .nav_link_text { opacity: var(--_state---false); } sur l'enfant.
Migrer de Client-First à Lumos, c'est investir du temps pour en gagner beaucoup plus ensuite. Le responsive sans breakpoints accélère chaque build. Le theming par cascade élimine les doublons. Le système trigger/state rend le CSS plus propre et plus maintenable.
La courbe d'apprentissage est réelle, surtout les deux premières semaines. Mais une fois que tu as intégré les patterns (variables responsive, trigger/state, structure section/container/layout), tu ne veux plus revenir en arrière.
L'écosystème Webflow pousse clairement vers plus de variables, plus de composants, plus de container queries. Lumos est aligné avec cette direction. Client-First reste pertinent pour les petits projets ou les équipes juniors, mais pour les builds complexes et scalables, Lumos est le bon choix.
Besoin d'accompagnement sur votre migration Lumos ? Chez Klyra, studio spécialisé Lumos, c'est notre spécialité.
FAQ's
Frequently Asked Questions
Pas forcément. Si ton site Client-First fonctionne bien et n'a pas besoin d'évoluer significativement, la migration n'apporte pas assez de valeur pour justifier le temps investi. En revanche, si tu prévois une refonte ou un scaling important du site, c'est le bon moment pour passer à Lumos dès le début du nouveau build.
Lumos est plus technique que Client-First pour un client non-développeur. Les noms de classes sont moins descriptifs, et le système de variables demande une compréhension minimale du CSS. Pour les projets où le client intervient régulièrement dans le Designer, Client-First reste souvent le meilleur choix. Pour les projets gérés par un développeur, Lumos prend l'avantage.
Compte environ deux à trois semaines de pratique intensive pour être à l'aise avec les concepts clés (variables responsive, trigger/state, nommage). Le premier projet complet prend environ 30% de temps en plus que d'habitude. Dès le deuxième projet, tu commences à aller plus vite qu'en Client-First sur les builds complexes.
Oui, et c'est même l'un de ses points forts. L'approche par composants de Lumos est conçue pour s'intégrer aux composants natifs de Webflow. Le CMS fonctionne normalement avec les classes Lumos. Les variables modes permettent même de changer le thème d'un composant CMS selon son contexte d'affichage.
Techniquement oui, mais c'est déconseillé. Les conventions de nommage, le système de spacing et l'approche responsive sont fondamentalement différents. Mixer les deux créera de la confusion pour tout développeur qui reprend le projet plus tard. Choisis un framework et tiens-le sur l'ensemble du build.
